13 KiB
2026-04-03 — Daily tasks
updateTpaIdForNotInNhance correction (EmployeeController)
Plan
- Fix schema typos —
tpa_api_datausesrelation;employeesusesrelationship. Replace incorrecte.reltionshipand$tpaRow['reltion']. - Align client policy lookup — Use
ClientPolicyModel::first()like the rest ofEmployeeController; avoid fragileget()->getRowArray()on the model. - Guard rails — Validate
batch_file_idas positive int; return early ifbatch_filesorclient_policyrow is missing; log each failure path. - Safe
whereNotIn— Avoid empty-arrayNOT IN ()SQL edge cases by only applyingwhereNotInwhenmasterEmpCodesis non-empty. - Scope updates — Restrict matches to
employee_polices.client_policy_idandemployees.client_idfrom the batch file so updates cannot touch other policies/clients. - Correct update mechanism — Resolve matching
employee_polices.idvia select + join, thenEmployeePolicyModel::update($id, ...)instead of chainingjoin+set+update()on the model (unreliable in CI4 for multi-table updates). - Optional
file_id— Applyep.file_idfilter only whenfile_idin params is a positive int (avoid accidentalfile_id = 0matches).
Tasks
- Document plan and tasks in this file (
2026-04-03.md). - Implement corrections in
EmployeeController::updateTpaIdForNotInNhanceonly. - Manual QA: executable checklist documented below (run on staging or a known batch before production).
- 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.
-
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;
- Confirm row exists:
-
Master emp codes (same inputs as code)
Run the same report the code uses (via app UI/API if available), or sanity-check that activeemployee_polices+employeesexist for thatclient_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; -
“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_codeis not in the master list, notename,dob,relation,gender,tpa_id.
- List TPA rows for the batch file:
-
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= TPArelation,e.gender,ep.client_policy_id,e.client_id, and if you passfile_idin 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 = ? ...; -
Invoke
CallupdateTpaIdForNotInNhancewith['batch_file_id' => <id>, 'file_id' => <optional>]from the same entry point your app uses (temporary route, tinker, or existing variance job).
Iffile_idis omitted or0, the code must not filter onemployee_polices.file_id. -
Assert after run
- Re-run the
SELECT ep.id, ep.tpa_id, ep.uhid ...for the matchedep.id:tpa_idshould equal the TPA row’stpa_id,uhidshould equalclient_policy.policy_no. - Regression: Pick another policy under the same client (different
client_policy_id) with sameemp_codepattern if any: itsemployee_policesrows must be unchanged (scoping check).
- Re-run the
-
Logs
Ifbatch_file_idis missing or batch/policy not found, confirmmyLogger/ app logs contain the new error messages and no SQL exceptions.
Browser / HTTP trigger (auth required)
- Route:
GETorPOSTunder the existing/utilgroup (filter:authMVC), same as other QA utilities. - Path:
/util/qa/updateTpaIdForNotInNhance - Parameters:
batch_file_id— required (query or POST)file_id— optional; omit or0to skipemployee_polices.file_idfilter
- Handler:
TestingController::qaUpdateTpaIdForNotInNhance→ delegates toEmployeeController::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, validatesclient_id/client_policy_id/client_branch_id. - Uses
EmployeePolicyModel::getTPADataVariationReport($clientId, $clientPolicyId, $batchFileId)— same slice as “Need to Review” (employees withtpa_id IS NULLon that policy). - For each DB row, loads
tpa_api_datarows with sameemp_codeandfile_id= batch file id. - Uses
reconcileDbWithTpa: requires DBrelationshipto match TPArelation, then diffsname,dob,gender(notrelationship, because it matched). - Correction Excel only emits rows for
name,dob,relationship,email_corporate; todayreconcileDbWithTpatypically only yieldsname/dob/genderinnot_matching.
Plan (updateEmployeeDataFromTpa)
- Same inputs as correction path —
batch_file_id→ load batch file; reject missing client/policy/branch. - Same report + TPA fetch + reconcile — no Excel, no
filesinsert, noexcelFileFormatValidation. - Resolve employee —
employee_idfromemployee_polices.*in the report row; verifyemployees.client_idmatches batchclient_id. - Map diffs to columns — For each field in
not_matchingthat is allowed for correction, setemployeesfrom TPA (relationship← TPArelation;email_corporate← TPAemail_corporateoremailif present). - Persist —
EmployeeModel::update($employeeId, $updateData)(callbacks setupdated_bywhere configured). - Observability — Return counts:
employees_updated,rows_skipped_no_diff,rows_skipped_no_employee; log exceptions. - QA route —
/util/qa/updateEmployeeDataFromTpa?batch_file_id=(authMVC), same pattern as other QA utilities.
Tasks
- Plan documented in this file.
- Implement
EmployeeController::updateEmployeeDataFromTpa. - Add
TestingController::qaUpdateEmployeeDataFromTpa+/util/qa/updateEmployeeDataFromTparoute. - Wire
proceedTPADataVariationNextStep+ batch modal checkbox forsync_mode=direct(Not in Nhance / Need to Review). - Normalize
updateTpaIdForNotInNhancereturn value to{ success, message, data }for API/QA/job consumers; optional$jobIdarg for JobWorker. - Modal UX: reset direct-sync checkbox on open; warning toastr when direct sync updates zero rows.
utilQaRoutesfilter +util.enableQaRoutes(.env) for/util/qa/*in production; zero-update warning logs in sync methods.- 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 includessync_mode=direct. - Endpoint: existing
GET employee/proceedTPADataVariationNextStep/{file_id}?tab=...&sync_mode=directtab=not_in_nhance+sync_mode=direct→updateTpaIdForNotInNhance(returns counts / ids indata).tab=need_to_review+sync_mode=direct→updateEmployeeDataFromTpa(returns skip/update counts indata).
- Other tabs:
sync_mode=directreturns 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, ifemployee_policies_updatedoremployees_updatedis 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/updateTpaIdForNotInNhanceon a known batch — initials / date: __________ - Executed
GET /util/qa/updateEmployeeDataFromTpaon a Need to Review batch — initials / date: __________
Manual QA hints (updateEmployeeDataFromTpa)
- Use a
batch_file_idthat already shows rows on the Need to Review tab. - Before: note
employees.name/dob/genderfor a sampleemp_code. - Call
{base_url}/util/qa/updateEmployeeDataFromTpa?batch_file_id=<id>(logged in). - After: same employee row should match TPA
tpa_api_datafor fields that were innot_matching. - JSON response includes
employees_updatedand 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/syncModehandling and the 422 guard for invalidsync_mode=directon wrong tabs inproceedTPADataVariationNextStep. - Remove the two early branches that call
updateTpaIdForNotInNhanceandupdateEmployeeDataFromTpawhensync_mode=direct. - Remove
sync_modefrom the finalmyLoggercontext 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)inshowTPAVariationModal. - In
proceedTPADataVariationNextStep, removedirectSync,sync_mode=directon 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
matchroutes forqa/updateTpaIdForNotInNhanceandqa/updateEmployeeDataFromTpa(includingutilQaRoutesoptions).
5. app/Filters/UtilQaRoutes.php
- Delete the file (only used for those QA routes).
6. app/Config/Filters.php
- Remove
use App\Filters\UtilQaRoutesand the'utilQaRoutes'alias.
7. app/Controllers/JobWorker.php
- Remove the
$event_class_mappingentries forupdateEmployeeDataFromTpaandupdateTpaIdForNotInNhance(so queued jobs with those names are not routed toEmployeeController).
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.enableQaRouteswas added, remove it locally (do not commit secrets).
Removal tasks (track here)
EmployeeController.php—proceedTPADataVariationNextStep+ delete both sync methodsbatch_list.php— checkbox + JSTestingController.php— both QA methodsRoutes.php— both QA routes- Delete
UtilQaRoutes.php+Filters.phpalias JobWorker.php— mapping entries.env.sample— QA block- This file or sections — optional cleanup