diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php index 0b1fc090..49412b34 100644 --- a/app/Controllers/LeadsController.php +++ b/app/Controllers/LeadsController.php @@ -2288,6 +2288,8 @@ class LeadsController extends BaseController // 'Insurer' => $rfq_data['insurer_name'] ?? " - ", // 'TPA' => $rfq_data['tpa_name'] ?? " - ", 'Policy Type' => $this->leadType[$rfq_data['lead_type']] ?? "", + 'Mortality Experience for last 3 years' => $claim_history == "1" ? "Mentioned in Claims sheet" : "Nil", + ]; }else { diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index ed1fdc15..4421fb71 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -968,6 +968,58 @@ class TicketController extends BaseController return $extra_fields; } + /** + * Overlay conditional `required` rules onto a base validation rule-set based on the + * submitted `claim_status_id`. For example, when claim_status_id is a "Settled" status + * (11/24/34/44), fields like `utr_details` and `settled_date` are promoted from + * `permit_empty` to `required` so the request is rejected when they are blank. + * + * Letter URL fields (`approved_letter`, `settle_letter`) accept an alternative PDF + * upload, so they are intentionally not promoted here; that pairing is enforced by + * the upload validation flow. `approved_description` stays optional to match the + * existing UI contract. + */ + private function applyClaimStatusConditionalRules(array $rules): array + { + $claimStatusId = (int) $this->request->getPost('claim_status_id'); + if ($claimStatusId <= 0) { + return $rules; + } + + if (!isset($this->extraFields[$claimStatusId]) || !is_array($this->extraFields[$claimStatusId])) { + return $rules; + } + + $requiredFields = $this->extraFields[$claimStatusId]; + $skipFields = ['approved_letter', 'settle_letter', 'approved_description']; + + foreach ($requiredFields as $field) { + if (in_array($field, $skipFields, true) || !isset($rules[$field])) { + continue; + } + + $existingRules = $rules[$field]['rules'] ?? ''; + $parts = $existingRules === '' + ? [] + : array_values(array_filter(array_map('trim', explode('|', $existingRules)), function ($part) { + return $part !== '' && $part !== 'permit_empty'; + })); + + if (!in_array('required', $parts, true)) { + array_unshift($parts, 'required'); + } + $rules[$field]['rules'] = implode('|', array_unique($parts)); + + if (!isset($rules[$field]['errors']) || !is_array($rules[$field]['errors'])) { + $rules[$field]['errors'] = []; + } + $label = $rules[$field]['label'] ?? ucwords(str_replace('_', ' ', $field)); + $rules[$field]['errors']['required'] = $label . ' is required for the selected claim status.'; + } + + return $rules; + } + public function view_ticket($ticket_id) { // $ticket_data = $this->ticketMasterModel->where('id', $ticket_id)->where('is_active', 1)->first(); @@ -1456,6 +1508,8 @@ class TicketController extends BaseController ]; } + $rules = $this->applyClaimStatusConditionalRules($rules); + if (!$this->validate($rules)) { return $this->response->setStatusCode(400)->setJSON([ 'status' => false, @@ -1944,6 +1998,9 @@ class TicketController extends BaseController 'return_remark' => ['label' => 'Return Remark','rules' => 'permit_empty','errors' => []], ]; } + + $rules = $this->applyClaimStatusConditionalRules($rules); + if (!$this->validate($rules)) { return $this->response->setStatusCode(400)->setJSON([ 'status' => false, @@ -3053,7 +3110,7 @@ class TicketController extends BaseController } } - public function getLastMatchedStatus($incoming_form_values, $old_ticket_data) + public function getLastMatchedStatusOld($incoming_form_values, $old_ticket_data) { if (empty($incoming_form_values) || !isset($incoming_form_values['claim_status_id']) || !isset($incoming_form_values['extra_fields_array_for_validate'])) { return null; @@ -3122,6 +3179,71 @@ class TicketController extends BaseController return $lastMatchedStatus; } + public function getLastMatchedStatus($incoming_form_values, $old_ticket_data) + { + // Preserve the incoming claim_status_id (if any) as the safe fallback so callers + // never accidentally nullify the status when validation inputs are missing. + $incomingStatus = $incoming_form_values['claim_status_id'] ?? null; + + if (empty($incoming_form_values) || !isset($incoming_form_values['extra_fields_array_for_validate'])) { + return $incomingStatus; + } + + $lastMatchedStatus = $incomingStatus; + + $statusMapping = json_decode($incoming_form_values['extra_fields_array_for_validate'], true); + if (!is_array($statusMapping) || empty($statusMapping)) { + return $incomingStatus; + } + + // Drop transitional / aggregate statuses that should never be auto-selected. + $removeKeys = is_array($this->removeArrayKey) ? $this->removeArrayKey : []; + $statusMapping = array_diff_key($statusMapping, $removeKeys); + + $oldStatusId = is_array($old_ticket_data) ? ($old_ticket_data['claim_status_id'] ?? null) : null; + + $skipFields = ['approved_description']; + + foreach ($statusMapping as $status => $requiredFields) { + if (empty($requiredFields)) { + continue; + } + + // Skip the current/old status — we only advance forward to a newer status. + if ($oldStatusId !== null && (int) $status === (int) $oldStatusId) { + continue; + } + + if (!is_array($requiredFields)) { + $requiredFields = [$requiredFields]; + } + + $allFieldsMatched = true; + foreach ($requiredFields as $field) { + if (in_array($field, $skipFields, true)) { + continue; + } + + if (!isset($incoming_form_values[$field]) || $incoming_form_values[$field] === '' || $incoming_form_values[$field] === null) { + $allFieldsMatched = false; + break; + } + } + + if ($allFieldsMatched) { + $lastMatchedStatus = $status; + } + } + + // When a TPA number is present, promote the base "registered" statuses + // (1 -> 2 for standard, 67 -> 68 for the alternate flow). + if (!empty($incoming_form_values['tpa_no']) && in_array((int) $lastMatchedStatus, [1, 67], true)) { + $lastMatchedStatus = ((int) $lastMatchedStatus === 1) ? 2 : 68; + } + + return $lastMatchedStatus; + } + public function getPolicyStartDate() { diff --git a/app/Models/UserModel.php b/app/Models/UserModel.php index a73d35ef..8f62c9ae 100755 --- a/app/Models/UserModel.php +++ b/app/Models/UserModel.php @@ -148,10 +148,22 @@ class UserModel extends Model ->get() ->getResultArray(); + // The user_teams join produces one row per (user, team) pair, so users + // belonging to multiple teams appear multiple times. Collapse to one + // row per user while keeping a team_id from [6, 7] when available, so + // the existing in_array($user['team_id'], [6, 7]) checks in the views + // continue to work correctly. + $deduped = []; + foreach ($data as $row) { + $userId = $row['id']; + if (!isset($deduped[$userId])) { + $deduped[$userId] = $row; + } elseif (in_array($row['team_id'], [6, 7])) { + $deduped[$userId]['team_id'] = $row['team_id']; + } + } - // dd($data); - - return $data; + return array_values($deduped); } } diff --git a/app/Views/leads_form.php b/app/Views/leads_form.php index d6942deb..d94ca75b 100644 --- a/app/Views/leads_form.php +++ b/app/Views/leads_form.php @@ -2172,7 +2172,7 @@ // // // //
@@ -2187,7 +2187,7 @@ // // //
// //
@@ -2245,7 +2245,7 @@ } function getClaimHistoryLabel(leadType) { - return String(leadType) === '1' ? 'Mortality Claims' : 'Claims History'; + return String(leadType) === '1' ? 'Mortality Experience' : 'Claims Experience'; } function shouldShowClaimHistorySwitch(leadType, policyTypeId) { @@ -2304,7 +2304,7 @@ @@ -2361,7 +2361,7 @@ @@ -2381,7 +2381,7 @@ diff --git a/app/Views/leads_non_eb.php b/app/Views/leads_non_eb.php index d13ecb49..dd046a61 100644 --- a/app/Views/leads_non_eb.php +++ b/app/Views/leads_non_eb.php @@ -400,7 +400,7 @@ var pageBackButton = ' @@ -906,11 +906,11 @@ var pageBackButton = '" class="topbar-icon diff --git a/app/Views/rfq/claims_details_non_eb.php b/app/Views/rfq/claims_details_non_eb.php index 3141be9b..8eb69793 100644 --- a/app/Views/rfq/claims_details_non_eb.php +++ b/app/Views/rfq/claims_details_non_eb.php @@ -16,7 +16,7 @@ : [['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'; + $claimHistoryLabel = $leadType === 1 ? 'Mortality Experience' : 'Claims Experience'; ?>
diff --git a/app/Views/rfq/gpa.php b/app/Views/rfq/gpa.php index 21029eaa..d0979b55 100644 --- a/app/Views/rfq/gpa.php +++ b/app/Views/rfq/gpa.php @@ -64,8 +64,8 @@ && 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'; + ? 'Mortality Experience' + : 'Claims Experience'; ?>
diff --git a/app/Views/ticket_form_gmc.php b/app/Views/ticket_form_gmc.php index e473d36b..03034d81 100644 --- a/app/Views/ticket_form_gmc.php +++ b/app/Views/ticket_form_gmc.php @@ -579,6 +579,42 @@ var doa; var STATUS_SECTION_CLASSES = ['cda_ir', 'settled', 'approved', 'rejected', 'up_qdr', 'up_cnu', 'canceled', 'returned', 'payment', 'non_id']; var statusSectionInitialValues = {}; + // Cached full mapping of claim_status_id -> required fields. + // The hidden input gets destructively reduced when the status dropdown changes, + // so we capture the full map once at load time for use by frontend required-logic. + var STATUS_REQUIRED_FIELDS_MAP = {}; + + function initStatusRequiredFieldsMap() { + var raw = $('#extra_fields_array_for_validate').val(); + if (!raw) { + STATUS_REQUIRED_FIELDS_MAP = {}; + return; + } + try { + var parsed = JSON.parse(raw); + STATUS_REQUIRED_FIELDS_MAP = (parsed && typeof parsed === 'object') ? parsed : {}; + } catch (e) { + STATUS_REQUIRED_FIELDS_MAP = {}; + } + } + + function getRequiredFieldsForSelectedStatus() { + if (!STATUS_REQUIRED_FIELDS_MAP) { + return []; + } + var selected = $('#claim_status_id').val(); + if (selected === undefined || selected === null || selected === '') { + return []; + } + var fields = STATUS_REQUIRED_FIELDS_MAP[selected]; + if (Array.isArray(fields)) { + return fields; + } + if (fields) { + return [fields]; + } + return []; + } function captureSectionInitialValues(sectionClass) { if (!sectionClass) { @@ -656,12 +692,40 @@ return; } if (sectionClass === 'approved' || sectionClass === 'settled') { + // The URL-or-File letter pair has its own validity rules (see enforceLetterPairRules). + // We still need to enforce required on the other status-mandated fields + // (e.g. utr_details, settled_date, approved_amount, approved_date), which the + // previous early-return was skipping. enforceLetterPairRules(); - updateSectionRequiredLabels(sectionClass, hasSectionChanged(sectionClass)); + + var letterPairIds = sectionClass === 'approved' + ? ['approved_letter', 'approved_letter_file', 'approved_description'] + : ['settle_letter', 'settle_letter_file']; + + var statusRequiredFields = getRequiredFieldsForSelectedStatus(); + var sectionChanged = hasSectionChanged(sectionClass); + + $('.' + sectionClass).find('input, textarea, select').each(function () { + var id = this.id; + if (!id || letterPairIds.indexOf(id) !== -1) { + return; + } + var statusRequires = statusRequiredFields.indexOf(id) !== -1; + $(this).prop('required', statusRequires || sectionChanged); + }); + + var statusMandatesSection = false; + for (var i = 0; i < statusRequiredFields.length; i++) { + if ($('.' + sectionClass + ' #' + statusRequiredFields[i]).length > 0) { + statusMandatesSection = true; + break; + } + } + updateSectionRequiredLabels(sectionClass, sectionChanged || statusMandatesSection); return; } var changed = hasSectionChanged(sectionClass); - $('.' + sectionClass).find('input, textarea, select').each(function() { + $('.' + sectionClass).find('input, textarea, select').each(function () { if (this.id === 'approved_description') { return; } @@ -738,6 +802,7 @@ allowInput: false }); + initStatusRequiredFieldsMap(); updateClaimStatusDisplay("") var extraFields = ; GlobelExtraFields = extraFields; diff --git a/app/Views/view_rfq.php b/app/Views/view_rfq.php index b3ec317f..5a6bcbc4 100644 --- a/app/Views/view_rfq.php +++ b/app/Views/view_rfq.php @@ -1,3 +1,5 @@ + +