From 44161347d203e94e8bc1d36ce13247332b90a24b Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Fri, 7 Aug 2026 11:29:33 +0530 Subject: [PATCH] FEAT_GET_EMPLOYEE_DTAILS --- app/Config/Routes.php | 3 + app/Controllers/EmployeeRestController.php | 516 +++++++++++++++++++++ 2 files changed, 519 insertions(+) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index e50dd0f0..e816ef8b 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -487,6 +487,8 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) { $routes->get('testMediAssistWellness','TestingController::testMediAssistWellness'); $routes->match(['get', 'post'], 'decryptVisitSso', 'ApiServiceController::decryptVisitSso'); // disabled for now do not remove this $routes->get("getInsurerClaimFormDownloadUrl", "EmployeeRestController::getInsurerClaimFormDownloadUrl"); + $routes->match(['get', 'post'], "getEmployeePolicyWiseDetails", "EmployeeRestController::getEmployeePolicyWiseDetails"); + // $routes->group('claims-collection-v2', static function ($routes) { // $routes->get('preview', 'ClaimsCollectionV2DashboardController::preview'); @@ -808,6 +810,7 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel $routes->post("calculatePremium", "EmployeeRestController::calculatePremium"); $routes->get("getEmployeeOldPolicy", "EmployeeRestController::getEmployeeOldPolicy"); $routes->get("getEmployeeActiveOrInactivePolicy", "EmployeeRestController::getEmployeeActiveOrInactivePolicy"); + $routes->match(['get', 'post'], "getEmployeePolicyWiseDetails", "EmployeeRestController::getEmployeePolicyWiseDetails"); $routes->get("getFEContent", "EmployeeRestController::getFEContent"); $routes->get("getAdvertisementImage", "EmployeeRestController::getAdvertisementImage"); $routes->get("getEcardURL", "EmployeeRestController::getEcardURL"); diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 4c572897..8743c94e 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -7198,4 +7198,520 @@ class EmployeeRestController extends AdminController } } + /** + * Policy-wise employee details API. + * Input: emp_code, client_id (numeric id or MD5 hash of id) + * Returns one object per enrolled active policy with members, claims, premium and terms. + */ + public function getEmployeePolicyWiseDetails() + { + try { + $emp_code = trim((string) ($this->request->getGet('emp_code') ?? $this->request->getPost('emp_code') ?? '')); + $client_id = $this->request->getGet('client_id') ?? $this->request->getPost('client_id') ?? null; + + if ($emp_code === '' || $client_id === null || $client_id === '') { + return $this->respond([ + 'status' => 'failed', + 'code' => 400, + 'message' => 'Required parameters missing: emp_code and client_id are required', + 'data' => [], + ], 200); + } + + $client_id = $this->resolveClientId($client_id); + if (empty($client_id)) { + return $this->respond([ + 'status' => 'failed', + 'code' => 404, + 'message' => 'Invalid client_id', + 'data' => [], + ], 200); + } + + $employeeRows = $this->employeeModel + ->where('emp_code', $emp_code) + ->where('client_id', $client_id) + ->where('is_active', 1) + ->findAll(); + + if (empty($employeeRows)) { + return $this->respond([ + 'status' => 'failed', + 'code' => 404, + 'message' => 'Employee not found for the given emp_code and client_id', + 'data' => [], + ], 200); + } + + $employeeIds = array_column($employeeRows, 'id'); + $dayInterval = 10; + + $enrolledPolicyIds = $this->employeePolicyModel + ->select('client_policy_id') + ->whereIn('employee_id', $employeeIds) + ->where('is_active', 1) + ->whereIn('status', ['active', 'expired']) + ->groupBy('client_policy_id') + ->findColumn('client_policy_id'); + + if (empty($enrolledPolicyIds)) { + return $this->respond([ + 'status' => 'failed', + 'code' => 404, + 'message' => 'No active policies found for the employee', + 'data' => [], + ], 200); + } + + $enrolledPolicies = $this->clientPolicyModel + ->select("client_policy.*, policy_type.policy_type, policy_type.long_name AS policy_long_name, insurers.name AS insurer_name, tpa.name AS tpa_name, tpa.network_hospitals AS network_hospitals_url, DATE_ADD(client_policy.policy_end_date, INTERVAL {$dayInterval} DAY) AS claims_grace_date") + ->join('policy_type', 'policy_type.id = client_policy.policy_type_id', 'left') + ->join('insurers', 'insurers.id = client_policy.insurer_id', 'left') + ->join('tpa', 'tpa.id = client_policy.tpa_id', 'left') + ->whereIn('client_policy.id', $enrolledPolicyIds) + ->where('client_policy.is_active', 1) + ->where('client_policy.policy_status', 1) + ->orderBy('client_policy.id', 'ASC') + ->findAll(); + + if (empty($enrolledPolicies)) { + return $this->respond([ + 'status' => 'failed', + 'code' => 404, + 'message' => 'No active policies found for the employee', + 'data' => [], + ], 200); + } + + $result = []; + foreach ($enrolledPolicies as $policy) { + $clientPolicyId = (int) $policy['id']; + $policyTypeId = (int) $policy['policy_type_id']; + + $ticketMeta = $this->getPolicyTicketMeta($policyTypeId); + $termsRaw = json_decode($policy['policy_terms'] ?? '{}'); + $termsArray = json_decode($policy['policy_terms'] ?? '{}', true) ?: []; + + $coveredMembers = $this->employeePolicyModel + ->select(' + employees.id AS employee_id, + employees.emp_code, + employees.name, + employees.relationship, + employees.relationship_code, + employees.family_floater_key, + employees.gender, + employees.dob, + employees.doj, + employees.email_personal, + employees.email_corporate, + employees.mobile, + employees.band, + employees.designation, + employees.unit, + employees.emp_status, + employees.basic_pay, + employees.client_id, + employees.client_branch_id, + employee_polices.id AS emp_policy_id, + employee_polices.uhid, + employee_polices.tpa_id, + employee_polices.rand_string, + employee_polices.basic_cover_si, + employee_polices.premium, + employee_polices.rata_premimum, + employee_polices.gst, + employee_polices.payable_employee, + employee_polices.date_coverage, + employee_polices.policy_end_date AS member_policy_end_date, + employee_polices.days, + employee_polices.status AS emp_policy_status, + employee_polices.pre_existing_alignments, + employee_polices.claim_status, + employee_polices.date_of_exit, + employee_polices.reason_for_exit + ') + ->join('employees', 'employees.id = employee_polices.employee_id', 'left') + ->whereIn('employee_polices.employee_id', $employeeIds) + ->where('employee_polices.client_policy_id', $clientPolicyId) + ->where('employee_polices.is_active', 1) + ->whereIn('employee_polices.status', ['active', 'expired']) + ->where('employees.is_active', 1) + ->findAll(); + + if (empty($coveredMembers)) { + continue; + } + + $empDetails = $this->buildEmpDetailsByRelation($coveredMembers); + $premiumDetails = $this->buildPremiumDetails($coveredMembers, $policyTypeId); + $claimDetails = $this->getClaimsForPolicy($emp_code, $clientPolicyId); + + $displayTerms = []; + if (!empty($termsArray['enrollment_display_key'])) { + $displayTerms = $termsArray['enrollment_display_key']; + } else { + $displayTerms = $this->policyTermsFiter($termsRaw, $ticketMeta['policy_group']); + } + + $result[] = [ + 'policy_details' => [ + 'client_id' => (int) $policy['client_id'], + 'client_branch_id' => (int) $policy['client_branch_id'], + 'client_policy_id' => $clientPolicyId, + 'policy_no' => $policy['policy_no'], + 'policy_type_id' => $policyTypeId, + 'policy_type' => $policy['policy_type'], + 'policy_name' => $policy['policy_type'], + 'heading' => $policy['policy_long_name'], + 'insurer_name' => $policy['insurer_name'], + 'tpa_name' => $policy['tpa_name'], + 'network_hospitals_url' => $policy['network_hospitals_url'], + 'policy_start_date' => $this->convertDateFormatDisplay($policy['policy_start_date']), + 'policy_end_date' => $this->convertDateFormatDisplay($policy['policy_end_date']), + 'claims_grace_date' => $this->convertDateFormatDisplay($policy['claims_grace_date']), + 'policy_status' => ((int) $policy['policy_status'] === 1) ? 'Active' : 'InActive', + 'is_addon' => (int) $policy['is_addon'], + 'open_for_enrollment' => (int) ($policy['open_for_enrollment'] ?? 0), + 'inception_type' => $policy['inception_type'], + 'disclaimer' => $policy['disclaimer'], + 'sum_insured_label' => $ticketMeta['sum_insured_label'], + 'claim_subject' => $ticketMeta['claim_subject'], + ], + 'terms_and_conditions' => [ + 'raw' => $termsArray, + 'display' => $displayTerms, + ], + 'premium_details' => $premiumDetails, + 'claim_details' => $claimDetails, + 'emp_details' => $empDetails, + ]; + } + + if (empty($result)) { + return $this->respond([ + 'status' => 'failed', + 'code' => 404, + 'message' => 'No policy coverage found for the employee', + 'data' => [], + ], 200); + } + + return $this->respond([ + 'status' => 'success', + 'code' => 200, + 'message' => 'Employee policy-wise details fetched successfully', + 'data' => [ + 'policy_data' => $result, + 'support' => $this->getClientSupportContacts((int) $client_id), + ], + ], 200); + } catch (\Exception $e) { + $this->myLogger->logme('error', 'getEmployeePolicyWiseDetails: ' . $e->getMessage() . ' --- ' . $e->getLine()); + return $this->respond([ + 'status' => 'failed', + 'code' => 500, + 'message' => 'Something went wrong while fetching employee policy-wise details', + 'data' => [], + ], 500); + } + } + + /** + * Resolve numeric client_id from MD5 hash or plain id. + */ + private function resolveClientId($client_id) + { + if (is_string($client_id) && preg_match('/^[a-f0-9]{32}$/i', $client_id)) { + $client = $this->clientModel->where('MD5(id)', $client_id)->first(); + return $client['id'] ?? null; + } + + if (is_numeric($client_id)) { + $client = $this->clientModel->where('id', (int) $client_id)->where('is_active', 1)->first(); + return $client['id'] ?? (int) $client_id; + } + + return null; + } + + /** + * Support contacts for a client. + * level 1 = Head, level 2 = Manager, level 3 = Account Manager + */ + private function getClientSupportContacts(int $clientId): array + { + $support = [ + 'account_managers' => [], + 'managers' => [], + 'heads' => [], + ]; + + $records = $this->clientRMModel + ->select('client_rm.level, user_profiles.first_name, user_profiles.email, user_profiles.mobile') + ->join('user_profiles', 'user_profiles.id = client_rm.user_id') + ->where('client_rm.client_id', $clientId) + ->where('client_rm.is_active', 1) + ->whereIn('client_rm.level', [1, 2, 3]) + ->findAll(); + + foreach ($records as $record) { + $contact = [ + 'name' => $record['first_name'] ?? null, + 'mobile' => $record['mobile'] ?? null, + 'email' => $record['email'] ?? null, + ]; + + $level = (int) ($record['level'] ?? 0); + if ($level === 3) { + $support['account_managers'][] = $contact; + } elseif ($level === 2) { + $support['managers'][] = $contact; + } elseif ($level === 1) { + $support['heads'][] = $contact; + } + } + + return $support; + } + + private function getPolicyTicketMeta(int $policyTypeId): array + { + if ($policyTypeId === 1) { + return [ + 'policy_group' => 'gpa', + 'ticket_type_id' => 2, + 'ticket_settled_status_id'=> 24, + 'claim_subject' => 'Claim GPA', + 'sum_insured_label' => 'Sum Assured', + ]; + } + if ($policyTypeId === 6) { + return [ + 'policy_group' => 'other', + 'ticket_type_id' => 3, + 'ticket_settled_status_id'=> 34, + 'claim_subject' => 'Claim EDLI', + 'sum_insured_label' => 'Sum Assured', + ]; + } + if ($policyTypeId === 7) { + return [ + 'policy_group' => 'other', + 'ticket_type_id' => 4, + 'ticket_settled_status_id'=> 44, + 'claim_subject' => 'Claim GTLI', + 'sum_insured_label' => 'Sum Assured', + ]; + } + if ($policyTypeId === 72) { + return [ + 'policy_group' => 'other', + 'ticket_type_id' => 72, + 'ticket_settled_status_id'=> 76, + 'claim_subject' => 'Claim OPD', + 'sum_insured_label' => 'Sum Insured', + ]; + } + + return [ + 'policy_group' => 'gmc', + 'ticket_type_id' => 1, + 'ticket_settled_status_id'=> 11, + 'claim_subject' => 'Claim GMC', + 'sum_insured_label' => 'Sum Insured', + ]; + } + + /** + * Group covered members as: + * self => object, spouse/child/parent/parent_in_law/... => array + */ + private function buildEmpDetailsByRelation(array $coveredMembers): array + { + $empDetails = [ + 'self' => new \stdClass(), + ]; + + foreach ($coveredMembers as $member) { + $relationKey = $this->normalizeRelationKey($member); + $memberData = $this->formatMemberDetails($member); + + if ($relationKey === 'self') { + $empDetails['self'] = $memberData; + continue; + } + + if (!isset($empDetails[$relationKey]) || !is_array($empDetails[$relationKey])) { + $empDetails[$relationKey] = []; + } + $empDetails[$relationKey][] = $memberData; + } + + return $empDetails; + } + + private function normalizeRelationKey(array $member): string + { + $floaterKey = strtolower(trim((string) ($member['family_floater_key'] ?? ''))); + $floaterKey = preg_replace('/\d+/', '', $floaterKey); + + if (in_array($floaterKey, ['self', 'spouse', 'child', 'parent', 'parent_in_law'], true)) { + return $floaterKey; + } + + $relationship = trim((string) ($member['relationship'] ?? '')); + if (strcasecmp($relationship, 'Self') === 0) { + return 'self'; + } + + $mapped = $this->RelationshipMap($relationship); + if (!empty($mapped)) { + return $mapped; + } + + $normalized = strtolower(str_replace([' ', '-'], '_', $relationship)); + return $normalized !== '' ? $normalized : 'other'; + } + + private function formatMemberDetails(array $member): array + { + $eCardDownload = null; + if (!empty($member['tpa_id']) && !empty($member['rand_string'])) { + $eCardDownload = base_url('download-e-card/') . $member['rand_string'] . '/1'; + } + + return [ + 'employee_id' => (int) ($member['employee_id'] ?? 0), + 'emp_policy_id' => (int) ($member['emp_policy_id'] ?? 0), + 'emp_code' => $member['emp_code'] ?? null, + 'name' => $member['name'] ?? null, + 'relationship' => $member['relationship'] ?? null, + 'relationship_code' => $member['relationship_code'] ?? null, + 'family_floater_key' => $member['family_floater_key'] ?? null, + 'gender' => $member['gender'] ?? null, + 'dob' => !empty($member['dob']) ? $this->convertDateFormatDMY($member['dob']) : null, + 'doj' => !empty($member['doj']) ? $this->convertDateFormatDMY($member['doj']) : null, + 'email_personal' => $member['email_personal'] ?? null, + 'email_corporate' => $member['email_corporate'] ?? null, + 'mobile' => $member['mobile'] ?? null, + 'band' => $member['band'] ?? null, + 'designation' => $member['designation'] ?? null, + 'unit' => $member['unit'] ?? null, + 'emp_status' => $member['emp_status'] ?? null, + 'basic_pay' => $member['basic_pay'] ?? null, + 'client_id' => isset($member['client_id']) ? (int) $member['client_id'] : null, + 'client_branch_id' => isset($member['client_branch_id']) ? (int) $member['client_branch_id'] : null, + 'uhid' => $member['uhid'] ?? null, + 'tpa_id' => $member['tpa_id'] ?? null, + 'eCardDownload' => $eCardDownload, + 'basic_cover_si' => $member['basic_cover_si'] ?? 0, + 'premium' => $member['premium'] ?? 0, + 'rata_premimum' => $member['rata_premimum'] ?? 0, + 'gst' => $member['gst'] ?? 0, + 'payable_employee' => isset($member['payable_employee']) ? (int) $member['payable_employee'] : 0, + 'date_coverage' => !empty($member['date_coverage']) ? $this->convertDateFormatDMY($member['date_coverage']) : null, + 'member_policy_end_date' => !empty($member['member_policy_end_date']) ? $this->convertDateFormatDMY($member['member_policy_end_date']) : null, + 'days' => $member['days'] ?? null, + 'emp_policy_status' => $member['emp_policy_status'] ?? null, + 'pre_existing_alignments' => $member['pre_existing_alignments'] ?? null, + 'claim_status' => $member['claim_status'] ?? null, + 'date_of_exit' => !empty($member['date_of_exit']) ? $this->convertDateFormatDMY($member['date_of_exit']) : null, + 'reason_for_exit' => $member['reason_for_exit'] ?? null, + ]; + } + + private function buildPremiumDetails(array $coveredMembers, int $policyTypeId): array + { + $siValue = 0; + $premiumTotal = 0; + $gstTotal = 0; + $rataTotal = 0; + + foreach ($coveredMembers as $member) { + if ($siValue == 0 && isset($member['basic_cover_si'])) { + $siValue = $member['basic_cover_si']; + } + $premiumTotal += (float) ($member['premium'] ?? 0); + $gstTotal += (float) ($member['gst'] ?? 0); + $rataTotal += (float) ($member['rata_premimum'] ?? 0); + } + + // Match existing app behaviour: hide premium/gst for base GPA/GMC in summary views + $hidePremium = in_array($policyTypeId, [1, 2], true); + + return [ + 'sum_insured' => $siValue, + 'total_premium' => $hidePremium ? 0 : round($premiumTotal), + 'total_gst' => $hidePremium ? 0 : round($gstTotal), + 'total_rata_premium'=> $hidePremium ? 0 : round($rataTotal), + 'total_with_gst' => $hidePremium ? 0 : round($premiumTotal + $gstTotal), + 'member_count' => count($coveredMembers), + ]; + } + + private function getClaimsForPolicy(string $empCode, int $clientPolicyId): array + { + $db = db_connect(); + $claims = $db->table('ticket_master tm') + ->select([ + 'tm.id AS ticket_id', + 'tm.claim_number AS claim_no', + 'tm.ticket_type_id', + 'tm.claim_status_id', + "CASE + WHEN tcs.display_name IS NULL OR tcs.display_name = '' + THEN tcs.claim_status + ELSE UPPER(tcs.display_name) + END AS status", + "CASE + WHEN tm.tpa_claim_type IS NOT NULL AND tm.tpa_claim_type != '' + THEN tm.tpa_claim_type + ELSE 'Reimbursement' + END AS claim_type", + 'tm.emp_name', + 'tm.emp_code', + 'tm.relationship', + 'tm.insured_name', + 'tm.hospital_name', + 'tm.doa', + 'tm.dod', + 'tm.claim_amount', + 'tm.approved_amount', + 'tm.si_amt', + 'tm.policy_no', + 'tm.tpa_no', + 'tm.client_policy_id', + 'DATE_FORMAT(tm.created_at, "%d-%m-%Y") AS ticket_created_date', + 'tm.raised_date', + 'tm.registration_date', + 'tm.approved_date', + 'tm.settled_date', + 'tm.denial_date', + 'tm.denial_reason', + 'tm.utr_details', + ]) + ->join('ticket_claim_status tcs', 'tcs.id = tm.claim_status_id', 'left') + ->where('tm.emp_code', $empCode) + ->where('tm.client_policy_id', $clientPolicyId) + ->where('tm.is_active', 1) + ->orderBy('tm.id', 'DESC') + ->get() + ->getResultArray(); + + $totalClaimAmount = 0; + $totalApprovedAmount = 0; + foreach ($claims as $claim) { + $totalClaimAmount += (float) ($claim['claim_amount'] ?? 0); + $totalApprovedAmount += (float) ($claim['approved_amount'] ?? 0); + } + + return [ + 'count' => count($claims), + 'total_claim_amount' => round($totalClaimAmount, 2), + 'total_approved_amount' => round($totalApprovedAmount, 2), + 'claims' => $claims, + ]; + } + }