diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php index b69fe231..18eac66a 100644 --- a/app/Controllers/ApiServiceController.php +++ b/app/Controllers/ApiServiceController.php @@ -15,6 +15,7 @@ use App\Controllers\MediAssistApiController; use App\Controllers\FhplApiController; use App\Controllers\VoloApiController; use App\Models\BatchFileModel; +use App\Models\ClaimFilesModel; use App\Models\FileModel; use App\Helpers\TPADataCompareHelper; use App\Helpers\TPADataCompareHelper2; @@ -25,6 +26,7 @@ class ApiServiceController extends BaseController // protected $format = 'json'; protected $db; protected $employeePolicyModel; + protected $claimFilesModel; protected $medi_assist_primary_key; protected $vidal_primary_key; protected $icici_primary_key; @@ -36,6 +38,7 @@ class ApiServiceController extends BaseController { $this->db = \Config\Database::connect(); $this->employeePolicyModel = new EmployeePolicyModel(); + $this->claimFilesModel = new ClaimFilesModel(); $this->medi_assist_primary_key = getenv('MEDI_ASSIST_PRIMARY_KEY_CONSTANT'); $this->vidal_primary_key = getenv('VIDAL_PRIMARY_KEY_CONSTANT'); $this->icici_primary_key = getenv('ICICI_PRIMARY_KEY_CONSTANT'); @@ -177,26 +180,20 @@ class ApiServiceController extends BaseController $voloApiController = new VoloApiController(); $data['eCardDownload'] = $voloApiController->EcardRequest( $emp_code, $policy_no , $employee_policy[0]['tpa_id'] ); - }else{ - - if($type == "download"){ - // direct download - $data['eCardDownload'] = base_url('download-e-card/') . $employee_policy[0]['rand_string'].'/1'; - }else{ - if(isset($all_member) && !empty($all_member)){ - // view and download all members - $data['eCardDownload'] = base_url('download-e-card/') . $employee_policy[0]['rand_string'].'/1/1'; - }else{ - // view and download single member - $data['eCardDownload'] = base_url('download-e-card/') . $employee_policy[0]['rand_string'].'/0/1'; - } - } } - $data['message'] = "E-card generated"; - if(empty($data['eCardDownload'])){ - $data['message'] = "E-card not generated"; - } + if (empty($data['eCardDownload'])) { + $data['eCardDownload'] = $this->buildDefaultEcardDownloadUrl( + $employee_policy[0]['rand_string'], + $type, + $all_member ?? null + ); + } + + $data['message'] = "E-card generated"; + if(empty($data['eCardDownload'])){ + $data['message'] = "E-card not generated"; + } } else { $data['eCardDownload'] = null; @@ -220,6 +217,19 @@ class ApiServiceController extends BaseController } } + private function buildDefaultEcardDownloadUrl(string $randString, string $type = 'download', $allMember = null): string + { + if ($type === 'download') { + return base_url('download-e-card/') . $randString . '/1'; + } + + if (!empty($allMember)) { + return base_url('download-e-card/') . $randString . '/1/1'; + } + + return base_url('download-e-card/') . $randString . '/0/1'; + } + // Get TPAID public function getTPAID() { @@ -583,6 +593,13 @@ class ApiServiceController extends BaseController ]); } + if (! $this->claimFilesModel->hasPdfFileForTicket($claimId)) { + return $this->response->setJSON([ + 'status' => false, + 'message' => 'No PDF file found for this claim' + ]); + } + $result = $this->pushClaims($claimId); if ($result !== null && is_array($result)) { diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index 5ec861eb..d14c8de7 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -763,7 +763,7 @@ class ClientController extends AdminController public function saveDeposit() { - $rules = [ + $rules = [ 'amount' => [ 'rules' => 'required|numeric|greater_than_equal_to[0]', @@ -799,7 +799,7 @@ class ClientController extends AdminController ], 'cd_ac_no' => [ - 'rules' => 'required|regex_match[/^[a-zA-Z0-9\/\-_]+$/]', + 'rules' => 'required|regex_match[/^[a-zA-Z0-9\/\-_ ]+$/]', 'errors' => [ 'required' => 'CD Account number is required.', 'regex_match' => 'CD Account number can only contain letters, numbers, hyphens(-), underscores(_), and slashes(/).', @@ -874,12 +874,14 @@ class ClientController extends AdminController $record_date = null; } + $cd_master_data = $this->CDMasterModel->where('id', $cd_ac_pk)->where('is_active', 1)->first(); + $data = [ 'amount' => $sanitized_post_data['amount'] ?? null, 'sub_type_id' => $sanitized_post_data['sub_type_id'] ?? null, 'client_id' => $sanitized_post_data['client_id'] ?? null, 'client_policy_id' => null, - 'cd_ac_no' => $cd_ac_no ?? null, + 'cd_ac_no' => $cd_master_data['cd_ac_no'] ?? null, 'cd_ac_pk' => $cd_ac_pk ?? null, 'endorsement_no' => null, 'insurer_id' => $sanitized_post_data['insurer_id'] ?? null, diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 05873250..4722727d 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -517,7 +517,7 @@ class EmployeeController extends AdminController ") ->join('client_policy', 'client_policy.id = batch_files.client_policy_id') ->join('insurers', 'client_policy.insurer_id = insurers.id') - ->join('tpa', 'client_policy.tpa_id = tpa.id') + ->join('tpa', 'client_policy.tpa_id = tpa.id', 'left') ->join('client_branch', 'client_branch.id = batch_files.client_branch_id') ->join('policy_type', 'policy_type.id = client_policy.policy_type_id') ->join('clients', 'clients.id = client_policy.client_id') @@ -574,7 +574,6 @@ class EmployeeController extends AdminController ->orderBy('batch_files.id', 'desc') ->find(); - // dd($data['fileList']);die(); if ($this->request->getMethod() == "get") { $this->loadLayout('import_export', $data); @@ -4255,25 +4254,36 @@ class EmployeeController extends AdminController $emp_data_wo_tpa_id = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id); // Reconcile DB records against TPA records and classify records for rec_type updates. + $consumedTpaIdsByEmpCode = []; foreach ($emp_data_wo_tpa_id as $db_key => $db_row) { - $tpa_temp_data = $tpaByEmpCode[$db_row['emp_code']] ?? []; - $match = $this->reconcileDbWithTpa($db_row, $tpa_temp_data); + $empCode = (string) ($db_row['emp_code'] ?? ''); + $empId = (string) ($db_row['id'] ?? ''); + $empName = (string) ($db_row['name'] ?? ''); + $tpa_temp_data = $tpaByEmpCode[$empCode] ?? []; + $excludeTpaIds = $consumedTpaIdsByEmpCode[$empCode] ?? []; + $match = $this->reconcileDbWithTpa($db_row, $tpa_temp_data, $excludeTpaIds); $emp_data_wo_tpa_id[$db_key]['match'] = $match; if (($match['status'] ?? '') === 'matched') { $matchedTpaId = (int) ($match['tpa_record']['id'] ?? 0); + // echo 'matched' . $matchedTpaId . ' for emp_code ' . $empCode . PHP_EOL . '
'; if ($matchedTpaId > 0) { + $consumedTpaIdsByEmpCode[$empCode][] = $matchedTpaId; // If compare-fields list has differences, the row must be reviewed. // Otherwise keep it as matched. $recTypeById[$matchedTpaId] = empty($match['not_matching']) ? 'matched' : 'need_to_review'; } } else { - // No relation-level match found for this DB member. - // Mark all candidate TPA rows for the same emp_code as review-required. + // echo 'not matched' . ' for emp_code ' . $empCode . PHP_EOL . ' - ' . $empId . ' - ' . $empName . ' - ' . '
'; + // No match for this DB member: flag same-relation TPA rows not already paired. + $dbRel = strtolower(trim((string) ($db_row['relationship'] ?? ''))); foreach ($tpa_temp_data as $candidate) { + if (strtolower(trim((string) ($candidate['relation'] ?? ''))) !== $dbRel) { + continue; + } $candidateId = (int) ($candidate['id'] ?? 0); - if ($candidateId > 0) { - $recTypeById[$candidateId] = 'need_to_review'; + if ($candidateId > 0 && !in_array($candidateId, $excludeTpaIds, true)) { + $recTypeById[$candidateId] = ''; } } } @@ -4306,76 +4316,75 @@ class EmployeeController extends AdminController $db->transComplete(); } - // this will match tpa api data with emp/emp policy table and update ref in tpa api data once - $this->reconTpaApiDataWithEmployeepolicies(['file_id' => $file_id]); + // this will match tpa api data with emp/emp policy table and update ref in tpa api data once + $this->reconTpaApiDataWithEmployeepolicies(['file_id' => $file_id]); } else { - // echo 'else';die; // Cached mode: - // Read previously classified rows from rec_type, keep response shape compatible - // with existing UI/export (`mismatch_data` still contains DB row + match payload). + // `not_in_nhance` stays sourced from persisted rec_type snapshot. + // `mismatch_data` must match compute-mode shape: every policy row with + // tpa_id NULL gets reconcileDbWithTpa against *all* active TPA rows for + // that emp_code (not only rows flagged need_to_review), otherwise second+ + // loads drop rows / lose not_matching vs the first compute pass. $not_in_nhance = $tpaApiDataModel->select('*') ->where('is_active', 1) ->where('file_id', $file_id) ->where('rec_type', 'not_in_nhance') ->findAll(); - $needToReviewRows = $tpaApiDataModel->select('*') - ->where('is_active', 1) + $allActiveTpaRowsCached = $tpaApiDataModel->select('*') ->where('file_id', $file_id) - ->where('rec_type', 'need_to_review') + ->where('is_active', 1) ->findAll(); - $needToReviewByEmpCode = []; - foreach ($needToReviewRows as $row) { - $needToReviewByEmpCode[$row['emp_code']][] = $row; + $tpaByEmpCodeCached = []; + foreach ($allActiveTpaRowsCached as $tpaRow) { + $tpaByEmpCodeCached[$tpaRow['emp_code']][] = $tpaRow; } - $baseRows = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id); - foreach ($baseRows as $db_row) { - $candidates = $needToReviewByEmpCode[$db_row['emp_code']] ?? []; - if (empty($candidates)) { - continue; - } - - $selectedTpa = null; - foreach ($candidates as $candidate) { - // Prefer same-relation row to mimic reconcileDbWithTpa relation matching. - if (strtolower((string) ($candidate['relation'] ?? '')) === strtolower((string) ($db_row['relationship'] ?? ''))) { - $selectedTpa = $candidate; - break; + $emp_data_wo_tpa_id = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id); + $consumedTpaIdsByEmpCodeCached = []; + foreach ($emp_data_wo_tpa_id as $db_key => $db_row) { + $empCode = (string) ($db_row['emp_code'] ?? ''); + $tpa_temp_data = $tpaByEmpCodeCached[$empCode] ?? []; + $excludeTpaIds = $consumedTpaIdsByEmpCodeCached[$empCode] ?? []; + $match = $this->reconcileDbWithTpa($db_row, $tpa_temp_data, $excludeTpaIds); + $emp_data_wo_tpa_id[$db_key]['match'] = $match; + if (($match['status'] ?? '') === 'matched') { + $matchedTpaId = (int) ($match['tpa_record']['id'] ?? 0); + if ($matchedTpaId > 0) { + $consumedTpaIdsByEmpCodeCached[$empCode][] = $matchedTpaId; } } - if ($selectedTpa === null) { - $selectedTpa = $candidates[0]; - } - - $db_row['match'] = [ - 'status' => 'matched', - 'tpa_record' => $selectedTpa, - 'not_matching' => [], - ]; - $emp_data_wo_tpa_id[] = $db_row; } } + // print_rr($emp_data_wo_tpa_id);die(); + + // Intentionally keep `not_in_tpa` live from current join/query logic // (as requested) and do not source it from rec_type snapshot. - $tpa_emp_codes = $tpaApiDataModel->select('emp_code') + $tpa_emp_codes = $tpaApiDataModel->select('ref') ->where('file_id', $file_id) ->where('is_active', 1) - ->groupBy('emp_code') + ->groupBy('ref') ->findAll(); - $tpa_emp_codes = array_column($tpa_emp_codes, 'emp_code'); - $not_in_tpa = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id, $tpa_emp_codes); + + // $tpa_emp_codes = array_column($tpa_emp_codes, 'ref'); + $tpa_ref = array_column($tpa_emp_codes, 'ref'); + $not_in_tpa = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id, $tpa_ref); + + // Format dates for UI/export (dd/mm/yyyy). Applied after reconciliation so + // reconcileDbWithTpa can still compare raw Y-m-d values from the database. + $this->formatVariationReportDataForDisplay($not_in_tpa, $not_in_nhance, $emp_data_wo_tpa_id); if (!empty($not_in_tpa) || !empty($not_in_nhance) || !empty($emp_data_wo_tpa_id)) { $not_in_nhance_button_enable_status = false; - if(count($not_in_tpa)) - { - foreach($not_in_nhance as $nih) - { - if($nih['ref'] === '' || empty($nih['ref'])) - { + if (count($not_in_nhance)) { + foreach ($not_in_nhance as $nih) { + $hasRefKey = array_key_exists('ref', $nih); + $ref = $hasRefKey ? $nih['ref'] : null; + $refIsEmpty = $ref === null || $ref === ''; + if ($refIsEmpty) { $not_in_nhance_button_enable_status = true; break; } @@ -4410,6 +4419,21 @@ class EmployeeController extends AdminController $not_in_nhance_deletion_count ); + $not_matched_count = 0; + $not_matched_data = []; + foreach ($emp_data_wo_tpa_id as $key => $row) { + $notMatching = $row['match']['not_matching'] ?? []; + if (isset($row['match']) && is_array($notMatching) && $notMatching !== []) { + $not_matched_count++; + $not_matched_data[] = $row; + } + } + + $need_to_review_proceed_button_text = sprintf( + 'Proceed - Need to Review ( %d )', + $not_matched_count + ); + $response = [ 'not_in_tpa' => $not_in_tpa, 'not_in_nhance' => $not_in_nhance, @@ -4418,6 +4442,9 @@ class EmployeeController extends AdminController 'not_in_nhance_inception_count' => $not_in_nhance_inception_count, 'not_in_nhance_deletion_count' => $not_in_nhance_deletion_count, 'not_in_nhance_proceed_button_text' => $not_in_nhance_proceed_button_text, + 'not_matched_count' => $not_matched_count, + 'not_matched_data' => $not_matched_data, + 'need_to_review_proceed_button_text' => $need_to_review_proceed_button_text, ]; if ($type === 'view') { @@ -4889,10 +4916,12 @@ class EmployeeController extends AdminController } $mismatchRows = []; + $consumedTpaIdsByEmpCode = []; foreach ($dbRows as $dbRow) { + $empCode = (string) ($dbRow['emp_code'] ?? ''); $tpaRows = $TpaApiDataModel->select('*') - ->where('emp_code', $dbRow['emp_code']) + ->where('emp_code', $empCode) ->where('file_id', $batchFileId) ->where('is_active', 1) ->findAll(); @@ -4901,7 +4930,14 @@ class EmployeeController extends AdminController continue; } - $match = $this->reconcileDbWithTpa($dbRow, $tpaRows); + $excludeTpaIds = $consumedTpaIdsByEmpCode[$empCode] ?? []; + $match = $this->reconcileDbWithTpa($dbRow, $tpaRows, $excludeTpaIds); + if (($match['status'] ?? '') === 'matched') { + $matchedTpaId = (int) ($match['tpa_record']['id'] ?? 0); + if ($matchedTpaId > 0) { + $consumedTpaIdsByEmpCode[$empCode][] = $matchedTpaId; + } + } if (($match['status'] ?? '') !== 'matched') { continue; @@ -5190,9 +5226,12 @@ class EmployeeController extends AdminController $rowsSkippedNoDiff = 0; $rowsSkippedNoEmployee = 0; + $consumedTpaIdsByEmpCode = []; + foreach ($dbRows as $dbRow) { + $empCode = (string) ($dbRow['emp_code'] ?? ''); $tpaRows = $TpaApiDataModel->select('*') - ->where('emp_code', $dbRow['emp_code'] ?? '') + ->where('emp_code', $empCode) ->where('file_id', $batchFileId) ->where('is_active', 1) ->findAll(); @@ -5201,7 +5240,8 @@ class EmployeeController extends AdminController continue; } - $match = $this->reconcileDbWithTpa($dbRow, $tpaRows); + $excludeTpaIds = $consumedTpaIdsByEmpCode[$empCode] ?? []; + $match = $this->reconcileDbWithTpa($dbRow, $tpaRows, $excludeTpaIds); if (($match['status'] ?? '') !== 'matched') { continue; @@ -5210,6 +5250,11 @@ class EmployeeController extends AdminController $tpaRecord = $match['tpa_record'] ?? []; $notMatching = $match['not_matching'] ?? []; + $matchedTpaId = (int) ($tpaRecord['id'] ?? 0); + if ($matchedTpaId > 0) { + $consumedTpaIdsByEmpCode[$empCode][] = $matchedTpaId; + } + if (!is_array($notMatching) || $notMatching === []) { $rowsSkippedNoDiff++; continue; @@ -5524,57 +5569,169 @@ class EmployeeController extends AdminController ]; } - public function reconcileDbWithTpa(array $db, array $tpaRows): array + /** + * Convert a single variation-report date value to dd/mm/yyyy for display. + */ + private function formatVariationReportDateField($value): string { - // Name normalization - $normalizeName = function ($name) { + if ($value === null || $value === '') { + return ''; + } + + $formatted = change_date_format((string) $value, null, 'd/m/Y'); + + return ($formatted !== null && $formatted !== '') ? (string) $formatted : (string) $value; + } + + /** + * Format known date columns on one variation-report row (TPA or DB). + */ + private function formatVariationReportRowDates(array $row, array $dateFields = ['dob', 'doj']): array + { + foreach ($dateFields as $field) { + if (!array_key_exists($field, $row)) { + continue; + } + if ($row[$field] === null || $row[$field] === '') { + continue; + } + $row[$field] = $this->formatVariationReportDateField($row[$field]); + } + + return $row; + } + + /** + * Apply dd/mm/yyyy formatting to all variation-report payloads returned to the UI/export. + */ + private function formatVariationReportDataForDisplay( + array &$notInTpa, + array &$notInNhance, + array &$mismatchData + ): void { + foreach ($notInTpa as $idx => $row) { + $notInTpa[$idx] = $this->formatVariationReportRowDates($row); + } + + foreach ($notInNhance as $idx => $row) { + $notInNhance[$idx] = $this->formatVariationReportRowDates($row); + } + + foreach ($mismatchData as $idx => $row) { + $row = $this->formatVariationReportRowDates($row); + if (isset($row['match']['tpa_record']) && is_array($row['match']['tpa_record'])) { + $row['match']['tpa_record'] = $this->formatVariationReportRowDates($row['match']['tpa_record']); + } + $mismatchData[$idx] = $row; + } + } + + /** + * Pair one Nhance policy row with a TPA API row for the same emp_code. + * + * When multiple dependents share a relation (e.g. two Sons), candidates are scored + * on name / DOB / gender and the best unique match wins. Already-paired TPA ids + * (same emp_code) can be passed via $excludeTpaIds so each TPA row maps once. + */ + public function reconcileDbWithTpa(array $db, array $tpaRows, array $excludeTpaIds = []): array + { + $normalizeName = static function ($name) { return strtolower( - preg_replace('/[.\s_]+/', '', trim($name)) + preg_replace('/[.\s_]+/', '', trim((string) $name)) ); }; - foreach ($tpaRows as $tpa) { + $normalizeRelation = static function ($relation) { + return strtolower(trim((string) $relation)); + }; - // 1️⃣ emp_code + relation must match - if ( - // ($db['emp_code'] ?? '') !== ($tpa['emp_code'] ?? '') || - strtolower($db['relationship']) !== strtolower($tpa['relation']) - ) { + $dbRel = $normalizeRelation($db['relationship'] ?? ''); + + $candidates = []; + foreach ($tpaRows as $tpa) { + if (isset($tpa['match']['status']) && $tpa['match']['status'] === 'matched') { continue; } - // 2️⃣ Field comparison - $diff = []; - - if ( - ($db['name'] ?? '') !== - ($tpa['name'] ?? '') - ) { - $diff[] = 'name'; + $tpaId = (int) ($tpa['id'] ?? 0); + if ($tpaId > 0 && in_array($tpaId, $excludeTpaIds, true)) { + continue; } - if (($db['dob'] ?? '') !== ($tpa['dob'] ?? '')) { - $diff[] = 'dob'; + if ($normalizeRelation($tpa['relation'] ?? '') !== $dbRel) { + continue; } - if ( - strtoupper($db['gender'] ?? '') !== - strtoupper($tpa['gender'] ?? '') - ) { - $diff[] = 'gender'; - } - - // 3️⃣ Match found - return [ - 'status' => 'matched', - 'tpa_record' => $tpa, - 'not_matching' => $diff // empty = perfect match - ]; + $candidates[] = $tpa; + } + + if ($candidates === []) { + return ['status' => 'no_match']; + } + + $scoreCandidate = static function (array $tpa) use ($db, $normalizeName) { + $score = 0; + if ($normalizeName($db['name'] ?? '') === $normalizeName($tpa['name'] ?? '')) { + $score += 4; + } + if ((string) ($db['dob'] ?? '') === (string) ($tpa['dob'] ?? '')) { + $score += 2; + } + if (strtoupper(trim((string) ($db['gender'] ?? ''))) === strtoupper(trim((string) ($tpa['gender'] ?? '')))) { + $score += 1; + } + + return $score; + }; + + $bestTpa = null; + $bestScore = -1; + foreach ($candidates as $tpa) { + $score = $scoreCandidate($tpa); + if ($score > $bestScore) { + $bestScore = $score; + $bestTpa = $tpa; + } + } + + if ($bestTpa === null) { + return ['status' => 'no_match']; + } + + // Multiple Son/Daughter rows: require a unique tie-breaker (name or DOB). + if (count($candidates) > 1) { + $topCount = 0; + foreach ($candidates as $tpa) { + if ($scoreCandidate($tpa) === $bestScore) { + $topCount++; + } + } + if ($topCount > 1 || $bestScore < 2) { + return ['status' => 'no_match']; + } + } + + $diff = []; + + if ($normalizeName($db['name'] ?? '') !== $normalizeName($bestTpa['name'] ?? '')) { + $diff[] = 'name'; + } + + if ((string) ($db['dob'] ?? '') !== (string) ($bestTpa['dob'] ?? '')) { + $diff[] = 'dob'; + } + + if ( + strtoupper(trim((string) ($db['gender'] ?? ''))) !== + strtoupper(trim((string) ($bestTpa['gender'] ?? ''))) + ) { + $diff[] = 'gender'; } - // 4️⃣ No match found return [ - 'status' => 'no_match' + 'status' => 'matched', + 'tpa_record' => $bestTpa, + 'not_matching' => $diff, ]; } diff --git a/app/Controllers/FhplApiController.php b/app/Controllers/FhplApiController.php index cbaf1115..6d684e1c 100644 --- a/app/Controllers/FhplApiController.php +++ b/app/Controllers/FhplApiController.php @@ -554,30 +554,32 @@ class FhplApiController extends BaseController foreach ($employeePolicyData as $policy) { $hasMatchForThisPolicy = false; foreach ($allMembers as $m) { + $apiRelation = map_relationship(trim($m['RELATION'] ?? '')); if ( - strtolower(trim($policy['name'])) === strtolower(trim($m['BENEFICIARY_NAME'] ?? '')) && - ($policy['emp_code'] ?? '') == ($m['EMPLOYEE_ID'] ?? '') && - strtolower($policy['relationship']) === strtolower($m['RELATION'] ?? '') + strtolower(trim((string) ($policy['name'] ?? ''))) === strtolower(trim((string) ($m['BENEFICIARY_NAME'] ?? ''))) + && trim((string) ($policy['emp_code'] ?? '')) === trim((string) ($m['EMPLOYEE_ID'] ?? '')) + && strtolower(trim((string) ($policy['relationship'] ?? ''))) === strtolower(trim((string) $apiRelation)) ) { - $hasMatchForThisPolicy = true; - - $sql = "UPDATE employee_polices SET tpa_id = ? WHERE id = ?"; - $this->db->query($sql, [$m['MEMBERSHIP_NO'], $policy['emp_policy_id']]); + $tpaId = $m['MEMBERSHIP_NO'] ?? $m['MEMBERSHIP_NO'] ?? null; + $sql = 'UPDATE employee_polices SET tpa_id = ? WHERE id = ?'; + $this->db->query($sql, [$tpaId, $policy['emp_policy_id']]); // for e-card send - if(strtolower(trim($policy['relationship'])) == 'self'){ + if (strtolower(trim((string) ($policy['relationship'] ?? ''))) === 'self') { $employee_policy_ids[] = $policy['emp_policy_id']; } - + if ($this->db->affectedRows() > 0) { - $updated++; - log_message('error', "FHPL - TPA ID Pull Updated tpa_id={$m['MEMBERSHIP_NO']} for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}"); + $updated++; + log_message('error', "FHPL - TPA ID Pull Updated tpa_id={$tpaId} for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}"); } else { - log_message('error', "FHPL - TPA ID Pull No update (already set or not matched) for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}"); + log_message('error', "FHPL - TPA ID Pull No update (already set or not matched) for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}"); } + + break; } } @@ -1070,7 +1072,7 @@ class FhplApiController extends BaseController 'gender' => format_gender_v2($row['GENDER'] ?? null), 'self' => strtolower($row['RELATION'] ?? '') === 'self' ? 1 : 0, - 'tpa_id' => trim($row['TPA_TPADETAIL_ID'] ?? null), + 'tpa_id' => trim($row['MEMBERSHIP_NO'] ?? null), 'age' => is_numeric($row['AGE'] ?? null) ? (int) $row['AGE'] : null, 'is_active' => 1, diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php index 7f347d6f..0b1fc090 100644 --- a/app/Controllers/LeadsController.php +++ b/app/Controllers/LeadsController.php @@ -368,8 +368,10 @@ class LeadsController extends BaseController $id = $this->request->getPost('id'); $actual_lead_id = $this->request->getPost('actual_lead_id'); $actual_lead_id = ! empty($actual_lead_id) ? $actual_lead_id : null; - $postData = $this->request->getPost(); - $data = $this->prepareLeadData(); + + $this->normalizeClaimHistoryPostData(); + $postData = $this->request->getPost(); + $data = $this->prepareLeadData(); $rules = [ @@ -526,47 +528,65 @@ class LeadsController extends BaseController ]; if ((int) $this->request->getPost('claim_history') === 1) { - $rules['first_year.*'] = [ - 'rules' => 'required|regex_match[/^\d{4}-\d{4}$/]', - 'errors' => ['required' => 'Claim Year is required for all entries.', 'regex_match' => 'Year must be in format YYYY-YYYY.'], - ]; - $rules['first_policy_type_.*'] = [ - 'rules' => 'required|regex_match[/^[a-zA-Z0-9 _-]+$/]', - 'errors' => ['required' => 'Policy Type is required in Claim History.', - 'regex_match' => 'Policy Type only letters, numbers, space, hyphens and underscores are allowed', - ], - ]; - $rules['first_date_of_loss_.*'] = [ - 'rules' => 'required|regex_match[/^[0-9]{2}-[0-9]{2}-[0-9]{4}$/]', - 'errors' => ['required' => 'Date of Loss is required.', - 'regex_match' => 'Date of Loss must be inValid format.'], - ]; - $rules['first_cause_of_loss.*'] = [ - 'rules' => 'required|regex_match[/^[a-zA-Z0-9 _-]+$/]', - 'errors' => [ - 'required' => 'Cause of Loss is required.', - 'regex_match' => 'Cause of Loss only letters, numbers, space, hyphens and underscores are allowed', - ], - ]; - $rules['first_claim_amount.*'] = [ - 'rules' => 'required|numeric', - 'errors' => [ - 'required' => 'Claim Amount is required.', - 'numeric' => 'Claim Amount must be a number.', - ], - ]; - $rules['first_settled_amount.*'] = [ - 'rules' => 'required|numeric', - 'errors' => ['required' => 'Settled Amount is required.', - 'numeric' => 'Settled Amount must be a number.'], - ]; - $rules['first_claim_status.*'] = [ - 'rules' => 'required|alpha_space', - 'errors' => [ - 'required' => 'Claim Status is required.', - 'alpha_space' => 'Claim Status should only contain letters and spaces.', - ], - ]; + $nilClaimsRows = $this->resolveNilClaimRowFlags($postData); + $claimRowCount = $this->getClaimHistoryRowCount($postData, $nilClaimsRows); + + for ($claimIndex = 0; $claimIndex < $claimRowCount; $claimIndex++) { + $rules["first_year.$claimIndex"] = [ + 'rules' => 'required|regex_match[/^\d{4}-\d{4}$/]', + 'errors' => [ + 'required' => 'Claim Year is required for all entries.', + 'regex_match' => 'Year must be in format YYYY-YYYY.', + ], + ]; + + if (! empty($nilClaimsRows[$claimIndex])) { + continue; + } + + $rules["first_policy_type_.$claimIndex"] = [ + 'rules' => 'required|regex_match[/^[a-zA-Z0-9 _-]+$/]', + 'errors' => [ + 'required' => 'Policy Type is required in Claim History.', + 'regex_match' => 'Policy Type only letters, numbers, space, hyphens and underscores are allowed', + ], + ]; + $rules["first_date_of_loss_.$claimIndex"] = [ + 'rules' => 'required|regex_match[/^[0-9]{2}-[0-9]{2}-[0-9]{4}$/]', + 'errors' => [ + 'required' => 'Date of Loss is required.', + 'regex_match' => 'Date of Loss must be inValid format.', + ], + ]; + $rules["first_cause_of_loss.$claimIndex"] = [ + 'rules' => 'required|regex_match[/^[a-zA-Z0-9 _-]+$/]', + 'errors' => [ + 'required' => 'Cause of Loss is required.', + 'regex_match' => 'Cause of Loss only letters, numbers, space, hyphens and underscores are allowed', + ], + ]; + $rules["first_claim_amount.$claimIndex"] = [ + 'rules' => 'required|numeric', + 'errors' => [ + 'required' => 'Claim Amount is required.', + 'numeric' => 'Claim Amount must be a number.', + ], + ]; + $rules["first_settled_amount.$claimIndex"] = [ + 'rules' => 'required|numeric', + 'errors' => [ + 'required' => 'Settled Amount is required.', + 'numeric' => 'Settled Amount must be a number.', + ], + ]; + $rules["first_claim_status.$claimIndex"] = [ + 'rules' => 'required|alpha_space', + 'errors' => [ + 'required' => 'Claim Status is required.', + 'alpha_space' => 'Claim Status should only contain letters and spaces.', + ], + ]; + } } } @@ -576,65 +596,75 @@ class LeadsController extends BaseController $claimHistoryPolicyTypes = [1, 6, 7]; $hasClaimHistoryPolicy = count(array_intersect($postedPolicyTypeIds, $claimHistoryPolicyTypes)) > 0; $isEbClaimHistory = $leadFormType === 1 - && in_array((int) ($postData['lead_type'] ?? 0), [2, 3], true) + && in_array((int) ($postData['lead_type'] ?? 0), [1, 2, 3], true) && $hasClaimHistoryPolicy && (int) ($postData['claim_history'] ?? 0) === 1; if ($isEbClaimHistory) { - $rules['first_year.*'] = [ - 'rules' => 'required|regex_match[/^\d{4}-\d{4}$/]', - 'errors' => [ - 'required' => 'Claim Year is required for all entries.', - 'regex_match' => 'Year must be in format YYYY-YYYY.', - ], - ]; - $rules['emp_id.*'] = [ - 'rules' => 'required', - 'errors' => ['required' => 'Employee ID is required in Claim History.'], - ]; - $rules['emp_name.*'] = [ - 'rules' => 'required', - 'errors' => ['required' => 'Employee Name is required in Claim History.'], - ]; - $rules['gender.*'] = [ - 'rules' => 'required|in_list[Female,Male]', - 'errors' => [ - 'required' => 'Gender is required in Claim History.', - 'in_list' => 'Gender must be Female or Male.', - ], - ]; - $rules['designation.*'] = [ - 'rules' => 'required', - 'errors' => ['required' => 'Designation is required in Claim History.'], - ]; - $rules['sum_insured.*'] = [ - 'rules' => 'required|numeric', - 'errors' => [ - 'required' => 'Sum Insured is required in Claim History.', - 'numeric' => 'Sum Insured must be a number.', - ], - ]; - $rules['first_death_date.*'] = [ - 'rules' => 'required|regex_match[/^[0-9]{2}-([0-9]{2}|[A-Za-z]{3})-[0-9]{4}$/]', - 'errors' => [ - 'required' => 'Date of Death is required.', - 'regex_match' => 'Date of Death must be in DD-MM-YYYY or DD-MMM-YYYY format.', - ], - ]; - $rules['first_cause_of_death.*'] = [ - 'rules' => 'required|in_list[natural_death,suicide,accident,cardiac_arrest,septic_shock,heart_attack]', - 'errors' => [ - 'required' => 'Nature/Cause Of Death is required.', - 'in_list' => 'Nature/Cause Of Death is invalid.', - ], - ]; - $rules['first_claim_amount.*'] = [ - 'rules' => 'required|numeric', - 'errors' => [ - 'required' => 'Claim/Settled Amount is required.', - 'numeric' => 'Claim/Settled Amount must be a number.', - ], - ]; + $nilClaimsRows = $this->resolveNilClaimRowFlags($postData); + $claimRowCount = $this->getClaimHistoryRowCount($postData, $nilClaimsRows); + + for ($claimIndex = 0; $claimIndex < $claimRowCount; $claimIndex++) { + $rules["first_year.$claimIndex"] = [ + 'rules' => 'required|regex_match[/^\d{4}-\d{4}$/]', + 'errors' => [ + 'required' => 'Claim Year is required for all entries.', + 'regex_match' => 'Year must be in format YYYY-YYYY.', + ], + ]; + + if (! empty($nilClaimsRows[$claimIndex])) { + continue; + } + + $rules["emp_id.$claimIndex"] = [ + 'rules' => 'required', + 'errors' => ['required' => 'Employee ID is required in Claim History.'], + ]; + $rules["emp_name.$claimIndex"] = [ + 'rules' => 'required', + 'errors' => ['required' => 'Employee Name is required in Claim History.'], + ]; + $rules["gender.$claimIndex"] = [ + 'rules' => 'required|in_list[Female,Male]', + 'errors' => [ + 'required' => 'Gender is required in Claim History.', + 'in_list' => 'Gender must be Female or Male.', + ], + ]; + $rules["designation.$claimIndex"] = [ + 'rules' => 'required', + 'errors' => ['required' => 'Designation is required in Claim History.'], + ]; + $rules["sum_insured.$claimIndex"] = [ + 'rules' => 'required|numeric', + 'errors' => [ + 'required' => 'Sum Insured is required in Claim History.', + 'numeric' => 'Sum Insured must be a number.', + ], + ]; + $rules["first_death_date.$claimIndex"] = [ + 'rules' => 'required|regex_match[/^[0-9]{2}-([0-9]{2}|[A-Za-z]{3})-[0-9]{4}$/]', + 'errors' => [ + 'required' => 'Date of Death is required.', + 'regex_match' => 'Date of Death must be in DD-MM-YYYY or DD-MMM-YYYY format.', + ], + ]; + $rules["first_cause_of_death.$claimIndex"] = [ + 'rules' => 'required|in_list[natural_death,suicide,accident,cardiac_arrest,septic_shock,heart_attack]', + 'errors' => [ + 'required' => 'Nature/Cause Of Death is required.', + 'in_list' => 'Nature/Cause Of Death is invalid.', + ], + ]; + $rules["first_claim_amount.$claimIndex"] = [ + 'rules' => 'required|numeric', + 'errors' => [ + 'required' => 'Claim/Settled Amount is required.', + 'numeric' => 'Claim/Settled Amount must be a number.', + ], + ]; + } } // 1. MANUALLY VALIDATE FILES BEFORE PROCESSING @@ -2866,7 +2896,9 @@ class LeadsController extends BaseController //claim history new sheet; if ($claim_history == 1 && !empty($rfq_data['fin_years_claims'])) { - $claim_details = json_decode($rfq_data['fin_years_claims'], true) ?? []; + $claim_details = $this->sanitizeClaimDetailsForExport( + json_decode($rfq_data['fin_years_claims'], true) ?? [] + ); if (! empty($claim_details['finyear'])) { @@ -4654,6 +4686,209 @@ class LeadsController extends BaseController } } + private function normalizeClaimHistoryPostData(): void + { + $post = $this->request->getPost(); + + if ((int) ($post['claim_history'] ?? 0) !== 1) { + return; + } + + $rows = $this->getFinyearRowsFromPost($post); + + if ($rows === []) { + return; + } + + $leadFormType = (int) ($post['lead_form_type'] ?? 1); + $claimArrays = $leadFormType === 2 + ? $this->buildNonEbClaimHistoryPostArrays($rows) + : $this->buildEbClaimHistoryPostArrays($rows); + + $this->request->setGlobal('post', array_merge($post, $claimArrays)); + } + + /** + * Remove internal nil_claims flag from stored/exported claim rows. + * + * @param array $claimDetails + * + * @return array + */ + private function sanitizeClaimDetailsForExport(array $claimDetails): array + { + if (empty($claimDetails['finyear']) || ! is_array($claimDetails['finyear'])) { + return $claimDetails; + } + + $claimDetails['finyear'] = array_map(static function ($record) { + if (! is_array($record)) { + return $record; + } + + unset($record['nil_claims']); + + return $record; + }, $claimDetails['finyear']); + + return $claimDetails; + } + + /** + * @return list> + */ + private function getFinyearRowsFromPost(array $postData): array + { + $jsonPayload = $postData['finyear'] ?? $postData['fin_years_claims'] ?? null; + + if (! is_string($jsonPayload) || $jsonPayload === '') { + return []; + } + + $decoded = json_decode($jsonPayload, true); + + if (! is_array($decoded) || empty($decoded['finyear']) || ! is_array($decoded['finyear'])) { + return []; + } + + return $decoded['finyear']; + } + + /** + * @param list> $rows + * + * @return array> + */ + private function buildEbClaimHistoryPostArrays(array $rows): array + { + $arrays = [ + 'first_year' => [], + 'nil_claims' => [], + 'emp_id' => [], + 'emp_name' => [], + 'gender' => [], + 'designation' => [], + 'sum_insured' => [], + 'first_death_date' => [], + 'first_cause_of_death' => [], + 'first_claim_amount' => [], + ]; + + foreach ($rows as $row) { + $isNil = ! empty($row['nil_claims']); + + $arrays['first_year'][] = (string) ($row['year'] ?? ''); + $arrays['nil_claims'][] = $isNil ? '1' : '0'; + + if ($isNil) { + $arrays['emp_id'][] = 'Nil'; + $arrays['emp_name'][] = 'Nil'; + $arrays['gender'][] = 'Nil'; + $arrays['designation'][] = 'Nil'; + $arrays['sum_insured'][] = 'Nil'; + $arrays['first_death_date'][] = 'Nil'; + $arrays['first_cause_of_death'][] = 'Nil'; + $arrays['first_claim_amount'][] = 'Nil'; + } else { + $arrays['emp_id'][] = (string) ($row['emp_id'] ?? ''); + $arrays['emp_name'][] = (string) ($row['emp_name'] ?? ''); + $arrays['gender'][] = (string) ($row['gender'] ?? ''); + $arrays['designation'][] = (string) ($row['designation'] ?? ''); + $arrays['sum_insured'][] = (string) ($row['sum_insured'] ?? ''); + $arrays['first_death_date'][] = (string) ($row['death_date'] ?? ''); + $arrays['first_cause_of_death'][] = (string) ($row['cause_of_death'] ?? ''); + $arrays['first_claim_amount'][] = (string) ($row['settled'] ?? ($row['claim_amount'] ?? '')); + } + } + + return $arrays; + } + + /** + * @param list> $rows + * + * @return array> + */ + private function buildNonEbClaimHistoryPostArrays(array $rows): array + { + $arrays = [ + 'first_year' => [], + 'nil_claims' => [], + 'first_policy_type_' => [], + 'first_date_of_loss_' => [], + 'first_cause_of_loss' => [], + 'first_claim_amount' => [], + 'first_settled_amount' => [], + 'first_claim_status' => [], + ]; + + foreach ($rows as $row) { + $isNil = ! empty($row['nil_claims']); + + $arrays['first_year'][] = (string) ($row['year'] ?? ''); + $arrays['nil_claims'][] = $isNil ? '1' : '0'; + + if ($isNil) { + $arrays['first_policy_type_'][] = 'Nil'; + $arrays['first_date_of_loss_'][] = 'Nil'; + $arrays['first_cause_of_loss'][] = 'Nil'; + $arrays['first_claim_amount'][] = 'Nil'; + $arrays['first_settled_amount'][] = 'Nil'; + $arrays['first_claim_status'][] = 'Nil'; + } else { + $arrays['first_policy_type_'][] = (string) ($row['policy_type'] ?? ''); + $arrays['first_date_of_loss_'][] = (string) ($row['date_of_loss'] ?? ''); + $arrays['first_cause_of_loss'][] = (string) ($row['cause_of_loss'] ?? ''); + $arrays['first_claim_amount'][] = (string) ($row['claim_amount'] ?? ''); + $arrays['first_settled_amount'][] = (string) ($row['settled_amount'] ?? ''); + $arrays['first_claim_status'][] = (string) ($row['status'] ?? ''); + } + } + + return $arrays; + } + + /** + * @return array Row index => 1 when nil claims, else 0 + */ + private function resolveNilClaimRowFlags(array $postData): array + { + $flags = []; + + foreach ((array) ($postData['nil_claims'] ?? []) as $idx => $val) { + $flags[(int) $idx] = (int) $val; + } + + foreach ($this->getFinyearRowsFromPost($postData) as $idx => $row) { + if (! is_array($row)) { + continue; + } + + if (! empty($row['nil_claims'])) { + $flags[(int) $idx] = 1; + } elseif (! isset($flags[(int) $idx])) { + $flags[(int) $idx] = 0; + } + } + + return $flags; + } + + /** + * @param array $nilClaimFlags + */ + private function getClaimHistoryRowCount(array $postData, array $nilClaimFlags): int + { + $counts = [ + count((array) ($postData['first_year'] ?? [])), + count($nilClaimFlags), + ]; + + $counts[] = count($this->getFinyearRowsFromPost($postData)); + + return max(0, ...$counts); + } + public function getLastFiveFinancialYears(): array { $year = (int) date('Y'); @@ -4921,8 +5156,11 @@ class LeadsController extends BaseController $data['lead_edit_data']['multi_file_html'] = trim($html) !== '' ? $html : null; } - if (! in_array((int) $data['lead_edit_data']['lead_type'], [1, 3], true) && $data['lead_edit_data']['lead_form_type'] == 2) { - $data['lead_edit_data']['claims_details_html'] = view('rfq/claims_details_non_eb', $data['lead_edit_data']); + if (in_array((int) $data['lead_edit_data']['lead_type'], [1, 2, 3], true) && $data['lead_edit_data']['lead_form_type'] == 2) { + $data['lead_edit_data']['claims_details_html'] = view('rfq/claims_details_non_eb', [ + 'lead_edit_data' => $data['lead_edit_data'], + 'lastFiveYears' => $data['lastFiveYears'] ?? $this->getLastFiveFinancialYears(), + ]); } else { $data['lead_edit_data']['claims_details_html'] = ""; } @@ -5372,6 +5610,16 @@ class LeadsController extends BaseController { helper('excel_util_helper'); + $finyear = array_map(static function ($record) { + if (! is_array($record)) { + return $record; + } + + unset($record['nil_claims']); + + return $record; + }, $finyear); + $first = $finyear[0] ?? null; if (! is_array($first) || $first === []) { @@ -5844,8 +6092,11 @@ class LeadsController extends BaseController public function generateViewPageHtml($policy_type_id, $data = []) { - $data['insurer'] = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(); - $data['tpa'] = $this->tpaBranchModel->getTpaBranchesWithTpaNames(); + $data['insurer'] = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(); + $data['tpa'] = $this->tpaBranchModel->getTpaBranchesWithTpaNames(); + $data['lastFiveYears'] = $data['lastFiveYears'] ?? $this->getLastFiveFinancialYears(); + $data['gpaClaimType'] = $data['gpaClaimType'] ?? $this->claim_type_for_gpa; + $data['causeOfDeath'] = $data['causeOfDeath'] ?? $this->cause_of_death; $viewMap = [ 1 => 'rfq/gpa', @@ -6483,7 +6734,9 @@ class LeadsController extends BaseController if (! empty($rfq_data['fin_years_claims']) && $claim_history == 1) { - $claim_details = json_decode($rfq_data['fin_years_claims'], true) ?? []; + $claim_details = $this->sanitizeClaimDetailsForExport( + json_decode($rfq_data['fin_years_claims'], true) ?? [] + ); if (! empty($claim_details['finyear'])) { diff --git a/app/Controllers/TicketServiceController.php b/app/Controllers/TicketServiceController.php index 24e5e463..ffa6f154 100644 --- a/app/Controllers/TicketServiceController.php +++ b/app/Controllers/TicketServiceController.php @@ -1297,6 +1297,7 @@ class TicketServiceController extends AdminController } else { //check the employee and insured + $params['is_from'] = 'claim_dump'; $employee_data = $ticketMasterModal->getEmployeeAndEmployeePolicyDetails($params) ?? []; // dd($employee_data); if (count($employee_data) == 0) { diff --git a/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php b/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php index 566bb703..467fceba 100644 --- a/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php +++ b/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php @@ -19,6 +19,7 @@ abstract class BaseTpaClaimImportService protected $claimDumpFileModel; protected $clientPolicyModel; protected $policyNumberMapping; + protected $tpaTableMapping; public function __construct() { @@ -33,6 +34,14 @@ abstract class BaseTpaClaimImportService (int) env('R_CARE_PRIMARY_KEY_CONSTANT') => 'Policy Number', (int) env('ICICI_PRIMARY_KEY_CONSTANT') => 'POLICY_NO', ]; + $this->tpaTableMapping = [ + (int) env('VIDAL_PRIMARY_KEY_CONSTANT') => 'claims_dump_vidal', + (int) env('ABHI_PRIMARY_KEY_CONSTANT') => 'claims_dump_abhi', + (int) env('MEDI_ASSIST_PRIMARY_KEY_CONSTANT') => 'claims_dump_medi_assist', + (int) env('FHPL_PRIMARY_KEY_CONSTANT') => 'claims_dump_fhpl', + (int) env('R_CARE_PRIMARY_KEY_CONSTANT') => 'claims_dump_reliance', + (int) env('ICICI_PRIMARY_KEY_CONSTANT') => 'claims_dump_icici', + ]; } /** @@ -58,8 +67,7 @@ abstract class BaseTpaClaimImportService } if (empty($rows)) { - $this->db->transRollback(); // ROLLBACK BEFORE RETURN - return ['status' => false, 'message' => 'Excel file contains no data or wrong file upload']; + return $this->failTpaClaimDumpInsert($fileId, 'Excel file contains no data or wrong file upload'); } if(isset($this->policyNumberMapping[$fileData['tpa_id']]) && !empty($this->policyNumberMapping[$fileData['tpa_id']])){ @@ -70,22 +78,19 @@ abstract class BaseTpaClaimImportService if($client_policy_data['policy_no'] != ($rows[0][$policy_number_column] ?? '')){ - $this->db->transRollback(); - return ['status' => false, 'message' => 'Policy number mismatch in the file and in the system']; + return $this->failTpaClaimDumpInsert($fileId, 'Policy number mismatch in the file and in the system'); } $tpaInsertData = $this->mapTPAData($rows, $fileId); if (empty($tpaInsertData)) { - $this->db->transRollback(); // ROLLBACK BEFORE RETURN - return ['status' => false, 'message' => 'These records already exist in the system.']; + return $this->failTpaClaimDumpInsert($fileId, 'These records already exist in the system.'); } $return_res = $this->bulkInsertTPATable($tpaInsertData); if ($return_res !== true) { - $this->db->transRollback(); // ROLLBACK BEFORE RETURN - return ['status' => false, 'message' => 'TPA Import bulk insert failed']; + return $this->failTpaClaimDumpInsert($fileId, 'TPA Import bulk insert failed'); } // 2. Commit if everything is fine @@ -93,9 +98,7 @@ abstract class BaseTpaClaimImportService return ['status' => true, 'message' => 'File uploaded successfully', 'record_count' => count($tpaInsertData)]; } catch (\Throwable $e) { - // 3. Rollback on any crash/exception - $this->db->transRollback(); - return ['status' => false, 'message' => 'System error : ' . $e->getMessage()]; + return $this->failTpaClaimDumpInsert($fileId, 'System error : ' . $e->getMessage()); } } @@ -113,7 +116,7 @@ abstract class BaseTpaClaimImportService // Check if mapping failed if (!$ticketMasterData['status']) { - $this->db->transRollback(); // ALWAYS rollback before early return + $this->rollbackAndCleanupClaimDumpData($file_id); return $ticketMasterData; } @@ -125,13 +128,11 @@ abstract class BaseTpaClaimImportService if (!empty($ticketMasterData['mapped_array'])) { $insert_res = $this->importClaimMaster($ticketMasterData['mapped_array']); if (!$insert_res) { - $this->db->transRollback(); - return ['status' => false, 'message' => 'Ticket Master Claim bulk insert failed']; + return $this->failTicketMasterInsert($file_id, 'Ticket Master Claim bulk insert failed'); } // Map newly created ticket IDs back to the TPA staging table if (!$this->updateTicketIdInTPATable($file_id)) { - $this->db->transRollback(); - return ['status' => false, 'message' => 'Updating ticket_id in TPA table failed']; + return $this->failTicketMasterInsert($file_id, 'Updating ticket_id in TPA table failed'); } $message .= 'Ticket Master Claim bulk insert success. '; @@ -144,8 +145,7 @@ abstract class BaseTpaClaimImportService if (!empty($ticketMasterData['rejected_reason_array'])) { $update_res = $this->updateTicketMasterRejectedReasonInTPATable($ticketMasterData['rejected_reason_array']); if (!$update_res) { - $this->db->transRollback(); - return ['status' => false, 'message' => 'Updating rejected reasons failed']; + return $this->failTicketMasterInsert($file_id, 'Updating rejected reasons failed'); } $message .= empty($ticketMasterData['mapped_array']) @@ -156,24 +156,69 @@ abstract class BaseTpaClaimImportService // If nothing was processed but no error occurred if (!$hasExecutedTask) { - $this->db->transRollback(); - return ['status' => false, 'message' => 'No data found to process.']; + return $this->failTicketMasterInsert($file_id, 'No data found to process.'); } // 2. Commit the transaction $this->db->transCommit(); + + if (!$status) { + $this->cleanupClaimDumpData($file_id); + } + return ['status' => $status, 'message' => trim($message)]; } catch (\Throwable $th) { - // 3. Rollback on crash - $this->db->transRollback(); - return [ - 'status' => false, - 'message' => 'System error during Ticket Master Insert: ' . $th->getMessage() - ]; + $fileId = (int) ($params['file_id'] ?? 0); + return $this->failTicketMasterInsert( + $fileId, + 'System error during Ticket Master Insert: ' . $th->getMessage() + ); } } + /** + * Remove TPA staging rows and ticket_master rows created for a failed claim dump upload. + */ + protected function cleanupClaimDumpData(int $fileId): void + { + if ($fileId <= 0) { + return; + } + + $fileData = $this->claimDumpFileModel->where('id', $fileId)->first(); + if (empty($fileData)) { + return; + } + + $tpaId = (int) ($fileData['tpa_id'] ?? 0); + $tpaTable = $this->tpaTableMapping[$tpaId] ?? null; + + if ($tpaTable !== null) { + $this->db->table($tpaTable)->where('file_id', $fileId)->delete(); + } + + $this->db->table('ticket_master')->where('file_id', $fileId)->delete(); + } + + protected function rollbackAndCleanupClaimDumpData(int $fileId): void + { + $this->db->transRollback(); + $this->cleanupClaimDumpData($fileId); + } + + protected function failTpaClaimDumpInsert(int $fileId, string $message): array + { + $this->rollbackAndCleanupClaimDumpData($fileId); + return ['status' => false, 'message' => $message]; + } + + protected function failTicketMasterInsert(int $fileId, string $message): array + { + $this->rollbackAndCleanupClaimDumpData($fileId); + return ['status' => false, 'message' => $message]; + } + /** * Read Excel and return associative rows (header based) */ @@ -324,7 +369,15 @@ abstract class BaseTpaClaimImportService * Dublicate check in the TPA specific table records */ public function getEmployeeDetails(int $client_id, int $client_policy_id, string $emp_code, string $relation): array - { + { + + $client_policy_data = $this->clientPolicyModel->where('id', $client_policy_id)->first(); + if(!empty($client_policy_data)){ + if(!empty($client_policy_data['base_policy'])){ + $client_policy_id = $client_policy_data['base_policy']; + } + } + $EmployeeModel = new EmployeeModel(); $employeeData = $EmployeeModel ->select([ diff --git a/app/Models/ClaimFilesModel.php b/app/Models/ClaimFilesModel.php index 055b9b3b..66bd25ed 100644 --- a/app/Models/ClaimFilesModel.php +++ b/app/Models/ClaimFilesModel.php @@ -59,4 +59,18 @@ class ClaimFilesModel extends Model return $data; } + + /** + * Whether the claim (ticket) has at least one active PDF in claim_files. + */ + public function hasPdfFileForTicket($ticketId): bool + { + return $this->where('ticket_id', $ticketId) + ->where('is_active', 1) + ->groupStart() + ->where('mime_type', 'pdf') + ->orWhere('mime_type', 'application/pdf') + ->groupEnd() + ->countAllResults(false) > 0; + } } diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php index dac8f8d6..474221b2 100755 --- a/app/Models/EmployeePolicyModel.php +++ b/app/Models/EmployeePolicyModel.php @@ -756,14 +756,17 @@ class EmployeePolicyModel extends Model LEFT JOIN ( SELECT emp_code, + group_key, CAST(MAX(CASE WHEN field_name = 'basic_cover_si' THEN new_value END) AS UNSIGNED) AS new_basic_cover_si, CAST(MAX(CASE WHEN field_name = 'premium' THEN new_value END) AS DECIMAL(10,2)) AS new_si_premium, CAST(MAX(CASE WHEN field_name = 'premium' THEN old_value END) AS DECIMAL(10,2)) AS old_si_premium, MAX(CASE WHEN field_name = 'si_enhancement_date' THEN new_value END) AS date_of_coverage FROM emp_endorsement $subquery_endorsement_condition - GROUP BY emp_code - ) AS sidata ON a.emp_code = sidata.emp_code + AND actions = 'si' + AND status != 'truncated' + GROUP BY emp_code, group_key + ) AS sidata ON a.emp_code = sidata.emp_code AND a.group_key = sidata.group_key WHERE employee_polices.client_policy_id = '{$client_policy_id}' AND employees.client_branch_id = '{$client_branch_id}' $endorsement_condition @@ -2252,7 +2255,7 @@ class EmployeePolicyModel extends Model } else if(count($emp_codes) > 0 && $all == false) { - $result->whereNotIn('emp.emp_code',$emp_codes); + $result->whereNotIn('employee_polices.id',$emp_codes); } else if(count($emp_codes) == 0 && $all == true) { diff --git a/app/Models/TicketMasterModel.php b/app/Models/TicketMasterModel.php index 8a6128ca..f6ea661d 100644 --- a/app/Models/TicketMasterModel.php +++ b/app/Models/TicketMasterModel.php @@ -1118,12 +1118,23 @@ class TicketMasterModel extends Model $policy_no = $params['policy_no'] ?? null; $relationship = $params['relationship'] ?? null; $insured_name = $params['insured_name'] ?? null; + $is_from = $params['is_from'] ?? null; // $client_name = "6-Eleven"; // $emp_code = "EMP0020K12"; // $emp_name = "Lokesh"; // $policy_no = "GMC-1999/2000/2021/2022"; + $base_policy_id = null; + if($is_from == "claim_dump"){ + $client_policy_data = $this->db->table('client_policy')->where('policy_no', trim($policy_no))->where('is_active', 1)->get()->getRowArray(); + if(isset($client_policy_data) && !empty($client_policy_data)){ + if(!empty($client_policy_data['base_policy'])) { + $base_policy_id = $client_policy_data['base_policy']; + } + } + } + $builder = $this->db->table('employees e'); $builder->select(" e.id as emp_id, @@ -1161,7 +1172,13 @@ class TicketMasterModel extends Model $builder->where('e.emp_code', trim($emp_code)); $builder->where('e.name', trim($emp_name)); $builder->where('c.client_name', trim($client_name)); - $builder->where('cp.policy_no', trim($policy_no)); + + if(!empty($base_policy_id)) { + $builder->where('cp.id', trim($base_policy_id)); + } else { + $builder->where('cp.policy_no', trim($policy_no)); + } + $builder->where('LOWER(e.relationship)', strtolower('self')); $query = $builder->get(); diff --git a/app/Views/batch_list.php b/app/Views/batch_list.php index e63140ef..5ebdebc5 100755 --- a/app/Views/batch_list.php +++ b/app/Views/batch_list.php @@ -112,18 +112,44 @@ for ($i = 0; $i < $batch_col_count; $i++) { max-width: 95%; } +/* Make the modal content a flex column so only the body scrolls */ #tpa_variation_modal .modal-content { max-height: 90vh; + display: flex; + flex-direction: column; } +/* Internal vertical scroll for large tables, keep header/footer fixed */ #tpa_variation_modal .modal-body { - max-height: calc(85vh - 50px); + flex: 1 1 auto; overflow-y: auto; direction: ltr; } +/* Tab panes must shrink inside flex modal-body so scrollX width is correct */ +#tpa_variation_modal .tab-content, +#tpa_variation_modal .tab-pane { + min-width: 0; +} + +/* Outer .table-responsive must not scroll when DataTables scrollX is active (see custom.css) */ #tpa_variation_modal .table-responsive { - overflow-x: auto; + width: 100%; + max-width: 100%; +} + +#tpa_variation_modal .dataTables_wrapper { + width: 100%; + max-width: 100%; +} + +#tpa_variation_modal .dataTables_scrollHead { + overflow: hidden !important; +} + +#tpa_variation_modal .dataTables_scrollBody { + overflow-x: auto !important; + -webkit-overflow-scrolling: touch; } #tpa_variation_modal table { @@ -548,6 +574,10 @@ for ($i = 0; $i < $batch_col_count; $i++) { let tpaNotInNhanceProceedEnabled = true; /** From API `not_in_nhance_proceed_button_text` — label for Proceed on "Not in Nhance" tab. */ let tpaNotInNhanceProceedButtonText = 'Proceed - Not in Nhance'; + /** From API `not_matched_count` — when 0, Proceed is disabled on "Need to Review" tab. */ + let tpaNeedToReviewProceedEnabled = true; + /** From API `need_to_review_proceed_button_text` — label for Proceed on "Need to Review" tab. */ + let tpaNeedToReviewProceedButtonText = 'Proceed - Need to Review ( 0 )'; const tpaVariationColumns = { not_in_nhance: [ @@ -694,6 +724,16 @@ for ($i = 0; $i < $batch_col_count; $i++) { tpaNotInNhanceProceedButtonText = 'Proceed - Not in Nhance'; } + const notMatchedCount = parseInt(data.not_matched_count, 10); + tpaNeedToReviewProceedEnabled = !isNaN(notMatchedCount) && notMatchedCount > 0; + if (typeof data.need_to_review_proceed_button_text === 'string' && data.need_to_review_proceed_button_text.trim() !== '') { + tpaNeedToReviewProceedButtonText = data.need_to_review_proceed_button_text.trim(); + } else if (!isNaN(notMatchedCount)) { + tpaNeedToReviewProceedButtonText = 'Proceed - Need to Review ( ' + notMatchedCount + ' )'; + } else { + tpaNeedToReviewProceedButtonText = 'Proceed - Need to Review ( 0 )'; + } + showTPAVariationTabByLinkId('not-in-nhance-tab'); updateTPAProceedButton('not-in-nhance-tab'); adjustVariationTableByTabId('not-in-nhance-tab'); @@ -711,6 +751,20 @@ for ($i = 0; $i < $batch_col_count; $i++) { updateTPAProceedButton($activeTab.attr('id')); } + function bindVariationScrollHeadSync($wrap) { + const $body = $wrap.find('.dataTables_scrollBody'); + const $head = $wrap.find('.dataTables_scrollHead'); + if (!$body.length || !$head.length) { + return; + } + $body.off('scroll.nhTpaVarHScroll').on('scroll.nhTpaVarHScroll', function () { + $head.scrollLeft($(this).scrollLeft()); + }); + $head.off('scroll.nhTpaVarHScroll').on('scroll.nhTpaVarHScroll', function () { + $body.scrollLeft($(this).scrollLeft()); + }); + } + function getVariationDataTableConfig() { return { dom: "<'dt-top'lf>" + @@ -722,7 +776,15 @@ for ($i = 0; $i < $batch_col_count; $i++) { paging: true, ordering: false, info: false, + scrollX: true, + scrollY: false, + scrollCollapse: false, autoWidth: false, + initComplete: function () { + const $wrap = $(this.api().table().container()); + $wrap.closest('.table-responsive').addClass('nh-dt-no-outer-scroll'); + bindVariationScrollHeadSync($wrap); + }, language: { search: `
@@ -773,8 +835,17 @@ for ($i = 0; $i < $batch_col_count; $i++) { } const dt = $table.DataTable(); + const $wrap = $(dt.table().container()); + bindVariationScrollHeadSync($wrap); dt.columns.adjust().draw(false); bindVariationSearchIcons($table); + + /* Re-measure after tab/modal becomes visible — hidden tables mis-size columns */ + setTimeout(function () { + if ($table.is(':visible')) { + dt.columns.adjust().draw(false); + } + }, 0); } function adjustVariationTableByTabId(tabId) { @@ -814,7 +885,10 @@ for ($i = 0; $i < $batch_col_count; $i++) { $button.prop('disabled', true); } } else if (activeId === 'need-to-review-tab') { - $button.text('Proceed - Need to Review'); + $button.text(tpaNeedToReviewProceedButtonText); + if (!tpaNeedToReviewProceedEnabled) { + $button.prop('disabled', true); + } } else if (activeId === 'not-in-tpa-tab') { $button.addClass('d-none'); } else { @@ -829,12 +903,32 @@ for ($i = 0; $i < $batch_col_count; $i++) { const activeId = $(e.target).attr('id'); updateTPAProceedButton(activeId); adjustVariationTableByTabId(activeId); + setTimeout(function () { + const tabToTableMap = { + 'not-in-nhance-tab': '#not_in_nhance_table', + 'not-in-tpa-tab': '#not_in_tpa_table', + 'need-to-review-tab': '#need_to_review_table' + }; + const sel = tabToTableMap[activeId]; + const $t = sel ? $(sel) : $(); + if ($.fn.DataTable.isDataTable($t)) { + $t.DataTable().columns.adjust().draw(false); + } + }, 50); }); $('#tpa_variation_modal').on('shown.bs.modal', function () { showTPAVariationTabByLinkId('not-in-nhance-tab'); updateTPAProceedButton('not-in-nhance-tab'); adjustVariationTableByTabId('not-in-nhance-tab'); + setTimeout(function () { + ['#not_in_nhance_table', '#not_in_tpa_table', '#need_to_review_table'].forEach(function (sel) { + const $t = $(sel); + if ($.fn.DataTable.isDataTable($t) && $t.is(':visible')) { + $t.DataTable().columns.adjust().draw(false); + } + }); + }, 50); }); $('#tpa_variation_modal').on('hidden.bs.modal', function () { @@ -1155,6 +1249,10 @@ for ($i = 0; $i < $batch_col_count; $i++) { } else if (activeId === 'not-in-tpa-tab') { proceedNotInTPA(); } else if (activeId === 'need-to-review-tab') { + if (!tpaNeedToReviewProceedEnabled) { + toastr.warning('No mismatched records to proceed.', 'WARNING'); + return; + } proceedNeedToReview(); } else { toastr.warning('Unknown tab selected.', 'WARNING'); diff --git a/app/Views/leads_form.php b/app/Views/leads_form.php index 36d930c8..d6942deb 100644 --- a/app/Views/leads_form.php +++ b/app/Views/leads_form.php @@ -163,7 +163,8 @@ -->
+ enctype="multipart/form-data" + data-parsley-excluded="input[type=button], input[type=submit], input[type=reset], input[type=hidden], [disabled], :hidden, .select2-search__field"> @@ -487,7 +488,7 @@ function restoreActualLeadGstNumber() { if ($('#actual_lead_id').val() && $('#actual_lead_id').val() != 0 && actualLeadGstNumber) { - $('#gst').val(actualLeadGstNumber); + $('#gst').val(String(actualLeadGstNumber).trim().toUpperCase()); } } @@ -770,18 +771,7 @@ leadTypeBsedHideAndShow(lead_type, false, policy_type_id) - if (lead_type == 1) { - $('.claim-row').hide(); - } else { - $('.claim-row').show(); - if (policy_type_id == 1) { - $('.gpaClaimFileds').show(); - $('.lifeClaimFields').hide(); - } else if (policy_type_id == 6 || policy_type_id == 7) { - $('.gpaClaimFileds').hide(); - $('.lifeClaimFields').show(); - } - } + updateClaimRowVisibility(policy_type_id); if (lead_type != 1 && policy_type_id != 1 && policy_type_id != 6 && policy_type_id != 7) { // updateRenewalFields(dataIncrement); @@ -1160,11 +1150,9 @@ leadTypeBsedHideAndShow(lead_type) - if (lead_type == 1) { - $('.claim-row').hide(); - } else if (!shouldShowClaimHistorySwitch(lead_type, policy_type_id)) { - $('.claim-row').show(); + updateClaimRowVisibility(policy_type_id); + if (!shouldShowClaimHistorySwitch(lead_type, policy_type_id)) { if (policy_type_id == 1) { $('.gpaClaimFileds').show(); $('.lifeClaimFields').hide(); @@ -1774,15 +1762,56 @@ event.preventDefault(); + $('.claim-row').each(function() { + const isNil = $(this).find('.nil-claims-checkbox').prop('checked'); + $(this).find('.nil-claims-value').val(isNil ? '1' : '0'); + }); + + if (typeof window.prepareLeadsFormForSubmit === 'function') { + window.prepareLeadsFormForSubmit(); + } + var isValid = $('#leads_form_id').parsley().validate(); if (!isValid) { - $('#leads_form_id').find('input, select, textarea').each(function() { - if ($(this).parsley().isValid() === false && !$(this).val()) { - console.log('Empty field ID:', this.id); + var invalidFields = typeof window.getLeadsFormInvalidFields === 'function' + ? window.getLeadsFormInvalidFields() + : []; + + if (invalidFields.length) { + console.table(invalidFields); + invalidFields.forEach(function(f) { + console.log('Invalid field:', f.label || f.name || f.id, f); + }); + + var firstInvalid = invalidFields[0]; + var fieldLabel = firstInvalid.label || firstInvalid.name || firstInvalid.id || 'A required field'; + var fieldMessage = (firstInvalid.messages && firstInvalid.messages.length) + ? firstInvalid.messages[0] + : (firstInvalid.isEmpty ? 'This field is required.' : 'Please check this field.'); + + if (typeof toastr !== 'undefined') { + toastr.warning(fieldLabel + ': ' + fieldMessage, 'Validation'); } - }); - console.log('Form is Empty', 'Warning'); + + if (firstInvalid.id) { + var $invalidField = $('#' + firstInvalid.id); + if ($invalidField.length) { + var scrollTarget = $invalidField.closest('.form-group, .card, .dynamic-form-row'); + if (scrollTarget.length) { + $('html, body').animate({ + scrollTop: scrollTarget.offset().top - 100 + }, 300); + } + $invalidField.focus(); + } + } + } else { + console.warn('Form validation failed'); + if (typeof toastr !== 'undefined') { + toastr.warning('Please correct the highlighted fields.', 'Validation'); + } + } return; } @@ -1803,12 +1832,11 @@ const jsonString = JSON.stringify(salse_person_id); console.log('jsonString', jsonString); - // Append the JSON string to the FormData object formData.append('salse_person_id', jsonString); - // Convert the claim experience array to JSON const finyearJsonString = gatherClaimExperienceData(policy_type_ids); console.log('finyearJsonString', finyearJsonString); formData.append('finyear', finyearJsonString); + syncClaimHistoryFieldsToFormData(formData); let claimHistoryStatus = $("#claim_history").length > 0 && $("#claim_history").prop("checked") ? 1 : 0; formData.set('claim_history', claimHistoryStatus); @@ -2065,6 +2093,25 @@ $(".claim-row").each(function() { + let isNilClaims = $(this).find(".nil-claims-checkbox").prop("checked"); + + if (isNilClaims) { + let year = $(this).find("[name='first_year[]']").val(); + claimData.push({ + "year": year, + "emp_id": "Nil", + "emp_name": "Nil", + "gender": "Nil", + "designation": "Nil", + "sum_insured": "Nil", + "death_date": "Nil", + "cause_of_death": "Nil", + "settled": "Nil", + "nil_claims": 1, + }); + return; + } + let year = $(this).find("[name='first_year[]']").val(); let claimAmount = $(this).find("[name='first_claim_amount[]']").val(); let claimStatus = $(this).find("[name='first_claim_status[]']").val(); @@ -2088,6 +2135,7 @@ "death_date": deathDate, "cause_of_death": causeOfDeath, "settled": claimAmount, + "nil_claims": 0, }); }); @@ -2196,8 +2244,37 @@ return ['1', '6', '7'].includes(String(policyTypeId)); } + function getClaimHistoryLabel(leadType) { + return String(leadType) === '1' ? 'Mortality Claims' : 'Claims History'; + } + function shouldShowClaimHistorySwitch(leadType, policyTypeId) { - return (leadType == 2 || leadType == 3) && isClaimHistoryPolicyType(policyTypeId); + return ['1', '2', '3'].includes(String(leadType)) && isClaimHistoryPolicyType(policyTypeId); + } + + function updateClaimRowVisibility(fallbackPolicyTypeId = null) { + const leadType = $('#lead_type').val(); + let policyTypeId = fallbackPolicyTypeId; + + if (policyTypeId == null || policyTypeId === '') { + const $policySelect = $('[id^="policy_type_id_"]').first(); + policyTypeId = $policySelect.length ? $policySelect.val() : ''; + } + + if (!shouldShowClaimHistorySwitch(leadType, policyTypeId)) { + $('.claim-row').hide(); + return; + } + + if ($('#claim_history').length) { + if ($('#claim_history').prop('checked')) { + $('.claim-row').show(); + } else { + $('.claim-row').hide(); + } + } else { + $('.claim-row').show(); + } } function appendThreeYearsClaims(count) { @@ -2210,20 +2287,21 @@ let lead_type = $('#lead_type').val(); let showClaimHistorySwitch = shouldShowClaimHistorySwitch(lead_type, policy_type_id); + let claimHistoryLabel = getClaimHistoryLabel(lead_type); console.log('claimIndex from parent', claimIndex); let increment = claimIndex; let claimsFields = `${showClaimHistorySwitch && !document.querySelector('#claim_history') ? `
- +

` : ``}`; claimsFields += `
-
- +
+ +
+ + +
+
+ +
+
-
- +
+
-
- +
+
-
- +
+
-
- +
+
-
- +
+
-
- +
+
-
- +
+
@@ -2345,6 +2432,8 @@ if (showClaimHistorySwitch) { claimHistoryToggle(); + } else { + updateClaimRowVisibility(policy_type_id); } toggleRequiredFields(); @@ -2363,15 +2452,198 @@ } } + function isClaimRowNilClaims($row) { + return $row.find('.nil-claims-checkbox').prop('checked'); + } + + function setClaimSelectValue($select, value) { + if (!$select.length) { + return; + } + + if ($select.find('option[value="' + value + '"]').length === 0) { + $select.append($('
` - let referenceDiv = document.getElementById('appendAreaForClaim'); - referenceDiv.insertAdjacentHTML('beforeend', html); - - appendThreeYearsClaims(); - } + setupNonEbClaimDetailsSection(); // Hide loader $('.loader').fadeOut(); @@ -675,6 +668,11 @@ var pageBackButton = '" class="topbar-icon const finyearJsonString = gatherClaimExperienceData(); console.log('finyearJsonString', finyearJsonString); formData.append('fin_years_claims', finyearJsonString); + syncClaimHistoryFieldsToFormData(formData); cliam_history_status = $("#claim_history").prop("checked") ? 1 : 0; @@ -799,7 +798,7 @@ var pageBackButton = '" class="topbar-icon } - leadTypeBsedHideAndShow(value, true) + leadTypeBsedHideAndShow(value, true); $('#contact_person_summary').empty(); $('#contact_person_summary').append($('

${sectionTitle}

`; + + referenceDiv.insertAdjacentHTML('beforeend', html); + appendThreeYearsClaims(); + updateNonEbClaimRowVisibility(leadType); + } + + function leadTypeBsedHideAndShow(value, resetValues = false, skipClaimSetup = false) { var actual_lead_id = $('#actual_lead_id').val(); if (value == 1 || value == 3) { $('.btnDiv').show(); - $('.claim-row').hide(); + + if (!skipClaimSetup && shouldShowNonEbClaimHistory(value)) { + setupNonEbClaimDetailsSection(value); + } else if (!shouldShowNonEbClaimHistory(value)) { + $('#appendAreaForClaim').empty(); + $('.claim-row').hide(); + } $('.emp_title_text').text('No of Employees') @@ -950,7 +1008,10 @@ var pageBackButton = '" class="topbar-icon var increment = 1; + function isClaimRowNilClaims($row) { + return $row.find('.nil-claims-checkbox').prop('checked'); + } + + function setClaimSelectValue($select, value) { + if (!$select.length) { + return; + } + + if ($select.find('option[value="' + value + '"]').length === 0) { + $select.append($(' -
- +
+
+
- + + +
+ + +
+
+ +
+
-
- +
+
-
- +
+
-
- +
+
-
- +
+
-
- +
+
@@ -1241,7 +1459,10 @@ var pageBackButton = '" class="topbar-icon let claimData = []; + if ($("#claim_history").length > 0 && !$("#claim_history").prop("checked")) { + return JSON.stringify({ + "finyear": claimData + }); + } + $(".claim-row").each(function() { + let isNilClaims = $(this).find(".nil-claims-checkbox").prop("checked"); + + if (isNilClaims) { + let year = $(this).find("[name='first_year[]']").val(); + claimData.push({ + "year": year, + "policy_type": "Nil", + "date_of_loss": "Nil", + "claim_amount": "Nil", + "settled_amount": "Nil", + "cause_of_loss": "Nil", + "status": "Nil", + "nil_claims": 1, + }); + return; + } + let year = $(this).find("[name='first_year[]']").val(); let policyType = $(this).find("[name='first_policy_type_[]']").val(); let dateOfLoss = $(this).find("[name='first_date_of_loss_[]']").val(); @@ -1292,6 +1536,7 @@ var pageBackButton = '" class="topbar-icon function claimHistoryToggle() { cliam_history_status = $("#claim_history").prop("checked") ? 1 : 0; - // alert(cliam_history_status); + if (cliam_history_status == 1) { if ($(".claim-row").length > 0) { - // Rows already exist, just show them - $(".claim-row").show(); + $(".claim-row").show(); } else { - // No rows yet, so create them appendThreeYearsClaims(); } - $(".claim-input").attr("required", true); - } else { + $(".claim-row").each(function() { + const $row = $(this); + $row.find('[name="first_year[]"]').prop("required", true); + + if (!isClaimRowNilClaims($row)) { + $row.find(".claim-input").not('[name="first_year[]"]').prop("required", true); + } + }); + } else { $(".claim-row").hide(); - $(".claim-input").removeAttr("required"); // Required Attributes Remove - $(".claim-input").val(""); // Value Reset + $(".claim-row").each(function() { + const $row = $(this); + $row.find('.nil-claims-checkbox').prop('checked', false); + $row.find('.nil-claims-value').val('0'); + $row.removeClass('claim-row-nil'); + $row.find('.claim-required-star').show(); + }); + $(".claim-input").removeAttr("required").prop('disabled', false).val(""); $(".claim-input").each(function() { - $(this).parsley().reset(); // Validation Reset + if ($(this).hasClass('select2-hidden-accessible')) { + $(this).val(null).trigger('change'); + } + if ($(this).parsley) { + $(this).parsley().reset(); + } }); } - } $('#exixting_client').change(function () { @@ -1476,5 +1736,12 @@ var pageBackButton = ' \ No newline at end of file diff --git a/app/Views/rfq/claims_details_non_eb.php b/app/Views/rfq/claims_details_non_eb.php index 8f565ee0..3141be9b 100644 --- a/app/Views/rfq/claims_details_non_eb.php +++ b/app/Views/rfq/claims_details_non_eb.php @@ -1,55 +1,85 @@ - '', 'claim_amount' => '', 'status' => '', 'claim_type' => '', 'cause_of_death' => '', 'death_date' => ''] ]; += 4) ? $year : $year - 1; + $lastFiveYears = []; + + for ($i = 0; $i < 6; $i++) { + $startYear = $currentFYStart - $i; + $lastFiveYears[] = "{$startYear}-" . ($startYear + 1); + } + } + + $claims = ! empty($lead_edit_data['fin_years_claims_array']) + ? $lead_edit_data['fin_years_claims_array'] + : [['year' => '', 'claim_amount' => '', 'status' => '', 'policy_type' => '', 'date_of_loss' => '', 'cause_of_loss' => '']]; + $leadType = (int) ($lead_edit_data['lead_type'] ?? 0); + $showClaimsSection = in_array($leadType, [1, 2, 3], true); + $claimHistoryLabel = $leadType === 1 ? 'Mortality Claims' : 'Claims History'; ?> +
- /> - + /> +

$value) { ?> + foreach ($claims as $key => $value) { + $isNilClaimRow = ! empty($value['nil_claims']); + ?> -
-
- - $year"; - } ?> + $selected = ($year == $value['year']) ? 'selected' : ''; + echo ""; + } ?>
+
- - + + +
+ > + +
-
- - + +
+ + >
-
- - +
+ + >
-
- - +
+ + >
-
- - +
+ + >
-
- - +
+ + > +
+
+ + >
@@ -59,5 +89,24 @@
- - \ No newline at end of file + + + + diff --git a/app/Views/rfq/gpa.php b/app/Views/rfq/gpa.php index 7fe37fb4..21029eaa 100644 --- a/app/Views/rfq/gpa.php +++ b/app/Views/rfq/gpa.php @@ -42,16 +42,35 @@ = 4) ? $year : $year - 1; + $lastFiveYears = []; + + for ($i = 0; $i < 6; $i++) { + $startYear = $currentFYStart - $i; + $lastFiveYears[] = "{$startYear}-" . ($startYear + 1); + } + } + + if (! isset($causeOfDeath) || ! is_array($causeOfDeath)) { + $causeOfDeath = []; + } + $savedClaims = !empty($lead_edit_data['fin_years_claims_array']) ? $lead_edit_data['fin_years_claims_array'] : []; $isClaimHistoryChecked = (isset($lead_edit_data['claim_history']) && (int) $lead_edit_data['claim_history'] === 1) || !empty($savedClaims); $showClaimHistorySwitch = isset($lead_edit_data['lead_type'], $lead_edit_data['policy_type_id']) - && in_array((int) $lead_edit_data['lead_type'], [2, 3], true) + && in_array((int) $lead_edit_data['lead_type'], [1, 2, 3], true) && in_array((int) $lead_edit_data['policy_type_id'], [1, 6, 7], true); + $claimHistoryLabel = (isset($lead_edit_data['lead_type']) && (int) $lead_edit_data['lead_type'] === 1) + ? 'Mortality Claims' + : 'Claims History'; ?>
> - +

@@ -59,13 +78,15 @@ $claims = !empty($savedClaims) ? $savedClaims : [ ['year' => '', 'claim_amount' => '', 'status' => '', 'claim_type' => '', 'cause_of_death' => '', 'death_date' => ''] ]; - foreach ($claims as $key => $value) { ?> + foreach ($claims as $key => $value) { + $isNilClaimRow = !empty($value['nil_claims']); + ?> -
+
-
- -
- - + + +
+ > + +
+
+ +
+ + >
-
- - +
+ + >
-
- - > - + + + +
-
- - +
+ + >
-
- - +
+ + >
-
- - +
+ + >
-
- - > $death_value) { $selected = ($cause == $value['cause_of_death']) ? 'selected' : ''; echo ""; } ?> + + +
-
- - +
+ + >
+