nhance/public/dev_logs/2026-04-03.md

172 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-04-03 — Daily tasks
## updateTpaIdForNotInNhance correction (EmployeeController)
### Plan
1. **Fix schema typos**`tpa_api_data` uses `relation`; `employees` uses `relationship`. Replace incorrect `e.reltionship` and `$tpaRow['reltion']`.
2. **Align client policy lookup** — Use `ClientPolicyModel::first()` like the rest of `EmployeeController`; avoid fragile `get()->getRowArray()` on the model.
3. **Guard rails** — Validate `batch_file_id` as positive int; return early if `batch_files` or `client_policy` row is missing; log each failure path.
4. **Safe `whereNotIn`** — Avoid empty-array `NOT IN ()` SQL edge cases by only applying `whereNotIn` when `masterEmpCodes` is non-empty.
5. **Scope updates** — Restrict matches to `employee_polices.client_policy_id` and `employees.client_id` from the batch file so updates cannot touch other policies/clients.
6. **Correct update mechanism** — Resolve matching `employee_polices.id` via select + join, then `EmployeePolicyModel::update($id, ...)` instead of chaining `join` + `set` + `update()` on the model (unreliable in CI4 for multi-table updates).
7. **Optional `file_id`** — Apply `ep.file_id` filter only when `file_id` in params is a positive int (avoid accidental `file_id = 0` matches).
### Tasks
- [x] Document plan and tasks in this file (`2026-04-03.md`).
- [x] Implement corrections in `EmployeeController::updateTpaIdForNotInNhance` only.
- [x] Manual QA: executable checklist documented below (run on staging or a known batch before production).
- [x] QA HTTP entry: `/util/qa/updateTpaIdForNotInNhance` (`TestingController::qaUpdateTpaIdForNotInNhance`, `authMVC`).
### Manual QA checklist (`updateTpaIdForNotInNhance`)
**Prereqs:** Pick a real `batch_files.id` that has `client_id`, `client_policy_id`, and linked `tpa_api_data.file_id` rows.
1. **Batch + policy**
- Confirm row exists: `SELECT id, client_id, client_policy_id FROM batch_files WHERE id = :batch_file_id;`
- Confirm policy exists: `SELECT id, policy_no FROM client_policy WHERE id = :client_policy_id;`
2. **Master emp codes (same inputs as code)**
Run the same report the code uses (via app UI/API if available), or sanity-check that active `employee_polices` + `employees` exist for that `client_id` + `client_policy_id`.
Spot-check: `SELECT e.emp_code FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = :client_policy_id AND e.client_id = :client_id AND ep.is_active = 1 AND ep.status = 'active' LIMIT 5;`
3. **“Not in Nhance” TPA rows for this file**
- List TPA rows for the batch file:
`SELECT id, emp_code, name, dob, relation, gender, tpa_id FROM tpa_api_data WHERE file_id = :batch_file_id AND is_active = 1;`
- For a test row whose `emp_code` is **not** in the master list, note `name`, `dob`, `relation`, `gender`, `tpa_id`.
4. **Matching employee_policy row (must exist for an update to happen)**
For that TPA row, confirm one row matches all of:
`e.emp_code`, `e.name`, `e.dob`, `e.relationship` = TPA `relation`, `e.gender`, `ep.client_policy_id`, `e.client_id`, and if you pass `file_id` in params, `ep.file_id`.
Example shape:
`SELECT ep.id, ep.tpa_id, ep.uhid, ep.file_id FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = ? AND e.client_id = ? AND e.emp_code = ? ...;`
5. **Invoke**
Call `updateTpaIdForNotInNhance` with `['batch_file_id' => <id>, 'file_id' => <optional>]` from the same entry point your app uses (temporary route, tinker, or existing variance job).
If `file_id` is omitted or `0`, the code must **not** filter on `employee_polices.file_id`.
6. **Assert after run**
- Re-run the `SELECT ep.id, ep.tpa_id, ep.uhid ...` for the matched `ep.id`: `tpa_id` should equal the TPA rows `tpa_id`, `uhid` should equal `client_policy.policy_no`.
- **Regression:** Pick another policy under the same client (different `client_policy_id`) with same `emp_code` pattern if any: its `employee_polices` rows must be **unchanged** (scoping check).
7. **Logs**
If `batch_file_id` is missing or batch/policy not found, confirm `myLogger` / app logs contain the new error messages and no SQL exceptions.
### Browser / HTTP trigger (auth required)
- **Route:** `GET` or `POST` under the existing **`/util`** group (filter: **`authMVC`**), same as other QA utilities.
- **Path:** `/util/qa/updateTpaIdForNotInNhance`
- **Parameters:**
- `batch_file_id` — required (query or POST)
- `file_id` — optional; omit or `0` to skip `employee_polices.file_id` filter
- **Handler:** `TestingController::qaUpdateTpaIdForNotInNhance` → delegates to `EmployeeController::updateTpaIdForNotInNhance`.
- **Example (logged-in session):**
`{base_url}/util/qa/updateTpaIdForNotInNhance?batch_file_id=123`
`{base_url}/util/qa/updateTpaIdForNotInNhance?batch_file_id=123&file_id=456`
**Production:** routes `/util/qa/updateTpaIdForNotInNhance` and `/util/qa/updateEmployeeDataFromTpa` are guarded by filter `utilQaRoutes`: in **`production`** they return **404 JSON** unless `.env` has **`util.enableQaRoutes = true`**. Non-production environments allow them without the flag (still require `authMVC` login).
**Server logs:** when direct sync / QA runs successfully but updates **zero** rows, `updateTpaIdForNotInNhance` and `updateEmployeeDataFromTpa` emit a **warning** via `myLogger` with batch id and context counts.
**Remove or restrict this route after QA** if you do not want it long-term in production (or leave the filter off unless `util.enableQaRoutes` is set).
---
## updateEmployeeDataFromTpa (Need to Review → direct DB sync)
### Review notes (`generateCorrectionUploadFromNeedToReview`)
- Loads `batch_files`, validates `client_id` / `client_policy_id` / `client_branch_id`.
- Uses `EmployeePolicyModel::getTPADataVariationReport($clientId, $clientPolicyId, $batchFileId)` — same slice as “Need to Review” (employees with `tpa_id IS NULL` on that policy).
- For each DB row, loads `tpa_api_data` rows with same `emp_code` and `file_id` = batch file id.
- Uses `reconcileDbWithTpa`: requires DB `relationship` to match TPA `relation`, then diffs `name`, `dob`, `gender` (not `relationship`, because it matched).
- Correction Excel only emits rows for `name`, `dob`, `relationship`, `email_corporate`; today `reconcileDbWithTpa` typically only yields `name` / `dob` / `gender` in `not_matching`.
### Plan (`updateEmployeeDataFromTpa`)
1. **Same inputs as correction path**`batch_file_id` → load batch file; reject missing client/policy/branch.
2. **Same report + TPA fetch + reconcile** — no Excel, no `files` insert, no `excelFileFormatValidation`.
3. **Resolve employee**`employee_id` from `employee_polices.*` in the report row; verify `employees.client_id` matches batch `client_id`.
4. **Map diffs to columns** — For each field in `not_matching` that is allowed for correction, set `employees` from TPA (`relationship` ← TPA `relation`; `email_corporate` ← TPA `email_corporate` or `email` if present).
5. **Persist**`EmployeeModel::update($employeeId, $updateData)` (callbacks set `updated_by` where configured).
6. **Observability** — Return counts: `employees_updated`, `rows_skipped_no_diff`, `rows_skipped_no_employee`; log exceptions.
7. **QA route**`/util/qa/updateEmployeeDataFromTpa?batch_file_id=` (authMVC), same pattern as other QA utilities.
### Tasks
- [x] Plan documented in this file.
- [x] Implement `EmployeeController::updateEmployeeDataFromTpa`.
- [x] Add `TestingController::qaUpdateEmployeeDataFromTpa` + `/util/qa/updateEmployeeDataFromTpa` route.
- [x] Wire `proceedTPADataVariationNextStep` + batch modal checkbox for `sync_mode=direct` (Not in Nhance / Need to Review).
- [x] Normalize `updateTpaIdForNotInNhance` return value to `{ success, message, data }` for API/QA/job consumers; optional `$jobId` arg for JobWorker.
- [x] Modal UX: reset direct-sync checkbox on open; warning toastr when direct sync updates zero rows.
- [x] `utilQaRoutes` filter + `util.enableQaRoutes` (.env) for `/util/qa/*` in production; zero-update **warning** logs in sync methods.
- [x] Manual QA: procedure and QA URLs documented below; run on staging with a real batch when available (compare `employees_updated` / skips to expected mismatches; optional parity with correction Excel row count).
### Production UI: direct sync (`sync_mode=direct`)
- **TPA variation modal** (`batch_list.php`): checkbox *“Sync directly to database (skip Excel)”* — when checked and user clicks **Proceed** on **Not in Nhance** or **Need to Review**, the request includes `sync_mode=direct`.
- **Endpoint:** existing `GET employee/proceedTPADataVariationNextStep/{file_id}?tab=...&sync_mode=direct`
- `tab=not_in_nhance` + `sync_mode=direct``updateTpaIdForNotInNhance` (returns counts / ids in `data`).
- `tab=need_to_review` + `sync_mode=direct``updateEmployeeDataFromTpa` (returns skip/update counts in `data`).
- **Other tabs:** `sync_mode=direct` returns **422** with a clear message (e.g. Not in TPA).
- **Default (checkbox off):** unchanged behaviour — Excel generation + existing pipelines.
- **UX safeguards** (`batch_list.js`): opening the TPA variation modal **unchecks** “direct sync” so it is not left on for another file. After **Proceed** with direct sync, if `employee_policies_updated` or `employees_updated` is **0**, the UI shows a **NOTICE** (warning) toastr instead of success-only, with a short hint to verify Nhance vs TPA matches.
### Sign-off (staging / UAT)
- [ ] Executed `GET /util/qa/updateTpaIdForNotInNhance` on a known batch — initials / date: __________
- [ ] Executed `GET /util/qa/updateEmployeeDataFromTpa` on a Need to Review batch — initials / date: __________
### Manual QA hints (`updateEmployeeDataFromTpa`)
- Use a `batch_file_id` that already shows rows on the **Need to Review** tab.
- Before: note `employees.name` / `dob` / `gender` for a sample `emp_code`.
- Call `{base_url}/util/qa/updateEmployeeDataFromTpa?batch_file_id=<id>` (logged in).
- After: same employee row should match TPA `tpa_api_data` for fields that were in `not_matching`.
- JSON response includes `employees_updated` and skip counters for quick sanity check.
---
## Removal checklist — direct-to-database TPA sync (pending confirmation)
**Status:** Not applied in code yet. When you confirm, remove the items below so TPA variation **Proceed** uses **Excel-only** paths: `generateEmployeeUploadFromNotInNhance` and `generateCorrectionUploadFromNeedToReview` only.
### 1. `app/Controllers/EmployeeController.php`
- Remove **`sync_mode` / `syncMode`** handling and the **422** guard for invalid `sync_mode=direct` on wrong tabs in **`proceedTPADataVariationNextStep`**.
- Remove the two **early branches** that call **`updateTpaIdForNotInNhance`** and **`updateEmployeeDataFromTpa`** when `sync_mode=direct`.
- Remove **`sync_mode`** from the final **`myLogger`** context in that method (if present).
### 2. `app/Views/batch_list.php`
- Remove the **modal footer** block: checkbox **`#tpaVariationDirectSync`** + label (“Sync directly to database…”).
- Remove **`$('#tpaVariationDirectSync').prop('checked', false)`** in **`showTPAVariationModal`**.
- In **`proceedTPADataVariationNextStep`**, remove **`directSync`**, **`sync_mode=direct`** on the URL, and the **zero-update NOTICE** / extra message logic; restore simple success/warning behaviour.
### 3. `app/Controllers/TestingController.php`
- Remove **`qaUpdateTpaIdForNotInNhance`**.
- Remove **`qaUpdateEmployeeDataFromTpa`**.
### 4. `app/Config/Routes.php` (under `/util` group)
- Remove the two **`match`** routes for **`qa/updateTpaIdForNotInNhance`** and **`qa/updateEmployeeDataFromTpa`** (including **`utilQaRoutes`** options).
### 5. `app/Filters/UtilQaRoutes.php`
- **Delete the file** (only used for those QA routes).
### 6. `app/Config/Filters.php`
- Remove **`use App\Filters\UtilQaRoutes`** and the **`'utilQaRoutes'`** alias.
### 7. `app/Controllers/JobWorker.php`
- Remove the **`$event_class_mapping`** entries for **`updateEmployeeDataFromTpa`** and **`updateTpaIdForNotInNhance`** (so queued jobs with those names are not routed to `EmployeeController`).
### 8. `.env.sample`
- Remove the **`util.enableQaRoutes`** / UTIL QA block.
### 9. `public/dev_logs/2026-04-03.md`
- **Either** delete this file **or** delete/trim sections that only document direct DB / QA / `sync_mode` (optional cleanup after code removal).
### 10. Local `.env` (manual)
- If **`util.enableQaRoutes`** was added, remove it locally (do not commit secrets).
### Removal tasks (track here)
- [ ] `EmployeeController.php``proceedTPADataVariationNextStep` + delete both sync methods
- [ ] `batch_list.php` — checkbox + JS
- [ ] `TestingController.php` — both QA methods
- [ ] `Routes.php` — both QA routes
- [ ] Delete `UtilQaRoutes.php` + `Filters.php` alias
- [ ] `JobWorker.php` — mapping entries
- [ ] `.env.sample` — QA block
- [ ] This file or sections — optional cleanup