diff --git a/.env.sample b/.env.sample index 709200e2..cc9a927c 100755 --- a/.env.sample +++ b/.env.sample @@ -132,6 +132,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 = diff --git a/GPA_Endorsement_Batch_v2.0 APIGEE.pdf b/GPA_Endorsement_Batch_v2.0 APIGEE.pdf new file mode 100644 index 00000000..feeac8b5 Binary files /dev/null and b/GPA_Endorsement_Batch_v2.0 APIGEE.pdf differ diff --git a/app/Config/Acl.php b/app/Config/Acl.php index cb6547a0..c1a1e56a 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -24,6 +24,7 @@ class Acl '#^/downloadFileTableFile#' => ['public' => true], '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]], '#^/getEmployeeActiveOrInactivePolicy#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], + '#^/test/chartbrewDashboardDemo#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/bulkEcardDownloadAsZip#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/sheet#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/sendextraparam#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], diff --git a/app/Config/Constants.php b/app/Config/Constants.php index d47699d8..9078b11c 100755 --- a/app/Config/Constants.php +++ b/app/Config/Constants.php @@ -131,3 +131,4 @@ define('UPLOAD_EXT_POLICY_DOCS', ['pdf', 'jpg', 'jpeg', 'png', 'xls', 'xlsx']); define('UPLOAD_EXT_LEAD_FILES', ['xls', 'xlsx', 'pdf', 'jpg', 'jpeg', 'png']); define('UPLOAD_EXT_EXCEL', ['xls', 'xlsx', 'ods', 'csv']); define('UPLOAD_EXT_MAIL_ATTACHMENTS', ['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx', 'xls', 'xlsx']); +define('UPLOAD_EXT_NON_EB_RACK_RATE', ['pdf', 'xls', 'xlsx']); diff --git a/app/Config/Routes.php b/app/Config/Routes.php index d45acf8a..9bad6caa 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -171,6 +171,9 @@ $routes->group("/client", ["filter" => "authMVC"], function ($routes) { $routes->post("policyGMCTerms", "ClientController::policyGMCTerms"); $routes->get("getterms", "ClientController::getterms"); $routes->get("remove/(:any)", "ClientController::removePolicy/$1"); + $routes->get("getNonEbRackRateFiles", "ClientController::getNonEbRackRateFiles"); + $routes->post("uploadNonEbRackRateFile", "ClientController::uploadNonEbRackRateFile"); + $routes->post("removeNonEbRackRateFile", "ClientController::removeNonEbRackRateFile"); }); $routes->group("kyc", ["filter" => "authMVC"], function ($routes) { @@ -574,6 +577,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'); @@ -886,6 +890,7 @@ $routes->group('test', function($routes) { $routes->get('logo_renaming','TestingController::logo_renaming'); $routes->get('testingquerys','TestingController::testingquerys'); $routes->get('thzReminderCrone','ThzController::getOpenTicketsOlderThan24HoursAndAssignNextLevel'); + $routes->get('chartbrewDashboardDemo','TestingController::chartbrewDashboardDemo'); // $routes->get('createDefaultMailTempalteInDB','TestingController::createDefaultMailTempalteInCrossDB'); // $routes->get('createDefaultMailTempalteInSameDB','TestingController::createDefaultMailTempalteInSameDB'); }); diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php index f4782afb..013aea7a 100644 --- a/app/Controllers/ApiServiceController.php +++ b/app/Controllers/ApiServiceController.php @@ -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"){ @@ -232,7 +245,13 @@ class ApiServiceController extends BaseController $policy_id = $this->request->getPost('client_policy_id') ?? null; $fileModel = new BatchFileModel(); - $filesData = $fileModel->where('is_active', 1)->where('event_type', 'api')->where('status', 'inprogress')->countAllResults(); + $filesData = $fileModel + ->join('client_policy', 'client_policy.id = batch_files.client_policy_id') + ->where('client_policy.tpa_id', $tpa_id) + ->where('batch_files.is_active', 1) + ->where('batch_files.event_type', 'api') + ->where('batch_files.status', 'inprogress') + ->countAllResults(); if($filesData > 0){ log_message('error', "TPA GetBenefDetails job is already in process."); @@ -322,6 +341,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 +392,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"; diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index df96dde0..2d124c53 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -964,6 +964,8 @@ class ClientController extends AdminController 'tpa_branch_code' => $item->tpa_branch_code, 'branch_name' => $item->branch_name ?? ' - ', 'policy_type_id' => $item->policy_type_id, + 'allocg' => $item->allocg, + 'lead_misc' => $item->lead_misc, ]; }, $rawList)) : []; $editData['client_policy']['role'] = get_role_id(); @@ -3113,6 +3115,89 @@ class ClientController extends AdminController } } + public function getNonEbRackRateFiles() + { + $clientPolicyId = $this->request->getGet('client_policy_id'); + $policy = $this->clientPolicyModel->where('id', $clientPolicyId)->first(); + + if (!$policy) { + return $this->respond(['status' => false, 'message' => 'Policy not found'], 200); + } + + $files = []; + $jsonField = is_array($policy) ? ($policy['non_eb_rack_rate_files'] ?? null) : ($policy->non_eb_rack_rate_files ?? null); + + if (!empty($jsonField)) { + $files = json_decode($jsonField, true) ?? []; + } + + return $this->respond(['status' => true, 'files' => $files], 200); + } + + public function uploadNonEbRackRateFile() + { + $clientPolicyId = $this->request->getPost('client_policy_id'); + $policy = $this->clientPolicyModel->where('id', $clientPolicyId)->first(); + + if (!$policy) { + return $this->respond(['status' => false, 'message' => 'Policy not found'], 200); + } + + $uploadFilePath = WRITEPATH . 'uploads/non_eb_rack_rate'; + $fileName = file_Upload($this->request->getFile('file'), $uploadFilePath, UPLOAD_EXT_NON_EB_RACK_RATE); + + if (empty($fileName)) { + return $this->respond(['status' => false, 'message' => 'Invalid file. Only PDF and Excel files are allowed.'], 200); + } + + $originalName = $this->request->getFile('file')->getClientName(); + $ext = pathinfo($fileName, PATHINFO_EXTENSION); + + $jsonField = is_array($policy) ? ($policy['non_eb_rack_rate_files'] ?? null) : ($policy->non_eb_rack_rate_files ?? null); + $files = !empty($jsonField) ? (json_decode($jsonField, true) ?? []) : []; + + $fileEntry = [ + 'name' => $fileName, + 'original_name' => $originalName, + 'type' => $ext, + 'uploaded_at' => date('Y-m-d H:i:s'), + ]; + + $files[] = $fileEntry; + + $this->clientPolicyModel->where('id', $clientPolicyId)->set(['non_eb_rack_rate_files' => json_encode($files)])->update(); + + return $this->respond(['status' => true, 'file' => $fileEntry], 200); + } + + public function removeNonEbRackRateFile() + { + $clientPolicyId = $this->request->getPost('client_policy_id'); + $filename = $this->request->getPost('filename'); + $policy = $this->clientPolicyModel->where('id', $clientPolicyId)->first(); + + if (!$policy) { + return $this->respond(['status' => false, 'message' => 'Policy not found'], 200); + } + + $jsonField = is_array($policy) ? ($policy['non_eb_rack_rate_files'] ?? null) : ($policy->non_eb_rack_rate_files ?? null); + $files = !empty($jsonField) ? (json_decode($jsonField, true) ?? []) : []; + + $files = array_values(array_filter($files, function ($file) use ($filename) { + return $file['name'] !== $filename; + })); + + $this->clientPolicyModel->where('id', $clientPolicyId)->set(['non_eb_rack_rate_files' => json_encode($files)])->update(); + + // Delete physical file + $filePath = WRITEPATH . 'uploads/non_eb_rack_rate/' . $filename; + if (file_exists($filePath)) { + unlink($filePath); + } + + return $this->respond(['status' => true], 200); + } + public function deactivatePolicyTransactionsPolicy($clientPolicyId) { // Deactivate policy_transaction records @@ -6380,12 +6465,13 @@ class ClientController extends AdminController $client_type = $this->request->getGet('client_type') ?? null; // Check in Policy Transaction (BDS) - $bds_count = $this->policyTransactionModel + $bds_data = $this->policyTransactionModel ->where('is_active', 1) ->where('action_type', 'inception') ->where('TRIM(policy_no)', $policy_no) ->where('policy_no IS NOT NULL AND policy_no <> ""') - ->countAllResults(); + ->orderBy('id', 'desc') + ->first() ?? []; // Check in Enrollment (client_policy) $client_policy_data = $this->clientPolicyModel @@ -6395,14 +6481,15 @@ class ClientController extends AdminController ->first(); // Decide message + count - if ($bds_count > 0) { + if (count($bds_data) > 0) { return $this->respond([ 'status' => true, 'message' => "This policy number is already linked to another policy in the BDS", 'code' => 409, - 'data' => $bds_count, + 'data' => $bds_data['id'], 'received_data' => $received_data, + 'pt_id' => $bds_data['id'], 'client_policy_id' => $client_policy_data['id'] ?? null ], 200); @@ -6421,8 +6508,9 @@ class ClientController extends AdminController return $this->respond([ 'status' => false, - 'message' => 'No Data Found', + 'message' => 'Policy number not found in BDS or Enrollment, so proceed to add a new policy.', 'code' => 404, + 'is_dublicate' => false, 'received_data' => $received_data, 'client_policy_id' => null ], 200); diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 40bbb7f9..6c5afb5c 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -2272,8 +2272,10 @@ class EmployeeRestController extends AdminController where is_active = 1 and status = $emp_policy_status and client_policy_id = client_policy.id - ) as total_premium + ) as total_premium, + CASE WHEN policy_type.allocg IN ('Non-EB', 'Marine') THEN 'Non-EB' ELSE 'EB' END as allocg ", false) + ->join('policy_type', 'policy_type.id = client_policy.policy_type_id', 'left') ->where('md5(client_policy.client_id)', $this->request->getGet('client_id')) ->where('client_policy.client_branch_id', $this->request->getGet('client_branch_id')) ->where('client_policy.is_active', 1) @@ -4520,6 +4522,29 @@ class EmployeeRestController extends AdminController ]; // print_r($post_data); die; + + $ClientPolicyData = $this->clientPolicyModel + ->select(" + client_policy.id as client_policy_id , + client_policy.client_id as client_id, + client_policy.policy_type_id as policy_type_id, + client_policy.is_addon as is_addon , + client_policy.open_for_enrollment as OpenForEnrollment , + client_policy.inception_type as inception_type, + client_policy.policy_no as policy_no, + client_policy.insurer_id as insurer_id, + DATE_FORMAT(client_policy.policy_start_date, '%d-%m-%Y') AS policy_start_date, + DATE_FORMAT(client_policy.policy_end_date, '%d-%m-%Y') AS policy_expiry_date, + CASE WHEN policy_type.allocg IN ('Non-EB', 'Marine') THEN 'Non-EB' ELSE 'EB' END as allocg + ", false) + ->join('policy_type', 'policy_type.id = client_policy.policy_type_id', 'left') + ->where('md5(client_policy.client_id)', $post_data['client_id']) + ->where('client_policy.client_branch_id', $post_data['client_branch_id']) + ->where('client_policy.is_active', 1) + // ->where('client_policy.policy_status', $this->request->getGet('policy_status')) + ->whereIn('client_policy.id', $post_data['policy_id']) + ->first(); + if (empty($post_data['client_id'])) { return $this->respondCreated(['status' => false, 'message' => 'Client is required', 'data' => []]); } @@ -4538,7 +4563,7 @@ class EmployeeRestController extends AdminController // print_r($client_data); die; - if ($client_data['hr_file_processed_by'] == 1) { + if ($client_data['hr_file_processed_by'] == 1 && $ClientPolicyData['allocg'] == 'EB') { $responce = $this->fileUploadInFilesTable($post_data); } else { $responce = $this->fileUploadInHrFileUploadTable($post_data); diff --git a/app/Controllers/FhplApiController.php b/app/Controllers/FhplApiController.php index 643a2f95..f43430f4 100644 --- a/app/Controllers/FhplApiController.php +++ b/app/Controllers/FhplApiController.php @@ -59,6 +59,8 @@ class FhplApiController extends BaseController curl_close($ch); + // dd($response); + return [ 'status' => $httpCode === 200, 'http_code' => $httpCode, @@ -112,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']; @@ -207,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']; @@ -306,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; @@ -409,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"){ @@ -719,7 +721,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'])) { return ['status' => false,'message' => 'FHPL Token generation failed']; @@ -797,7 +799,7 @@ 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 ['status' => false,'message' => 'FHPL Token generation failed']; @@ -829,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)); + } } } diff --git a/app/Controllers/HealthIndiaApiController.php b/app/Controllers/HealthIndiaApiController.php index 52705e77..01e86c12 100644 --- a/app/Controllers/HealthIndiaApiController.php +++ b/app/Controllers/HealthIndiaApiController.php @@ -141,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; @@ -258,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'); @@ -378,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; @@ -483,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") { @@ -729,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'); @@ -827,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'); diff --git a/app/Controllers/ICICILombardController.php b/app/Controllers/ICICILombardController.php index 717f8a05..5b1ed258 100644 --- a/app/Controllers/ICICILombardController.php +++ b/app/Controllers/ICICILombardController.php @@ -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 ]; diff --git a/app/Controllers/JobWorker.php b/app/Controllers/JobWorker.php index 5840ac3f..6455806a 100755 --- a/app/Controllers/JobWorker.php +++ b/app/Controllers/JobWorker.php @@ -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', diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index 7bce36eb..18acb569 100644 --- a/app/Controllers/PolicyTransactionController.php +++ b/app/Controllers/PolicyTransactionController.php @@ -549,6 +549,8 @@ class PolicyTransactionController extends BaseController public function viewInception() { $bds_edit_pt_id = $this->request->getGet('pt_id') ?? null; + $view = $this->request->getGet('view') ?? null; + $data['tab_name'] = 'Policies'; $data['page_name'] = 'Policies'; @@ -618,7 +620,7 @@ class PolicyTransactionController extends BaseController $issuer = empty($issuer) ? 0 : $issuer; $status = empty($status) ? 0 : $status; // Corrected from `$issuer` - if(empty($bds_edit_pt_id)){ + if(empty($bds_edit_pt_id) && empty($view)){ if ($this->request->is('get')) { // Fetch inception data list diff --git a/app/Controllers/TestingController.php b/app/Controllers/TestingController.php index 917af897..51e71485 100644 --- a/app/Controllers/TestingController.php +++ b/app/Controllers/TestingController.php @@ -1322,7 +1322,7 @@ class TestingController extends BaseController * If env values are not present, sensible dummy defaults are used so that * the function can still be exercised. */ - public function testMediAssistWellness() + public function testMediAssistWellnessOld() { // Configuration – prefer environment variables, fall back to demo values @@ -1374,4 +1374,169 @@ class TestingController extends BaseController ], ], 200); } + + public function chartbrewDashboardDemo() + { + // 1. Configuration - Use a Chartbrew-specific Secret Key from .env + $chartbrew_base_url = "https://analytics.nhanceindia.in/report/my-first-dashboard-oHbWNWH0"; + $chartbrew_secret = getenv('METABASE_SECRET_KEY'); // Ensure this is set in your .env + + // 2. Get dynamic parameters (matching your screenshot's naming convention) + $policy_id = $this->request->getGet('client_policy_id') ?? 4687; + + // 3. Define the Payload + // Note: 'sub' (Subject) should usually be the user ID or a unique identifier + // depending on Chartbrew's specific JWT requirements. + $payload = [ + "sub" => [ + "type" => "Project", + "id" => 4, // Integer type usually preferred + "sharePolicyId" => 4 + ], + "iat" => time(), + "exp" => time() + (10 * 60), // 10 minute expiration + ]; + + // 4. Encode the JWT + // Make sure you have 'use Firebase\JWT\JWT;' at the top of your controller + $token = JWT::encode($payload, $chartbrew_secret, 'HS256'); + + // 5. Construct the URL + // We use http_build_query to ensure special characters are handled correctly + $params = [ + 'token' => $token, + 'theme' => 'light', + 'client_policy_id' => $policy_id + ]; + + $url = $chartbrew_base_url . '?' . http_build_query($params); + + // 6. Optional API response + if ($this->request->getGet('api') == 1) { + return $this->response->setJSON([ + 'status' => 'success', + 'data' => [ + 'chartbrewUrl' => $url, + 'policy_id' => $policy_id + ] + ]); + } + + // 7. Return the View + return view('chartbrew_dashboard_view', [ + 'iframe_url' => $url, + 'policy_id' => $policy_id + ]); + } + + public function testMediAssistWellness() + { + // Config + $keyString = env('MEDIASSIST_WELLNESS_KEY'); + $ivString = env('MEDIASSIST_WELLNESS_IV'); + $loginUrlTemplate = env('MEDIASSIST_WELLNESS_LOGIN_URL'); + $partnerCorpId = '15963'; + + $cipher_algorithm = 'AES-256-CBC'; + + // Payload (MATCH EXACT CASE from doc) + $payload = [ + 'Id' => '15022', + 'expiryTime' => (string)(time() + 600), // string format safer + 'CPartnerId' => $partnerCorpId, + ]; + + $plainJson = json_encode($payload, JSON_UNESCAPED_SLASHES); + + // ✅ IMPORTANT: Ensure correct key + IV length (ASCII based) + $key = substr(str_pad($keyString, 32, '0'), 0, 32); // 32 bytes + $iv = substr(str_pad($ivString, 16, '0'), 0, 16); // 16 bytes + + // Encrypt + $cipherTextRaw = openssl_encrypt( + $plainJson, + $cipher_algorithm, + $key, + OPENSSL_RAW_DATA, + $iv + ); + + if ($cipherTextRaw === false) { + return $this->respond([ + 'status' => false, + 'message' => 'Encryption failed.', + ], 500); + } + + // ✅ Use ONLY Base64 (NO urlencode unless explicitly required) + $encryptedSSO = base64_encode($cipherTextRaw); + + // Build URL + $loginUrl = str_replace( + ['{0}', '{1}'], + [$partnerCorpId, $encryptedSSO], + $loginUrlTemplate + ); + + return $this->respond([ + 'status' => true, + 'data' => [ + 'loginUrl' => $loginUrl, + 'encryptedSSO' => $encryptedSSO, + 'plainPayload' => $payload, + 'decryptMediAssistWellness' => $this->decryptMediAssistWellness($encryptedSSO), + ], + ], 200); + } + + public function decryptMediAssistWellness($encryptedSSO) + { + // Config + $keyString = env('MEDIASSIST_WELLNESS_KEY'); + $ivString = env('MEDIASSIST_WELLNESS_IV'); + + $cipher_algorithm = 'AES-256-CBC'; + + // Ensure same key + IV format used in encryption + $key = substr(str_pad($keyString, 32, '0'), 0, 32); // 32 bytes + $iv = substr(str_pad($ivString, 16, '0'), 0, 16); // 16 bytes + + // Decode Base64 + $cipherTextRaw = base64_decode($encryptedSSO, true); + + + if ($cipherTextRaw === false) { + return [ + 'status' => false, + 'message' => 'Invalid Base64 string.', + ]; + } + + // Decrypt + $decrypted = openssl_decrypt( + $cipherTextRaw, + $cipher_algorithm, + $key, + OPENSSL_RAW_DATA, + $iv + ); + + if ($decrypted === false) { + return [ + 'status' => false, + 'message' => 'Decryption failed.', + ]; + } + + // Convert JSON to array + $data = json_decode($decrypted, true); + + return [ + 'status' => true, + 'data' => [ + 'decryptedRaw' => $decrypted, + 'decoded' => $data + ], + ]; + } } diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index 2d99b088..f157d697 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -574,7 +574,9 @@ class TicketController extends BaseController ->join("({$subquery->getCompiledSelect()}) tat_category", 'tm.id = tat_category.ticket_id', 'left') ->where('tm.is_active', 1) ->whereNotIn('claim_status_id', [11, 12, 13, 22, 24, 32, 34, 42, 44, 47, 53, 58, 65]) - ->orderBy('tm.id', 'DESC'); + ->orderBy('tm.id', 'DESC') + ->limit(100); + $data = $query->get()->getResultArray(); diff --git a/app/Controllers/VidalApiController.php b/app/Controllers/VidalApiController.php index 92249118..c689b5df 100644 --- a/app/Controllers/VidalApiController.php +++ b/app/Controllers/VidalApiController.php @@ -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)); @@ -1065,8 +1067,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 + ]; + } + - } diff --git a/app/Controllers/VoloApiController.php b/app/Controllers/VoloApiController.php new file mode 100644 index 00000000..16d5f65b --- /dev/null +++ b/app/Controllers/VoloApiController.php @@ -0,0 +1,924 @@ +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} + */ + 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 $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 + */ + 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 $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 $requestData + * @return array|\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 $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 $apiData Decoded JSON root from Volo get-Enroll-dump + * @return list> + */ + 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; + } +} diff --git a/app/Models/BatchFileModel.php b/app/Models/BatchFileModel.php index e791553a..7b32877b 100755 --- a/app/Models/BatchFileModel.php +++ b/app/Models/BatchFileModel.php @@ -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 diff --git a/app/Models/ClientPolicyModel.php b/app/Models/ClientPolicyModel.php index 762e8c40..c3acb681 100755 --- a/app/Models/ClientPolicyModel.php +++ b/app/Models/ClientPolicyModel.php @@ -59,6 +59,7 @@ class ClientPolicyModel extends Model "is_from_lead", "wellness_plan_id", "wellness_vendor_id", + "non_eb_rack_rate_files", ]; // Callbacks @@ -135,6 +136,8 @@ class ClientPolicyModel extends Model ->select('tpa_branch.branch_name as tpa_branch_name, tpa_branch.branch_code as tpa_branch_code') ->select('policy_type.policy_type as policy_type_name') ->select('client_branch.branch_name as branch_name') + ->select('policy_type.allocg as allocg') + ->select('leads.misc as lead_misc') ->join('insurers', 'insurers.id = client_policy.insurer_id') ->join('insurer_branch', 'client_policy.insurer_branch_id = insurer_branch.id') ->join('tpa', 'tpa.id = client_policy.tpa_id', 'left') diff --git a/app/Models/PolicyTransactionModel.php b/app/Models/PolicyTransactionModel.php index 514b63d2..940aeb41 100644 --- a/app/Models/PolicyTransactionModel.php +++ b/app/Models/PolicyTransactionModel.php @@ -1112,7 +1112,7 @@ // Default to Last 30 Days if No Filters Are Applied if (empty($client_id) && empty($insurer_id) && empty($policy_type_id) && empty($date_type) && empty($issuer) && empty($where)) { - $fromDate = date('Y-m-d', strtotime('-90 days')); + $fromDate = date('Y-m-d', strtotime('-30 days')); $toDate = date('Y-m-d 23:59:59'); $builder->where('policy_transaction.created_at >=', $fromDate) diff --git a/app/Views/chartbrew_dashboard_view.php b/app/Views/chartbrew_dashboard_view.php new file mode 100644 index 00000000..afb3d55d --- /dev/null +++ b/app/Views/chartbrew_dashboard_view.php @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/Views/client_onboarding.php b/app/Views/client_onboarding.php index 3b00d236..96697d78 100755 --- a/app/Views/client_onboarding.php +++ b/app/Views/client_onboarding.php @@ -454,6 +454,40 @@ + + +