request->getGet('client_policy') ?? $this->request->getGet('client_policy_id') ?? $this->request->getPost('client_policy') ?? $this->request->getPost('client_policy_id') ?? 0 ); if ($id > 0) { return $id; } if ($fallback !== null && $fallback > 0) { return $fallback; } return 0; } /** * Resolve KPI by Metabase numeric id or method slug. */ protected function resolveKpiMethod(string $kpiKey): ?string { $kpiKey = trim($kpiKey); if ($kpiKey === '') { return null; } if (in_array($kpiKey, ClaimsCollectionV2DashboardModel::KPI_MAP, true)) { return $kpiKey; } if (ctype_digit($kpiKey)) { $id = (int) $kpiKey; return ClaimsCollectionV2DashboardModel::KPI_MAP[$id] ?? null; } return null; } /** * JSON: single KPI by slug or Metabase id. */ public function kpi(string $kpiMethod = '') { $policyId = $this->resolvePolicyId(); if ($policyId <= 0) { return $this->respond([ 'status' => false, 'message' => 'client_policy or client_policy_id is required.', ], 422); } $kpiMethod = $this->resolveKpiMethod($kpiMethod); if ($kpiMethod === null) { return $this->respond([ 'status' => false, 'message' => 'Unknown KPI. Pass Metabase id or method slug.', 'allowed' => ClaimsCollectionV2DashboardModel::KPI_MAP, ], 404); } $model = new ClaimReportDashboardModel(); $metabaseId = array_search($kpiMethod, ClaimsCollectionV2DashboardModel::KPI_MAP, true); return $this->respond([ 'status' => true, 'policy_id' => $policyId, 'claims_source' => $model->resolveClaimsTable($policyId), 'kpi_id' => $metabaseId !== false ? (int) $metabaseId : null, 'kpi' => $kpiMethod, 'label' => ClaimsCollectionV2DashboardModel::KPI_LABELS[$kpiMethod] ?? $kpiMethod, 'rows' => $model->getKpi($kpiMethod, $policyId), ]); } /** * JSON: all KPIs. */ public function all() { $policyId = $this->resolvePolicyId(); if ($policyId <= 0) { return $this->respond([ 'status' => false, 'message' => 'client_policy or client_policy_id is required.', ], 422); } $generatedAt = (new ClaimDumpFileModel())->getGeneratedAtForPolicy($policyId); // if ($generatedAt === null) { // return $this->respond([ // 'status' => false, // 'message' => 'claim_dump_date is mandatory. No claim dump date found for this policy.', // ], 422); // } $model = new ClaimReportDashboardModel(); $data = $model->getAllKpis($policyId); $source = $data['_meta']['claims_source'] ?? $model->resolveClaimsTable($policyId); unset($data['_meta']); return $this->respond([ 'status' => true, 'policy_id' => $policyId, 'claims_source' => $source, 'generated_at' => $generatedAt, 'data' => $data, ]); } /** * Admin preview UI — KPI grid for manual testing. */ public function preview(int $policyId = 4687) { $policyId = $this->resolvePolicyId($policyId); $path = $this->request->getUri()->getPath(); $isJwt = stripos($path, 'employeeRest') !== false; $prefix = $isJwt ? 'employeeRest/claims-collection-report' : 'util/claims-collection-report'; return view('claims_collection_v2_dashboard', [ 'policy_id' => $policyId, 'kpi_map' => ClaimsCollectionV2DashboardModel::KPI_MAP, 'kpi_labels' => ClaimsCollectionV2DashboardModel::KPI_LABELS, 'api_all_url' => base_url($prefix . '/all'), 'api_kpi_url' => base_url($prefix . '/kpi'), ]); } /** * Sync TPA dump tables → claim_report. * Only rows where ticket_id IS NOT NULL and is_active = 1 are copied. * Idempotent: existing (client_policy_id, claim_number) rows are skipped. * No request parameters required. * * GET /util/claims-collection-report/sync */ public function sync() { @set_time_limit(0); @ini_set('max_execution_time', '0'); $db = db_connect(); if (!$db->tableExists('claim_report')) { return $this->respond([ 'status' => false, 'message' => 'Table claim_report does not exist. Run migrations first.', ], 500); } // env_key => [dump_table, claim_number_col, dump_col => claim_report_col mapping] $tpaTableMap = [ 'VIDAL_PRIMARY_KEY_CONSTANT' => [ 'table' => 'claims_dump_vidal', 'claim_col' => 'insurer_claim_number', 'mapping' => [ 'insurer_claim_number' => 'claim_number', 'employee_number' => 'emp_code', 'date_of_admission' => 'doa', 'date_of_discharge' => 'dod', 'claim_amount' => 'claim_amount', 'approved_amount' => 'approved_amount', 'sum_insured' => 'si_amt', 'claim_status' => 'tpa_claim_status', 'hospital_name' => 'hospital_name', 'hospital_address' => 'hospital_address', 'hospital_city' => 'hospital_city', 'hospital_state' => 'hospital_state', 'hospital_pincode' => 'hospital_pin_code', 'type_of_claim' => 'tpa_claim_type', 'diagnosis' => 'tpa_ailments', 'tpa_claim_number' => 'tpa_no', ], ], 'ABHI_PRIMARY_KEY_CONSTANT' => [ 'table' => 'claims_dump_abhi', 'claim_col' => 'abhi_claim_no', 'mapping' => [ 'abhi_claim_no' => 'claim_number', 'member_code' => 'emp_code', 'doa' => 'doa', 'dod' => 'dod', 'intimation_date' => 'date_of_intimat', 'claim_status' => 'tpa_claim_status', 'claimed_amount' => 'claim_amount', 'hospital_name' => 'hospital_name', 'hospital_city' => 'hospital_city', 'hospital_state' => 'hospital_state', 'settled_date' => 'settled_date', 'healthcard_id' => 'tpa_no', 'claim_type' => 'tpa_claim_type', 'diagnosis' => 'tpa_ailments', 'abhi_amount_less_coins_current_month' => 'approved_amount', 'patient_age' => 'age', 'gender' => 'gender', 'relation' => 'relation', ], ], 'MEDI_ASSIST_PRIMARY_KEY_CONSTANT' => [ 'table' => 'claims_dump_medi_assist', 'claim_col' => 'claim_id', 'mapping' => [ 'claim_id' => 'claim_number', 'pribenef_employee_code' => 'emp_code', 'date_of_admission' => 'doa', 'date_of_discharge' => 'dod', 'intimation_date' => 'date_of_intimat', 'settled_date' => 'settled_date', 'processed_date' => 'approved_date', 'claim_status' => 'tpa_claim_status', 'claim_amount' => 'claim_amount', 'claim_approved_amount' => 'approved_amount', 'hospital_name' => 'hospital_name', 'hospital_address' => 'hospital_address', 'hospital_city' => 'hospital_city', 'hospital_state' => 'hospital_state', 'hospital_pincode' => 'hospital_pin_code', 'claim_type' => 'tpa_claim_type', 'primary_ailment_name' => 'tpa_ailments', 'benef_sum_insured' => 'si_amt', 'benef_gender' => 'gender', 'benef_age' => 'age', 'benef_relation' => 'relation', 'incurred_amount' => 'incurred_amount', ], ], 'FHPL_PRIMARY_KEY_CONSTANT' => [ 'table' => 'claims_dump_fhpl', 'claim_col' => 'claim_id', 'mapping' => [ 'claim_id' => 'claim_number', 'employee_id' => 'emp_code', 'admission_date' => 'doa', 'discharge_date' => 'dod', 'claim_received_date' => 'date_of_intimat', 'claim_passed_date' => 'approved_date', 'settled_date' => 'settled_date', 'current_claim_status' => 'tpa_claim_status', 'claim_amount' => 'claim_amount', 'settled_amount' => 'approved_amount', 'incurred_amount' => 'incurred_amount', 'coverage_amount' => 'si_amt', 'provider_name' => 'hospital_name', 'provider_address' => 'hospital_address', 'provider_state' => 'hospital_state', 'provider_place' => 'hospital_city', 'provider_pincode' => 'hospital_pin_code', 'claim_type' => 'tpa_claim_type', 'diagnosis' => 'tpa_ailments', 'uhid_no' => 'tpa_no', 'gender' => 'gender', 'years' => 'age', 'relationship' => 'relation', ], ], 'R_CARE_PRIMARY_KEY_CONSTANT' => [ 'table' => 'claims_dump_reliance', 'claim_col' => 'cl_inward_no', 'mapping' => [ 'cl_inward_no' => 'claim_number', 'employee_member_id' => 'emp_code', 'doa_opd_treatment_from' => 'doa', 'dod_opd_treatment_to' => 'dod', 'approved_date' => 'approved_date', 'cheque_neft_date' => 'settled_date', 'claimed_amount' => 'claim_amount', 'net_sanction_amount' => 'approved_amount', 'final_status' => 'tpa_claim_status', 'hospital_name' => 'hospital_name', 'hospital_state' => 'hospital_state', 'hospital_district' => 'hospital_city', 'uhid' => 'tpa_no', 'diagnosis' => 'tpa_ailments', 'member_reimbursement_cl_type' => 'tpa_claim_type', 'gender' => 'gender', 'age' => 'age', 'relation' => 'relation', 'sum_insured' => 'si_amt', ], ], 'ICICI_PRIMARY_KEY_CONSTANT' => [ 'table' => 'claims_dump_icici', 'claim_col' => 'claim_number', 'mapping' => [ 'claim_number' => 'claim_number', 'employee_member_id' => 'emp_code', 'doa' => 'doa', 'dod' => 'dod', 'payment_date' => 'settled_date', 'claimed_amount' => 'claim_amount', 'net_sanct_amt' => 'approved_amount', 'updated_status' => 'tpa_claim_status', 'hospital_name' => 'hospital_name', 'hospital_city' => 'hospital_city', 'hospital_state' => 'hospital_state', 'type_of_claim' => 'tpa_claim_type', 'diagnosis' => 'tpa_ailments', 'uhid' => 'tpa_no', 'sum_insured' => 'si_amt', 'gender' => 'gender', 'age' => 'age', 'relation' => 'relation', ], ], ]; // Build tpa_id → config map from env $tpaMap = []; foreach ($tpaTableMap as $envKey => $cfg) { $tpaId = (int) env($envKey); if ($tpaId > 0) { $tpaMap[$tpaId] = $cfg; } } $totalFound = 0; $totalInserted = 0; $totalSkipped = 0; $totalFailed = 0; $tpaResults = []; $now = date('Y-m-d H:i:s'); foreach ($tpaMap as $tpaId => $cfg) { $dumpTable = $cfg['table']; $claimCol = $cfg['claim_col']; $mapping = $cfg['mapping']; if (!$db->tableExists($dumpTable)) { $tpaResults[] = [ 'tpa_id' => $tpaId, 'table' => $dumpTable, 'status' => 'skipped', 'detail' => 'Dump table does not exist.', 'found' => 0, 'inserted' => 0, 'skipped' => 0, 'failed' => 0, ]; continue; } // Fetch all active dump rows with a ticket_id (all columns) $dumpRows = $db->table($dumpTable) ->where('is_active', 1) ->where('ticket_id IS NOT NULL', null, false) ->get() ->getResultArray(); // Pre-load all related ticket_master rows in one query $ticketIds = array_filter(array_column($dumpRows, 'ticket_id')); $ticketsById = []; if (!empty($ticketIds)) { $ticketRows = $db->table('ticket_master') ->whereIn('id', array_values(array_unique($ticketIds))) ->get() ->getResultArray(); foreach ($ticketRows as $tm) { $ticketsById[(int) $tm['id']] = $tm; } } $found = count($dumpRows); $inserted = 0; $skipped = 0; $failed = 0; $totalFound += $found; foreach ($dumpRows as $row) { $claimNumber = trim((string) ($row[$claimCol] ?? '')); $clientPolicyId = (int) ($row['client_policy_id'] ?? 0); if ($claimNumber === '' || $clientPolicyId <= 0) { $skipped++; $totalSkipped++; continue; } // Fetch linked ticket_master row for emp_id / insured_emp_id $ticket = $ticketsById[(int) ($row['ticket_id'] ?? 0)] ?? null; // Check if already exists in claim_report $existing = $db->table('claim_report') ->where('client_policy_id', $clientPolicyId) ->where('claim_number', $claimNumber) ->get() ->getRowArray(); // Base row metadata from dump; employee/system IDs always from ticket_master $reportRow = [ 'tpa_id' => $tpaId, 'client_id' => $row['client_id'] ?? ($ticket['client_id'] ?? null), 'file_id' => $row['file_id'] ?? ($ticket['file_id'] ?? null), 'ticket_id' => $row['ticket_id'], 'source_table' => $dumpTable, 'source_row_id' => $row['id'], 'is_active' => 1, 'updated_at' => $now, 'emp_id' => $ticket['emp_id'] ?? null, 'insured_emp_id' => $ticket['insured_emp_id'] ?? null, 'claim_status_id' => $ticket['claim_status_id'] ?? null, ]; // 1) Fill ALL claim_report data fields from ticket_master first $ticketCols = [ 'emp_code', 'tpa_no', 'gender', 'age', 'relation', 'claim_amount', 'approved_amount', 'si_amt', 'incurred_amount', 'tpa_claim_status', 'tpa_claim_type', 'tpa_ailments', 'doa', 'dod', 'date_of_intimat', 'settled_date', 'approved_date', 'hospital_name', 'hospital_city', 'hospital_state', 'hospital_pin_code', 'hospital_address', 'claim_dump_date', ]; if ($ticket) { foreach ($ticketCols as $col) { $ticketVal = $ticket[$col] ?? null; // ticket_master uses "relationship"; claim_report uses "relation" if ($col === 'relation' && ($ticketVal === null || $ticketVal === '')) { $ticketVal = $ticket['relationship'] ?? null; } if ($ticketVal !== null && $ticketVal !== '') { $reportRow[$col] = $ticketVal; } } } // 2) Dump table fills only fields still null/empty after ticket_master foreach ($mapping as $dumpCol => $reportCol) { $current = $reportRow[$reportCol] ?? null; if ($current !== null && $current !== '') { continue; } if (array_key_exists($dumpCol, $row) && $row[$dumpCol] !== null && $row[$dumpCol] !== '') { $reportRow[$reportCol] = $row[$dumpCol]; } } // incurred_amount final fallback if (empty($reportRow['incurred_amount'])) { $reportRow['incurred_amount'] = $reportRow['approved_amount'] ?? $reportRow['claim_amount'] ?? null; } if ($existing) { // Update existing row with full data $ok = $db->table('claim_report') ->where('client_policy_id', $clientPolicyId) ->where('claim_number', $claimNumber) ->update($reportRow); if ($ok) { $skipped++; $totalSkipped++; } else { $failed++; $totalFailed++; } continue; } // New insert $reportRow['client_policy_id'] = $clientPolicyId; $reportRow['claim_number'] = $claimNumber; $reportRow['created_at'] = $now; $ok = $db->table('claim_report')->insert($reportRow); if ($ok) { $inserted++; $totalInserted++; } else { $failed++; $totalFailed++; } } $tpaResults[] = [ 'tpa_id' => $tpaId, 'table' => $dumpTable, 'status' => 'done', 'found' => $found, 'inserted' => $inserted, 'skipped' => $skipped, 'failed' => $failed, ]; } return $this->respond([ 'status' => $totalFailed === 0, 'message' => $totalFailed === 0 ? 'Sync completed successfully.' : 'Sync completed with some failures.', 'summary' => [ 'total_found' => $totalFound, 'total_inserted' => $totalInserted, 'total_skipped' => $totalSkipped, 'total_failed' => $totalFailed, ], 'tpa_results' => $tpaResults, ]); } /** * Admin check only: raw JSON on screen (no dashboard UI). */ public function debug(int $policyId = 4687) { $policyId = $this->resolvePolicyId($policyId); if ($policyId <= 0) { return $this->response ->setStatusCode(422) ->setBody('client_policy or client_policy_id is required.'); } $model = new ClaimReportDashboardModel(); $data = $model->getAllKpis($policyId); $source = $data['_meta']['claims_source'] ?? $model->resolveClaimsTable($policyId); unset($data['_meta']); $body = json_encode([ 'status' => true, 'policy_id' => $policyId, 'claims_source' => $source, 'data' => $data, ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); return $this->response ->setHeader('Content-Type', 'application/json; charset=UTF-8') ->setBody($body); } }