360 lines
14 KiB
PHP
360 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Commands;
|
|
|
|
use App\Libraries\TpaClaimsImportFactory;
|
|
use CodeIgniter\CLI\BaseCommand;
|
|
use CodeIgniter\CLI\CLI;
|
|
use InvalidArgumentException;
|
|
|
|
/**
|
|
* Copy linked TPA dump + ticket_master claims into claim_report.
|
|
*
|
|
* Usage:
|
|
* php spark claim:sync-report
|
|
* php spark claim:sync-report --policy=12
|
|
* php spark claim:sync-report --tpa=mediassist --policy=12
|
|
* php spark claim:sync-report --limit=500
|
|
* php spark claim:sync-report --ticket-only
|
|
*/
|
|
class SyncClaimReportFromDump extends BaseCommand
|
|
{
|
|
protected $group = 'Claims';
|
|
protected $name = 'claim:sync-report';
|
|
protected $description = 'Sync claim_report from TPA dump tables + ticket_master';
|
|
protected $usage = 'claim:sync-report [--policy=ID] [--tpa=NAME|all] [--limit=N] [--ticket-only]';
|
|
protected $options = [
|
|
'--policy' => 'Optional client_policy_id',
|
|
'--tpa' => 'icici|abhi|mediassist|fhpl|rcare|vidal|all (default: all)',
|
|
'--limit' => 'Batch size per dump query (default 500)',
|
|
'--ticket-only' => 'Skip dump tables; copy only from ticket_master',
|
|
];
|
|
|
|
/**
|
|
* @return array<string, array{env:string,table:string}>
|
|
*/
|
|
private function tpaConfigs(): array
|
|
{
|
|
return [
|
|
'vidal' => [
|
|
'env' => 'VIDAL_PRIMARY_KEY_CONSTANT',
|
|
'table' => 'claims_dump_vidal',
|
|
],
|
|
'abhi' => [
|
|
'env' => 'ABHI_PRIMARY_KEY_CONSTANT',
|
|
'table' => 'claims_dump_abhi',
|
|
],
|
|
'mediassist' => [
|
|
'env' => 'MEDI_ASSIST_PRIMARY_KEY_CONSTANT',
|
|
'table' => 'claims_dump_medi_assist',
|
|
],
|
|
'fhpl' => [
|
|
'env' => 'FHPL_PRIMARY_KEY_CONSTANT',
|
|
'table' => 'claims_dump_fhpl',
|
|
],
|
|
'rcare' => [
|
|
'env' => 'R_CARE_PRIMARY_KEY_CONSTANT',
|
|
'table' => 'claims_dump_reliance',
|
|
],
|
|
'icici' => [
|
|
'env' => 'ICICI_PRIMARY_KEY_CONSTANT',
|
|
'table' => 'claims_dump_icici',
|
|
],
|
|
];
|
|
}
|
|
|
|
public function run(array $params)
|
|
{
|
|
$db = db_connect();
|
|
|
|
if (!$db->tableExists('claim_report')) {
|
|
CLI::error('Table claim_report does not exist. Run: php spark migrate');
|
|
return EXIT_ERROR;
|
|
}
|
|
|
|
// Prefer $params (works from HTTP command() helper) then CLI options (spark).
|
|
$policyId = (int) ($params['policy'] ?? CLI::getOption('policy') ?? 0);
|
|
$limit = (int) ($params['limit'] ?? CLI::getOption('limit') ?? 500);
|
|
$ticketOnly = array_key_exists('ticket-only', $params) || CLI::getOption('ticket-only') !== null;
|
|
$tpaOpt = strtolower(trim((string) ($params['tpa'] ?? CLI::getOption('tpa') ?? 'all')));
|
|
|
|
if ($limit <= 0) {
|
|
$limit = 500;
|
|
}
|
|
|
|
$totalMapped = 0;
|
|
$totalSkipped = 0;
|
|
$errors = 0;
|
|
|
|
if (!$ticketOnly) {
|
|
CLI::write('Phase 1: sync from TPA dump tables (linked ticket_id rows)...', 'yellow');
|
|
|
|
$configs = $this->tpaConfigs();
|
|
if ($tpaOpt !== '' && $tpaOpt !== 'all') {
|
|
if (!isset($configs[$tpaOpt])) {
|
|
CLI::error('Unknown --tpa=' . $tpaOpt . '. Use: ' . implode('|', array_keys($configs)) . '|all');
|
|
return EXIT_ERROR;
|
|
}
|
|
$configs = [$tpaOpt => $configs[$tpaOpt]];
|
|
}
|
|
|
|
foreach ($configs as $key => $cfg) {
|
|
$tpaId = (int) env($cfg['env']);
|
|
$table = $cfg['table'];
|
|
|
|
if ($tpaId <= 0) {
|
|
CLI::write(" [SKIP] {$key}: env {$cfg['env']} not set", 'light_gray');
|
|
continue;
|
|
}
|
|
|
|
if (!$db->tableExists($table)) {
|
|
CLI::write(" [SKIP] {$key}: table {$table} missing", 'light_gray');
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$service = TpaClaimsImportFactory::make($tpaId);
|
|
} catch (InvalidArgumentException $e) {
|
|
CLI::write(' [SKIP] ' . $key . ': ' . $e->getMessage(), 'light_gray');
|
|
continue;
|
|
}
|
|
|
|
$offset = 0;
|
|
$tpaMapped = 0;
|
|
|
|
while (true) {
|
|
$builder = $db->table($table)
|
|
->select('id, file_id, ticket_id, client_policy_id')
|
|
->where('is_active', 1)
|
|
->where('ticket_id IS NOT NULL', null, false)
|
|
->orderBy('id', 'ASC')
|
|
->limit($limit, $offset);
|
|
|
|
if ($policyId > 0) {
|
|
$builder->where('client_policy_id', $policyId);
|
|
}
|
|
|
|
$dumpRows = $builder->get()->getResultArray();
|
|
if ($dumpRows === []) {
|
|
break;
|
|
}
|
|
|
|
// Group dump IDs by file_id for mapClaimReportData
|
|
$byFile = [];
|
|
foreach ($dumpRows as $row) {
|
|
$fileId = (int) ($row['file_id'] ?? 0);
|
|
$dumpId = (int) ($row['id'] ?? 0);
|
|
if ($fileId <= 0 || $dumpId <= 0) {
|
|
$totalSkipped++;
|
|
continue;
|
|
}
|
|
$byFile[$fileId][] = $dumpId;
|
|
}
|
|
|
|
foreach ($byFile as $fileId => $dumpIds) {
|
|
$result = $service->backfillClaimReportByDumpIds((int) $fileId, $dumpIds);
|
|
if (!$result['status']) {
|
|
CLI::error(" [FAIL] {$key} file_id={$fileId} upsert failed");
|
|
$errors++;
|
|
continue;
|
|
}
|
|
$tpaMapped += (int) $result['count'];
|
|
$totalMapped += (int) $result['count'];
|
|
}
|
|
|
|
$offset += count($dumpRows);
|
|
CLI::write(" {$key}: processed {$offset} dump rows (mapped so far {$tpaMapped})", 'green');
|
|
|
|
if (count($dumpRows) < $limit) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
CLI::write(" [DONE] {$key} mapped≈{$tpaMapped}", 'green');
|
|
}
|
|
} else {
|
|
CLI::write('Skipping dump tables (--ticket-only).', 'yellow');
|
|
}
|
|
|
|
CLI::write('Phase 2: fill gaps from ticket_master dump-sourced claims...', 'yellow');
|
|
$tmResult = $this->syncFromTicketMaster($db, $policyId, $limit);
|
|
if ($tmResult === false) {
|
|
return EXIT_ERROR;
|
|
}
|
|
|
|
$totalMapped += $tmResult['mapped'];
|
|
$totalSkipped += $tmResult['skipped'];
|
|
|
|
CLI::write(
|
|
"Done. dump+ticket mapped≈{$totalMapped}, skipped={$totalSkipped}, errors={$errors}",
|
|
$errors > 0 ? 'red' : 'green'
|
|
);
|
|
|
|
return $errors > 0 ? EXIT_ERROR : EXIT_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @return array{mapped:int,skipped:int}|false
|
|
*/
|
|
private function syncFromTicketMaster($db, int $policyId, int $limit)
|
|
{
|
|
if (!$db->tableExists('ticket_master')) {
|
|
CLI::error('ticket_master missing');
|
|
return false;
|
|
}
|
|
|
|
$offset = 0;
|
|
$mapped = 0;
|
|
$skipped = 0;
|
|
$now = date('Y-m-d H:i:s');
|
|
|
|
while (true) {
|
|
$builder = $db->table('ticket_master')
|
|
->where('is_active', 1)
|
|
->groupStart()
|
|
->where('claim_dump_ref_id IS NOT NULL', null, false)
|
|
->orWhere('file_id IS NOT NULL', null, false)
|
|
->groupEnd()
|
|
->where("claim_number IS NOT NULL AND TRIM(claim_number) != ''", null, false)
|
|
->orderBy('id', 'ASC')
|
|
->limit($limit, $offset);
|
|
|
|
if ($policyId > 0) {
|
|
$builder->where('client_policy_id', $policyId);
|
|
}
|
|
|
|
$tickets = $builder->get()->getResultArray();
|
|
if ($tickets === []) {
|
|
break;
|
|
}
|
|
|
|
$rows = [];
|
|
foreach ($tickets as $tm) {
|
|
$claimNumber = trim((string) ($tm['claim_number'] ?? ''));
|
|
$clientPolicyId = (int) ($tm['client_policy_id'] ?? 0);
|
|
if ($claimNumber === '' || $clientPolicyId <= 0) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
// Resolve dump provenance when possible
|
|
$sourceTable = null;
|
|
$tpaId = (int) ($tm['tpa_id'] ?? 0);
|
|
foreach ($this->tpaConfigs() as $cfg) {
|
|
if ($tpaId === (int) env($cfg['env'])) {
|
|
$sourceTable = $cfg['table'];
|
|
break;
|
|
}
|
|
}
|
|
|
|
$rows[] = [
|
|
'tpa_id' => $tm['tpa_id'] ?? null,
|
|
'client_id' => $tm['client_id'] ?? null,
|
|
'client_policy_id' => $clientPolicyId,
|
|
'file_id' => $tm['file_id'] ?? null,
|
|
'ticket_id' => $tm['id'] ?? null,
|
|
'source_table' => $sourceTable,
|
|
'source_row_id' => $tm['claim_dump_ref_id'] ?? null,
|
|
'claim_number' => $claimNumber,
|
|
'emp_code' => $tm['emp_code'] ?? null,
|
|
'tpa_no' => $tm['tpa_no'] ?? null,
|
|
'emp_id' => $tm['emp_id'] ?? null,
|
|
'insured_emp_id' => $tm['insured_emp_id'] ?? null,
|
|
'claim_amount' => $tm['claim_amount'] ?? null,
|
|
'approved_amount' => $tm['approved_amount'] ?? null,
|
|
'incurred_amount' => $tm['approved_amount'] ?? $tm['claim_amount'] ?? null,
|
|
'si_amt' => $tm['si_amt'] ?? null,
|
|
'tpa_claim_status' => $tm['tpa_claim_status'] ?? null,
|
|
'claim_status_id' => $tm['claim_status_id'] ?? null,
|
|
'tpa_claim_type' => $tm['tpa_claim_type'] ?? null,
|
|
'tpa_ailments' => $tm['tpa_ailments'] ?? null,
|
|
'doa' => $tm['doa'] ?? null,
|
|
'dod' => $tm['dod'] ?? null,
|
|
'date_of_intimat' => $tm['date_of_intimat'] ?? null,
|
|
'settled_date' => $tm['settled_date'] ?? null,
|
|
'approved_date' => $tm['approved_date'] ?? null,
|
|
'claim_dump_date' => $tm['claim_dump_date'] ?? null,
|
|
'hospital_name' => $tm['hospital_name'] ?? null,
|
|
'hospital_city' => $tm['hospital_city'] ?? null,
|
|
'hospital_state' => $tm['hospital_state'] ?? null,
|
|
'hospital_pin_code' => $tm['hospital_pin_code'] ?? null,
|
|
'hospital_address' => $tm['hospital_address'] ?? null,
|
|
'gender' => null,
|
|
'age' => null,
|
|
'relation' => $tm['relationship'] ?? null,
|
|
'is_active' => 1,
|
|
'created_at' => $now,
|
|
'updated_at' => $now,
|
|
];
|
|
}
|
|
|
|
if ($rows !== [] && $this->upsertRows($db, $rows) === false) {
|
|
CLI::error('ticket_master upsert failed at offset ' . $offset);
|
|
return false;
|
|
}
|
|
|
|
$mapped += count($rows);
|
|
$offset += count($tickets);
|
|
CLI::write(" ticket_master: processed {$offset} rows (mapped {$mapped})", 'green');
|
|
|
|
if (count($tickets) < $limit) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ['mapped' => $mapped, 'skipped' => $skipped];
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $rows
|
|
*/
|
|
private function upsertRows($db, array $rows): bool
|
|
{
|
|
$columns = [
|
|
'tpa_id', 'client_id', 'client_policy_id', 'file_id', 'ticket_id',
|
|
'source_table', 'source_row_id', 'claim_number', 'emp_code', 'tpa_no',
|
|
'emp_id', 'insured_emp_id', 'claim_amount', 'approved_amount', 'incurred_amount',
|
|
'si_amt', 'tpa_claim_status', 'claim_status_id', 'tpa_claim_type', 'tpa_ailments',
|
|
'doa', 'dod', 'date_of_intimat', 'settled_date', 'approved_date', 'claim_dump_date',
|
|
'hospital_name', 'hospital_city', 'hospital_state', 'hospital_pin_code', 'hospital_address',
|
|
'gender', 'age', 'relation', 'is_active', 'created_at', 'updated_at',
|
|
];
|
|
|
|
$updateCols = array_values(array_diff($columns, ['client_policy_id', 'claim_number', 'created_at']));
|
|
|
|
foreach (array_chunk($rows, 100) as $chunk) {
|
|
$placeholders = [];
|
|
$binds = [];
|
|
foreach ($chunk as $row) {
|
|
$rowPlaceholders = [];
|
|
foreach ($columns as $col) {
|
|
$rowPlaceholders[] = '?';
|
|
$binds[] = $row[$col] ?? null;
|
|
}
|
|
$placeholders[] = '(' . implode(', ', $rowPlaceholders) . ')';
|
|
}
|
|
|
|
$updates = [];
|
|
foreach ($updateCols as $col) {
|
|
// Prefer non-empty dump enrichment already written in phase 1:
|
|
// only overwrite when VALUES has a non-null value.
|
|
if (in_array($col, ['gender', 'age', 'relation', 'approved_amount', 'incurred_amount', 'tpa_ailments', 'tpa_claim_type', 'source_table', 'source_row_id'], true)) {
|
|
$updates[] = '`' . $col . '` = COALESCE(VALUES(`' . $col . '`), `' . $col . '`)';
|
|
} else {
|
|
$updates[] = '`' . $col . '` = VALUES(`' . $col . '`)';
|
|
}
|
|
}
|
|
|
|
$sql = 'INSERT INTO `claim_report` (`' . implode('`, `', $columns) . '`) VALUES '
|
|
. implode(', ', $placeholders)
|
|
. ' ON DUPLICATE KEY UPDATE ' . implode(', ', $updates);
|
|
|
|
if ($db->query($sql, $binds) === false) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|