172 lines
13 KiB
Markdown
172 lines
13 KiB
Markdown
# 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 row’s `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
|