diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 92d76636..db43bc32 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -445,6 +445,8 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) { $routes->get("claim_dump_excel_error/(:any)", "TicketController::getClaimDumpExcelFileErrors/$1"); $routes->get("download_claim_dump_file/(:any)", "TicketController::downloadClaimDumpFile/$1"); $routes->match(['get', 'post'], 'truncateClaimDumpFile', 'TicketController::truncateClaimDumpFile'); + $routes->match(['get', 'post'], 'reprocessClaimDumpPending', 'TicketController::reprocessClaimDumpPending'); + $routes->match(['get', 'post'], 'getClaimDumpPendingRows', 'TicketController::getClaimDumpPendingRows'); $routes->post('uploadMultiFileFromRfq', 'LeadsController::uploadMultiFileFromRfq'); $routes->get('downloadMemberFile/(:any)', 'LeadsController::downloadMemberFile/$1'); $routes->get('downloadFullMemberDataExcelErrorFile/(:any)', 'LeadsController::downloadFullMemberDataExcelErrorFile/$1'); diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index d8139383..a23a8711 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -4360,6 +4360,10 @@ class TicketController extends BaseController ->orderBy('claim_dump_files.id', 'desc') ->findAll(); + $data['claim_dump_file_data'] = $this->attachPendingDumpTicketCounts( + $data['claim_dump_file_data'] ?? [] + ); + return $this->loadLayout('claim_dump_file_list', $data); }else{ @@ -4562,6 +4566,362 @@ class TicketController extends BaseController ], 200); } } + /** + * List dump rows for a file where ticket_id is still NULL (not moved to ticket_master). + */ + public function getClaimDumpPendingRows() + { + $fileId = (int) ($this->request->getGet('file_id') ?? $this->request->getPost('file_id') ?? 0); + if ($fileId <= 0) { + return $this->respond(['status' => false, 'code' => 400, 'message' => 'file_id is required'], 200); + } + + $fileData = $this->claimDumpFileModel->where('id', $fileId)->where('is_active', 1)->first(); + if (empty($fileData)) { + return $this->respond(['status' => false, 'code' => 404, 'message' => 'File not found'], 200); + } + + $tpaId = (int) ($fileData['tpa_id'] ?? 0); + $tableMap = $this->getTpaDumpTableMap(); + $tpaTable = $tableMap[$tpaId] ?? null; + if ($tpaTable === null) { + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'Pending dump view is only supported for TPA claim dumps', + ], 200); + } + + $displayMap = $this->getPendingDumpDisplayColumns($tpaId); + $selectCols = array_values(array_unique(array_merge(['id'], array_keys($displayMap)))); + + $db = db_connect(); + if (!$db->tableExists($tpaTable)) { + return $this->respond(['status' => false, 'code' => 400, 'message' => 'Dump table not found'], 200); + } + + // Only select columns that exist on the table. + $existingCols = array_column($db->query('SHOW COLUMNS FROM `' . $tpaTable . '`')->getResultArray(), 'Field'); + $selectCols = array_values(array_intersect($selectCols, $existingCols)); + if ($selectCols === []) { + $selectCols = ['id']; + } + + $rows = $db->table($tpaTable) + ->select(implode(', ', $selectCols)) + ->where('file_id', $fileId) + ->where('is_active', 1) + ->where('ticket_id IS NULL', null, false) + ->orderBy('id', 'ASC') + ->limit(500) + ->get() + ->getResultArray(); + + $headers = []; + foreach ($selectCols as $col) { + $headers[] = [ + 'key' => $col, + 'label' => $displayMap[$col] ?? $col, + ]; + } + + return $this->respond([ + 'status' => true, + 'code' => 200, + 'message' => 'Pending dump rows loaded', + 'data' => [ + 'file_id' => $fileId, + 'file_name' => $fileData['file_name'] ?? '', + 'tpa_id' => $tpaId, + 'count' => count($rows), + 'headers' => $headers, + 'rows' => $rows, + ], + ], 200); + } + + /** + * Display columns for pending dump modal (db_column => label). + * + * @return array + */ + private function getPendingDumpDisplayColumns(int $tpaId): array + { + $byTpa = [ + (int) env('ICICI_PRIMARY_KEY_CONSTANT') => [ + 'id' => 'Dump ID', + 'employee_member_id' => 'Emp Code', + 'main_member_name' => 'Employee Name', + 'insured_name' => 'Insured Name', + 'uhid' => 'UHID / TPA No', + 'claimed_amount' => 'Claim Amount', + 'doa' => 'DOA', + 'updated_status' => 'Status', + 'relation' => 'Relation', + 'master_reject_reason' => 'Reject Reason', + ], + (int) env('ABHI_PRIMARY_KEY_CONSTANT') => [ + 'id' => 'Dump ID', + 'member_code' => 'Emp Code', + 'proposer_name' => 'Employee Name', + 'patient_name' => 'Insured Name', + 'healthcard_id' => 'UHID / TPA No', + 'claimed_amount' => 'Claim Amount', + 'doa' => 'DOA', + 'claim_status' => 'Status', + 'relation' => 'Relation', + 'master_reject_reason' => 'Reject Reason', + ], + (int) env('MEDI_ASSIST_PRIMARY_KEY_CONSTANT') => [ + 'id' => 'Dump ID', + 'pribenef_employee_code' => 'Emp Code', + 'pribenef_name' => 'Employee Name', + 'benef_name' => 'Insured Name', + 'event_id' => 'UHID / TPA No', + 'claim_amount' => 'Claim Amount', + 'date_of_admission' => 'DOA', + 'claim_status' => 'Status', + 'benef_relation' => 'Relation', + 'master_reject_reason' => 'Reject Reason', + ], + (int) env('FHPL_PRIMARY_KEY_CONSTANT') => [ + 'id' => 'Dump ID', + 'employee_id' => 'Emp Code', + 'main_member_name' => 'Employee Name', + 'member_name' => 'Insured Name', + 'uhid_no' => 'UHID / TPA No', + 'claim_amount' => 'Claim Amount', + 'admission_date' => 'DOA', + 'current_claim_status' => 'Status', + 'relationship' => 'Relation', + 'master_reject_reason' => 'Reject Reason', + ], + (int) env('R_CARE_PRIMARY_KEY_CONSTANT') => [ + 'id' => 'Dump ID', + 'employee_member_id' => 'Emp Code', + 'insured_name' => 'Employee Name', + 'patient_name' => 'Insured Name', + 'uhid' => 'UHID / TPA No', + 'claimed_amount' => 'Claim Amount', + 'doa_opd_treatment_from' => 'DOA', + 'final_status' => 'Status', + 'relation' => 'Relation', + 'master_reject_reason' => 'Reject Reason', + ], + (int) env('VIDAL_PRIMARY_KEY_CONSTANT') => [ + 'id' => 'Dump ID', + 'employee_number' => 'Emp Code', + 'primary_policy_holder_name' => 'Employee Name', + 'patient_name' => 'Insured Name', + 'primary_policy_holder_card_id' => 'UHID / TPA No', + 'claim_amount' => 'Claim Amount', + 'date_of_admission' => 'DOA', + 'claim_status' => 'Status', + 'relation' => 'Relation', + 'master_reject_reason' => 'Reject Reason', + ], + ]; + + return $byTpa[$tpaId] ?? [ + 'id' => 'Dump ID', + 'master_reject_reason' => 'Reject Reason', + ]; + } + + /** + * Re-run Job 2 for dump rows that never got a ticket_master link (ticket_id IS NULL). + */ + public function reprocessClaimDumpPending() + { + $fileId = (int) ($this->request->getGet('file_id') ?? $this->request->getPost('file_id') ?? 0); + log_message('error', '[CLAIM_DUMP][CTRL_REPROCESS_PENDING_START] file_id=' . $fileId); + + if ($fileId <= 0) { + return $this->respond(['status' => false, 'code' => 400, 'message' => 'file_id is required'], 200); + } + + $fileData = $this->claimDumpFileModel->where('id', $fileId)->where('is_active', 1)->first(); + if (empty($fileData)) { + return $this->respond(['status' => false, 'code' => 404, 'message' => 'File not found'], 200); + } + + if (($fileData['status'] ?? '') === 'processing') { + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'Cannot reprocess while import is processing', + ], 200); + } + + $tpaId = (int) ($fileData['tpa_id'] ?? 0); + if ($tpaId <= 0) { + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'Reprocess is only supported for TPA claim dumps', + ], 200); + } + + $tableMap = $this->getTpaDumpTableMap(); + $tpaTable = $tableMap[$tpaId] ?? null; + if ($tpaTable === null) { + return $this->respond(['status' => false, 'code' => 400, 'message' => 'Unsupported TPA'], 200); + } + + try { + $db = db_connect(); + $pendingBefore = (int) $db->table($tpaTable) + ->where('file_id', $fileId) + ->where('is_active', 1) + ->where('ticket_id IS NULL', null, false) + ->countAllResults(); + + if ($pendingBefore <= 0) { + return $this->respond([ + 'status' => true, + 'code' => 200, + 'message' => 'No pending dump rows to process', + 'data' => ['pending_before' => 0], + ], 200); + } + + // Allow previously rejected unlinked rows to be tried again. + $db->table($tpaTable) + ->where('file_id', $fileId) + ->where('is_active', 1) + ->where('ticket_id IS NULL', null, false) + ->where('master_reject_reason IS NOT NULL', null, false) + ->set(['master_reject_reason' => null]) + ->update(); + + $handler = \App\Libraries\TpaClaimsImportFactory::make($tpaId); + $result = $handler->runTicketMasterInsert(['file_id' => $fileId]); + + $pendingAfter = (int) $db->table($tpaTable) + ->where('file_id', $fileId) + ->where('is_active', 1) + ->where('ticket_id IS NULL', null, false) + ->countAllResults(); + + if (!empty($result['status'])) { + $this->claimDumpFileModel->update($fileId, [ + 'status' => 'success', + 'reason' => null, + ]); + } + + log_message( + 'error', + '[CLAIM_DUMP][CTRL_REPROCESS_PENDING_DONE] file_id=' . $fileId + . ' pending_before=' . $pendingBefore + . ' pending_after=' . $pendingAfter + . ' status=' . (!empty($result['status']) ? 'true' : 'false') + . ' message=' . ($result['message'] ?? '') + ); + + $moved = max(0, $pendingBefore - $pendingAfter); + $message = !empty($result['status']) + ? "Processed pending dump rows. Moved {$moved} of {$pendingBefore} to ticket master." + : ($result['message'] ?? 'Reprocess failed'); + + if (!empty($result['status']) && $pendingAfter > 0) { + $message .= " {$pendingAfter} row(s) still pending (e.g. employee not found)."; + } + + return $this->respond([ + 'status' => !empty($result['status']), + 'code' => !empty($result['status']) ? 200 : 400, + 'message' => $message, + 'data' => [ + 'pending_before' => $pendingBefore, + 'pending_after' => $pendingAfter, + 'moved' => $moved, + 'job2' => $result, + ], + ], 200); + } catch (\Throwable $th) { + $this->myLogger->logme('error', 'reprocessClaimDumpPending: ' . $th->getMessage()); + log_message('error', '[CLAIM_DUMP][CTRL_REPROCESS_PENDING_EXCEPTION] file_id=' . $fileId . ' error=' . $th->getMessage()); + return $this->respond([ + 'status' => false, + 'code' => 500, + 'message' => 'Reprocess failed: ' . $th->getMessage(), + ], 200); + } + } + + /** + * @return array + */ + private function getTpaDumpTableMap(): array + { + return [ + (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', + ]; + } + + /** + * Attach pending dump row counts (ticket_id IS NULL) for list UI. + * + * @param list> $files + * @return list> + */ + private function attachPendingDumpTicketCounts(array $files): array + { + if ($files === []) { + return $files; + } + + $tableMap = $this->getTpaDumpTableMap(); + $byTpa = []; + foreach ($files as $file) { + $tpaId = (int) ($file['tpa_id'] ?? 0); + $fileId = (int) ($file['file_id'] ?? 0); + if ($tpaId > 0 && $fileId > 0 && isset($tableMap[$tpaId])) { + $byTpa[$tpaId][] = $fileId; + } + } + + $counts = []; + $db = db_connect(); + foreach ($byTpa as $tpaId => $fileIds) { + $fileIds = array_values(array_unique($fileIds)); + if ($fileIds === []) { + continue; + } + $table = $tableMap[$tpaId]; + if (!$db->tableExists($table)) { + continue; + } + + $rows = $db->table($table) + ->select('file_id, COUNT(*) AS pending_count', false) + ->where('is_active', 1) + ->where('ticket_id IS NULL', null, false) + ->whereIn('file_id', $fileIds) + ->groupBy('file_id') + ->get() + ->getResultArray(); + + foreach ($rows as $row) { + $counts[(int) $row['file_id']] = (int) $row['pending_count']; + } + } + + foreach ($files as &$file) { + $fileId = (int) ($file['file_id'] ?? 0); + $file['pending_ticket_count'] = $counts[$fileId] ?? 0; + } + unset($file); + + return $files; + } + // -------- END CLAIM DUMP UPLOAD ---------------------------------------------------------------------------------------------- public function saveIRDocsJson() { diff --git a/app/Views/claim_dump_file_list.php b/app/Views/claim_dump_file_list.php index 2e320ff3..85c39f95 100644 --- a/app/Views/claim_dump_file_list.php +++ b/app/Views/claim_dump_file_list.php @@ -163,17 +163,25 @@ ' . $file['user_name'] . '' ?> + 0; + ?> - - + + + + partial + +
pending ticket(s)
@@ -195,6 +203,21 @@ + + + + View Data () + + + + Process Pending () + + + + + + + +