From e30c17ae37157f1325fa23f593aba1eb15898e51 Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Fri, 31 Jul 2026 18:21:28 +0530 Subject: [PATCH 1/3] FIX_THE_REQIUIRED --- app/Views/employee_data_list.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Views/employee_data_list.php b/app/Views/employee_data_list.php index 56126102..2e15874e 100755 --- a/app/Views/employee_data_list.php +++ b/app/Views/employee_data_list.php @@ -434,8 +434,8 @@ $gst_total = 0;
- - + +
From bf2908723afe3bacf1dd7c717ae981c430b9ca10 Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Sat, 1 Aug 2026 11:56:03 +0530 Subject: [PATCH 2/3] FIX_DIAGONSIS_COMMENTS --- app/Controllers/HrLoginDiagnoseController.php | 146 ++++++++-- app/Views/hr_login_diagnose.php | 264 +++++++++++++----- 2 files changed, 326 insertions(+), 84 deletions(-) diff --git a/app/Controllers/HrLoginDiagnoseController.php b/app/Controllers/HrLoginDiagnoseController.php index 0b7a1fa3..4ec2eb30 100644 --- a/app/Controllers/HrLoginDiagnoseController.php +++ b/app/Controllers/HrLoginDiagnoseController.php @@ -81,7 +81,11 @@ class HrLoginDiagnoseController extends AdminController 'HR_NOT_FOUND', 'high', 'No active HR found in post level_contacts for the given email/mobile (contact_type=client).', - 'Create/activate the HR contact under the correct client branch, or verify the email/mobile.' + [ + 'Option A: Verify email/mobile spelling and that level_contacts.contact_type = client and is_active = 1.', + 'Option B: Create/activate the HR contact under the correct client_branch (ref_id = branch id).', + 'Option C: If HR exists only in pre DB, create the matching post level_contacts row first.', + ] ); return [ @@ -89,6 +93,7 @@ class HrLoginDiagnoseController extends AdminController 'overall_status' => 'FAIL', 'summary' => 'HR not found in post DB.', 'issues' => $issues, + 'problems' => $issues, 'post' => ['contacts' => []], 'hr_access_control'=> [], 'pre' => ['reachable' => null, 'mappings' => []], @@ -102,6 +107,7 @@ class HrLoginDiagnoseController extends AdminController $accessRows = []; $preMaps = []; $loginCards = []; + $pairRows = []; $preReachable = null; try { @@ -115,7 +121,11 @@ class HrLoginDiagnoseController extends AdminController 'PRE_DB_UNREACHABLE', 'high', 'Could not connect to preDB: ' . $e->getMessage(), - 'Check preDB credentials in Database config / .env.' + [ + 'Option A: Check preDB hostname/database/username/password in app/Config/Database.php or .env.', + 'Option B: Confirm pre DB server is reachable from this host (network/firewall).', + 'Option C: Re-run diagnose after connectivity is restored to validate PRE mapping.', + ] ); } @@ -130,16 +140,24 @@ class HrLoginDiagnoseController extends AdminController $issues[] = $this->issue( 'BRANCH_INACTIVE', 'high', - "Branch inactive for post_hr_id={$contact['post_hr_id']} (branch #{$contact['post_branch_id']}).", - 'Activate client_branch.is_active=1 for this branch.' + "Branch inactive for post_hr_id={$contact['post_hr_id']} (branch #{$contact['post_branch_id']}, {$contact['branch_name']}).", + [ + "Option A: UPDATE client_branch SET is_active=1 WHERE id={$contact['post_branch_id']};", + 'Option B: In Client Onboarding, activate this branch and re-check login.', + 'Note: Login join requires client_branch.is_active=1.', + ] ); } if (!$flags['CLIENT_ACTIVE']) { $issues[] = $this->issue( 'CLIENT_INACTIVE', 'high', - "Client inactive for post_hr_id={$contact['post_hr_id']} (client #{$contact['post_client_id']}).", - 'Activate clients.is_active=1 for this client.' + "Client inactive for post_hr_id={$contact['post_hr_id']} (client #{$contact['post_client_id']}, {$contact['client_name']}).", + [ + "Option A: UPDATE clients SET is_active=1 WHERE id={$contact['post_client_id']};", + 'Option B: Activate the client in admin and re-run diagnose.', + 'Note: Login join requires clients.is_active=1.', + ] ); } @@ -160,8 +178,12 @@ class HrLoginDiagnoseController extends AdminController $issues[] = $this->issue( 'NO_HR_ACCESS_CONTROL_ROW', 'high', - "No hr_access_control row for post_hr_id={$contact['post_hr_id']}, post_branch_id={$contact['post_branch_id']}, post_client_id={$contact['post_client_id']}.", - 'Open Client Onboarding → HR Access and save at least one module for this HR/branch.' + "No hr_access_control row for post_hr_id={$contact['post_hr_id']}, post_branch_id={$contact['post_branch_id']}, post_client_id={$contact['post_client_id']} ({$contact['client_name']} / {$contact['branch_name']}).", + [ + 'Option A: Open Client Onboarding → HR Access for this client, select at least one module for this HR/branch, then Save.', + "Option B: Insert hr_access_control with post_hr_id={$contact['post_hr_id']}, post_branch_id={$contact['post_branch_id']}, post_client_id={$contact['post_client_id']} and allowed_modules JSON.", + 'Note: Without this row, getVerifiedHrData returns empty token for this card.', + ] ); } else { $modules = json_decode($access['allowed_modules'] ?? '[]', true); @@ -176,8 +198,12 @@ class HrLoginDiagnoseController extends AdminController $issues[] = $this->issue( 'EMPTY_ALLOWED_MODULES', 'high', - "hr_access_control id={$access['id']} exists but allowed_modules is empty.", - 'Assign pre/post modules in HR Access Control and save.' + "hr_access_control id={$access['id']} exists but allowed_modules is empty for post_hr_id={$contact['post_hr_id']}.", + [ + 'Option A: Open HR Access Control, tick PRE/POST modules for this HR, Save.', + "Option B: UPDATE hr_access_control SET allowed_modules='{\"pre\":[1],\"post\":[2,3,4]}' WHERE id={$access['id']}; (adjust module ids as needed).", + 'Note: Empty modules → token is treated as not ready.', + ] ); } } @@ -206,25 +232,52 @@ class HrLoginDiagnoseController extends AdminController if ($preReachable === true) { if (empty($preMap['PRE_BRANCH_LINKED'])) { + $postBranchId = (int) ($contact['post_branch_id'] ?? 0); $issues[] = $this->issue( 'PRE_BRANCH_NOT_LINKED', 'medium', - "Post branch #{$contact['post_branch_id']} has no valid pre_branch_id link.", - 'Set client_branch.pre_branch_id to the matching pre branch id.' + "Post branch #{$postBranchId} ({$contact['branch_name']}) has no valid pre_branch_id link (current pre_branch_id=" . ($contact['pre_branch_id'] ?? 'null') . ").", + [ + "Option A: Set client_branch.pre_branch_id on post branch #{$postBranchId} to the matching pre client_branch.id.", + 'Option B: Use Testing/mapping tools to sync post↔pre branch ids, then re-run diagnose.', + 'Option C: Confirm the pre branch exists and is_active=1 before linking.', + 'Note: Without this link, PRE HR/client mapping cannot be resolved.', + ] ); } elseif (empty($preMap['PRE_HR_MATCHED'])) { $issues[] = $this->issue( 'PRE_HR_NOT_MATCHED', 'medium', - "No pre level_contacts match for email+mobile under pre client #{$preMap['pre_client_id']}.", - 'Align email and mobile between pre and post HR contacts.' + "No pre level_contacts match for email/mobile under pre client #{$preMap['pre_client_id']} " + . "(post_hr_id={$contact['post_hr_id']}, email={$contact['hr_mail']}, mobile={$contact['hr_mobile']}).", + [ + 'Option A: Align email AND mobile between pre and post level_contacts for this HR.', + "Option B: Create/activate pre HR contact under pre client #{$preMap['pre_client_id']} with the same email/mobile.", + 'Option C: Check pre contact_type=client and is_active=1 on the matching branch.', + ] ); } elseif (empty($preMap['PRE_IDS_CONSISTENT']) && !empty($access)) { + $storedHr = (int) ($access['pre_hr_id'] ?? 0); + $storedClient = (int) ($access['pre_client_id'] ?? 0); + $storedBranch = (int) ($access['pre_branch_id'] ?? 0); + $liveHr = (int) ($preMap['pre_hr_id'] ?? 0); + $liveClient = (int) ($preMap['pre_client_id'] ?? 0); + $liveBranch = (int) ($preMap['pre_branch_id'] ?? 0); + $accessId = (int) ($access['id'] ?? 0); + $issues[] = $this->issue( 'PRE_IDS_INCONSISTENT', 'medium', - "hr_access_control pre ids do not match live pre data for post_hr_id={$contact['post_hr_id']}.", - 'Re-save HR Access Control so pre_hr_id / pre_client_id / pre_branch_id are refreshed.' + "hr_access_control pre ids do not match live pre data for post_hr_id={$contact['post_hr_id']} " + . "(client #{$contact['post_client_id']}, branch #{$contact['post_branch_id']}). " + . "Stored (hr_access_control id={$accessId}): pre_hr_id={$storedHr}, pre_client_id={$storedClient}, pre_branch_id={$storedBranch}. " + . "Live pre: pre_hr_id={$liveHr}, pre_client_id={$liveClient}, pre_branch_id={$liveBranch}.", + [ + 'Option A: Open Client Onboarding → HR Access for this client, select modules for this HR, Save (form must send live pre ids).', + "Option B (recommended): UPDATE hr_access_control SET pre_hr_id={$liveHr}, pre_client_id={$liveClient}, pre_branch_id={$liveBranch} WHERE id={$accessId};", + 'Option C: If UI re-save keeps old ids, auto-refresh in saveHrAccessData is commented out — enable it or use Option B.', + 'Note: POST login can still work; this mainly affects PRE modules/JWT pre mapping.', + ] ); } } @@ -244,6 +297,29 @@ class HrLoginDiagnoseController extends AdminController : (!$flags['CLIENT_ACTIVE'] ? 'CLIENT_INACTIVE' : 'UNKNOWN'))), ]; + $pairRows[] = [ + 'post' => [ + 'post_hr_id' => (int) $contact['post_hr_id'], + 'hr_name' => $contact['hr_name'] ?? '', + 'hr_mail' => $contact['hr_mail'] ?? '', + 'hr_mobile' => $contact['hr_mobile'] ?? '', + 'is_active' => (int) ($contact['is_active'] ?? 0), + 'post_branch_id' => (int) ($contact['post_branch_id'] ?? 0), + 'branch_name' => $contact['branch_name'] ?? '', + 'branch_active' => (int) ($contact['branch_active'] ?? 0), + 'pre_branch_id' => $contact['pre_branch_id'] ?? null, + 'post_client_id' => (int) ($contact['post_client_id'] ?? 0), + 'client_name' => $contact['client_name'] ?? '', + 'client_active' => (int) ($contact['client_active'] ?? 0), + 'has_access' => ! empty($access), + 'token_ready' => $tokenReady, + 'hr_active' => (int) ($contact['is_active'] ?? 0) === 1, + ], + 'pre' => $preMap, + 'access_id' => isset($access['id']) ? (int) $access['id'] : null, + 'has_token' => $canLoginCard, + ]; + $contact['hr_found'] = true; $contact['flags'] = $flags; } @@ -307,6 +383,26 @@ class HrLoginDiagnoseController extends AdminController $tokenCards = array_filter($loginCards, static fn ($c) => ! empty($c['has_token'])); $preMatched = array_filter($preMaps, static fn ($m) => ! empty($m['PRE_HR_MATCHED'])); + // Group PRE/POST pairs by post client for client-wise display. + $byClientMap = []; + foreach ($pairRows as $pair) { + $cid = (int) ($pair['post']['post_client_id'] ?? 0); + $key = (string) $cid; + if (! isset($byClientMap[$key])) { + $byClientMap[$key] = [ + 'post_client_id' => $cid, + 'client_name' => $pair['post']['client_name'] ?? '', + 'client_active' => (int) ($pair['post']['client_active'] ?? 0), + 'rows' => [], + ]; + } + $byClientMap[$key]['rows'][] = $pair; + } + $byClient = array_values($byClientMap); + usort($byClient, static function ($a, $b) { + return strcasecmp((string) ($a['client_name'] ?? ''), (string) ($b['client_name'] ?? '')); + }); + return [ 'input' => ['email' => $email, 'mobile' => $mobile], 'overall_status' => $overall, @@ -315,6 +411,7 @@ class HrLoginDiagnoseController extends AdminController 'summary' => $summary, 'issues' => $deduped, 'problems' => $deduped, + 'by_client' => $byClient, 'post' => [ 'contacts' => $postContacts, 'raw_found' => count($postContacts) > 0, @@ -355,6 +452,7 @@ class HrLoginDiagnoseController extends AdminController 'pre_matched' => count($preMatched), 'token_cards' => count($tokenCards), 'access_rows' => count(array_filter($accessRows, static fn ($a) => ! empty($a['id']))), + 'client_count' => count($byClient), 'would_return_both' => $anyToken && count($preMatched) > 0, 'winner' => ($anyToken && count($preMatched) > 0) ? 'both' : ($anyToken ? 'post' : (count($preMatched) > 0 ? 'pre' : 'none')), 'reason' => $summary, @@ -514,13 +612,25 @@ class HrLoginDiagnoseController extends AdminController return $result; } - private function issue(string $code, string $severity, string $message, string $fix = ''): array + /** + * @param string|array $fix + * @return array{code:string,severity:string,message:string,fix:string,fixes:array} + */ + private function issue(string $code, string $severity, string $message, $fix = ''): array { + if (is_array($fix)) { + $fixes = array_values(array_filter(array_map('strval', $fix))); + } else { + $fixes = preg_split("/\r\n|\n|\r/", (string) $fix) ?: []; + $fixes = array_values(array_filter(array_map('trim', $fixes))); + } + return [ 'code' => $code, 'severity' => $severity, 'message' => $message, - 'fix' => $fix, + 'fix' => implode("\n", $fixes), + 'fixes' => $fixes, ]; } } diff --git a/app/Views/hr_login_diagnose.php b/app/Views/hr_login_diagnose.php index 7df3c90a..5ed50f7f 100644 --- a/app/Views/hr_login_diagnose.php +++ b/app/Views/hr_login_diagnose.php @@ -132,8 +132,46 @@ .badge-high{background:var(--high-badge-bg);color:var(--high-badge-text);} .code{font-family:var(--mono);font-size:12.5px;color:var(--danger-code);font-weight:600;} .fix-text{color:var(--text-secondary);} + .fix-list{margin:0;padding-left:18px;} + .fix-list li{margin-bottom:6px;line-height:1.35;} + .fix-list li:last-child{margin-bottom:0;} + .problems-table td.fix-cell{min-width:320px;max-width:480px;} + .problems-table td.msg-cell{min-width:260px;} - .compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:20px;} + .compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:12px;} + .client-block{margin-bottom:0;} + .client-block-head{ + display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap; + padding:12px 16px;background:#F8F9FA;border-bottom:1px solid var(--border); + font-size:13.5px;font-weight:700; + } + .client-block-head .meta{font-weight:400;color:var(--text-muted);font-size:12.5px;} + .client-block .compare-grid{margin:0;padding:12px;background:#fff;border-radius:0;} + .client-block .compare-grid + .compare-grid{border-top:1px dashed var(--border);} + .branch-label{font-size:12px;color:var(--text-secondary);font-weight:600;margin:0 0 8px;padding:0 4px;} + + .client-tabs-wrap{margin-bottom:20px;} + .client-tabs{ + display:flex;gap:4px;border-bottom:1px solid var(--border);margin-bottom:0;padding:0 4px; + flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch; + } + .client-tab{ + padding:10px 14px;font-size:12.5px;font-weight:600;color:var(--text-secondary); + cursor:pointer;border-bottom:2px solid transparent;background:none;border-top:none;border-left:none;border-right:none; + font-family:var(--sans);white-space:nowrap;flex:0 0 auto;max-width:260px;overflow:hidden;text-overflow:ellipsis; + } + .client-tab.active{color:var(--teal-dark);border-bottom-color:var(--teal);} + .client-tab:hover:not(.active){color:var(--text-primary);} + .client-tab .badge-count{ + display:inline-block;margin-left:6px;font-size:10px;font-weight:700;padding:1px 6px;border-radius:999px; + background:var(--low-badge-bg);color:var(--low-badge-text); + } + .client-tab.active .badge-count{background:var(--teal-tint);color:var(--teal-dark);} + .client-panel{ + display:none;border:1px solid var(--border);border-top:none; + border-radius:0 0 var(--radius-md) var(--radius-md);background:#fff;overflow:hidden; + } + .client-panel.active{display:block;} .compare-card{border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden;background:#fff;} .compare-head{ padding:14px 20px;background:#F8F9FA;border-bottom:1px solid var(--border); @@ -246,6 +284,7 @@ $problems = $result['problems'] ?? ($result['issues'] ?? []); $accessRows = $result['hr_access_control'] ?? []; $loginSim = $result['login_simulation'] ?? []; + $byClient = $result['by_client'] ?? []; $postPrimary = $post['primary'] ?? []; $prePrimary = $pre['primary'] ?? []; $postFs = $post['filters_summary'] ?? []; @@ -265,87 +304,156 @@ - + - + - + - - + +
SeverityCodeCode MessageFixFix
No problems detected.
+ + + +
    + +
  1. + +
+ +
-
-
-
PRE (enrollment)
- -
- - - - - - - - - - - - - - - - - - - - - - - -
Raw found
Eligible (matched)
preDB reachable
PRE_BRANCH_LINKED
PRE_HR_MATCHED
PRE_IDS_CONSISTENT
PRE_CLIENT_MAPPED
pre_hr_id
name
email
mobile
client
branch
pre_client_id
pre_branch_id
-
+
Client-wise PRE / POST ( client)
+ +
+ -
-
POST (live)
- - - - - - - - - - - - - - - - - - - - -
Raw found - -
Eligible for login
hr active
branch active
client active
has access row
token ready
post_hr_id
name
email
mobile
client
branch
+ +
+

No client mappings to display.

-
+ +
+
+ $clientBlock): ?> + + + +
-
+ $clientBlock): ?> + +
+
+
+
+ + # +
+
+ branch/HR row + · token ready / + · client +
+
+ + + +
+
+
PRE (enrollment)
+

Branch:

+ + + + + + + + + + + + + +
PRE_BRANCH_LINKED
PRE_HR_MATCHED
PRE_IDS_CONSISTENT
PRE_CLIENT_MAPPED
pre_hr_id
name
email
mobile
client
branch
pre_client_id
pre_branch_id
+
+ +
+
POST (live)
+

Branch:

+ + + + + + + + + + + + + + +
Eligible for login
hr active
branch active
client active
has access row
token ready
post_hr_id
name
email
mobile
client
branch
access id
+
+
+ +
+
+ +
+ + +
@@ -359,6 +467,7 @@ POST eligible PRE eligible POST contacts + Clients mapped PRE matched Access rows with id Token-ready cards @@ -537,7 +646,20 @@ diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php index ebc63494..0d32c339 100755 --- a/app/Views/layout/header.php +++ b/app/Views/layout/header.php @@ -2005,6 +2005,9 @@ body[data-sidebar-size="condensed"] .footer {
  • View Members
  • +
  • + View Pending Approvals +
  • View Endorsement
  • diff --git a/app/Views/policy_gmc_terms.php b/app/Views/policy_gmc_terms.php index 7fbabc3e..a9b65060 100755 --- a/app/Views/policy_gmc_terms.php +++ b/app/Views/policy_gmc_terms.php @@ -229,6 +229,11 @@ style="width: 35%;;" type="number" name="self_max_age" id="self_max_age" onchange="lowerIsEighteen(this)">
    + +
    + Is Payable by employee: + +
    @@ -253,6 +258,11 @@ style="width: 35%;;" type="number" name="spouse_max_age" id="spouse_max_age" onchange="lowerIsEighteen(this)">
    + +
    + Is Payable by employee: + +
    @@ -280,6 +290,11 @@ style="width: 35%;;" type="number" name="child_max_age" id="child_max_age" oninput="this.value = this.value.replace(/\D/g, '').substring(0, 2)">
    + +
    + Is Payable by employee: + +
    @@ -326,6 +341,11 @@ onchange="lowerIsEighteen(this)">
    +
    + Is Payable by employee: + +
    + @@ -1406,46 +1426,14 @@ $('#other_member_max_age').val(jsonObject[key].elders.max); } - // if (key.includes("is_payable_employee")) { - - // if (jsonObject[key]) { - - // if (jsonObject[key].self == 0) { - // $('#is_payable_employee_for_self').prop('checked', - // false); - // } else { - // $('#is_payable_employee_for_self').prop('checked', - // true); - // } - - // if (jsonObject[key].spouse == 0) { - // $('#is_payable_employee_for_spouse').prop('checked', - // false); - // } else { - // $('#is_payable_employee_for_spouse').prop('checked', - // true); - // } - - // if (jsonObject[key].childern == 0) { - // $('#is_payable_employee_for_child').prop('checked', - // false); - // } else { - // $('#is_payable_employee_for_child').prop('checked', - // true); - // } - - // // if (jsonObject[key].elders == 0) { - // // $('#is_payable_employee_for_elders').prop('checked', - // // false); - // // } else { - // // $('#is_payable_employee_for_elders').prop('checked', - // // true); - // // } - - - // } - - // } + if (key.includes("is_payable_employee")) { + if (jsonObject[key]) { + $('#is_payable_employee_for_self').prop('checked', jsonObject[key].self == 1); + $('#is_payable_employee_for_spouse').prop('checked', jsonObject[key].spouse == 1); + $('#is_payable_employee_for_child').prop('checked', jsonObject[key].childern == 1); + $('#is_payable_employee_for_elders').prop('checked', jsonObject[key].elders == 1); + } + } if (key.includes("enrollment_display_key") && key != "") { diff --git a/docs/dependent-approval-apis.md b/docs/dependent-approval-apis.md new file mode 100644 index 00000000..1756789a --- /dev/null +++ b/docs/dependent-approval-apis.md @@ -0,0 +1,283 @@ +# Dependent Approval APIs + +Base path: `/employeeRest/` + +Auth: JWT + App-Signature (`authJWT`, `appSignature`) + +--- + +## 1. Get Employee Policy (Dependent Add UI) + +| | | +|---|---| +| **Method** | `GET` | +| **URL** | `/employeeRest/getEmployeePolicy` | +| **Handler** | `EmployeeRestController::getEmployeeByPolicyv2` | + +> **Note:** Route currently maps to `getEmployeePolicyv2` (method missing). Intended handler is `getEmployeeByPolicyv2`. + +### Query Params + +| Param | Required | Description | +|---|---|---| +| `id` | Yes | Self employee id | +| `emp_code` | Yes | Employee code | +| `client_id` | Yes | Client id | +| `client_branch_id` | Yes | Branch id | +| `client_policy_id` | Yes | GMC client policy id | + +### Success Response + +```json +{ + "status": "success", + "code": 200, + "message": "Employee policy and dependent details fetched successfully", + "data": { + "...": "policy details, mapped_family_floaters, allowed_relationships" + }, + "EmployeePolicy": [], + "add_button_show": true +} +``` + +### Error Responses + +| code | message | +|---|---| +| 400 | Required parameters missing | +| 400 | Only GMC policy is supported for dependent add | +| 404 | Employee policy not found | +| 500 | Something went wrong while fetching employee policy details | + +--- + +## 2. Add / Update Dependent (Pending Approval) + +| | | +|---|---| +| **Method** | `POST` | +| **URL** | `/employeeRest/addEmployeeAndDependence` | +| **Handler** | `EmployeeRestController::addEmployeeAndDependencev2` | +| **Content-Type** | `application/json` | + +### Request Body + +JSON **array** of dependent objects: + +```json +[ + { + "emp_code": "E001", + "client_id": 10, + "client_branch_id": 5, + "client_policy_id": 100, + "name": "John Doe", + "relationship": "Spouse", + "dob": "01/01/1990", + "basic_cover_si": 500000, + "dependent_effective_date": "01/08/2026", + "hr_id": 12 + } +] +``` + +### Fields + +| Field | Required | Notes | +|---|---|---| +| `emp_code` | Yes | Parent employee code | +| `client_id` | Yes | Client id | +| `client_branch_id` | Yes | Used for premium update | +| `client_policy_id` | Yes | Client policy id | +| `name` | Yes | Dependent name | +| `relationship` | Yes | e.g. Spouse / Son / Daughter | +| `dob` | Yes | Converted to `Y-m-d` | +| `basic_cover_si` | Yes | Sum insured | +| `dependent_effective_date` | Yes (new) | Coverage start date | +| `hr_id` | No | If set → created by HR; else USER | +| `id` | No | If set → update existing dependent | + +### Behavior + +- Creates/updates dependent with `emp_status = pending_approval` +- Creates employee policy with `status = pending_approval` +- Recalculates premium for the family + +### Success Response + +```json +{ + "status": "success", + "code": 200, + "data": [] +} +``` + +### Error Responses + +| code | data | +|---|---| +| 404 | Requested parameters are required | +| 404 | No Matches | +| 500 | Exception message | + +--- + +## 3. Delete Dependent + +| | | +|---|---| +| **Method** | `GET` | +| **URL** | `/employeeRest/deleteDependence` | +| **Handler** | `EmployeeRestController::deleteDependencev2` | + +### Query Params + +| Param | Required | Description | +|---|---|---| +| `id` | Yes | Dependent employee id | + +### Behavior + +Soft-deletes employee and policy: + +- `emp_status` / `status` → `truncated` +- `is_active` → `0` + +### Success Response + +```json +{ + "status": "success", + "code": 200, + "data": [] +} +``` + +### Error Responses + +| code | data | +|---|---| +| 404 | `[]` (missing `id`) | +| 500 | Exception message | + +--- + +## 4. List Pending Approval Dependents + +| | | +|---|---| +| **Method** | `GET` | +| **URL** | `/employeeRest/getPendingApprovalDependents` | +| **Handler** | `EmployeeRestController::getPendingApprovalDependents` | + +### Query Params + +| Param | Required | Description | +|---|---|---| +| `client_id` | No | Client filter | +| `client_branch_id` / `branch_id` | No | Branch filter | +| `client_policy_id` / `policy_id` | No | Policy filter | +| `search` | No | Name / emp_code search | + +### Success Response + +```json +{ + "status": "success", + "code": 200, + "message": "Pending approval dependents fetched successfully", + "data": [] +} +``` + +### Error Responses + +| code | message | +|---|---| +| 404 | No pending approval dependents found | +| 500 | Exception message | + +--- + +## 5. Approve / Reject Dependent + +| | | +|---|---| +| **Method** | `POST` | +| **URL** | `/employeeRest/processDependentAdd` | +| **Handler** | `EmployeeRestController::processDependentAdd` | +| **Content-Type** | `application/json` | + +### Request Body + +```json +{ + "employee_id": 123, + "client_policy_id": 100, + "status": "approved", + "hr_id": 12 +} +``` + +### Fields + +| Field | Required | Notes | +|---|---|---| +| `employee_id` | Yes | Dependent employee id | +| `client_policy_id` | Yes | Policy id | +| `status` | Yes | `approved` or `rejected` (default: `approved`) | +| `hr_id` | No | If set → approved by HR; else ACM | + +### Behavior + +| status | Employee | Policy | +|---|---|---| +| `approved` | `emp_status = active` | `status = active` | +| `rejected` | `emp_status = rejected`, `is_active = 0` | `status = rejected`, `is_active = 0` | + +### Success Response + +```json +{ + "status": "success", + "code": 200, + "data": [] +} +``` + +### Error Responses + +| code | data | +|---|---| +| 400 | Request body is required | +| 400 | employee_id is required | +| 400 | client_policy_id is required | +| 400 | status is invalid | +| 400 | Dependent is already approved | +| 400 | Dependent is not pending approval | +| 404 | Employee not found or inactive | +| 404 | Employee policy not found or inactive | +| 500 | Failed to update employee/policy status | + +--- + +## Typical Flow + +``` +1. getEmployeePolicy + → show family slots / add buttons + +2. addEmployeeAndDependence + → submit dependent → pending_approval + +3. getPendingApprovalDependents + → HR / ACM review list + +4. processDependentAdd + → approve or reject + +5. deleteDependence + → soft-delete if needed +```