nhance/app/Views/docs/inception.php
2026-05-22 15:01:14 +05:30

390 lines
16 KiB
PHP
Raw 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.

<?php
/**
* Inception (employee Excel upload) — content only
* app/Views/docs/inception.php
*
* Based on:
* - app/Views/employee_upload.php
* - app/Controllers/EmployeeServiceController.php
* (excelFileFormatValidation, excelFileDataValidation, employeesOnboardPreprocess)
* - app/Controllers/EmployeeController.php (upload entry)
* - app/Controllers/JobWorker.php (background jobs)
*/
?>
<p>
<strong>Inception</strong> here means onboarding employees and dependents from an Excel upload
(<code>files.action = inception</code> or related actions like <code>missed_inception</code>,
<code>addition</code>, <code>dependent_addition</code>). The same three-step pipeline runs for those
actions; this page focuses on the <strong>inception</strong> path.
</p>
<p>
Manual policy inception (form UI under <code>policy_tranction/inception</code>) is a separate flow
in <code>PolicyTransactionController</code> — not covered by these three functions.
</p>
<h2 id="overview">Overview</h2>
<div class="mermaid-wrapper">
<div class="mermaid">
flowchart LR
A["Upload Excel on employee upload"] --> B["excelFileFormatValidation"]
B --> C["excelFileDataValidation"]
C --> D["employeesOnboardPreprocess"]
D --> E["employeesOnboardProcess plus policy_transaction"]
B -->|errors| F["files.status failed"]
C -->|errors| F
D -->|no families inserted| F
D -->|OK| G["files.status success"]
</div>
</div>
<p><strong>In short:</strong></p>
<ul>
<li><strong>Step 1 — Format:</strong> Headers, column count/order, per-cell type and mandatory rules.</li>
<li><strong>Step 2 — Data:</strong> Family-level checks (Self row, duplicates, policy terms, DB conflicts).</li>
<li><strong>Step 3 — Preprocess:</strong> Premium via rack rates, then insert employees and inception policy transaction.</li>
<li>Large files (&gt; 1 MB) run steps 13 as background jobs via <code>JobWorker</code>.</li>
</ul>
<h2 id="key-files-routes">Key files and routes</h2>
<table>
<thead>
<tr><th>Area</th><th>Location</th></tr>
</thead>
<tbody>
<tr>
<td>UI</td>
<td><code>app/Views/employee_upload.php</code> — client, branch, policy, action <strong>Inception</strong>, file upload</td>
</tr>
<tr>
<td>Upload handler</td>
<td><code>EmployeeController::employeesUplodWithEvents</code></td>
</tr>
<tr>
<td>Pipeline logic</td>
<td><code>EmployeeServiceController</code> — the three functions on this page</td>
</tr>
<tr>
<td>Job dispatch</td>
<td><code>app/Controllers/JobWorker.php</code> — maps job names to <code>EmployeeServiceController</code></td>
</tr>
<tr>
<td>Column / Excel helpers</td>
<td><code>app/Helpers/excel_util_helper.php</code> — <code>check_columns_name</code>, custom validators</td>
</tr>
<tr>
<td>Upload record</td>
<td><code>files</code> table via <code>FileModel</code> — <code>status</code>, <code>action</code>, <code>reason</code></td>
</tr>
<tr>
<td>Premium</td>
<td><a href="<?= base_url('docs/eb-rack-rate-calculation') ?>">EB rack rate calculation</a> — <code>calculate_premium_new</code>, <code>employeesOnboardProcess</code></td>
</tr>
</tbody>
</table>
<p><strong>Routes</strong> (group <code>/employee</code>, filter <code>authMVC</code>):</p>
<ul>
<li><code>GET /employee/upload</code> — upload screen</li>
<li><code>POST /employee/upload</code> — upload + start validation (<code>upload-action-type=inception</code>)</li>
<li><code>GET /employee/excel_error/{file_id}</code> — returns <code>files.reason</code> JSON for the error modal</li>
</ul>
<p>
REST upload (mobile/HR): <code>POST employeeRest/employeeUpload</code> — same pipeline via
<code>EmployeeRestController</code>.
</p>
<div class="callout info">
<span>i</span>
<div>
<strong><code>files.policy_id</code></strong> stores <strong>client policy id</strong> (<code>client_policies.id</code>),
not the insurer policy master id. Slab/rack lookups use this id with <code>client_id</code>.
</div>
</div>
<h2 id="sync-vs-jobs">Sync vs background jobs</h2>
<table>
<thead>
<tr><th>File size</th><th>Step 1</th><th>Steps 23</th></tr>
</thead>
<tbody>
<tr>
<td>&lt; 1 MB</td>
<td><code>excelFileFormatValidation</code> runs inline in the upload request</td>
<td>Always queued: <code>excelFileDataValidation</code> → <code>employeesOnboardPreprocess</code></td>
</tr>
<tr>
<td>≥ 1 MB</td>
<td>Job <code>excelFileFormatValidation</code></td>
<td>Same job chain after format passes</td>
</tr>
</tbody>
</table>
<p>
After upload the UI usually shows <code>files.status = inprogress</code> until jobs finish.
Poll notifications or refresh the upload list; use <code>/employee/excel_error/{id}</code> when status is <code>failed</code>.
</p>
<h2 id="entry-points">Entry points</h2>
<p>Job chain for inception (and missed_inception / addition / dependent_addition):</p>
<p><code>excelFileFormatValidation</code> → <code>excelFileDataValidation</code> → <code>employeesOnboardPreprocess</code></p>
<h2 id="format-validation">Step 1: excelFileFormatValidation</h2>
<p>Runs on the uploaded sheet before any DB business rules.</p>
<ul>
<li>Loads file from <code>writable/uploads/excel/{file_name}</code>.</li>
<li>Uses <code>$inception_excel_columns</code> when <code>action</code> is inception (same column set for addition / dependent_addition / missed_inception).</li>
<li>Checks policy has terms and slab rates configured — otherwise fails early.</li>
<li>Validates each data row: mandatory (by action code <code>I</code>), date/mobile formats, allowed lists, custom helpers (DOB, relationship, SI, mobile duplicate, etc.).</li>
<li>Stops at first empty row (treated as end of data).</li>
</ul>
<h3 id="format-errors">Common format error codes</h3>
<table>
<thead>
<tr><th>Code</th><th>Meaning</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>Mandatory value missing</td></tr>
<tr><td>2</td><td>Wrong format (e.g. date, mobile)</td></tr>
<tr><td>3</td><td>Value not in allowed list</td></tr>
<tr><td>4</td><td>Custom validation failed (DOB, relationship, SI, etc.)</td></tr>
<tr><td>5</td><td>File / policy / slab configuration problem</td></tr>
<tr><td>6</td><td>Column headers wrong or out of order</td></tr>
</tbody>
</table>
<p>On failure: <code>files.status = failed</code>, <code>reason</code> JSON with row/column errors; user notification via pull notification.</p>
<p><strong>Lead-policy branch:</strong> If inception file is for a policy created from leads (<code>policy_entry_from == 3</code> and <code>is_from_lead</code> set), format validation queues <code>compareMemberDataAndInceptionData</code> instead of going straight to data validation.</p>
<h3 id="reason-json">files.reason shape (debugging)</h3>
<p>Stored as JSON string on <code>files.reason</code>. Typical failure payload:</p>
<pre><code>{
"error_type": 1,
"error_summary": { "4": 2, "1": 1 },
"error_data": {
"3": {
"dob": { "error": ["Invalid date format"], "value": "01/01/1990" }
}
}
}</code></pre>
<ul>
<li><code>error_type</code> — <code>1</code> = format step, <code>2</code> = data step</li>
<li><code>error_summary</code> — counts per error code (after aggregation)</li>
<li><code>error_data</code> — keyed by <strong>Excel row number</strong> (1-based, header is row 1)</li>
</ul>
<h2 id="data-validation">Step 2: excelFileDataValidation</h2>
<p>Runs after format passes. Groups rows by <strong>EMP ID</strong> (family) and applies business rules.</p>
<div class="mermaid-wrapper">
<div class="mermaid">
flowchart TD
A["Group rows by emp_id"] --> B{"Self in family?"}
B -->|No| C["Error: Self not found"]
B -->|Yes| D{"Duplicate name in family?"}
D -->|Yes| E["Error: Twofold name"]
D -->|No| F{"Emp code already in DB?"}
F -->|Yes| G["Error: duplicate emp code"]
F -->|No| H{"Dependents match policy terms?"}
H -->|No| I["Dependent conflict errors"]
H -->|Yes| J["Row OK for this family"]
</div>
</div>
<p>Typical inception checks:</p>
<ul>
<li><strong>Self</strong> row required (unless GMC parents policy allows otherwise).</li>
<li>No duplicate names within the same family in the file.</li>
<li>Employee code must not already exist for inception / addition / enrollment.</li>
<li>Dependent rules vs <code>policy_terms</code> (family composition, LGBTQ flag, etc.).</li>
<li>Name + emp id consistency vs database (<code>name_and_empid_check_in_db</code>).</li>
</ul>
<p>On success for inception: queues job <code>employeesOnboardPreprocess</code>. Other actions queue different jobs (deletion, correction, etc.).</p>
<h3 id="data-errors">Common data-validation error codes</h3>
<table>
<thead>
<tr><th>Code</th><th>Meaning</th></tr>
</thead>
<tbody>
<tr><td>7</td><td>Duplicate name within same family in the Excel file</td></tr>
<tr><td>9</td><td>Record already exists in DB (inception / addition)</td></tr>
<tr><td>10</td><td>Record not found (used on deletion flows)</td></tr>
<tr><td>14</td><td>Self row missing in family</td></tr>
<tr><td>26</td><td>Duplicate employee code in file or DB</td></tr>
</tbody>
</table>
<h2 id="preprocess">Step 3: employeesOnboardPreprocess</h2>
<p>Calculates premium and writes members to the database.</p>
<ol>
<li>Reload Excel; group by <code>emp_id</code>.</li>
<li>For each family: <code>calculate_premium_new()</code> using policy terms + slab rates + rack config.</li>
<li><code>employeesOnboardProcess()</code> — insert/update <code>employees</code>, <code>employee_polices</code>, create <code>policy_transaction</code> (inception).</li>
<li>If at least one family inserted → <code>files.status = success</code>; else failed with rack-rate message.</li>
</ol>
<p>
Optional second path: <code>client_policy_id</code> without <code>file_id</code> — converts enrolled DB members
to inception (enrollment → inception), not from Excel.
</p>
<p>
<strong>TPA batch:</strong> When <code>batch_file_id</code> is present on the job payload, success also queues
<code>updateEmployeeDataFromTpa</code>, <code>reconTpaApiDataWithEmployeepolicies</code>, and
<code>initializeDeletionProcessForTpaApiData</code> (multi-file TPA reconcile flow).
</p>
<h2 id="excel-columns">Inception Excel columns</h2>
<p>
Defined in <code>EmployeeServiceController::$inception_excel_columns</code>.
Header row must match exactly — <strong>19 columns (AS)</strong>, row 1 only.
Dates use format <code>d-M-Y</code> (e.g. <code>4-Apr-1990</code>).
One <strong>Self</strong> row per <strong>EMP ID</strong>; other rows are dependents.
</p>
<table>
<thead>
<tr><th>Col</th><th>Header</th><th>Required (inception)</th><th>Notes</th></tr>
</thead>
<tbody>
<tr><td>A</td><td>S.No</td><td>Yes</td><td></td></tr>
<tr><td>B</td><td>EMP ID</td><td>Yes</td><td>Family key</td></tr>
<tr><td>C</td><td>NAME OF EMP/DEP</td><td>Yes</td><td></td></tr>
<tr><td>D</td><td>DOB</td><td>Yes</td><td><code>d-M-Y</code>; age vs relationship checked</td></tr>
<tr><td>E</td><td>Gender</td><td>Yes</td><td>M / F (several casings allowed)</td></tr>
<tr><td>F</td><td>RELATIONSHIP</td><td>Yes</td><td>Self, Spouse, Son, Daughter, …</td></tr>
<tr><td>G</td><td>BASIC COVER SI</td><td>Conditional</td><td>Validated against slab when applicable</td></tr>
<tr><td>H</td><td>Date of Coverage</td><td>No</td><td>Mandatory for addition / DA only</td></tr>
<tr><td>I</td><td>DOJ</td><td>No</td><td></td></tr>
<tr><td>J</td><td>Basic Pay</td><td>No</td><td>Used when policy terms need it</td></tr>
<tr><td>K</td><td>Band/Grade</td><td>No</td><td></td></tr>
<tr><td>L</td><td>Designation</td><td>No</td><td></td></tr>
<tr><td>M</td><td>Phone</td><td>No</td><td>Mobile format; duplicate check</td></tr>
<tr><td>N</td><td>Email</td><td>No</td><td>Duplicate check in file</td></tr>
<tr><td>O</td><td>PRE EXISTING AILMENTS</td><td>Yes</td><td><code>0</code> or <code>1</code></td></tr>
<tr><td>P</td><td>Change event</td><td>No</td><td>Not used for pure inception</td></tr>
<tr><td>Q</td><td>Date of exit</td><td>No</td><td>Deletion only</td></tr>
<tr><td>R</td><td>Reason for exit</td><td>No</td><td>Deletion only</td></tr>
<tr><td>S</td><td>Unit</td><td>No</td><td>Must match branch units when filled</td></tr>
</tbody>
</table>
<p>Sample file: use the download link on the employee upload screen (environment-specific).</p>
<h2 id="family-example">Family row layout example</h2>
<p>
All rows with the same <strong>EMP ID</strong> (column B) are treated as one family.
Step 2 requires exactly one <strong>Self</strong> row in that group; dependents share the same EMP ID.
Step 3 runs premium and DB insert once per family.
</p>
<p><strong>Example:</strong> one employee (<code>EMP001</code>) with spouse and son — three data rows plus header.</p>
<table>
<thead>
<tr>
<th>Row</th>
<th>S.No</th>
<th>EMP ID</th>
<th>NAME</th>
<th>DOB</th>
<th>Gender</th>
<th>RELATIONSHIP</th>
<th>BASIC COVER SI</th>
<th>PED</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td colspan="8"><em>Header row (all 19 columns AS required in file)</em></td></tr>
<tr>
<td>2</td>
<td>1</td>
<td>EMP001</td>
<td>Raj Kumar</td>
<td>15-Jan-1985</td>
<td>M</td>
<td>Self</td>
<td>500000</td>
<td>0</td>
</tr>
<tr>
<td>3</td>
<td>2</td>
<td>EMP001</td>
<td>Priya Kumar</td>
<td>20-Mar-1988</td>
<td>F</td>
<td>Spouse</td>
<td>500000</td>
<td>0</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>EMP001</td>
<td>Arjun Kumar</td>
<td>10-Jun-2015</td>
<td>M</td>
<td>Son</td>
<td>500000</td>
<td>0</td>
</tr>
</tbody>
</table>
<p><strong>Rules illustrated:</strong></p>
<ul>
<li><strong>Same EMP ID</strong> on rows 24 → one family processed in step 3.</li>
<li><strong>Self</strong> on row 2 only — row 3 without Self would fail with code 14.</li>
<li><strong>DOB</strong> uses <code>d-M-Y</code>; ages are checked against relationship (e.g. Son vs Self).</li>
<li><strong>PED</strong> (PRE EXISTING AILMENTS) = <code>0</code> or <code>1</code> on every member for inception.</li>
<li><strong>BASIC COVER SI</strong> must match slab rules when the policy uses SI-based racks (often same amount across the family).</li>
<li>Columns HS can be blank for inception when not mandatory; phone/email must be unique in the file if filled.</li>
</ul>
<p>
A second employee in the same file uses a <strong>different EMP ID</strong> (e.g. <code>EMP002</code>) with its own Self row — each EMP ID is a separate family loop in preprocess.
</p>
<h2 id="developer-steps">Developer steps</h2>
<ol>
<li>Confirm policy has <code>policy_terms</code> JSON and slab/rack rates for the client policy.</li>
<li>Upload via <code>/employee/upload</code> with action <code>inception</code>; note <code>file_id</code> in response or <code>files</code> table.</li>
<li>If <code>status = failed</code>, call <code>GET /employee/excel_error/{file_id}</code> or read <code>files.reason</code>.</li>
<li>Map <code>error_data</code> row keys back to Excel (row 1 = header).</li>
<li>If format passes but preprocess fails with rack message, debug <code>calculate_premium_new</code> (see rack-rate doc) and SI/slab config.</li>
<li>For stuck <code>inprogress</code>, check job queue / <code>JobWorker</code> logs for the three job names.</li>
</ol>
<h2 id="pitfalls">Common pitfalls</h2>
<ul>
<li><strong>Policy not ready</strong> — missing <code>policy_terms</code> or slab rates fails step 1 with code 5.</li>
<li><strong>Missing Self row</strong> — one Self per EMP ID in the file (code 14 in step 2).</li>
<li><strong>Wrong header row</strong> — column count or name mismatch (code 5 / 6).</li>
<li><strong>Rack rate / SI</strong> — preprocess succeeds only if <code>calculate_premium_new</code> returns data for every family.</li>
<li><strong>File status</strong> — watch <code>files.reason</code> JSON for row-level errors after failure.</li>
</ul>