GWM : icici & volo tpa integration

This commit is contained in:
Gowtham M 2026-03-25 17:59:44 +05:30
parent beb8620926
commit c21f641d58
13 changed files with 1591 additions and 175 deletions

View File

@ -131,6 +131,18 @@ HEALTH_INDIA_PASSWORD =
HEALTH_INDIA_PRIMARY_KEY_CONSTANT =
# Volo / TrueCover (EWA) — ewatpa.com APIs
VOLO_PRIMARY_KEY_CONSTANT =
VOLO_API_ADMIN_BASE_URL = https://uatapiadmin.ewatpa.com
VOLO_API_CONSUMER_BASE_URL = https://uatapiconsumer.ewatpa.com
VOLO_API_EMAIL =
VOLO_API_PASSWORD =
VOLO_LOGGED_IN_PORTAL = POLICY_CONFIGURATION_PORTAL
# Optional: if get-entity-from-policy cannot be used
VOLO_DEFAULT_ENTITY_ID =
# Required for claim intimation — hospital id from Volo network master
VOLO_DEFAULT_HOSPITAL_ID =
#For sending mail for leads RFQ/QCR
LEAD_INSURER_FROM_MAIL_ID =
LEAD_CLIENT_FROM_MAIL_ID =

Binary file not shown.

View File

@ -69,7 +69,7 @@ class Filters extends BaseConfig
'before' => [
'HttpRequestLog' => ['except' => 'cli/*'],
'Cors',
'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission','downloadEmployeeEcardZip']],
// 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission','downloadEmployeeEcardZip']],
'SecurityInputFilter' => ['except' => ['/client/notification/create','/ticket/crud_mail_template/*','test_mail','leads/sendMail'] ],
'GlobalPostFileUploadGuard'
// 'csrf',

View File

@ -564,6 +564,7 @@ $routes->cli('cli/MediAssit-ClaimStatusUpdate','MediAssistApiController::ClaimSt
$routes->cli('cli/Vidal-ClaimStatusUpdate','VidalApiController::ClaimStatusUpdate');
$routes->cli('cli/Fhpl-ClaimStatusUpdate','FhplApiController::ClaimStatusUpdate');
$routes->cli('cli/HealthIndia-ClaimStatusUpdate','HealthIndiaApiController::ClaimStatusUpdate');
$routes->cli('cli/Volo-ClaimStatusUpdate','VoloApiController::ClaimStatusUpdate');
// Sync TPA Claims to Nhance
$routes->cli('cli/MediAssit-syncTpaClaimToNhance','MediAssistApiController::syncTpaClaimToNhance');

View File

@ -13,6 +13,7 @@ use App\Controllers\VidalApiController;
use App\Controllers\ICICILombardController;
use App\Controllers\MediAssistApiController;
use App\Controllers\FhplApiController;
use App\Controllers\VoloApiController;
use App\Models\BatchFileModel;
use App\Models\FileModel;
use App\Helpers\TPADataCompareHelper;
@ -29,6 +30,7 @@ class ApiServiceController extends BaseController
protected $icici_primary_key;
protected $fhpl_primary_key;
protected $health_india_primary_key;
protected $volo_primary_key;
public function __construct()
{
@ -39,6 +41,7 @@ class ApiServiceController extends BaseController
$this->icici_primary_key = getenv('ICICI_PRIMARY_KEY_CONSTANT');
$this->fhpl_primary_key = getenv('FHPL_PRIMARY_KEY_CONSTANT');
$this->health_india_primary_key = getenv('HEALTH_INDIA_PRIMARY_KEY_CONSTANT');
$this->volo_primary_key = getenv('VOLO_PRIMARY_KEY_CONSTANT');
}
// Push Claims
@ -68,6 +71,10 @@ class ApiServiceController extends BaseController
{ // health india
$healthIndiaApiController = new HealthIndiaApiController;
return $healthIndiaApiController->SubmitClaim($claimId);
}else if ($tpaID == $this->volo_primary_key)
{ // Volo / TrueCover (EWA)
$voloApiController = new VoloApiController();
return $voloApiController->SubmitClaim($claimId);
}else{
log_message('error', "This ticket id ( {$claimId} ) TPA has no API service enabled. TPA ID : {$tpaID}");
}
@ -164,6 +171,12 @@ class ApiServiceController extends BaseController
$healthIndiaApiController = new HealthIndiaApiController;
$data['eCardDownload'] = $healthIndiaApiController->EcardRequest( $emp_code, $policy_no , $employee_policy[0]['tpa_id'] );
}else if($employee_policy[0]['tpa_primary_id'] == $this->volo_primary_key)// Volo / TrueCover
{
$voloApiController = new VoloApiController();
$data['eCardDownload'] = $voloApiController->EcardRequest( $emp_code, $policy_no , $employee_policy[0]['tpa_id'] );
}else{
if($type == "download"){
@ -322,6 +335,15 @@ class ApiServiceController extends BaseController
return $this->respond(['status' => true, 'code' => 200, 'message' => 'Action Triggered','data' => [] ]);
}else if ($tpa_id == $this->volo_primary_key) // Volo / TrueCover
{
$file_id = $fileModel->insert($data);
log_message('error', "Files table inserted successfully, File id : {$file_id}");
$r = Jobs::addJob(['job_name' => 'VoloGetBenefDetails', 'payload' => ['policy_no' => $policy_no, 'file_id' => $file_id, 'client_policy_id' => $policy_id, 'return_type' => 'job']]);
log_message('error', "VoloGetBenefDetails job pushed successfully.");
return $this->respond(['status' => true, 'code' => 200, 'message' => 'Action Triggered','data' => [] ]);
}else{
return $this->respond(['status' => false, 'code' => 200,'message' => 'TPA not found ','data' => [] ]);
}
@ -364,6 +386,12 @@ class ApiServiceController extends BaseController
$res = $healthIndiaApiController->ClaimDetail($claimId);
return $this->response->setJSON(['status' => $res['status'],'message' => $res['message'] ]);
}else if ($tpaID == $this->volo_primary_key) { // Volo / TrueCover
$voloApiController = new VoloApiController();
$res = $voloApiController->ClaimDetail($claimId);
return $this->response->setJSON(['status' => $res['status'],'message' => $res['message'] ]);
}else{
log_message('error', "This ticket id ( {$claimId} ) TPA has no API service enabled. TPA ID : {$tpaID}");
$message = "This TPA has no API service enabled";

View File

@ -54,19 +54,18 @@ class FhplApiController extends BaseController
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
return $this->response->setJSON([
'status' => false,
'error' => curl_error($ch),
]);
return ['status' => false,'error' => curl_error($ch),];
}
curl_close($ch);
return $this->response->setJSON([
// dd($response);
return [
'status' => $httpCode === 200,
'http_code' => $httpCode,
'data' => json_decode($response, true),
]);
];
}
public function SubmitClaim($claimId = null) // 515
@ -115,7 +114,7 @@ class FhplApiController extends BaseController
$fileContent = base64_encode(file_get_contents($pdfPath));
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['access_token'])) {
log_message('error', "FHPL - Claim Push FAILED | claimId: '.$claimId.' - FHPL Token generation failed");
return ['status' => false, 'message' => 'Claim Push FAILED | FHPL Token generation failed'];
@ -193,7 +192,7 @@ class FhplApiController extends BaseController
}
return ['status' => false, 'message' => 'Claim Push API SUCCESS BUT claimsInfo EMPTY'];
// return $this->response->setJSON($response);
}
public function ClaimDetail($claimId = null) //515
@ -210,7 +209,7 @@ class FhplApiController extends BaseController
if(!$ticket) return ['status'=>false,'message'=>'Invalid claim'];
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['access_token'])) {
return ['status' => false,'message' => 'FHPL Token generation failed'];
@ -309,7 +308,7 @@ class FhplApiController extends BaseController
helper('api');
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['access_token'])) {
log_message('error', 'FHPL - Ecard Request FAILED | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | Message: FHPL Token generation failed');
return null;
@ -412,7 +411,7 @@ class FhplApiController extends BaseController
}
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['access_token'])) {
log_message('error', 'FHPL - TPA ID Pull | FHPL Token generation failed');
if($function_calling_type == "job"){
@ -722,10 +721,10 @@ class FhplApiController extends BaseController
helper('api');
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['access_token'])) {
return $this->response->setJSON(['status' => false,'message' => 'FHPL Token generation failed']);
return ['status' => false,'message' => 'FHPL Token generation failed'];
}
$token = $tokenResponse['data']['access_token'];
@ -800,10 +799,10 @@ class FhplApiController extends BaseController
try {
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['access_token'])) {
return $this->response->setJSON(['status' => false,'message' => 'FHPL Token generation failed']);
return ['status' => false,'message' => 'FHPL Token generation failed'];
}
$token = $tokenResponse['data']['access_token'];
@ -832,9 +831,23 @@ class FhplApiController extends BaseController
$response = call_third_party_api($url,'POST',$headers,$body);
if(!empty($response['data'])){
log_message('error', 'FHPL - Sync TPA Claims | Exception thrown while calling GetTPA_ClaimsDetails API: ' . json_encode($response));
$finalResult = array_merge($finalResult,$response['data']);
if (!empty($response['data'])) {
log_message('error', 'FHPL - Sync TPA Claims API Response: ' . json_encode($response));
// Convert to array if it's JSON string
if (is_string($response['data'])) {
$decodedData = json_decode($response['data'], true);
} else {
$decodedData = $response['data'];
}
// Merge only if it's array
if (is_array($decodedData)) {
$finalResult = array_merge($finalResult, $decodedData);
} else {
log_message('error', 'FHPL - Data is not an array: ' . print_r($response['data'], true));
}
}
}

View File

@ -61,10 +61,7 @@ class HealthIndiaApiController extends BaseController
if (curl_errno($ch)) {
log_message('error', 'HEALTH_INDIA TOKEN GENERATION FAILED | Error: ' . curl_error($ch));
curl_close($ch);
return $this->response->setJSON([
'status' => false,
'error' => curl_error($ch),
]);
return ['status' => false, 'error' => curl_error($ch)];
}
curl_close($ch);
@ -77,11 +74,11 @@ class HealthIndiaApiController extends BaseController
log_message('error', 'HEALTH_INDIA TOKEN GENERATION FAILED | Response: ' . $response);
}
return $this->response->setJSON([
return [
'status' => $httpCode === 200,
'http_code' => $httpCode,
'data' => $responseData,
]);
];
}
public function SubmitClaim($claimId = null)
@ -144,7 +141,7 @@ class HealthIndiaApiController extends BaseController
$fileContent = base64_encode(file_get_contents($pdfPath));
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Token generation failed");
return;
@ -261,7 +258,7 @@ class HealthIndiaApiController extends BaseController
}
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
log_message('error', 'HEALTH_INDIA - Claim Status FAILED | claimId: ' . $claimId . ' - Token generation failed');
@ -381,7 +378,7 @@ class HealthIndiaApiController extends BaseController
log_message('error', "HEALTH_INDIA - Ecard Request | Started | employeeId: {$employeeId} | policyNo: {$policyNo} | memberId: {$memberId}");
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
log_message('error', "HEALTH_INDIA - Ecard Request | employeeId: {$employeeId} | policyNo: {$policyNo} | Message: Token generation failed");
return null;
@ -486,7 +483,7 @@ class HealthIndiaApiController extends BaseController
}
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
log_message('error', 'HEALTH_INDIA - TPA ID Pull | Token generation failed');
if ($function_calling_type == "job") {
@ -732,7 +729,7 @@ class HealthIndiaApiController extends BaseController
log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Started');
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
log_message('error', 'HEALTH_INDIA - Sync TPA Claims FAILED | Token generation failed');
@ -830,7 +827,7 @@ class HealthIndiaApiController extends BaseController
log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Started');
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
log_message('error', 'HEALTH_INDIA - Sync TPA Claims FAILED | Token generation failed');

View File

@ -5,10 +5,129 @@ namespace App\Controllers;
use CodeIgniter\Controller;
use Kint;
use Ramsey\Uuid\Uuid;
use App\Models\BatchFileModel;
class ICICILombardController extends AdminController
{
/**
* Fetch UHID details for a completed batch and update `employee_polices.uhid`.
*
* @param array $batch Row from batch_files joined with client_policy (must include: id, client_policy_id, icici_batch_id, icici_correlation_id, icici_endorsement_policy_no)
* @param string|null $overrideImid If provided, uses this value instead of icici_batch_id.
* @return array {new_status, updatedCount, response}
*/
private function fetchUhidAndUpdateEmployeePolicies(array $batch, ?string $overrideImid = null): array
{
helper('api');
$tokenResponse = $this->generateAuthToken('esbgpauhid');
if (!$tokenResponse || empty($tokenResponse['data']['access_token'])) {
return [
'new_status' => 'FAILED',
'updatedCount' => 0,
'response' => $tokenResponse,
'error' => 'Token generation failed.',
];
}
$token = $tokenResponse['data']['access_token'];
$url = env('ICICI_BASE_URL') . '/fetchuhid';
$headers = [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
];
$correlationId = !empty($batch['icici_correlation_id'])
? $batch['icici_correlation_id']
: sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
);
$imid = $overrideImid ?: ($batch['icici_batch_id'] ?? null);
if (empty($imid) || empty($batch['icici_endorsement_policy_no'])) {
return [
'new_status' => 'FAILED',
'updatedCount' => 0,
'response' => null,
'error' => 'IMID or endorsement PolicyNumber missing for UHID fetch.',
];
}
$body = [
'PolicyNumber' => $batch['icici_endorsement_policy_no'],
'IMID' => $imid,
'CorrelationId' => $correlationId,
];
$response = call_third_party_api($url, 'POST', $headers, $body, true);
$apiData = $response['data'] ?? [];
$newFlag = 'FAILED';
$updatedCount = 0;
if (!empty($response['status']) && $response['status'] === true && (($apiData['statusMessage'] ?? null) === 'SUCCESS')) {
$newFlag = 'COMPLETED';
// Update UHID in employee_polices table based on memberDetails
$memberDetails = $apiData['memberDetails'] ?? [];
if (!empty($memberDetails) && is_array($memberDetails)) {
$db = \Config\Database::connect();
$clientPolicyId = (int) ($batch['client_policy_id'] ?? 0);
foreach ($memberDetails as $member) {
$employeeMemberId = $member['employeeMemberId'] ?? null;
$uhid = $member['uhid'] ?? null;
if (empty($employeeMemberId) || empty($uhid)) {
continue;
}
// Find employee by emp_code = employeeMemberId
$employee = $db->table('employees')
->select('id')
->where('emp_code', $employeeMemberId)
->get()
->getRowArray();
if (empty($employee)) {
continue;
}
// Update UHID for that employee and policy
$db->table('employee_polices')
->where('employee_id', $employee['id'])
->where('client_policy_id', $clientPolicyId)
->set('uhid', $uhid)
->update();
$updatedCount++;
}
}
}
$batchModel = new BatchFileModel();
$batchModel->update($batch['id'], [
'icici_uhid_status_flag' => $newFlag,
]);
return [
'new_status' => $newFlag,
'updatedCount' => $updatedCount,
'response' => $response,
'request' => $body,
];
}
public function generateAuthToken($scope = 'esbhealth')
{
helper('api');
@ -21,7 +140,7 @@ class ICICILombardController extends AdminController
'grant_type' => env('ICICI_GRANT_TYPE'),
'username' => env('ICICI_USER_NAME'),
'password' => env('ICICI_PASSWORD'),
'scope' => env('ICICI_API_SCOPE'),
'scope' => $scope ?: env('ICICI_API_SCOPE'),
'client_id' => env('ICICI_CLIENT_ID'),
'client_secret' => env('ICICI_CLIENT_SECRET')
];
@ -37,6 +156,7 @@ class ICICILombardController extends AdminController
]);
}
// Debug removed: return token response to caller.
return $response;
}
@ -44,11 +164,12 @@ class ICICILombardController extends AdminController
{
$client_id = $this->request->getGet('client_id');
$client_branch_id = $this->request->getGet('client_branch_id');
$policy_id = $this->request->getGet('policy_id');
// Prefer `client_policy_id` key (also accept legacy `policy_id`)
$policy_id = $this->request->getGet('client_policy_id') ?? $this->request->getGet('policy_id');
$event = $this->request->getGet('event');
//fetch token
$tokenResponse = $this->generateAuthToken();
$tokenResponse = $this->generateAuthToken('esbgpabatchcreation');
if (!$tokenResponse || empty($tokenResponse['data']['access_token'])) {
return $this->response->setJSON([
'status' => false,
@ -66,91 +187,71 @@ class ICICILombardController extends AdminController
];
//Prepare body data
// $db = \Config\Database::connect();
// $data = $db->table('employee_polices ep')
// ->select('cp.policy_no as policyNumber, cp.cd_ac_no as CDBGAccountNumber,
// e.id,e.emp_code as MemberEmpId, e.doj as DOJ, e.name as InsuredName, e.dob as DOB, e.relationship as Relationship,
// e.gender as Gender, ep.date_coverage as DOC,ep.basic_cover_si as SumInsured, e.email_corporate as EmailId
// ')
// ->join('employees e', 'e.id = ep.employee_id')
// ->join('client_policy cp', 'ep.client_policy_id = cp.id')
// ->where('ep.client_policy_id', $policy_id)
// ->where('ep.status', 'active')
// ->where('ep.is_active', 1)
// // ->where('ep.uhid', null)
// ->get()
// ->getResultArray();
// $body = $this->formatPolicyData($data);
// dd($body);
// Prepare body data from employee policies
$db = \Config\Database::connect();
$data = $db->table('employee_polices ep')
->select('cp.policy_no as policyNumber, cp.cd_ac_no as CDBGAccountNumber,
e.id,e.emp_code as MemberEmpId, e.doj as DOJ, e.name as InsuredName, e.dob as DOB, e.relationship as Relationship,
e.gender as Gender, ep.date_coverage as DOC,ep.basic_cover_si as SumInsured, e.email_corporate as EmailId
')
->join('employees e', 'e.id = ep.employee_id')
->join('client_policy cp', 'ep.client_policy_id = cp.id')
->where('ep.client_policy_id', $policy_id)
->where('ep.status', 'active')
->where('ep.is_active', 1)
// ->where('ep.uhid', null)
->get()
->getResultArray();
// dd($data);
if (empty($data)) {
return $this->response->setJSON([
'status' => false,
'message' => 'No active employee policies found for given policy.',
'data' => [],
]);
}
$body = $this->formatPolicyData($data);
if (empty($body['CDBGAccountNumber'])) {
return $this->response->setJSON([
'status' => false,
'message' => 'CDBGAccountNumber is empty for selected policy. Please configure policy CDBG account number.',
'data' => $body,
]);
}
// $body = [
// "PolicyNumber" => "4016/PPN/A/O/53167743/00/000",
// "CDBGAccountNumber" => "CD-MUM-0026",
// "CorrelationId" => "550e8400-e29b-41d4-a716-446655440016",
// "MemberDetails" => [
// [
// "MemberEmpId" => "EMPID3625562",
// "DOJ" => "21-MAR-2019",
// "InsuredName" => "Jeeva",
// "DOB" => "7-JUL-1993",
// "Relationship" => "SELF",
// "Gender" => "MALE",
// "DOC" => '28-Oct-2025',
// "SumInsured" => "500000",
// "EmailId" => "Jeeva@GMAIL.COM",
// "FlagStatus" => "A"
// ],
// [
// "MemberEmpId" => "EMPID3625562",
// "DOJ" => "21-MAR-2019",
// "InsuredName" => "Muthu",
// "DOB" => "8-AUG-1970",
// "Relationship" => "MOTHER",
// "Gender" => "FEMALE",
// "DOC" => '28-Oct-2025',
// "EmailId" => "Muthu@GMAIL.COM",
// "FlagStatus" => "A"
// ],
// ]
// ];
$body = [
"PolicyNumber" => "4016/PPN/A/O/53185987/00/000",
"CDBGAccountNumber" => "CD-MUM-0026",
"CorrelationId" => "550e8400-e29b-41d4-a716-446655440023",
"MemberDetails" => [
[
"MemberEmpId" => "EMPID3625566",
"DOJ" => "21-MAR-2019",
"InsuredName" => "sanjeev",
"DOB" => "7-JUL-1993",
"Relationship" => "SELF",
"Gender" => "MALE",
"DOC" => '25-Jan-2026',
"SumInsured" => "500000",
"EmailId" => "sanjeev@GMAIL.COM",
"FlagStatus" => "A"
],
[
"MemberEmpId" => "EMPID3625566",
"DOJ" => "21-MAR-2019",
"InsuredName" => "bhavya",
"DOB" => "8-AUG-1970",
"Relationship" => "MOTHER",
"Gender" => "FEMALE",
"DOC" => '25-Jan-2026',
"EmailId" => "bhavya@GMAIL.COM",
"FlagStatus" => "A"
],
]
];
if (empty($body['MemberDetails'])) {
return $this->response->setJSON([
'status' => false,
'message' => 'No valid member records available for ICICI enrollment payload.',
'data' => $body,
]);
}
$response = call_third_party_api($url, 'POST', $headers, $body, true); // true = raw body mode
// print_rr(json_encode($response));die();
// Save batch information only on successful API call
if (!empty($response['status']) && $response['status'] === true) {
$apiData = $response['data'] ?? [];
$batchModel = new BatchFileModel();
$batchModel->insert([
'client_id' => $client_id,
'client_policy_id' => $policy_id,
'client_branch_id' => $client_branch_id,
'event_type' => $event,
'insurer_or_tpa' => 'ICICI_LOMBARD',
'actions' => 'ICICI_GPA_ENROLLMENT',
'is_active' => 1,
'icici_correlation_id' => $body['CorrelationId'] ?? null,
'icici_batch_id' => $apiData['batchId'] ?? null,
'icici_status_flag' => 'PENDING',
'icici_status_message' => $apiData['message'] ?? null,
'icici_endorsement_policy_no' => null,
'icici_uhid_status_flag' => 'PENDING',
]);
}
return $this->response->setJSON($response);
}
@ -158,8 +259,11 @@ class ICICILombardController extends AdminController
{
helper('api');
// User request: use `client_policy_id` key (also accept legacy `policy_id`)
$clientPolicyId = $this->request->getGet('client_policy_id') ?? $this->request->getGet('policy_id');
//fetch token
$tokenResponse = $this->generateAuthToken();
$tokenResponse = $this->generateAuthToken('esbgpabatchstatus');
if (!$tokenResponse || empty($tokenResponse['data']['access_token'])) {
return $this->response->setJSON([
'status' => false,
@ -176,61 +280,156 @@ class ICICILombardController extends AdminController
'Content-Type: application/json'
];
// dd($headers);
$db = \Config\Database::connect();
$body = [
"PolicyNumber" => "4016/PPN/A/O/53185987/00/000",
"BatchId" => "3728144",
"CorrelationId" => "550e8400-e29b-41d4-a716-446655440022"
];
// Fetch all pending / in-process batches for ICICI
$query = $db->table('batch_files bf')
->select('bf.id, bf.client_policy_id, bf.icici_batch_id, bf.icici_correlation_id, cp.policy_no')
->join('client_policy cp', 'cp.id = bf.client_policy_id')
->where('bf.is_active', 1)
->whereIn('bf.icici_status_flag', ['PENDING', 'IN_PROCESS'])
->where('bf.icici_batch_id IS NOT NULL');
$response = call_third_party_api($url, 'POST', $headers, $body, true);
if (!empty($clientPolicyId)) {
$query->where('bf.client_policy_id', (int) $clientPolicyId);
}
return $this->response->setJSON($response);
$batches = $query->get()->getResultArray();
if (empty($batches)) {
return $this->response->setJSON([
'status' => true,
'message' => 'No pending ICICI GPA batches found.',
'data' => [],
]);
}
$batchModel = new BatchFileModel();
$results = [];
foreach ($batches as $batch) {
$body = [
'PolicyNumber' => $batch['policy_no'],
'BatchId' => $batch['icici_batch_id'],
'CorrelationId' => $batch['icici_correlation_id'],
];
$response = call_third_party_api($url, 'POST', $headers, $body, true);
$apiData = $response['data'] ?? [];
$message = $apiData['message'] ?? null;
$statusMessage = $apiData['statusMessage'] ?? null;
$newStatusFlag = 'FAILED';
if (!empty($response['status']) && $response['status'] === true && $statusMessage === 'SUCCESS') {
if ($message === 'Process Completed') {
$newStatusFlag = 'COMPLETED';
} elseif ($message === 'In Process') {
$newStatusFlag = 'IN_PROCESS';
} else {
$newStatusFlag = 'PENDING';
}
}
$updateData = [
'icici_status_flag' => $newStatusFlag,
'icici_status_message' => $message,
'icici_endorsement_policy_no'=> $apiData['endorsementPolicyNo'] ?? null,
];
// If process completed successfully, UHID step becomes pending
if ($newStatusFlag === 'COMPLETED') {
$updateData['icici_uhid_status_flag'] = 'PENDING';
}
$batchModel->update($batch['id'], $updateData);
// After COMPLETED, trigger UHID fetch internally (no extra imid param).
$uhidResult = null;
if ($newStatusFlag === 'COMPLETED') {
// Ensure we pass endorsement policy number to the internal UHID fetch helper.
$batch['icici_endorsement_policy_no'] = $updateData['icici_endorsement_policy_no'] ?? null;
$uhidResult = $this->fetchUhidAndUpdateEmployeePolicies($batch);
}
$results[] = [
'batch_file_id' => $batch['id'],
'request' => $body,
'response' => $response,
'new_status' => $newStatusFlag,
'uhid_fetch' => $uhidResult,
];
}
return $this->response->setJSON([
'status' => true,
'message' => 'Batch status updated.',
'data' => $results,
]);
}
public function fetchUHIDDetails()
{
helper('api');
//fetch token
$tokenResponse = $this->generateAuthToken('esbgpauhid');
// dd($tokenResponse);
if (!$tokenResponse || empty($tokenResponse['data']['access_token'])) {
// Accept `client_policy_id` key (also accept legacy `policy_id`)
$policy_id = $this->request->getGet('client_policy_id') ?? $this->request->getGet('policy_id');
$imid = $this->request->getGet('imid'); // optional; if omitted we derive from icici_batch_id
if (empty($policy_id)) {
return $this->response->setJSON([
'status' => false,
'message' => 'Token generation failed.',
'data' => $tokenResponse
'status' => false,
'message' => 'client_policy_id is required.',
'data' => [],
]);
}
$token = $tokenResponse['data']['access_token'];
// print_rr($token);
$batchModel = new BatchFileModel();
$batch = $batchModel
->where('client_policy_id', $policy_id)
->where('is_active', 1)
->where('icici_status_flag', 'COMPLETED')
->whereIn('icici_uhid_status_flag', ['PENDING', 'FAILED'])
->orderBy('id', 'DESC')
->first();
$url = env('ICICI_BASE_URL').'/fetchuhid';
$headers = [
'Authorization: Bearer ' . $token,
'Content-Type: application/json'
];
if (empty($batch)) {
return $this->response->setJSON([
'status' => false,
'message' => 'No completed ICICI GPA batch found for UHID fetch.',
'data' => [],
]);
}
$body = [
"PolicyNumber" => "4016/PPN/A/O/53185987/00/001",
"IMID" => "201580517901",
"CorrelationId" => "550e8400-e29b-41d4-a716-446655440022"
];
$uhidResult = $this->fetchUhidAndUpdateEmployeePolicies($batch, $imid);
$response = call_third_party_api($url, 'POST', $headers, $body, true);
// dd($response);
return $this->response->setJSON($response);
return $this->response->setJSON([
'status' => true,
'message' => 'UHID details fetched.',
'data' => [
'batch_file_id' => $batch['id'],
'request' => $uhidResult['request'] ?? [],
'response' => $uhidResult['response'] ?? [],
'new_status' => $uhidResult['new_status'] ?? 'FAILED',
'uhid_updated_count' => $uhidResult['updatedCount'] ?? 0,
],
]);
}
public function formatPolicyData($data)
{
// Helper to format date
// Helper to format date as DD-MMM-YYYY (e.g. 7-JUL-1993)
$formatDate = function ($date) {
return strtoupper(date('j-M-Y', strtotime($date))); // Example: 7-JUL-1983
if (empty($date)) {
return null;
}
$timestamp = strtotime($date);
if ($timestamp === false) {
return null;
}
return strtoupper(date('j-M-Y', $timestamp));
};
// Generate UUID v4 for CorrelationId
@ -248,26 +447,42 @@ class ICICILombardController extends AdminController
);
};
// Map MemberDetails
$memberDetails = array_map(function ($row) use ($formatDate) {
return [
"MemberEmpId" => $row['MemberEmpId'],
"DOJ" => $formatDate($row['DOJ']),
"InsuredName" => $row['InsuredName'],
"DOB" => $formatDate($row['DOB']),
"Relationship" => strtoupper($row['Relationship']),
"Gender" => strtoupper($row['Gender']),
"DOC" => $formatDate($row['DOC']),
"SumInsured" => $row['SumInsured'],
"EmailId" => $row['EmailId'],
"FlagStatus" => "A" // fixed value
$mapGender = function ($gender) {
$normalized = strtoupper(trim((string) $gender));
if ($normalized === 'M' || $normalized === 'MALE') {
return 'MALE';
}
if ($normalized === 'F' || $normalized === 'FEMALE') {
return 'FEMALE';
}
return $normalized;
};
// Map MemberDetails in ICICI expected request format
$memberDetails = [];
foreach ($data as $row) {
if (empty($row['MemberEmpId']) || empty($row['InsuredName']) || empty($row['DOB']) || empty($row['DOC'])) {
continue;
}
$memberDetails[] = [
"EmployeeMemberId" => preg_replace('/[^A-Za-z0-9]/', '', (string) $row['MemberEmpId']),
"DOJ" => $formatDate($row['DOJ']),
"InsuredName" => $row['InsuredName'],
"DOB" => $formatDate($row['DOB']),
"Relationship" => strtoupper((string) $row['Relationship']),
"Gender" => $mapGender($row['Gender'] ?? ''),
"DOC" => $formatDate($row['DOC']),
"SumInsured" => $row['SumInsured'],
"EmailId" => $row['EmailId'],
"FlagStatus" => "A"
];
}, $data);
}
// Final body
return [
"PolicyNumber" => $data[0]['policyNumber'] ?? null,
"CDBGAccountNumber" => $data[0]['CDBGAccountNumber'] ?? null , // "CD-MUM-0026",
"CDBGAccountNumber" => $data[0]['CDBGAccountNumber'] ?? env('ICICI_CDBG_ACCOUNT_NUMBER'),
"CorrelationId" => $generateUUID(),
"MemberDetails" => $memberDetails
];

View File

@ -211,6 +211,14 @@ class JobWorker extends AdminController
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\HealthIndiaApiController',
],
'VoloGetBenefDetails' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\VoloApiController',
],
'saveVoloAPIData' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\VoloApiController',
],
'bdsDumpExcelFileFormatValidation' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\PolicyTransactionController',

View File

@ -478,7 +478,7 @@ class VidalApiController extends BaseController
$body = [
'empNO' => "",
'tpaCardID' => "",
'claimID' => $ticket['claimID'],
'claimID' => $ticket['claimID'], //"GUR-0326-CL-0001471"
'emailID' => "",
'mobileNO' => "",
];
@ -487,6 +487,8 @@ class VidalApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
// dd($url, $method, $headers, $body, $response);
if ($response['status'] != true || empty($response['data']['data']['claims'][0])) {
log_message('error', 'VIDAL - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
@ -1035,8 +1037,141 @@ class VidalApiController extends BaseController
return $result;
}
public function IRSubmission($claimId = null)
{
log_message('error', "VIDAL - IR Submission | INIT for ticket_id={$claimId}");
// 1. FETCH TICKET DETAILS
$ticket = $this->db->table('ticket_master tm')
->select("
tm.id,
tm.tpa_no as memberId,
tm.tpa_claim_push_reference_no as claimInwardNO,
tm.tpa_claim_id as claimNO,
cp.policy_no as policyNo,
cp.policy_start_date as startDate,
cp.policy_end_date as endDate,
e.emp_code as employeeCode
")
->join('employees e', 'e.id = tm.emp_id', 'left')
->join('client_policy cp', 'tm.client_policy_id = cp.id', 'left')
->where('tm.id', $claimId)
->get()
->getRowArray();
if (!$ticket || empty($ticket['claimNO'])) {
log_message('error', "VIDAL - IR Submission FAILED → ClaimID NOT FOUND for ticket_id={$claimId}");
return [
'status' => false,
'message' => "ClaimID not found for ticket {$claimId}"
];
}
// 2. FETCH IR ATTACHMENTS
$fileData = $this->db->table('claim_files f')
->where('f.ticket_id', $claimId)
->where('f.docs_for_ir', 1)
->get()
->getResultArray();
if (empty($fileData)) {
log_message('error', "VIDAL - IR Submission FAILED → No IR attachments found for ticket_id={$claimId}");
return [
'status' => false,
'message' => 'IR attachments not found for the claim'
];
}
// 3. UPLOAD FILES TO VIDAL
$fileIdList = [];
foreach ($fileData as $file) {
if (empty($file['filePath'])) {
continue;
}
$filename = basename($file['filePath']);
$fullPath = WRITEPATH . 'uploads/claim_files/' . $filename;
$upload = $this->uploadFileToVidal($fullPath, $filename);
if (empty($upload['status']) || $upload['status'] !== true) {
log_message('error', "VIDAL - IR Submission FAILED → File upload failed");
return [
'status' => false,
'message' => 'File upload failed',
'data' => $upload
];
}
$fileIdList[] = $upload['fileId']; // deeplink URL
}
if (empty($fileIdList)) {
return [
'status' => false,
'message' => 'No valid files uploaded'
];
}
// 4. PREPARE REQUEST BODY
$body = [
"shortFallNo" => $ticket['claimNO'], // or actual shortfall number if different (GUR-0326-CL-0001471)
];
// If single file → fileId
if (count($fileIdList) === 1) {
$body["fileId"] = $fileIdList[0];
} else {
$body["fileIdList"] = $fileIdList;
}
log_message('error', "VIDAL - IR Submission Request Body => " . json_encode($body));
// 5. API CALL
helper('api');
$url = env('VIDAL_API_BASE_URL_IRSUBMISSION');
$method = 'POST';
$headers = [
'Content-Type: application/json',
'Ocp-Apim-Subscription-Key: ' . getenv('VIDAL_SUBSCRIPTION_KEY'),
];
$response = call_third_party_api($url, $method, $headers, json_encode($body));
log_message('error', "VIDAL - IR Submission API Response => " . json_encode($response));
// 6. HANDLE RESPONSE
if (empty($response['status']) || $response['status'] !== true) {
log_message(
'error',
"VIDAL - IR Submission FAILED for ClaimNO={$ticket['claimNO']} → Response=" . json_encode($response)
);
return [
'status' => false,
'message' => 'IR Submission failed',
'data' => $response
];
}
log_message('error', "VIDAL - IR Submission SUCCESS → ClaimNO={$ticket['claimNO']}");
return [
'status' => true,
'message' => 'IR Submitted successfully',
'data' => $response
];
}
}

View File

@ -0,0 +1,924 @@
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use App\Controllers\Jobs;
use App\Models\BatchFileModel;
use App\Models\EmployeePolicyModel;
use App\Models\TpaApiDataModel;
use CodeIgniter\API\ResponseTrait;
/**
* TrueCover / EWA TPA APIs (ewatpa.com) Volo integration layer.
*
* @see Postman collection (login, enrollment, hospitals, documents, claim flows).
*/
class VoloApiController extends BaseController
{
use ResponseTrait;
protected $db;
protected $voloTpaId;
/** @var string|null Cached access token for the current request cycle */
private ?string $cachedAccessToken = null;
public function __construct()
{
$this->db = \Config\Database::connect();
$this->voloTpaId = getenv('VOLO_PRIMARY_KEY_CONSTANT');
}
protected function adminBaseUrl(): string
{
return rtrim((string) getenv('VOLO_API_ADMIN_BASE_URL'), '/');
}
protected function consumerBaseUrl(): string
{
return rtrim((string) getenv('VOLO_API_CONSUMER_BASE_URL'), '/');
}
/**
* Obtain API access token (login).
*
* @return string|null Full accessToken value as returned by API (includes "Token " prefix when applicable)
*/
public function getAccessToken(): ?string
{
if ($this->cachedAccessToken !== null) {
return $this->cachedAccessToken;
}
helper('api');
$url = $this->adminBaseUrl() . '/external/login';
$body = [
'emailId' => getenv('VOLO_API_EMAIL'),
'password' => getenv('VOLO_API_PASSWORD'),
'loggedInPortal' => getenv('VOLO_LOGGED_IN_PORTAL') ?: 'POLICY_CONFIGURATION_PORTAL',
];
$headers = ['Content-Type: application/json'];
$response = call_third_party_api($url, 'POST', $headers, $body);
if (empty($response['status'])) {
log_message('error', 'VOLO - Login failed | ' . json_encode($response));
return null;
}
$data = $response['data'] ?? null;
if (!is_array($data)) {
log_message('error', 'VOLO - Login invalid response shape | ' . json_encode($response));
return null;
}
$token = $data['accessToken'] ?? null;
if ($token === null || $token === '' || $token === 'Token null') {
log_message('error', 'VOLO - Login rejected or empty token | ' . json_encode($data));
return null;
}
$this->cachedAccessToken = $token;
return $this->cachedAccessToken;
}
/**
* @return array{0: bool, 1: array<int, string>}
*/
protected function authorizedJsonHeaders(): array
{
$token = $this->getAccessToken();
if ($token === null) {
return [false, []];
}
return [true, [
'Content-Type: application/json',
'Authorization: ' . $token,
]];
}
/**
* GET /trueclaim/tpa/get-Enrollment-dump
*/
public function getEnrollmentDumpByEndorsement(string $insurerPolicyNumber, string $endorsmentNo)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$query = http_build_query([
'insurerPolicyNumber' => $insurerPolicyNumber,
'endorsmentNo' => $endorsmentNo,
]);
$url = $this->adminBaseUrl() . '/trueclaim/tpa/get-Enrollment-dump?' . $query;
return call_third_party_api($url, 'GET', $headers, []);
}
/**
* GET /trueclaim/tpa/getHospitalByInsurerName
*/
public function getHospitalByInsurerName(string $insurerName)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$query = http_build_query(['insurerName' => $insurerName]);
$url = $this->adminBaseUrl() . '/trueclaim/tpa/getHospitalByInsurerName?' . $query;
return call_third_party_api($url, 'GET', $headers, []);
}
/**
* POST /trueclaim/tpa/doc
*
* @param array<string, mixed> $body
*/
public function uploadDocument(array $body)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$url = $this->adminBaseUrl() . '/trueclaim/tpa/doc';
return call_third_party_api($url, 'POST', $headers, $body);
}
/**
* GET /trueclaim/tpa/get-Enroll-dump
*/
public function getEnrollmentDump(string $insurerPolicyNumber)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$query = http_build_query(['insurerPolicyNumber' => $insurerPolicyNumber]);
$url = $this->adminBaseUrl() . '/trueclaim/tpa/get-Enroll-dump?' . $query;
return call_third_party_api($url, 'GET', $headers, []);
}
/**
* POST consumer /truecover/external-service/claim-status
*/
public function fetchExternalClaimStatus(string $tpaClaimNo)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$url = $this->consumerBaseUrl() . '/truecover/external-service/claim-status';
$body = ['tpaClaimNo' => $tpaClaimNo];
return call_third_party_api($url, 'POST', $headers, $body);
}
/**
* POST /trueclaim/tpa/getTpaData
*
* @return array<string, mixed>
*/
public function getTpaData(string $startDate, string $endDate, string $entityId)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$url = $this->adminBaseUrl() . '/trueclaim/tpa/getTpaData';
$body = [
'startDate' => $startDate,
'endDate' => $endDate,
'entityId' => $entityId,
];
return call_third_party_api($url, 'POST', $headers, $body);
}
/**
* GET /trueclaim/create-new-all-member-id-card-pdf
* Returns raw API response; body may contain base64 PDF payload.
*/
public function getEcardPdfRequest(string $employeeId, string $entityId)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$query = http_build_query([
'employeeId' => $employeeId,
'entityId' => $entityId,
]);
$url = $this->adminBaseUrl() . '/trueclaim/create-new-all-member-id-card-pdf?' . $query;
return call_third_party_api($url, 'GET', $headers, []);
}
/**
* GET /trueclaim/get-entity-from-policy
*/
public function getEntityFromPolicy(string $policyNumber)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$query = http_build_query(['policyNumber' => $policyNumber]);
$url = $this->adminBaseUrl() . '/trueclaim/get-entity-from-policy?' . $query;
return call_third_party_api($url, 'GET', $headers, []);
}
/**
* POST /trueclaim/policy-bazaar/intimate-claim
*
* @param array<string, mixed> $payload
*/
public function intimateClaim(array $payload)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$url = $this->adminBaseUrl() . '/trueclaim/policy-bazaar/intimate-claim';
return call_third_party_api($url, 'POST', $headers, $payload);
}
/**
* POST /trueclaim/tpa/getClaimData?claimId=
*/
public function getClaimData(string $claimId)
{
helper('api');
[$ok, $headers] = $this->authorizedJsonHeaders();
if (!$ok) {
return ['status' => false, 'message' => 'VOLO token failed'];
}
$query = http_build_query(['claimId' => $claimId]);
$url = $this->adminBaseUrl() . '/trueclaim/tpa/getClaimData?' . $query;
return call_third_party_api($url, 'POST', $headers, new \stdClass());
}
/**
* Pull enrollment from Volo (get-Enroll-dump), match members, update employee_polices.tpa_id (memberId).
* Same flow as MediAssistApiController::MediAssistGetBenefDetails.
*
* @param array<string, mixed> $requestData
* @return array<string, mixed>|\CodeIgniter\HTTP\Response
*/
public function VoloGetBenefDetails($requestData)
{
$function_calling_type = $requestData['return_type'] ?? 'job';
try {
helper(['api', 'utility']);
$policyNo = $requestData['policy_no'] ?? null;
$client_policy_id = $requestData['client_policy_id'] ?? null;
if (empty($policyNo)) {
log_message('error', 'VOLO - TPA ID Pull | policy_no missing in request');
if ($function_calling_type === 'job') {
return ['status' => false, 'message' => 'policy_no required'];
}
return $this->respond(['status' => false, 'message' => 'policy_no required']);
}
if (empty($client_policy_id)) {
log_message('error', 'VOLO - TPA ID Pull | client_policy_id missing in request');
if ($function_calling_type === 'job') {
return ['status' => false, 'message' => 'client_policy_id required'];
}
return $this->respond(['status' => false, 'message' => 'client_policy_id required']);
}
log_message('error', "VOLO - TPA ID Pull | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
$employeePolicyModel = new EmployeePolicyModel();
$employeePolicyData = $employeePolicyModel
->select('
employees.*,
employee_polices.id as emp_policy_id,
employee_polices.client_policy_id,
')
->join('employees', 'employees.id = employee_polices.employee_id')
->where('employee_polices.is_active', 1)
->where('employee_polices.status', 'active')
->where('employees.is_active', 1)
->where('employees.emp_status', 'active')
->where('employee_polices.tpa_id IS NULL')
->where('employee_polices.client_policy_id', $client_policy_id)
->findAll();
if (empty($employeePolicyData)) {
log_message('error', 'VOLO - TPA ID Pull FAILED | employeePolicyData is empty (tpa_id IS NULL from nhance) for this TPA ID Pull request');
if ($function_calling_type === 'job') {
return ['status' => false, 'message' => 'employeePolicyData not found'];
}
return $this->respond(['status' => false, 'message' => 'employeePolicyData not found']);
}
$response = $this->getEnrollmentDump((string) $policyNo);
if (empty($response['status'])) {
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
$file_model = new BatchFileModel();
$file_model->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
log_message('error', "VOLO - Files table status updated for the file id : {$requestData['file_id']}");
}
log_message('error', 'VOLO - TPA ID Pull API FAILED | ' . json_encode($response));
if ($function_calling_type === 'job') {
return ['status' => false, 'message' => 'API call failed', 'data' => $response];
}
return $this->respond(['status' => false, 'message' => 'API call failed', 'data' => $response]);
}
$apiPayload = $response['data'] ?? null;
if (!is_array($apiPayload)) {
log_message('error', 'VOLO - TPA ID Pull FAILED | invalid response shape | ' . json_encode($response));
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
(new BatchFileModel())->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
}
if ($function_calling_type === 'job') {
return ['status' => false, 'message' => 'Invalid API response'];
}
return $this->respond(['status' => false, 'message' => 'Invalid API response']);
}
$allRows = $this->extractVoloEnrollmentRows($apiPayload);
if ($allRows === []) {
log_message('error', 'VOLO - TPA ID Pull FAILED | enrollment body empty | ' . json_encode($apiPayload));
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
(new BatchFileModel())->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
}
if ($function_calling_type === 'job') {
return ['status' => false, 'message' => 'enrollment body empty'];
}
return $this->respond(['status' => false, 'message' => 'enrollment body empty']);
}
$totalCount = count($allRows);
log_message('error', "VOLO - TPA ID Pull | fetched {$totalCount} enrollment row(s)");
$json = json_encode($allRows, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$filePath = WRITEPATH . 'tmp/' . time() . '_' . ($requestData['file_id'] ?? '0') . '_volo.json';
file_put_contents($filePath, $json);
if (!empty($requestData['file_id'])) {
Jobs::addJob([
'job_name' => 'saveVoloAPIData',
'payload' => [
'file_id' => $requestData['file_id'],
'json_file_path' => $filePath,
],
]);
}
$batch_file_success = 'success';
$updated = 0;
$employee_policy_ids = [];
foreach ($employeePolicyData as $policy_data) {
$hasMatchForThisPolicy = false;
foreach ($allRows as $row) {
if (!is_array($row)) {
continue;
}
$voloEmpCode = trim((string) ($row['memberEmployeeNo'] ?? $row['memberAltEmployeeNo'] ?? $row['empId'] ?? ''));
$voloMemberId = trim((string) ($row['memberId'] ?? ''));
if ($voloMemberId === '') {
continue;
}
if (
strtolower(trim((string) ($policy_data['name'] ?? ''))) === strtolower(trim((string) ($row['memberName'] ?? '')))
&& (string) ($policy_data['emp_code'] ?? '') === $voloEmpCode
&& $this->voloRelationsMatch((string) ($policy_data['relationship'] ?? ''), (string) ($row['relation'] ?? ''))
&& $this->voloGendersMatch((string) ($policy_data['gender'] ?? ''), (string) ($row['gender'] ?? ''))
&& $this->voloDobsMatch((string) ($policy_data['dob'] ?? ''), $row['DOB'] ?? $row['dob'] ?? null)
) {
$hasMatchForThisPolicy = true;
$sql = 'UPDATE employee_polices SET tpa_id = ? WHERE id = ?';
$this->db->query($sql, [$voloMemberId, $policy_data['emp_policy_id']]);
if (strtolower(trim((string) ($policy_data['relationship'] ?? ''))) === 'self') {
$employee_policy_ids[] = $policy_data['emp_policy_id'];
}
if ($this->db->affectedRows() > 0) {
$updated++;
log_message('error', "VOLO - Updated tpa_id={$voloMemberId} for emp_code={$voloEmpCode} policy={$policyNo}");
} else {
log_message('error', "VOLO - No update (already set or not matched) for emp_code={$voloEmpCode} policy={$policyNo}");
}
}
}
if (!$hasMatchForThisPolicy) {
$nhanceSideData = [
'name' => $policy_data['name'] ?? null,
'emp_code' => $policy_data['emp_code'] ?? null,
'relationship' => $policy_data['relationship'] ?? null,
'gender' => $policy_data['gender'] ?? null,
'dob' => $policy_data['dob'] ?? null,
];
$batch_file_success = 'partially success';
log_message('error', 'VOLO - No match for Nhance = ' . json_encode($nhanceSideData));
}
}
if ($employee_policy_ids !== []) {
log_message('error', 'VOLO - sendMailForDownloadingECard JOB PUSHED.');
Jobs::addJob(['job_name' => 'sendMailForDownloadingECard', 'payload' => ['ids' => $employee_policy_ids, 'client_policy_id' => $client_policy_id]]);
}
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
$file_model = new BatchFileModel();
$file_model->where('id', $requestData['file_id'])->set('status', $batch_file_success)->update();
log_message('error', "VOLO - Files table status updated for the file id : {$requestData['file_id']}");
}
log_message('error', "VOLO - TPA ID Pull SUCCESS | Total fetched={$totalCount}, updated={$updated}");
if ($function_calling_type === 'job') {
return [
'status' => true,
'message' => 'Updated successfully',
'total_fetched' => $totalCount,
'total_updated' => $updated,
];
}
return $this->respond([
'status' => true,
'message' => 'Updated successfully',
'total_fetched' => $totalCount,
'total_updated' => $updated,
]);
} catch (\Throwable $th) {
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
$file_model = new BatchFileModel();
$file_model->where('id', $requestData['file_id'])->set('status', 'failed-8')->update();
log_message('error', "VOLO - Files table status updated for the file id : {$requestData['file_id']}");
}
$errorData = [
'message' => $th->getMessage(),
'file' => $th->getFile(),
'line' => $th->getLine(),
];
log_message('error', 'VOLO - Exception in VoloGetBenefDetails: ' . json_encode($errorData));
if ($function_calling_type === 'job') {
return ['status' => false, 'message' => 'API call failed', 'data' => $errorData];
}
return $this->respond(['status' => false, 'message' => 'API call failed', 'data' => $errorData]);
}
}
/**
* Persist raw Volo enrollment rows into tpa_api_data (same pattern as saveMediAssitAPIData).
*
* @param array<string, mixed> $array
*/
public function saveVoloAPIData($array)
{
$file_id = $array['file_id'];
$json = file_get_contents($array['json_file_path']);
$records = json_decode($json, true);
if (!is_array($records)) {
return;
}
$file_model = new BatchFileModel();
$file_info = $file_model->where('id', $file_id)->find();
$tpaApiDataModel = new TpaApiDataModel();
$tpaApiDataModel->set('is_active', 0)->where('file_id', $file_id)->update();
$mappedRows = [];
foreach ($records as $row) {
if (!is_array($row)) {
continue;
}
$dobRaw = $row['DOB'] ?? $row['dob'] ?? null;
$dobYmd = null;
if ($dobRaw !== null && $dobRaw !== '') {
$dobYmd = $this->normalizeVoloDobToYmd($dobRaw);
}
$rel = trim((string) ($row['relation'] ?? ''));
$mappedRows[] = [
'file_id' => $file_id,
'emp_code' => trim((string) ($row['memberEmployeeNo'] ?? $row['empId'] ?? '')),
'name' => trim((string) ($row['memberName'] ?? '')),
'dob' => $dobYmd,
'relation' => $rel,
'gender' => $this->voloGenderToMediStyle((string) ($row['gender'] ?? '')),
'self' => in_array(strtoupper($rel), ['EMPLOYEE', 'SELF'], true) ? 1 : 0,
'tpa_id' => trim((string) ($row['memberId'] ?? '')),
'age' => isset($row['age']) && is_numeric($row['age']) ? (int) $row['age'] : null,
'is_active' => 1,
'created_by' => $file_info[0]['created_by'] ?? null,
];
}
if ($mappedRows !== []) {
$tpaApiDataModel->insertBatchWithChunkLog($mappedRows, 500, 'FILE_ID_' . $file_id);
}
}
/**
* @param array<string, mixed> $apiData Decoded JSON root from Volo get-Enroll-dump
* @return list<array<string, mixed>>
*/
protected function extractVoloEnrollmentRows(array $apiData): array
{
$body = $apiData['body'] ?? null;
if (is_array($body)) {
$out = [];
foreach ($body as $item) {
if (is_array($item)) {
$out[] = $item;
}
}
return $out;
}
return [];
}
protected function voloRelationsMatch(string $nhanceRel, string $voloRel): bool
{
$n = strtolower(trim(str_replace('-', ' ', $nhanceRel)));
$v = strtoupper(trim(str_replace('-', ' ', $voloRel)));
if ($n === 'self' && in_array($v, ['EMPLOYEE', 'PRIMARY', 'INSURED'], true)) {
return true;
}
return strtolower($v) === $n || $n === strtolower($v);
}
protected function voloGendersMatch(string $nh, string $volo): bool
{
return $this->genderNorm($nh) === $this->genderNorm($volo);
}
protected function genderNorm(string $g): string
{
$g = strtolower(trim($g));
if ($g === '' || $g === 'm' || strpos($g, 'male') === 0) {
return 'm';
}
if ($g === 'f' || strpos($g, 'female') === 0) {
return 'f';
}
return $g;
}
protected function voloDobsMatch(string $nhanceDob, mixed $voloDob): bool
{
$v = $this->normalizeVoloDobToYmd($voloDob);
if ($v === null || $v === '') {
return false;
}
$tsN = strtotime($nhanceDob);
if ($tsN === false) {
return false;
}
$n = date('Y-m-d', $tsN);
return $n === $v;
}
protected function normalizeVoloDobToYmd(mixed $dob): ?string
{
if ($dob === null || $dob === '') {
return null;
}
if (is_numeric($dob) && (float) $dob > 1_000_000_000_000) {
return date('Y-m-d', (int) (((float) $dob) / 1000));
}
$ts = strtotime(str_replace('/', '-', (string) $dob));
return $ts ? date('Y-m-d', $ts) : null;
}
protected function voloGenderToMediStyle(string $g): string
{
return $this->genderNorm($g) === 'f' ? 'F' : 'M';
}
/**
* Resolve entity id for a policy number (uses get-entity-from-policy).
*/
protected function resolveEntityId(string $policyNo): ?string
{
$fallback = getenv('VOLO_DEFAULT_ENTITY_ID');
if (!empty($fallback)) {
return (string) $fallback;
}
$res = $this->getEntityFromPolicy($policyNo);
if (empty($res['status']) || !is_array($res['data'])) {
return null;
}
$body = $res['data']['body'] ?? null;
if ($body === null || $body === '') {
return null;
}
return (string) $body;
}
//-----------------------------------------------------------------------------------------------------------------------------
/**
* Push claim via intimate-claim (policy-bazaar) API.
*/
public function SubmitClaim($claimId = null)
{
helper('api');
$data = $this->db->table('ticket_master tm')
->select('
tm.id,
tm.doa as admissionDate,
tm.dod as dischargeDate,
tm.claim_amount as requestedAmount,
tm.tpa_no as memberId,
cp.policy_no as policyNo,
cf.url as filePath
')
->join('client_policy cp', 'tm.client_policy_id = cp.id', 'left')
->join('claim_files cf', "cf.ticket_id = tm.id AND cf.file_type = 2 AND cf.mime_type = 'application/pdf'", 'left')
->where('tm.id', $claimId)
->get()
->getRowArray();
if (!$data) {
log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | claim not found');
return ['status' => false, 'message' => 'Claim Push FAILED | Claim not found'];
}
if (empty($data['filePath'])) {
log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | file missing');
return ['status' => false, 'message' => 'Claim Push FAILED | File Missing'];
}
$filename = basename($data['filePath']);
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename;
if (!is_readable($pdfPath)) {
log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | PDF not readable');
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server'];
}
$publicUrl = base_url('fileDownload?file_path=') . $pdfPath;
$entityId = $this->resolveEntityId($data['policyNo'] ?? '');
if ($entityId === null) {
log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | entity id not resolved');
return ['status' => false, 'message' => 'Claim Push FAILED | entity id not resolved'];
}
$hospitalId = getenv('VOLO_DEFAULT_HOSPITAL_ID');
if ($hospitalId === false || $hospitalId === '') {
log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | VOLO_DEFAULT_HOSPITAL_ID not set');
return ['status' => false, 'message' => 'Claim Push FAILED | hospital id not configured'];
}
$doa = !empty($data['admissionDate']) ? date('Y-m-d', strtotime($data['admissionDate'])) : '';
$dod = !empty($data['dischargeDate']) ? date('Y-m-d', strtotime($data['dischargeDate'])) : $doa;
$payload = [
'hospitalId' => (string) $hospitalId,
'memberId' => (string) ($data['memberId'] ?? ''),
'dateOfAdmission' => $doa,
'dateOfDischarge' => $dod,
'potentialClaimAmount' => (float) ($data['requestedAmount'] ?? 0),
'claimDocuments' => [
[
'documentName' => $filename,
'documentType' => 'medical_report',
'extension' => 'pdf',
'url' => $publicUrl,
],
],
'entityId' => (string) $entityId,
'insurerPolicyNumber' => (string) ($data['policyNo'] ?? ''),
];
log_message('error', 'VOLO - Claim Push | claimId: ' . $claimId . ' | payload: ' . json_encode($payload));
$response = $this->intimateClaim($payload);
if (empty($response['status'])) {
log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | ' . json_encode($response));
$this->db->table('ticket_master')
->where('id', $claimId)
->update(['tpa_push_response' => json_encode($response)]);
return ['status' => false, 'message' => 'Claim Push FAILED', 'response' => $response];
}
$apiData = $response['data'] ?? null;
$ref = null;
if (is_array($apiData)) {
$ref = $apiData['message'] ?? null;
}
if (!empty($ref)) {
$this->db->table('ticket_master')
->where('id', $claimId)
->update([
'tpa_claim_push_reference_no' => $ref,
'tpa_claim_id' => $ref,
'updated_at' => date('Y-m-d H:i:s'),
]);
log_message('error', 'VOLO - Claim Push SUCCESS | claimId: ' . $claimId . ' | ref: ' . $ref);
return ['status' => true, 'message' => 'Claim Push SUCCESS', 'response' => $response];
}
log_message('error', 'VOLO - Claim Push empty reference | claimId: ' . $claimId . ' | ' . json_encode($response));
return ['status' => false, 'message' => 'Claim Push API response missing reference', 'response' => $response];
}
/**
* Refresh claim status from consumer claim-status service.
*/
public function ClaimDetail($claimId = null)
{
helper('api');
$ticket = $this->db->table('ticket_master tm')
->select('tm.id, tm.tpa_claim_push_reference_no, tm.tpa_claim_id')
->where('tm.id', $claimId)
->get()
->getRowArray();
if (!$ticket) {
return ['status' => false, 'message' => 'Invalid claim'];
}
$tpaClaimNo = $ticket['tpa_claim_push_reference_no'] ?? $ticket['tpa_claim_id'] ?? null;
if (empty($tpaClaimNo)) {
log_message('error', 'VOLO - Claim status | missing TPA claim ref | ticket: ' . $claimId);
return ['status' => false, 'message' => 'TPA claim reference missing'];
}
$response = $this->fetchExternalClaimStatus((string) $tpaClaimNo);
if (empty($response['status']) || !is_array($response['data'])) {
log_message('error', 'VOLO - Claim status FAILED | ticket: ' . $claimId . ' | ' . json_encode($response));
return ['status' => false, 'message' => 'API call failed', 'data' => $response];
}
$payload = $response['data'];
$body = $payload['body'] ?? $payload;
$currentStatus = '';
if (is_array($body)) {
$currentStatus = (string) ($body['status'] ?? $body['claim_status'] ?? '');
}
if ($currentStatus === '') {
log_message('error', 'VOLO - Claim status empty | ticket: ' . $claimId . ' | ' . json_encode($response));
return ['status' => false, 'message' => 'Status not found in response', 'data' => $response];
}
$validStatuses = [
'READY_TO_PAY' => 11,
'PAID' => 11,
'SETTLED' => 11,
'REJECTED' => 8,
'DENIED' => 8,
'QUERY' => 4,
'PRE_AUTH_QUERY_RESPONDED' => 4,
'PRE_AUTH_QUERY' => 4,
'MEMBER_UNENDORSED' => 5,
'In-Progress' => 5,
'UNDER_PROCESS' => 5,
'UNDER PROCESS' => 5,
];
$normalized = strtoupper(str_replace(' ', '_', trim($currentStatus)));
$claimStatusId = $validStatuses[$currentStatus] ?? ($validStatuses[$normalized] ?? 5);
$updateArray = [
'tpa_claim_status' => $currentStatus,
'updated_at' => date('Y-m-d H:i:s'),
'claim_status_id' => $claimStatusId,
];
$this->db->table('ticket_master')->where('id', $claimId)->update($updateArray);
log_message('error', 'VOLO - Claim status SUCCESS | ticket: ' . $claimId . ' | status: ' . $currentStatus);
return [
'status' => true,
'message' => 'Claim status updated.',
'updated_status' => $currentStatus,
'api_response' => $response,
];
}
public function ClaimStatusUpdate()
{
helper('api');
$tickets = $this->db->table('ticket_master tm')
->select('tm.id')
->join('client_policy cp', 'tm.client_policy_id = cp.id', 'left')
->where('tm.tpa_claim_push_reference_no IS NOT NULL')
->whereNotIn('tm.claim_status_id', [8, 11, 12, 13, 66, 22, 24, 47, 49, 32, 34, 53, 55, 42, 44, 58, 60])
->where('tm.is_active', 1)
->where('cp.tpa_id', $this->voloTpaId)
->get()
->getResultArray();
$count = 0;
foreach ($tickets as $t) {
$this->ClaimDetail($t['id']);
$count++;
}
return $this->response->setJSON(['status' => true, 'updated' => $count]);
}
/**
* E-card PDF returns a data URL the app can open, or null on failure.
*
* @param string|null $voloEmployeeId Volo/TPA employee or member id stored in employee_polices.tpa_id
*/
public function EcardRequest($emp_code = null, $policy_no = null, $voloEmployeeId = null)
{
if (empty($voloEmployeeId)) {
log_message('error', 'VOLO - Ecard | missing Volo employee/member id | emp_code: ' . ($emp_code ?? ''));
return null;
}
$entityId = $this->resolveEntityId((string) $policy_no);
if ($entityId === null) {
log_message('error', 'VOLO - Ecard | entity id not resolved | policy: ' . ($policy_no ?? ''));
return null;
}
$res = $this->getEcardPdfRequest((string) $voloEmployeeId, $entityId);
if (empty($res['status']) || !is_array($res['data'])) {
log_message('error', 'VOLO - Ecard FAILED | ' . json_encode($res));
return null;
}
$body = $res['data']['body'] ?? null;
if (!is_string($body) || $body === '') {
log_message('error', 'VOLO - Ecard FAILED | empty body | ' . json_encode($res));
return null;
}
return 'data:application/pdf;base64,' . $body;
}
}

View File

@ -18,14 +18,21 @@ class BatchFileModel extends Model
'event_type',
'actions',
'count',
"created_by",
"updated_by",
"is_active",
"amount",
"status",
"error_data",
"client_branch_id",
"policy_issue_date",
'created_by',
'updated_by',
'is_active',
'amount',
'status',
'error_data',
'client_branch_id',
'policy_issue_date',
// ICICI Lombard GPA batch fields
'icici_correlation_id',
'icici_batch_id',
'icici_status_flag',
'icici_status_message',
'icici_endorsement_policy_no',
'icici_uhid_status_flag',
];
// Callbacks

View File

@ -0,0 +1,76 @@
<?php
namespace Tests\unit;
use App\Controllers\ICICILombardController;
use CodeIgniter\Test\CIUnitTestCase;
class ICICILombardControllerTest extends CIUnitTestCase
{
public function testFormatPolicyDataBuildsExpectedBatchPayload(): void
{
$controller = new ICICILombardController();
// Sample rows matching createEnrollmentBatch query output shape.
$input = [
[
'policyNumber' => '4016/PPN/A/O/53185987/00/000',
'CDBGAccountNumber' => 'CD-MUM-0026',
'MemberEmpId' => 'EMPID3625567',
'DOJ' => '2019-03-21',
'InsuredName' => 'sanjeev',
'DOB' => '1993-07-07',
'Relationship' => 'SELF',
'Gender' => 'male',
'DOC' => '25-Jan-2026',
'SumInsured' => '500000',
'EmailId' => 'sanjeev@GMAIL.COM',
],
[
'policyNumber' => '4016/PPN/A/O/53185987/00/000',
'CDBGAccountNumber' => 'CD-MUM-0026',
'MemberEmpId' => 'EMPID3625567',
'DOJ' => '2019-03-21',
'InsuredName' => 'bhavya',
'DOB' => '1970-08-08',
'Relationship' => 'MOTHER',
'Gender' => 'female',
'DOC' => '25-Jan-2026',
'SumInsured' => null,
'EmailId' => 'bhavya@GMAIL.COM',
],
];
$result = $controller->formatPolicyData($input);
$this->assertIsArray($result);
$this->assertSame('4016/PPN/A/O/53185987/00/000', $result['PolicyNumber']);
$this->assertSame('CD-MUM-0026', $result['CDBGAccountNumber']);
$this->assertMatchesRegularExpression(
'/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i',
$result['CorrelationId']
);
$this->assertCount(2, $result['MemberDetails']);
$first = $result['MemberDetails'][0];
$this->assertSame('EMPID3625567', $first['EmployeeMemberId']);
$this->assertSame('21-MAR-2019', $first['DOJ']);
$this->assertSame('sanjeev', $first['InsuredName']);
$this->assertSame('7-JUL-1993', $first['DOB']);
$this->assertSame('SELF', $first['Relationship']);
$this->assertSame('MALE', $first['Gender']);
$this->assertSame('25-JAN-2026', $first['DOC']);
$this->assertSame('500000', $first['SumInsured']);
$this->assertSame('sanjeev@GMAIL.COM', $first['EmailId']);
$this->assertSame('A', $first['FlagStatus']);
$second = $result['MemberDetails'][1];
$this->assertSame('bhavya', $second['InsuredName']);
$this->assertSame('8-AUG-1970', $second['DOB']);
$this->assertSame('MOTHER', $second['Relationship']);
$this->assertSame('FEMALE', $second['Gender']);
$this->assertSame('25-JAN-2026', $second['DOC']);
$this->assertNull($second['SumInsured']);
}
}