FIX_CLAIM_STATUS_MISS_MATCH
This commit is contained in:
parent
5dc49f7108
commit
998a74906d
@ -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()
|
||||
{
|
||||
|
||||
|
||||
@ -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("<?= isset($ticket_data['claim_status_id']) ? $ticket_data['claim_status_id'] : 0 ?>")
|
||||
var extraFields = <?= json_encode(isset($extra_fields) ? $extra_fields : []); ?>;
|
||||
GlobelExtraFields = extraFields;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user