diff --git a/app/Config/Acl.php b/app/Config/Acl.php
index 9e04a90a..80f7a2bd 100644
--- a/app/Config/Acl.php
+++ b/app/Config/Acl.php
@@ -17,7 +17,10 @@ class Acl
'#^/getVerifiedPosUserData#' => ['public' => true],
'#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]],
'#^/getEmployeeActiveOrInactivePolicy#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
+ '#^/sheet#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
+ '#^/sendextraparam#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
'#^/test/testingquerys#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
+ '#^/test/viewrfq#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
'#^/fedeploy#' => ['roles' => [ADMIN_ROLE_ID]],
'#^/visitOffBoardCheck#' => ['roles' => [ADMIN_ROLE_ID]],
'#^/logs#' => ['roles' => [ADMIN_ROLE_ID]],
diff --git a/app/Config/Filters.php b/app/Config/Filters.php
index c9431b94..6c031ae7 100755
--- a/app/Config/Filters.php
+++ b/app/Config/Filters.php
@@ -20,6 +20,8 @@ use App\Filters\SecurityInputFilter;
use App\Filters\GlobalPostFileUploadGuard;
use App\Filters\AclFilter;
use App\Filters\RateLimitFilter;
+use App\Filters\JwtApiRateLimitFilter;
+use App\Filters\AuthApiRateLimitFilter;
use App\Filters\AuthJWT;
@@ -51,6 +53,8 @@ class Filters extends BaseConfig
'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class,
'AclFilter' => AclFilter::class,
'ratelimit' => RateLimitFilter::class,
+ 'AuthApiRateLimitFilter' => AuthApiRateLimitFilter::class,
+ 'JwtApiRateLimitFilter' => JwtApiRateLimitFilter::class,
];
diff --git a/app/Config/RateLimiter.php b/app/Config/RateLimiter.php
new file mode 100644
index 00000000..99d8b60a
--- /dev/null
+++ b/app/Config/RateLimiter.php
@@ -0,0 +1,89 @@
+ 60, // max requests
+ 'window' => 60, // window in seconds
+ 'violation_soft' => 3, // violations before soft block
+ ];
+
+ /*
+ |--------------------------------------------------------------------------
+ | Auth API Routes (verifyMobile, verifyOTP, etc.)
+ |--------------------------------------------------------------------------
+ */
+ public array $authApi = [
+ 'limit' => 10, // max requests per window
+ 'window' => 180, // window in seconds (3 min)
+ 'violation_soft' => 3, // failed attempts before soft block
+ ];
+
+ /*
+ |--------------------------------------------------------------------------
+ | User-Level Progressive Block Durations (seconds)
+ | 0 = permanent until manual unblock
+ |--------------------------------------------------------------------------
+ */
+ public array $userBlock = [
+ 'soft_duration' => 0, // permanent, manual unblock only
+ 'medium_duration' => 7200, // 2 hours
+ 'hard_duration' => 86400, // 24 hours
+ // attempts while at a block level before escalating to next
+ 'medium_trigger' => 1, // attempts during soft → medium
+ 'hard_trigger' => 1, // attempts during medium → hard
+ ];
+
+ /*
+ |--------------------------------------------------------------------------
+ | IP-Level Throttle & Progressive Block (independent of user)
+ |--------------------------------------------------------------------------
+ */
+ public array $ipBlock = [
+ 'limit' => 120, // max requests per window
+ 'window' => 60, // window in seconds
+ 'violation_soft' => 5, // violations before soft block
+ 'soft_duration' => 0, // permanent, manual unblock only
+ 'medium_duration' => 7200, // 2 hours
+ 'hard_duration' => 86400, // 24 hours
+ 'medium_trigger' => 1, // attempts during soft → medium
+ 'hard_trigger' => 1, // attempts during medium → hard
+ ];
+
+ /*
+ |--------------------------------------------------------------------------
+ | Cache Key Prefixes
+ |--------------------------------------------------------------------------
+ */
+ public array $cacheKeys = [
+ 'ip_count' => 'rl_ip_count_',
+ 'ip_violations' => 'rl_ip_viol_',
+ 'ip_block' => 'rl_ip_block_',
+ 'ip_block_hits' => 'rl_ip_blkhit_',
+ 'user_count' => 'rl_usr_count_',
+ 'user_violations' => 'rl_usr_viol_',
+ 'user_block' => 'rl_usr_block_',
+ 'user_block_hits' => 'rl_usr_blkhit_',
+ ];
+
+ /*
+ |--------------------------------------------------------------------------
+ | HTTP Status Codes per block level
+ |--------------------------------------------------------------------------
+ */
+ public array $statusCodes = [
+ 'throttle' => 429,
+ 'soft' => 429,
+ 'medium' => 403,
+ 'hard' => 451,
+ ];
+}
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 0645578c..efde3147 100755
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -10,6 +10,15 @@ $routes->options('(:any)', function() {
// But having this route ensures OPTIONS isn't rejected as 404
});
+$routes->group('sheet', function ($routes) {
+ $routes->get('(:any)', 'GoogleSheetController::editor/$1');
+ $routes->get('(:any)/fetch', 'GoogleSheetController::fetch/$1');
+ $routes->post('(:any)/save', 'GoogleSheetController::save/$1');
+ $routes->get('(:any)/download', 'GoogleSheetController::download/$1');
+});
+
+
+
/**
* @var RouteCollection $routes
*/
@@ -787,8 +796,8 @@ $routes->get('FhplGetBenefDetails','FhplApiController::FhplGetBenefDetails');
$routes->get('EcardRequest','HealthIndiaApiController::EcardRequest');
$routes->get('HospitalNetwork','MediAssistApiController::HospitalNetwork');
$routes->get('VidalGetBenefDetails','VidalApiController::VidalGetBenefDetails');
-$routes->get('ClaimDetail','HealthIndiaApiController::ClaimDetail');
-$routes->get('SubmitClaim','HealthIndiaApiController::SubmitClaim');
+$routes->get('ClaimDetail','VidalApiController::ClaimDetail');
+$routes->get('SubmitClaim','VidalApiController::SubmitClaim');
$routes->get('IntimateClaim','MediAssistApiController::IntimateClaim');
$routes->get('IRSubmission','MediAssistApiController::IRSubmission');
$routes->get('ClaimStatusUpdate','MediAssistApiController::ClaimStatusUpdate');
@@ -896,6 +905,8 @@ $routes->group('logs', function($routes) {
$routes->group('sales', function($routes) {
// ==================== LEAD ROUTES ====================
+
+ $routes->get('/', 'SalesController::index');
// Get all leads with filters
$routes->get('leads', 'SalesController::getLeads');
@@ -974,6 +985,11 @@ $routes->group('sales', function($routes) {
// Delete note
$routes->delete('notes/(:num)', 'SalesController::deleteNote/$1');
+
+
+ //Dashboard
+ $routes->get('branchLevelDashboard', 'SalesController::branchLevelDashboard');
+ $routes->get('salesManagerLevelDashboard', 'SalesController::salesManagerLevelDashboard');
});
diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php
index 17320621..28b2aec6 100644
--- a/app/Controllers/ApiServiceController.php
+++ b/app/Controllers/ApiServiceController.php
@@ -688,51 +688,4 @@ class ApiServiceController extends BaseController
- // Get Claims
- public function getClaims($id)
- {
- if ($id == 1) {
- $controller = new VidalApiController();
- } elseif ($id == 2) {
- $controller = new ICICILombardController();
- } elseif ($id == 3) {
- $controller = new MediAssistApiController();
- }
- }
-
- // Get UHID
- public function getUhid($id)
- {
- if ($id == 1) {
- $controller = new VidalApiController();
- } elseif ($id == 2) {
- $controller = new ICICILombardController();
- } elseif ($id == 3) {
- $controller = new MediAssistApiController();
- }
- }
-
- // Push Enrollment
- public function pushEnrollment($id)
- {
- if ($id == 1) {
- $controller = new VidalApiController();
- } elseif ($id == 2) {
- $controller = new ICICILombardController();
- } elseif ($id == 3) {
- $controller = new MediAssistApiController();
- }
- }
-
- // Get Hospital Network
- public function getHospitalNetwork($id)
- {
- if ($id == 1) {
- $controller = new VidalApiController();
- } elseif ($id == 2) {
- $controller = new ICICILombardController();
- } elseif ($id == 3) {
- $controller = new MediAssistApiController();
- }
- }
}
diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php
index 780a56ac..195ce4b9 100755
--- a/app/Controllers/ClientController.php
+++ b/app/Controllers/ClientController.php
@@ -783,19 +783,11 @@ class ClientController extends AdminController
]
],
- // 'cd_ac_no' => [
- // 'rules' => 'required|regex_match[/^[a-zA-Z0-9\/_\\-]+$/]',
- // 'errors' => [
- // 'required' => 'Account number is required',
- // 'regex_match' => 'Account number can only contain letters, numbers, slashes (/), underscores (_), and hyphens (-)',
- // ]
- // ],
-
'cd_ac_no' => [
- 'rules' => 'required|numeric',
+ 'rules' => 'required|regex_match[/^[a-zA-Z0-9\/\-_]+$/]',
'errors' => [
- 'required' => 'CD Account number is required.',
- 'numeric' => 'CD Account number must contain only numbers.',
+ 'required' => 'CD Account number is required.',
+ 'regex_match' => 'CD Account number can only contain letters, numbers, hyphens(-), underscores(_), and slashes(/).',
]
],
@@ -6923,6 +6915,31 @@ class ClientController extends AdminController
// $res = $medi_assist->MediAssistGetBenefDetails(['policy_no' => '97000034240400000030', 'file_id' => 389, 'return_type' => 'job', 'client_policy_id' => 6192 ]);
// dd($res);
+ // // 1. Dummy JSON data create panrom (Temp file)
+ // $tempJsonFile = tempnam(sys_get_temp_dir(), 'test_vidal_');
+ // $dummyData = [
+ // [
+ // 'empNo' => 'EMP001',
+ // 'name' => 'John Doe',
+ // 'dob' => '01/01/1990',
+ // 'relationship' => 'Self',
+ // 'gender' => 'Male',
+ // 'enrollmentId' => 'TPA123',
+ // 'age' => 34
+ // ]
+ // ];
+
+ // file_put_contents($tempJsonFile, json_encode($dummyData));
+
+ // $inputArray = [
+ // 'file_id' => 10,
+ // 'json_file_path' => $tempJsonFile
+ // ];
+
+ // $vidalController = new VidalApiController();
+ // $res = $vidalController->saveVidalAPIData($inputArray);
+ // dd($res);
+
$employeeController = new EmployeeController();
// $response = $employeeController->getEmployeeEcardFromTmpFolderAndZipToS3(json_decode('{"batch_no":2,"last_emp_policy_id":"13218","folder_name":"bulk_ecards_IOCL-77448855996699885555_2026-02-05_09-32-22","processed_in_this_batch_data_count":7,"pdf_count":0,"hr_id":"1"}', true));
// $response = $employeeController->bulkEcardDownloadAsZipFromS3(json_decode('{"client_policy_id":"6066","hr_id":"1"}', true));
@@ -6991,6 +7008,7 @@ class ClientController extends AdminController
// $res = $policyTransactionController->validateInsurerStatement(['file_id' => '281']);
// $res = $policyTransactionController->updateInsurerStatement(['file_id' => '62']);
// $res = $policyTransactionController->bdsDumpExcelFileFormatValidation(['file_id' => '73']);
+ // $res = $policyTransactionController->insertBulkBdsData(['file_id' => '78']);
// dd($res);
// ----------EMP DATA SERVICE CONTROLLER--------------------------------------------------------------------------------
diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php
index e4a04375..4e7ddef7 100755
--- a/app/Controllers/EmployeeController.php
+++ b/app/Controllers/EmployeeController.php
@@ -336,9 +336,9 @@ class EmployeeController extends AdminController
//endof validation process
if (isset($result['error_summary']) && count($result['error_summary'])) {
if(!empty($post_data)){
- return ['status' => false, 'message' => 'file rejected with errors', 'file_id' => $file_id];
+ return ['status' => false, 'message' => 'File rejected with errors', 'file_id' => $file_id];
}else{
- return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200);
+ return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'File rejected with errors'], 200);
}
}
} else //if file size greater than 1 add the file as job
@@ -3669,7 +3669,7 @@ class EmployeeController extends AdminController
"policyStartDate" => $policyStartDate,
"policyEndDate" => $policyEndDate,
"plan" => $primary["wellness_plan_id"] ?? null,
- "source" => $primary['short_name'] ?? null,
+ "source" => 'NHANCE',
"employer" => $primary['short_name'] ?? null,
"employeeCode" => $empCode,
"accountNumber" => "", // Fill from DB if available
@@ -3690,8 +3690,8 @@ class EmployeeController extends AdminController
"name" => $row["name"],
"phone" => $row["mobile"],
"email" => $row["email_corporate"],
- "relationshipName" => strtoupper($row["relationship"] ?? ''),
- "gender" => $row["gender"],
+ "relationshipName" => $this->mapRelationship($row["relationship"],$row["gender"]),
+ "gender" => $row["gender"] == 'M' ? 'Male' : 'Female',
"dob" => $row["dob"]
];
}
@@ -3700,6 +3700,42 @@ class EmployeeController extends AdminController
}
+ function mapRelationship(string $relationship, ?string $gender = null): string
+ {
+ // Normalize input
+ $key = strtolower(trim($relationship));
+ $key = str_replace(['-', '_'], ' ', $key);
+ $key = preg_replace('/\s+/', ' ', $key);
+
+ // Base mapping
+ $map = [
+ 'self' => 'self',
+ 'son' => 'son',
+ 'daughter' => 'daughter',
+ 'father' => 'father',
+ 'mother' => 'mother',
+ 'father in law' => 'father in law',
+ 'father-in-law' => 'father in law',
+ 'mother in law' => 'mother in law',
+ 'mother-in-law' => 'mother in law',
+ ];
+
+ // Special handling for spouse
+ if ($key === 'spouse') {
+ if ($gender === 'M') {
+ return 'husband';
+ }
+ if ($gender === 'F') {
+ return 'wife';
+ }
+
+ // fallback if gender missing (better to throw error)
+ throw new \Exception("Gender required to map 'Spouse'");
+ }
+
+ return $map[$key] ?? '';
+ }
+
/**
* Send each family payload to API and attach the response
@@ -4021,8 +4057,7 @@ class EmployeeController extends AdminController
];
}
-
- function reconcileDbWithTpa(array $db, array $tpaRows): array
+ public function reconcileDbWithTpa(array $db, array $tpaRows): array
{
// Name normalization
$normalizeName = function ($name) {
@@ -4076,12 +4111,7 @@ class EmployeeController extends AdminController
];
}
-
- function exportVariationReportExcel(
- array $notInTPA,
- array $notInNhance,
- array $reviewNeeded,
- string $filename = 'employee_review.xlsx')
+ public function exportVariationReportExcel(array $notInTPA, array $notInNhance, array $reviewNeeded, string $filename = 'employee_review.xlsx')
{
function setCell($sheet, int $col, int $row, $value)
@@ -4281,7 +4311,7 @@ class EmployeeController extends AdminController
exit;
}
- public function bulkGenerateEcardAndStoreinS3(array $params = [])
+ public function bulkGenerateEcardAndStoreinS3(array $params = [])
{
$request = \Config\Services::request();
$isCli = is_cli();
diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php
index a187e819..fb17d59a 100755
--- a/app/Controllers/EmployeeRestController.php
+++ b/app/Controllers/EmployeeRestController.php
@@ -1673,10 +1673,16 @@ class EmployeeRestController extends AdminController
{
try {
- $client = $this->clientModel->where('md5(id)', $this->request->getGet('client_id'))->first();
+ $client_id = $this->request->getGet('client_id');
+ if (is_string($client_id) && preg_match('/^[a-f0-9]{32}$/i', $client_id)) {
+ $client = $this->clientModel->where('MD5(id)', $client_id)->first();
+ }else{
+ $client = $this->clientModel->where('id', $client_id)->first();
+ }
+
if (!empty($client)) {
$client['client_logo'] = base_url() . 'public/uploads/logo/' . $client['client_logo'];
- $clientPolicy = $this->clientPolicyModel->where('md5(client_id)', $this->request->getGet('client_id'))
+ $clientPolicy = $this->clientPolicyModel->where('client_id', $client['id'])
->where('client_branch_id', $this->request->getGet('client_branch_id'))->findAll();
return $this->respond(['status' => 'success', 'code' => 200, 'data' => ['client' => $client, 'client_policy' => $clientPolicy]], 200);
} else {
@@ -3763,7 +3769,11 @@ class EmployeeRestController extends AdminController
$fetchData['priority'] = 1;
$fetchData['mode_of_intimation'] = 3;
- $fetchData['claim_type'] = 1;
+
+ if(!isset($received_data['claim_type']) || (isset($received_data['claim_type']) && empty($received_data['claim_type']))) {
+ $received_data['claim_type'] = 1;
+ }
+
$fetchData = array_merge($fetchData, $received_data);
// $fetchData['relationship'] = strtolower($fetchData['relationship']) ?? $fetchData['relationship'];
@@ -3987,8 +3997,12 @@ class EmployeeRestController extends AdminController
// ])->setStatusCode(400);
$ticket_type = $this->ticketController->ticketType;
+ $claim_type = $this->ticketController->claimType;
+ unset($claim_type[1][2]);
+ unset($claim_type[1][4]);
+
$ticket_type = array_map(fn($value, $key) => (object) ['id' => $key, 'name' => $value], array_values($ticket_type), array_keys($ticket_type));
- return $this->response->setJSON(['ticket_type' => $ticket_type])->setStatusCode(200);
+ return $this->response->setJSON(['ticket_type' => $ticket_type, 'claim_type' => $claim_type])->setStatusCode(200);
}
// Get policy type ids
@@ -4017,6 +4031,10 @@ class EmployeeRestController extends AdminController
$this->myLogger->logme('error', "Policy type IDs fetched: " . json_encode($policy_type_ids));
$ticket_type = $this->ticketController->ticketType;
+ $claim_type = $this->ticketController->claimType;
+ unset($claim_type[1][2]);
+ unset($claim_type[1][4]);
+
$filtered = [];
$mapping = [
@@ -4050,7 +4068,7 @@ class EmployeeRestController extends AdminController
}
$filtered = array_values($filtered);
- return $this->response->setJSON(['status' => true, 'code' => 200, 'ticket_type' => $filtered])->setStatusCode(200);
+ return $this->response->setJSON(['status' => true, 'code' => 200, 'ticket_type' => $filtered, 'claim_type' => $claim_type])->setStatusCode(200);
} catch (\Throwable $e) {
$this->myLogger->logme('error', "Error in get_ticket_type: " . $e->getMessage() . " Trace: " . $e->getTraceAsString());
return $this->response->setJSON([
diff --git a/app/Controllers/FhplApiController.php b/app/Controllers/FhplApiController.php
index f2ac8b17..734bb438 100644
--- a/app/Controllers/FhplApiController.php
+++ b/app/Controllers/FhplApiController.php
@@ -98,7 +98,7 @@ class FhplApiController extends BaseController
if (count($data) && $data['filePath'] == null) {
- log_message('error', "TPA CLAIM PUSH FAILED FHPL | claimId: '.$claimId.' - Claim or File Missing");
+ log_message('error', "FHPL - Claim Push FAILED | claimId: '.$claimId.' - Claim or File Missing");
return;
}
@@ -107,7 +107,7 @@ class FhplApiController extends BaseController
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename;
if (!file_exists($pdfPath)) {
- log_message('error', "TPA CLAIM PUSH FAILED FHPL | claimId: '.$claimId.' - PDF not found on server");
+ log_message('error', "FHPL - Claim Push FAILED | claimId: '.$claimId.' - PDF not found on server");
return;
}
@@ -117,7 +117,7 @@ class FhplApiController extends BaseController
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
if (empty($tokenResponse['data']['access_token'])) {
- log_message('error', "TPA CLAIM PUSH FAILED FHPL | claimId: '.$claimId.' - FHPL Token generation failed");
+ log_message('error', "FHPL - Claim Push FAILED | claimId: '.$claimId.' - FHPL Token generation failed");
return;
}
$token = $tokenResponse['data']['access_token'];
@@ -152,14 +152,14 @@ class FhplApiController extends BaseController
"Content-Type: application/json"
];
- log_message('error', 'TPA CLAIM PUSH FHPL | claimId: '.$claimId.' | payload: '.json_encode($body));
+ log_message('error', 'FHPL - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
$response = call_third_party_api($url, 'POST', $headers, $body);
- log_message('error', 'TPA CLAIM PUSH FHPL RESPONSE | ' . json_encode($response));
+ log_message('error', 'FHPL - Claim Push RESPONSE | ' . json_encode($response));
if($response['status'] != true){
- log_message('error', 'TPA CLAIM PUSH FAILED FHPL | claimId: '.$claimId.' | response: '.json_encode($response));
+ log_message('error', 'FHPL - Claim Push FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
$this->db->table('ticket_master')
->where('id',$claimId)
->update([ 'tpa_push_response' => json_encode($response) ]);
@@ -184,10 +184,10 @@ class FhplApiController extends BaseController
'updated_at' => date('Y-m-d H:i:s')
]);
- log_message('error', 'TPA CLAIM PUSH SUCCESS FHPL | claimId: '.$claimId.' | claimNO: '.$fhplClaimNo);
+ log_message('error', 'FHPL - Claim Push SUCCESS | claimId: '.$claimId.' | claimNO: '.$fhplClaimNo);
}else {
- log_message('error', 'TPA CLAIM PUSH API SUCCESS BUT claimsInfo EMPTY | response: '.json_encode($response));
+ log_message('error', 'FHPL - Claim Push API SUCCESS BUT claimsInfo EMPTY | response: '.json_encode($response));
return;
}
}
@@ -235,21 +235,18 @@ class FhplApiController extends BaseController
// dd($response);
if (empty($response['data'][0])) {
- log_message('error', 'CLAIM STATUS FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
+ log_message('error', 'FHPL - Claim status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
return ['status' => false,'message' => 'API call failed.','data' => $response ];
}
+ // Extract claim status
+ $claimData = $response['data'][0];
+ $tpa_claim_no = $claimData['CLAIM_ID'] ?? '';
+ $currentStatus = $claimData['CLAIM_STATUS'] ?? '';
+ $tpa_claim_type = $claimData['CLAIM_TYPE'] ?? '';
+ $tpa_ailments = $claimData['AILMENT'] ?? '';
- $status = null;
-
- // find this claim
- foreach($response['data'] as $row){
- if($row['CLAIM_ID']==$ticket['claimNo']){
- $status = $row['CLAIM_STATUS'];
- }
- }
-
- $map = [
+ $validStatuses = [
"In-Progress" => 5,
"Under Process" => 5,
"Query" => 4,
@@ -259,14 +256,28 @@ class FhplApiController extends BaseController
"Required Information" => 4,
];
- if( $status != null && isset($map[$status]))
- {
- $this->db->table('ticket_master')->where('id',$claimId)->update(['claim_status_id'=>$map[$status],'tpa_claim_status'=>$status]);
- log_message('error', "CLAIM STATUS SUCCESS | Updated ticket ID $claimId with claim status: $status");
+ $updateArray = [
+ 'tpa_claim_status' => $currentStatus,
+ 'updated_at' => date('Y-m-d H:i:s'),
+ ];
+ if (isset($validStatuses[$currentStatus])) {
+ $updateArray['claim_status_id'] = $validStatuses[$currentStatus];
}
+ if (!empty($tpa_claim_type)) {
+ $updateArray['tpa_claim_type'] = $tpa_claim_type;
+ }
+ if (!empty($tpa_ailments)) {
+ $updateArray['tpa_ailments'] = $tpa_ailments;
+ }
+
- return ['status' => true,'message' => 'Claim status updated.','updated_status' => $status,'api_response' => $response];
+ $this->db->table('ticket_master')->where('id',$claimId)->update($updateArray);
+ log_message('error', "FHPL - Claim status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
+
+
+
+ return ['status' => true,'message' => 'Claim status updated.','updated_status' => $currentStatus,'api_response' => $response];
}
@@ -297,7 +308,7 @@ class FhplApiController extends BaseController
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
if (empty($tokenResponse['data']['access_token'])) {
- log_message('error', 'Ecard Request FAILED | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | Message: FHPL Token generation failed');
+ log_message('error', 'FHPL - Ecard Request FAILED | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | Message: FHPL Token generation failed');
return null;
}
$token = $tokenResponse['data']['access_token'];
@@ -317,12 +328,12 @@ class FhplApiController extends BaseController
// dd($response);
if (($response['status'] ?? false) !== true) {
- log_message('error', 'Ecard Request FAILED | response: ' . json_encode($response));
+ log_message('error', 'FHPL - Ecard Request FAILED | response: ' . json_encode($response));
return null;
}
if (empty($response['data'][0])) {
- log_message('error', 'Ecard Request FAILED | Empty data | response: ' . json_encode($response));
+ log_message('error', 'FHPL - Ecard Request FAILED | Empty data | response: ' . json_encode($response));
return null;
}
@@ -334,8 +345,8 @@ class FhplApiController extends BaseController
if (!empty($ecardUrl)) {
log_message(
- 'info',
- 'Ecard Request PUSH SUCCESS | employeeId: ' . $employeeId .
+ 'error',
+ 'FHPL - Ecard Request PUSH SUCCESS | employeeId: ' . $employeeId .
' | policyNo: ' . $policyNo .
' | ecardUrl: ' . $ecardUrl
);
@@ -343,7 +354,7 @@ class FhplApiController extends BaseController
}
}
- log_message('error', 'Ecard Request FAILED | response: ' . json_encode($response));
+ log_message('error', 'FHPL - Ecard Request FAILED | response: ' . json_encode($response));
return null;
}
@@ -360,7 +371,7 @@ class FhplApiController extends BaseController
$client_policy_id = $requestData['client_policy_id'] ?? null;
if (empty($policyNo)) {
- log_message('error', 'TPA ID PULL | policy_no missing in request');
+ log_message('error', 'FHPL - TPA ID Pull | policy_no missing in request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'policy_no required'];
}else{
@@ -369,7 +380,7 @@ class FhplApiController extends BaseController
}
if (empty($client_policy_id)) {
- log_message('error', 'TPA ID PULL | client_policy_id missing in request');
+ log_message('error', 'FHPL - TPA ID Pull | client_policy_id missing in request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'client_policy_id required'];
}else{
@@ -377,7 +388,7 @@ class FhplApiController extends BaseController
}
}
- log_message('error', "TPA ID PULL | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
+ log_message('error', "FHPL - TPA ID Pull | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
// Fetch file download dates
$batchFiles = $this->db->table('batch_files f')
@@ -389,7 +400,7 @@ class FhplApiController extends BaseController
->getResultArray();
if (empty($batchFiles)) {
- log_message('error', 'TPA ID PULL FAILED | batchFiles is empty for this tpa id pull request');
+ log_message('error', 'FHPL - TPA ID Pull FAILED | batchFiles is empty for this tpa id pull request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'batchFiles not found'];
}else{
@@ -400,7 +411,7 @@ class FhplApiController extends BaseController
// Generate FHPL Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
if (empty($tokenResponse['data']['access_token'])) {
- log_message('error', 'TPA ID PULL | FHPL Token generation failed');
+ log_message('error', 'FHPL - TPA ID Pull | FHPL Token generation failed');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'FHPL Token generation failed'];
}else{
@@ -430,12 +441,12 @@ class FhplApiController extends BaseController
"Range" => $range
];
- log_message('error', "TPA ID PULL | API parems " . json_encode([$url, 'POST', $headers, $body]));
+ log_message('error', "FHPL - TPA ID Pull | API parems " . json_encode([$url, 'POST', $headers, $body]));
$response = call_third_party_api($url, 'POST', $headers, $body);
if (($response['status'] ?? false) !== true) {
- log_message('error', 'FHPL API FAILED | response: ' . json_encode($response));
+ log_message('error', 'FHPL - TPA ID Pull API FAILED | response: ' . json_encode($response));
break;
}
@@ -467,7 +478,7 @@ class FhplApiController extends BaseController
log_message('error', "Failed to update file table status.");
}
- log_message('error', 'TPA ID PULL API FAILED | API failed: Empty menber data for this pull request');
+ log_message('error', 'FHPL - TPA ID Pull API FAILED | API failed: Empty menber data for this pull request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'API call failed', 'data' => 'Empty menber data for this pull request'];
@@ -524,9 +535,9 @@ class FhplApiController extends BaseController
if ($this->db->affectedRows() > 0) {
$updated++;
- log_message('error', "✅ Updated tpa_id={$m['TPA_TPADETAIL_ID']} for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
+ log_message('error', "FHPL - TPA ID Pull Updated tpa_id={$m['TPA_TPADETAIL_ID']} for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
} else {
- log_message('error', "⚠️ No update (already set or not matched) for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
+ log_message('error', "FHPL - TPA ID Pull No update (already set or not matched) for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
}
}
}
@@ -546,7 +557,7 @@ class FhplApiController extends BaseController
log_message(
'error',
- "❌ No match for Nhance = " . json_encode($nhanceSideData)
+ "FHPL - TPA ID Pull No match for Nhance = " . json_encode($nhanceSideData)
);
}
@@ -568,7 +579,7 @@ class FhplApiController extends BaseController
$totalCount = count($allMembers);
- log_message('error', "TPA ID PULL SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
+ log_message('error', "FHPL - TPA ID Pull SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
if($function_calling_type == "job"){
return [
@@ -742,6 +753,7 @@ 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']);
}
}
@@ -778,6 +790,52 @@ class FhplApiController extends BaseController
return ['status'=>true,'total'=>count($finalResult)];
}
+ public function saveFhplAPIData($array)
+ {
+ $file_id = $array['file_id'];
+ $json = file_get_contents($array['json_file_path']);
+ $records = json_decode($json, true);
+
+ // log_message('error','FHPL - saveFhplAPIData' . json_encode($array));//die();
+ $file_model = new BatchFileModel();
+ $file_info = $file_model->where('id', $file_id)->find();
+
+ $tpaApiDataModel = new TpaApiDataModel();
+
+ //deactivate old data
+ $tpaApiDataModel->set('is_active', 0)->where('file_id', $file_id)->update();
+
+ //covert tpa data to our model data
+ $mappedRows = [];
+
+ foreach ($records as $row) {
+
+ $mappedRows[] = [
+ 'file_id' => $file_id, // ← pass from controller
+ 'emp_code' => trim($row['EMPLOYEE_ID'] ?? ''),
+
+ 'name' => trim($row['EMPLOYEE_NAME'] ?? ''),
+ 'dob' => !empty($row['DATE_OF_BIRTH'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $row['DATE_OF_BIRTH']))) : null,
+
+ 'relation' => trim(strtolower($row['RELATION'] ?? '')),
+ 'gender' => format_gender_v2($row['GENDER'] ?? null),
+ 'self' => strtolower($row['RELATION'] ?? '') === 'self' ? 1 : 0,
+
+ 'tpa_id' => trim($row['TPA_TPADETAIL_ID'] ?? null),
+ 'age' => is_numeric($row['AGE'] ?? null) ? (int) $row['AGE'] : null,
+
+ 'is_active' => 1,
+ 'created_by' => $file_info[0]['created_by'] ?? null,
+ ];
+ }
+
+ // log_message('error','FHPL - COUNT' . count($mappedRows));
+ $result = $tpaApiDataModel->insertBatchWithChunkLog($mappedRows,500,('FILE_ID_'.$file_id));
+ // unlink($file_array['json_file_path']); // delete temp json file
+
+ return $result;
+ }
+
diff --git a/app/Controllers/GoogleSheetController.php b/app/Controllers/GoogleSheetController.php
new file mode 100644
index 00000000..e51f81ab
--- /dev/null
+++ b/app/Controllers/GoogleSheetController.php
@@ -0,0 +1,66 @@
+sheetLib = new GoogleSheetLib();
+ }
+
+ /* ---------- UI ---------- */
+ public function editor(string $sheetId)
+ {
+ return view('gsheet_editor', [
+ 'sheetId' => $sheetId
+ ]);
+ }
+
+ /* ---------- FETCH ---------- */
+ public function fetch(string $sheetId)
+ {
+ // $data = $this->sheetLib->read($sheetId);
+ // print_rr($data);die;
+ // return $this->response->setJSON($data);
+ echo 'Hi';
+ }
+
+ /* ---------- SAVE ---------- */
+ public function save(string $sheetId)
+ {
+ $rows = $this->request->getJSON(true);
+
+ if (!is_array($rows)) {
+ return $this->response
+ ->setStatusCode(400)
+ ->setJSON(['error' => 'Invalid data']);
+ }
+
+ $this->sheetLib->write($sheetId, $rows);
+
+ return $this->response->setJSON([
+ 'status' => 'success'
+ ]);
+ }
+
+ /* ---------- DOWNLOAD ---------- */
+ public function download(string $sheetId)
+ {
+ $content = $this->sheetLib->downloadExcel($sheetId);
+
+ return $this->response
+ ->setHeader(
+ 'Content-Type',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ )
+ ->setHeader(
+ 'Content-Disposition',
+ 'attachment; filename="sheet.xlsx"'
+ )
+ ->setBody($content);
+ }
+}
diff --git a/app/Controllers/HealthIndiaApiController.php b/app/Controllers/HealthIndiaApiController.php
index f10801fb..13bc10c3 100644
--- a/app/Controllers/HealthIndiaApiController.php
+++ b/app/Controllers/HealthIndiaApiController.php
@@ -3,6 +3,7 @@
namespace App\Controllers;
use App\Controllers\BaseController;
+use App\Controllers\TicketController;
use App\Models\BatchFileModel;
use App\Models\EmployeePolicyModel;
use App\Models\TpaApiDataModel;
@@ -18,11 +19,15 @@ class HealthIndiaApiController extends BaseController
use ResponseTrait;
protected $db;
protected $healthIndiaTpaId;
+ protected $claim_type_array;
public function __construct()
{
$this->db = \Config\Database::connect();
$this->healthIndiaTpaId = getenv('HEALTH_INDIA_PRIMARY_KEY_CONSTANT');
+
+ $this->ticketController = new TicketController();
+ $this->claim_type_array = $this->ticketController->claimType;
}
public function generateAuthToken()
@@ -79,11 +84,11 @@ class HealthIndiaApiController extends BaseController
]);
}
- public function SubmitClaim($claimId = 729)
+ public function SubmitClaim($claimId = null)
{
helper('api');
- log_message('error', 'TPA CLAIM PUSH HEALTH_INDIA | Started for claimId: ' . $claimId);
+ log_message('error', 'HEALTH_INDIA - Claim Push | Started for claimId: ' . $claimId);
$data = $this->db->table('ticket_master tm')
->select('
@@ -117,12 +122,12 @@ class HealthIndiaApiController extends BaseController
// dd($data);
if (!$data) {
- log_message('error', "TPA CLAIM PUSH FAILED HEALTH_INDIA | claimId: {$claimId} - Claim not found");
+ log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Claim not found");
return;
}
if ($data['filePath'] == null) {
- log_message('error', "TPA CLAIM PUSH FAILED HEALTH_INDIA | claimId: {$claimId} - File Missing");
+ log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - File Missing");
return;
}
@@ -131,7 +136,7 @@ class HealthIndiaApiController extends BaseController
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename;
if (!file_exists($pdfPath)) {
- log_message('error', "TPA CLAIM PUSH FAILED HEALTH_INDIA | claimId: {$claimId} - PDF not found on server at path: {$pdfPath}");
+ log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - PDF not found on server at path: {$pdfPath}");
return;
}
@@ -141,31 +146,31 @@ class HealthIndiaApiController extends BaseController
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
- log_message('error', "TPA CLAIM PUSH FAILED HEALTH_INDIA | claimId: {$claimId} - Token generation failed");
+ log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Token generation failed");
return;
}
$token = $tokenResponse['data']['result'][0]['access_token'];
// Map claim type: Reimbursement or Cashless
- $claimTypeMap = [
- 'reimbursement' => 'Reimbursement',
- 'cashless' => 'Cashless',
- ];
- $mappedClaimType = $claimTypeMap[strtolower($data['claimType'] ?? 'reimbursement')] ?? 'Reimbursement';
- // Map benefit type: IPD or OPD
+ // Map claim_type to benefit type (IPD / OPD)
+ $claimTypeValue = $this->claim_type_array[1][$data['claim_type'] ?? null] ?? null;
+
$benefitTypeMap = [
- 'ipd' => 'IPD',
- 'opd' => 'OPD',
+ 'Main Hospitalization' => 'IPD',
+ 'Pre / Post' => 'IPD',
+ 'ReOpen' => 'IPD',
+ 'OPD' => 'OPD',
];
- $mappedBenefitType = $benefitTypeMap[strtolower($data['benefitType'] ?? 'ipd')] ?? 'IPD';
+
+ $mappedBenefitType = $benefitTypeMap[$claimTypeValue] ?? 'IPD';
// Build Health India Claim Submission Request (API Section 5)
$body = [
"policY_NUMBER" => $data['policyNumber'],
"employeE_CODE" => $data['employeeCode'],
"membeR_ID" => $data['memberId'],
- "claiM_TYPE" => $mappedClaimType,
+ "claiM_TYPE" => 'Reimbursement',
"benefiT_TYPE" => $mappedBenefitType,
"claimeD_AMOUNT" => (string) $data['claimedAmount'],
"datE_OF_ADMISSION" => date('Y-m-d', strtotime($data['admissionDate'])),
@@ -201,16 +206,14 @@ class HealthIndiaApiController extends BaseController
"Content-Type: application/json"
];
- log_message('error', 'TPA CLAIM PUSH HEALTH_INDIA | claimId: ' . $claimId . ' | URL: ' . $url );
+ log_message('error', 'HEALTH_INDIA - Claim Push | claimId: ' . $claimId . ' | URL: ' . $url );
$response = call_third_party_api($url, 'POST', $headers, $body);
// dd($response);
- log_message('error', 'TPA CLAIM PUSH HEALTH_INDIA RESPONSE | claimId: ' . $claimId . ' | response: ' . json_encode($response));
-
if ($response['status'] != true) {
- log_message('error', 'TPA CLAIM PUSH FAILED HEALTH_INDIA | claimId: ' . $claimId . ' | response: ' . json_encode($response));
+ log_message('error', 'HEALTH_INDIA - Claim Push FAILED | claimId: ' . $claimId . ' | response: ' . json_encode($response));
$this->db->table('ticket_master')
->where('id', $claimId)
->update(['tpa_push_response' => json_encode($response)]);
@@ -224,35 +227,35 @@ class HealthIndiaApiController extends BaseController
$this->db->table('ticket_master')
->where('id', $claimId)
->update([
- 'claim_number' => $ccn,
- 'tpa_claim_id' => $ccn,
- 'tpa_claim_push_reference_no' => $ccn . '(' . $ccnExt . ')',
+ // 'claim_number' => $ccn,
+ // 'tpa_claim_id' => $ccn,
+ 'tpa_claim_push_reference_no' => $ccn . '-' . $ccnExt,
'updated_at' => date('Y-m-d H:i:s')
]);
- log_message('error', 'TPA CLAIM PUSH SUCCESS HEALTH_INDIA | claimId: ' . $claimId . ' | CCN: ' . $ccn . ' | CCN_EXT: ' . $ccnExt);
+ log_message('error', 'HEALTH_INDIA - Claim Push SUCCESS | claimId: ' . $claimId . ' | CCN: ' . $ccn . ' | CCN_EXT: ' . $ccnExt);
} else {
- log_message('error', 'TPA CLAIM PUSH HEALTH_INDIA API SUCCESS BUT CCN EMPTY | claimId: ' . $claimId . ' | response: ' . json_encode($response));
+ log_message('error', 'HEALTH_INDIA - Claim Push API SUCCESS BUT CCN EMPTY | claimId: ' . $claimId . ' | response: ' . json_encode($response));
return;
}
return;
}
- public function ClaimDetail($claimId = 729)
+ public function ClaimDetail($claimId = null)
{
helper('api');
- log_message('error', 'CLAIM STATUS HEALTH_INDIA | Started for claimId: ' . $claimId);
+ log_message('error', 'HEALTH_INDIA - Claim Status | Started for claimId: ' . $claimId);
$ticket = $this->db->table('ticket_master tm')
- ->select("tm.id, tm.tpa_claim_id as ccn, cp.policy_no, cp.policy_start_date, cp.policy_end_date, tm.emp_code")
+ ->select("tm.id, tm.tpa_claim_push_reference_no, cp.policy_no, cp.policy_start_date, cp.policy_end_date, tm.emp_code")
->join('client_policy cp', 'tm.client_policy_id=cp.id')
->where('tm.id', $claimId)
->get()->getRowArray();
if (!$ticket) {
- log_message('error', 'CLAIM STATUS FAILED HEALTH_INDIA | claimId: ' . $claimId . ' - Invalid claim');
+ log_message('error', 'HEALTH_INDIA - Claim Status FAILED | claimId: ' . $claimId . ' - Invalid claim');
return ['status' => false, 'message' => 'Invalid claim'];
}
@@ -260,7 +263,7 @@ class HealthIndiaApiController extends BaseController
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
- log_message('error', 'CLAIM STATUS FAILED HEALTH_INDIA | claimId: ' . $claimId . ' - Token generation failed');
+ log_message('error', 'HEALTH_INDIA - Claim Status FAILED | claimId: ' . $claimId . ' - Token generation failed');
return ['status' => false, 'message' => 'Token generation failed'];
}
@@ -269,10 +272,14 @@ class HealthIndiaApiController extends BaseController
$url = getenv('HEALTH_INDIA_BASE_URL') . "/Claims/GetClaims";
// Using claim number wise approach (Section 7.3 - option 3)
+ $reference = $ticket['tpa_claim_push_reference_no'];
+ $parts = explode('-', $reference);
+ $ccn = $parts[0] ?? null;
+ $ccnExt = $parts[1] ?? null;
$body = [
"policY_NUMBER" => $ticket['policy_no'],
- "CCN" => $ticket['ccn'],
- "CCN_EXT" => "0"
+ "CCN" => $ccn,
+ "CCN_EXT" => $ccnExt
];
$headers = [
@@ -280,49 +287,61 @@ class HealthIndiaApiController extends BaseController
"Content-Type: application/json"
];
- log_message('error', 'CLAIM STATUS HEALTH_INDIA | claimId: ' . $claimId . ' | Request: ' . json_encode($body));
+ log_message('error', 'HEALTH_INDIA - Claim Status | claimId: ' . $claimId . ' | Request: ' . json_encode($body));
$response = call_third_party_api($url, 'POST', $headers, $body);
// dd($response);
- log_message('error', 'CLAIM STATUS HEALTH_INDIA | claimId: ' . $claimId . ' | Response: ' . json_encode($response));
-
if (empty($response['data']['result'][0])) {
- log_message('error', 'CLAIM STATUS FAILED HEALTH_INDIA | claimId: ' . $claimId . ' | Empty response data');
+ log_message('error', 'HEALTH_INDIA - Claim Status FAILED | claimId: ' . $claimId . ' | Empty response data');
return ['status' => false, 'message' => 'API call failed.', 'data' => $response];
}
+ // Extract claim status
$claimData = $response['data']['result'][0];
- $status = $claimData['claiM_STATUS'] ?? null;
+ $tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? '';
+ $currentStatus = $claimData['claiM_STATUS'] ?? '';
+ $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? '';
+ $tpa_ailments = $claimData['ailment'] ?? '';
- // Status mapping based on API documentation
- $map = [
+ $validStatuses = [
+ "In-Progress" => 5,
"Under Process" => 5,
- "Pending for Bill Entry" => 5,
"Query" => 4,
"Paid" => 11,
"Rejected" => 8,
"Approved" => 8,
- "Outstanding" => 5,
+ "Required Information" => 4,
+ "Intimated and File NOT received" => 4,
];
- if ($status != null && isset($map[$status])) {
- $this->db->table('ticket_master')
- ->where('id', $claimId)
- ->update([
- 'claim_status_id' => $map[$status],
- 'tpa_claim_status' => $status
- ]);
- log_message('error', "CLAIM STATUS SUCCESS HEALTH_INDIA | Updated claimId: {$claimId} with status: {$status}");
- } else {
- log_message('error', "CLAIM STATUS HEALTH_INDIA | claimId: {$claimId} | Unknown status: {$status}");
+ $updateArray = [
+ 'tpa_claim_status' => $currentStatus,
+ 'tpa_claim_id' => $tpa_claim_no,
+ 'claim_number' => $tpa_claim_no,
+ 'updated_at' => date('Y-m-d H:i:s'),
+ ];
+ if (isset($validStatuses[$currentStatus])) {
+ $updateArray['claim_status_id'] = $validStatuses[$currentStatus];
}
+ if (!empty($tpa_claim_type)) {
+ $updateArray['tpa_claim_type'] = $tpa_claim_type;
+ }
+ if (!empty($tpa_ailments)) {
+ $updateArray['tpa_ailments'] = $tpa_ailments;
+ }
+
+
+
+ $this->db->table('ticket_master')->where('id',$claimId)->update($updateArray);
+
+ log_message('error', "HEALTH_INDIA - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
return [
'status' => true,
'message' => 'Claim status updated.',
- 'updated_status' => $status,
+ 'updated_status' => $currentStatus,
'api_response' => $response
];
}
@@ -331,7 +350,7 @@ class HealthIndiaApiController extends BaseController
{
helper('api');
- log_message('error', 'CLAIM STATUS UPDATE BULK HEALTH_INDIA | Started');
+ log_message('error', 'HEALTH_INDIA - Claim Status UPDATE BULK | Started');
$tickets = $this->db->table('ticket_master tm')
->select("tm.id, tm.tpa_claim_id, cp.policy_no")
@@ -347,7 +366,7 @@ class HealthIndiaApiController extends BaseController
$count++;
}
- log_message('error', 'CLAIM STATUS UPDATE BULK HEALTH_INDIA | Completed | Updated: ' . $count);
+ log_message('error', 'HEALTH_INDIA - Claim Status UPDATE BULK | Completed | Updated: ' . $count);
return $this->response->setJSON(['status' => true, 'updated' => $count]);
}
@@ -356,12 +375,12 @@ class HealthIndiaApiController extends BaseController
{
helper('api');
- log_message('error', "ECARD REQUEST HEALTH_INDIA | Started | employeeId: {$employeeId} | policyNo: {$policyNo} | memberId: {$memberId}");
+ 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);
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
- log_message('error', "ECARD REQUEST FAILED HEALTH_INDIA | employeeId: {$employeeId} | policyNo: {$policyNo} | Message: Token generation failed");
+ log_message('error', "HEALTH_INDIA - Ecard Request | employeeId: {$employeeId} | policyNo: {$policyNo} | Message: Token generation failed");
return null;
}
$token = $tokenResponse['data']['result'][0]['access_token'];
@@ -380,19 +399,19 @@ class HealthIndiaApiController extends BaseController
"Content-Type: application/json"
];
- log_message('error', 'ECARD REQUEST HEALTH_INDIA | Request: ' . json_encode($body));
+ log_message('error', 'HEALTH_INDIA - Ecard Request | Request: ' . json_encode($body));
$response = call_third_party_api($url, 'POST', $headers, $body);
- log_message('error', 'ECARD REQUEST HEALTH_INDIA | Response: ' . json_encode($response));
+ log_message('error', 'HEALTH_INDIA - Ecard Request | Response: ' . json_encode($response));
if (($response['status'] ?? false) !== true) {
- log_message('error', 'ECARD REQUEST FAILED HEALTH_INDIA | response: ' . json_encode($response));
+ log_message('error', 'HEALTH_INDIA - Ecard Request | response: ' . json_encode($response));
return null;
}
if (empty($response['data']['result'][0])) {
- log_message('error', 'ECARD REQUEST FAILED HEALTH_INDIA | Empty data | response: ' . json_encode($response));
+ log_message('error', 'HEALTH_INDIA - Ecard Request | Empty data | response: ' . json_encode($response));
return null;
}
@@ -402,12 +421,12 @@ class HealthIndiaApiController extends BaseController
$ecardUrl = $apiData['membeR_ECARD'] ?? '';
if (!empty($ecardUrl)) {
- log_message('error', "ECARD REQUEST SUCCESS HEALTH_INDIA | employeeId: {$employeeId} | policyNo: {$policyNo} | memberId: {$memberId} | ecardUrl: {$ecardUrl}");
+ log_message('error', "HEALTH_INDIA - Ecard Request | employeeId: {$employeeId} | policyNo: {$policyNo} | memberId: {$memberId} | ecardUrl: {$ecardUrl}");
return $ecardUrl;
}
}
- log_message('error', 'ECARD REQUEST FAILED HEALTH_INDIA | response: ' . json_encode($response));
+ log_message('error', 'HEALTH_INDIA - Ecard Request | response: ' . json_encode($response));
return null;
}
@@ -424,7 +443,7 @@ class HealthIndiaApiController extends BaseController
if (empty($policyNo)) {
- log_message('error', 'TPA ID PULL HEALTH_INDIA | policy_no missing in request');
+ log_message('error', 'HEALTH_INDIA - TPA ID Pull | policy_no missing in request');
if ($function_calling_type == "job") {
return ['status' => false, 'message' => 'policy_no required'];
} else {
@@ -433,7 +452,7 @@ class HealthIndiaApiController extends BaseController
}
if (empty($client_policy_id)) {
- log_message('error', 'TPA ID PULL HEALTH_INDIA | client_policy_id missing in request');
+ log_message('error', 'HEALTH_INDIA - TPA ID Pull | client_policy_id missing in request');
if ($function_calling_type == "job") {
return ['status' => false, 'message' => 'client_policy_id required'];
} else {
@@ -441,7 +460,7 @@ class HealthIndiaApiController extends BaseController
}
}
- log_message('error', "TPA ID PULL HEALTH_INDIA | called for policy_no: {$policyNo}, client_policy_id: {$client_policy_id}");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | called for policy_no: {$policyNo}, client_policy_id: {$client_policy_id}");
// Fetch file download dates
$batchFiles = $this->db->table('batch_files f')
@@ -455,7 +474,7 @@ class HealthIndiaApiController extends BaseController
if (empty($batchFiles)) {
- log_message('error', 'TPA ID PULL FAILED HEALTH_INDIA | batchFiles is empty for this tpa id pull request');
+ log_message('error', 'HEALTH_INDIA - TPA ID Pull FAILED | batchFiles is empty for this tpa id pull request');
if ($function_calling_type == "job") {
return ['status' => false, 'message' => 'batchFiles not found'];
} else {
@@ -466,7 +485,7 @@ class HealthIndiaApiController extends BaseController
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
- log_message('error', 'TPA ID PULL HEALTH_INDIA | Token generation failed');
+ log_message('error', 'HEALTH_INDIA - TPA ID Pull | Token generation failed');
if ($function_calling_type == "job") {
return ['status' => false, 'message' => 'Token generation failed'];
} else {
@@ -487,16 +506,16 @@ class HealthIndiaApiController extends BaseController
"policY_NUMBER" => $policyNo
];
- log_message('error', "TPA ID PULL HEALTH_INDIA | API params: " . json_encode(['url' => $url, 'method' => 'POST', 'body' => $body]));
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | API params: " . json_encode(['url' => $url, 'method' => 'POST', 'body' => $body]));
$response = call_third_party_api($url, 'POST', $headers, $body);
// dd($response);
- log_message('error', "TPA ID PULL HEALTH_INDIA | API Response Received ");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | API Response Received ");
if (($response['status'] ?? false) !== true) {
- log_message('error', 'HEALTH_INDIA API FAILED | response: ' . json_encode($response));
+ log_message('error', 'HEALTH_INDIA - TPA ID Pull API FAILED | response: ' . json_encode($response));
// update file table status after the tpa id failed to update
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
@@ -519,7 +538,7 @@ class HealthIndiaApiController extends BaseController
!is_array($response['data']['result']) ||
count($response['data']['result']) === 0
) {
- log_message('error', 'TPA ID PULL API FAILED HEALTH_INDIA | Empty member data for this pull request');
+ log_message('error', 'HEALTH_INDIA - TPA ID Pull API FAILED | Empty member data for this pull request');
// update file table status after the tpa id failed to update
if (isset($requestData['file_id']) && !empty($requestData['file_id'])) {
@@ -544,7 +563,7 @@ class HealthIndiaApiController extends BaseController
$filePath = WRITEPATH . 'tmp/' . time() . '_' . $requestData['file_id'] . '.json';
file_put_contents($filePath, $json);
- log_message('error', "TPA ID PULL HEALTH_INDIA | Saved JSON to: {$filePath}");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | Saved JSON to: {$filePath}");
// Call a job for dump JSON data to DB
$job_details = new Jobs();
@@ -556,7 +575,7 @@ class HealthIndiaApiController extends BaseController
]
]);
- log_message('error', "TPA ID PULL HEALTH_INDIA | Job added for saving API data");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | Job added for saving API data");
// ================= MATCHING LOGIC =================
@@ -610,9 +629,9 @@ class HealthIndiaApiController extends BaseController
if ($this->db->affectedRows() > 0) {
$updated++;
- log_message('error', "✅ HEALTH_INDIA | Updated tpa_id={$m['memberId']} for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | Updated tpa_id={$m['memberId']} for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
} else {
- log_message('error', "⚠️ HEALTH_INDIA | No update (already set or not matched) for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | No update (already set or not matched) for emp_policy_id={$policy['emp_policy_id']} policy={$policyNo}");
}
}
}
@@ -628,13 +647,13 @@ class HealthIndiaApiController extends BaseController
];
$batch_file_success = 'partially success';
- log_message('error', "❌ HEALTH_INDIA | No match for Nhance = " . json_encode($nhanceSideData));
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | No match for Nhance = " . json_encode($nhanceSideData));
}
}
// Send e-card
if (!empty($employee_policy_ids)) {
- log_message('error', "HEALTH_INDIA | sendMailForDownloadingECard JOB PUSHED.");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull | sendMailForDownloadingECard JOB PUSHED.");
Jobs::addJob([
'job_name' => 'sendMailForDownloadingECard',
'payload' => [
@@ -655,7 +674,7 @@ class HealthIndiaApiController extends BaseController
$totalCount = count($allMembers);
- log_message('error', "TPA ID PULL SUCCESS HEALTH_INDIA | completed. Total fetched={$totalCount}, updated={$updated}");
+ log_message('error', "HEALTH_INDIA - TPA ID Pull SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
if ($function_calling_type == "job") {
return [
@@ -707,13 +726,13 @@ class HealthIndiaApiController extends BaseController
{
helper('api');
- log_message('error', 'SYNC CLAIMS HEALTH_INDIA | Started');
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Started');
// Generate Health India Token
$tokenResponse = json_decode($this->generateAuthToken()->getBody(), true);
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
- log_message('error', 'SYNC CLAIMS FAILED HEALTH_INDIA | Token generation failed');
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims FAILED | Token generation failed');
return $this->response->setJSON(['status' => false, 'message' => 'Token generation failed']);
}
@@ -737,17 +756,17 @@ class HealthIndiaApiController extends BaseController
"policY_NUMBER" => $policy['policy_no']
];
- log_message('error', 'SYNC CLAIMS HEALTH_INDIA | Fetching for policy: ' . $policy['policy_no']);
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Fetching for policy: ' . $policy['policy_no']);
$response = call_third_party_api($url, 'POST', $headers, $body);
if (!empty($response['data']['result'])) {
$finalResult = array_merge($finalResult, $response['data']['result']);
- log_message('error', 'SYNC CLAIMS HEALTH_INDIA | Fetched ' . count($response['data']['result']) . ' claims for policy: ' . $policy['policy_no']);
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Fetched ' . count($response['data']['result']) . ' claims for policy: ' . $policy['policy_no']);
}
}
- log_message('error', 'SYNC CLAIMS HEALTH_INDIA | Total claims fetched: ' . count($finalResult));
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Total claims fetched: ' . count($finalResult));
// Insert / update ticket_master
$insertedCount = 0;
@@ -786,13 +805,13 @@ class HealthIndiaApiController extends BaseController
'created_at' => date('Y-m-d H:i:s')
]);
$insertedCount++;
- log_message('error', 'SYNC CLAIMS HEALTH_INDIA | Inserted claim: ' . ($row['CLAIM_NUMBER'] ?? 'N/A'));
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Inserted claim: ' . ($row['CLAIM_NUMBER'] ?? 'N/A'));
} else {
- log_message('error', 'SYNC CLAIMS HEALTH_INDIA | Skipped existing claim: ' . ($row['CLAIM_NUMBER'] ?? 'N/A'));
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Skipped existing claim: ' . ($row['CLAIM_NUMBER'] ?? 'N/A'));
}
}
- log_message('error', 'SYNC CLAIMS HEALTH_INDIA | Completed | Total: ' . count($finalResult) . ' | Inserted: ' . $insertedCount);
+ log_message('error', 'HEALTH_INDIA - Sync TPA Claims | Completed | Total: ' . count($finalResult) . ' | Inserted: ' . $insertedCount);
return $this->response->setJSON([
'status' => true,
@@ -800,4 +819,48 @@ class HealthIndiaApiController extends BaseController
'inserted' => $insertedCount
]);
}
+
+ public function saveHealthIndiaAPIData($array)
+ {
+ $file_id = $array['file_id'];
+ $json = file_get_contents($array['json_file_path']);
+ $records = json_decode($json, true);
+ // log_message('error','HEALTH_INDIA - saveHealthIndiaAPIData' . json_encode($array));//die();
+ $file_model = new BatchFileModel();
+ $file_info = $file_model->where('id', $file_id)->find();
+
+ $tpaApiDataModel = new TpaApiDataModel();
+
+ //deactivate old data
+ $tpaApiDataModel->set('is_active', 0)->where('file_id', $file_id)->update();
+
+ //covert tpa data to our model data
+ $mappedRows = [];
+
+ foreach ($records as $row) {
+
+ $mappedRows[] = [
+ 'file_id' => $file_id, // ← pass from controller
+ 'emp_code' => trim($row['employeeCode'] ?? ''),
+
+ 'name' => trim($row['insured_Name'] ?? ''),
+ 'dob' => !empty($row['dateOfBirth'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $row['dateOfBirth']))) : null,
+
+ 'relation' => map_relationship(trim($row['relation'] ?? null)),
+ 'gender' => strtoupper($row['gender'] ?? null),
+ 'self' => map_relationship(trim($row['relation'] ?? null)) === 'self' ? 1 : 0,
+
+ 'tpa_id' => trim($row['memberId'] ?? null),
+ 'age' => is_numeric($row['age'] ?? null) ? (int) $row['age'] : null,
+
+ 'is_active' => 1,
+ 'created_by' => $file_info[0]['created_by'] ?? null,
+ ];
+ }
+ // log_message('error','HEALTH_INDIA - COUNT' . count($mappedRows));
+ // print_rr($mappedRows);//die();
+ $result = $tpaApiDataModel->insertBatchWithChunkLog($mappedRows,500,('FILE_ID_'.$file_id));
+ // unlink($file_array['json_file_path']); // delete temp json file
+ }
+
}
\ No newline at end of file
diff --git a/app/Controllers/JobWorker.php b/app/Controllers/JobWorker.php
index 11338171..9aba4443 100755
--- a/app/Controllers/JobWorker.php
+++ b/app/Controllers/JobWorker.php
@@ -191,14 +191,26 @@ class JobWorker extends AdminController
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\VidalApiController',
],
+ 'saveVidalAPIData' => [
+ 'type' => 'CC', // Handler Category
+ 'handler' => 'App\Controllers\VidalApiController',
+ ],
'FhplGetBenefDetails' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\FhplApiController',
],
+ 'saveFhplAPIData' => [
+ 'type' => 'CC', // Handler Category
+ 'handler' => 'App\Controllers\FhplApiController',
+ ],
'HealthIndiaGetBenefDetails' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\HealthIndiaApiController',
],
+ 'saveHealthIndiaAPIData' => [
+ 'type' => 'CC', // Handler Category
+ 'handler' => 'App\Controllers\HealthIndiaApiController',
+ ],
'bdsDumpExcelFileFormatValidation' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\PolicyTransactionController',
@@ -207,22 +219,23 @@ class JobWorker extends AdminController
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\PolicyTransactionController',
],
- 'initiateWellnessOnboardJob' => [
+ 'initiateWellnessOnboardJob' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\EmployeeController',
- ], 'saveMediAssitAPIData' => [
+ ],
+ 'saveMediAssitAPIData' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\MediAssistApiController',
],
- 'bulkGenerateEcardAndStoreinS3' => [
+ 'bulkGenerateEcardAndStoreinS3' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\EmployeeController',
- ],
- 'bulkEcardDownloadAsZipFromS3' => [
+ ],
+ 'bulkEcardDownloadAsZipFromS3' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\EmployeeController',
- ],
- 'getEmployeeEcardFromTmpFolderAndZipToS3' => [
+ ],
+ 'getEmployeeEcardFromTmpFolderAndZipToS3' => [
'type' => 'CC', // Handler Category
'handler' => 'App\Controllers\EmployeeController',
]
diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php
index b826c277..b4eaac06 100644
--- a/app/Controllers/LeadsController.php
+++ b/app/Controllers/LeadsController.php
@@ -4319,27 +4319,27 @@ class LeadsController extends BaseController
}
}
- public function getLastFiveFinancialYears()
+ public function getLastFiveFinancialYears(): array
{
- $currentYear = date('Y');
- $currentMonth = date('m');
+ $year = (int) date('Y');
+ $month = (int) date('m');
+ // $month = (int) 5;
- // In India, the financial year starts from April (04)
- if ($currentMonth < 4) {
- $currentYear--; // Adjust year if it's Jan-Mar
- }
+ // Financial year starts in April
+ $currentFYStart = ($month >= 4) ? $year : $year - 1;
$financialYears = [];
- for ($i = 0; $i < 5; $i++) {
- $startYear = $currentYear - $i - 1;
- $endYear = $currentYear - $i;
- $financialYears[] = "$startYear-$endYear";
+ for ($i = 0; $i < 6; $i++) {
+ $startYear = $currentFYStart - $i;
+ $endYear = $startYear + 1;
+ $financialYears[] = "{$startYear}-{$endYear}";
}
return $financialYears;
}
+
// ------------ RFQ NON EB FUNCTIONS-----------------------------------------------------------------------------------------
public function rfqNonEB()
diff --git a/app/Controllers/LogController.php b/app/Controllers/LogController.php
index 99652ff3..980ed5f5 100644
--- a/app/Controllers/LogController.php
+++ b/app/Controllers/LogController.php
@@ -1,259 +1,146 @@
logPath = WRITEPATH . 'logs/';
- $this->session = session();
}
- /**
- * Display list of all log files
- */
public function index()
{
-
- $logFiles = $this->getLogFiles();
-
$data = [
- 'title' => 'Log Files',
- 'logFiles' => $logFiles
+ 'title' => 'Log Files',
+ 'logFiles' => $this->getLogFiles()
];
-
- return $this->loadLayout('logs/index', $data);
-
- // return view('logs/index', $data);
+ return view('logs/index', $data);
+ }
+
+ public function view($filename = null)
+ {
+ if (!$filename) return redirect()->to('/logs');
+
+ $filename = basename($filename);
+ $filePath = $this->logPath . $filename;
+
+ if (!file_exists($filePath)) return redirect()->to('/logs');
+
+ $db = \Config\Database::connect();
+
+ // 1. Fetch TPA List for the first row of tabs
+ $tpaConfigs = $db->table('tpa_log_config')->get()->getResultArray();
+
+ // 2. Dynamically get Action buttons from table columns
+ $allColumns = $db->getFieldNames('tpa_log_config');
+ $dynamicKeys = [];
+ foreach ($allColumns as $column) {
+ if ($column !== 'tpa_name') {
+ // Formatting: 'claim_push_key' -> 'Claim Push'
+ $label = str_replace(['_key', '_'], ['', ' '], $column);
+ $dynamicKeys[$column] = ucwords($label);
+ }
+ }
+
+ $selectedTpa = $this->request->getGet('tpa');
+ $selectedKey = $this->request->getGet('key');
+ $searchTerm = $this->request->getGet('search');
+
+ // Parse logs with current filters
+ $logEntries = $this->parseLogFileOptimized($filePath, $tpaConfigs, $selectedTpa, $selectedKey, $searchTerm);
+
+ // Date Pagination
+ $prevFile = $nextFile = null;
+ if (preg_match('/log-(\d{4}-\d{2}-\d{2})\.log/', $filename, $match)) {
+ $currentDate = $match[1];
+ $prevD = date('Y-m-d', strtotime('-1 day', strtotime($currentDate)));
+ $nextD = date('Y-m-d', strtotime('+1 day', strtotime($currentDate)));
+ if (file_exists($this->logPath . "log-$prevD.log")) $prevFile = "log-$prevD.log";
+ if (file_exists($this->logPath . "log-$nextD.log")) $nextFile = "log-$nextD.log";
+ }
+
+ $data = [
+ 'title' => 'TPA Logs: ' . $filename,
+ 'filename' => $filename,
+ 'logEntries' => $logEntries,
+ 'tpaConfigs' => $tpaConfigs,
+ 'dynamicKeys' => $dynamicKeys, // Dynamic Buttons
+ 'selectedTpa' => $selectedTpa,
+ 'selectedKey' => $selectedKey,
+ 'searchTerm' => $searchTerm,
+ 'prevFile' => $prevFile,
+ 'nextFile' => $nextFile
+ ];
+
+ return view('logs/view', $data);
+ }
+
+ private function parseLogFileOptimized($path, $configs, $tpaName, $keyType, $searchTerm)
+ {
+ $entries = [];
+ $handle = fopen($path, 'r');
+ if (!$handle) return [];
+
+ $filters = [];
+ if ($tpaName) {
+ $filters[] = $tpaName;
+ if ($keyType) {
+ foreach ($configs as $conf) {
+ if ($conf['tpa_name'] === $tpaName && isset($conf[$keyType])) {
+ $filters[] = $conf[$keyType];
+ }
+ }
+ }
+ }
+ if ($searchTerm) $filters[] = $searchTerm;
+
+ $currentEntry = null;
+ while (($line = fgets($handle)) !== false) {
+ if (preg_match('/^(\w+)\s*-\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s*-->\s*(.*)$/', $line, $matches)) {
+ if ($currentEntry && $this->matchesFilters($currentEntry['message'], $filters)) {
+ $entries[] = $currentEntry;
+ }
+ $currentEntry = ['level' => $matches[1], 'date' => $matches[2], 'message' => $matches[3]];
+ } elseif ($currentEntry !== null && trim($line) !== '') {
+ $currentEntry['message'] .= "\n" . $line;
+ }
+ }
+ if ($currentEntry && $this->matchesFilters($currentEntry['message'], $filters)) $entries[] = $currentEntry;
+
+ fclose($handle);
+ return array_reverse($entries);
+ }
+
+ private function matchesFilters($message, $filters)
+ {
+ if (empty($filters)) return false;
+ foreach ($filters as $f) {
+ if (stripos($message, $f) === false) return false;
+ }
+ return true;
}
- /**
- * Get all log files sorted by date (latest first)
- */
private function getLogFiles()
{
$files = [];
-
- if (!is_dir($this->logPath)) {
- return $files;
- }
-
+ if (!is_dir($this->logPath)) return $files;
$iterator = new \DirectoryIterator($this->logPath);
-
foreach ($iterator as $fileInfo) {
if ($fileInfo->isFile() && $fileInfo->getExtension() === 'log') {
$files[] = [
'name' => $fileInfo->getFilename(),
- 'path' => $fileInfo->getPathname(),
- 'size' => $this->formatBytes($fileInfo->getSize()),
- 'modified' => $fileInfo->getMTime(),
- 'modified_date' => date('Y-m-d H:i:s', $fileInfo->getMTime())
+ 'size' => round($fileInfo->getSize() / 1024, 2) . ' KB',
+ 'modified_date' => date('Y-m-d H:i:s', $fileInfo->getMTime()),
+ 'ts' => $fileInfo->getMTime()
];
}
}
-
- // Sort by modified time (latest first)
- usort($files, function($a, $b) {
- return $b['modified'] - $a['modified'];
- });
-
+ usort($files, fn($a, $b) => $b['ts'] - $a['ts']);
return $files;
}
-
- /**
- * View specific log file content
- */
- public function view($filename = null)
- {
-
-
-
- if (!$filename) {
- return redirect()->to('/logs')->with('error', 'No log file specified');
- }
-
- // Security: prevent directory traversal
- $filename = basename($filename);
- $filePath = $this->logPath . $filename;
-
- if (!file_exists($filePath)) {
- return redirect()->to('/logs')->with('error', 'Log file not found');
- }
-
- // ✅ extract date from filename: log-YYYY-MM-DD.log
- if (preg_match('/log-(\d{4}-\d{2}-\d{2})\.log/', $filename, $match)) {
- $currentDate = $match[1];
-
- $prevDate = date('Y-m-d', strtotime('-1 day', strtotime($currentDate)));
- $nextDate = date('Y-m-d', strtotime('+1 day', strtotime($currentDate)));
-
- $prevFile = "log-$prevDate.log";
- $nextFile = "log-$nextDate.log";
-
- $prevExists = file_exists($this->logPath . $prevFile);
- $nextExists = file_exists($this->logPath . $nextFile);
- }
-
- // Read log file content
- $content = file_get_contents($filePath);
- $logEntries = $this->parseLogFile($content);
-
- $data = [
- 'title' => 'View Log: ' . $filename,
- 'filename' => $filename,
- 'logEntries' => $logEntries,
- 'prevFile' => $prevExists ? $prevFile : null,
- 'nextFile' => $nextExists ? $nextFile : null,
- 'fileSize' => $this->formatBytes(filesize($filePath)),
- 'lastModified' => date('Y-m-d H:i:s', filemtime($filePath))
- ];
-
- // print_r( $data); die;
-
- return $this->loadLayout('logs/view', $data);
- // return view('logs/view', $data);
- }
-
- /**
- * Parse log file into structured array
- */
-
- private function parseLogFile($content)
- {
- $entries = [];
- $lines = explode("\n", $content);
-
- $currentEntry = null;
-
- // Messages to filter out
- $skipPatterns = [
- '/Session: Class initialized using/',
- '/Session class already loaded/',
- ];
-
- foreach ($lines as $line) {
- // Match CI4 log format: LEVEL - date --> message
- if (preg_match('/^(\w+)\s*-\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s*-->\s*(.*)$/', $line, $matches)) {
-
- // Save previous entry if exists (before checking skip)
- if ($currentEntry !== null) {
- $entries[] = $currentEntry;
- $currentEntry = null;
- }
-
- // Check if this message should be skipped
- $shouldSkip = false;
- foreach ($skipPatterns as $pattern) {
- if (preg_match($pattern, $matches[3])) {
- $shouldSkip = true;
- break;
- }
- }
-
- if ($shouldSkip) {
- continue;
- }
-
- // Start new entry
- $currentEntry = [
- 'level' => $matches[1],
- 'date' => $matches[2],
- 'message' => $matches[3]
- ];
- } elseif ($currentEntry !== null && trim($line) !== '') {
- // Continuation of previous message
- $currentEntry['message'] .= "\n" . $line;
- }
- }
-
- // Add last entry
- if ($currentEntry !== null) {
- $entries[] = $currentEntry;
- }
-
- return array_reverse($entries); // Latest first
- }
-
- /**
- * Download log file
- */
- public function download($filename = null)
- {
- if (!$filename) {
- return redirect()->to('/logs')->with('error', 'No log file specified');
- }
-
- $filename = basename($filename);
- $filePath = $this->logPath . $filename;
-
- if (!file_exists($filePath)) {
- return redirect()->to('/logs')->with('error', 'Log file not found');
- }
-
- return $this->response->download($filePath, null);
- }
-
- /**
- * Delete log file
- */
- public function delete($filename = null)
- {
- if (!$filename) {
- return redirect()->to('/logs')->with('error', 'No log file specified');
- }
-
- $filename = basename($filename);
- $filePath = $this->logPath . $filename;
-
- if (!file_exists($filePath)) {
- return redirect()->to('/logs')->with('error', 'Log file not found');
- }
-
- if (unlink($filePath)) {
- return redirect()->to('/logs')->with('success', 'Log file deleted successfully');
- } else {
- return redirect()->to('/logs')->with('error', 'Failed to delete log file');
- }
- }
-
- /**
- * Format bytes to human readable format
- */
- private function formatBytes($bytes, $precision = 2)
- {
- $units = ['B', 'KB', 'MB', 'GB', 'TB'];
-
- $bytes = max($bytes, 0);
- $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
- $pow = min($pow, count($units) - 1);
-
- $bytes /= pow(1024, $pow);
-
- return round($bytes, $precision) . ' ' . $units[$pow];
- }
-
- /**
- * Clear all log files
- */
- public function clearAll()
- {
- $logFiles = $this->getLogFiles();
- $deleted = 0;
-
- foreach ($logFiles as $file) {
- if (unlink($file['path'])) {
- $deleted++;
- }
- }
-
- return redirect()->to('/logs')->with('success', $deleted . ' log file(s) deleted successfully');
- }
}
\ No newline at end of file
diff --git a/app/Controllers/MediAssistApiController.php b/app/Controllers/MediAssistApiController.php
index 0452c797..26b82ce1 100644
--- a/app/Controllers/MediAssistApiController.php
+++ b/app/Controllers/MediAssistApiController.php
@@ -130,14 +130,14 @@ class MediAssistApiController extends BaseController
// ]
// ];
- log_message('error', 'TPA CLAIM PUSH | claimId: '.$claimId.' | payload: '.json_encode($body));
+ log_message('error','MEDI_ASSIST - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
$response = call_third_party_api($url, $method, $headers, $body);
if($response['status'] != true){
- log_message('error', 'TPA CLAIM PUSH FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
+ log_message('error','MEDI_ASSIST - Claim Push FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
$this->db->table('ticket_master')
->where('id',$claimId)
->update([ 'tpa_push_response' => json_encode($response) ]);
@@ -150,7 +150,7 @@ class MediAssistApiController extends BaseController
if(!empty($claimRef)){
- log_message('error', 'TPA CLAIM PUSH SUCCESS | claimId: '.$claimId.' | claimReferenceNo: '.$claimRef);
+ log_message('error','MEDI_ASSIST - Claim Push SUCCESS | claimId: '.$claimId.' | claimReferenceNo: '.$claimRef);
$this->db->table('ticket_master')
->where('id',$claimId)
@@ -159,7 +159,7 @@ class MediAssistApiController extends BaseController
return;
} else {
- log_message('error', 'TPA CLAIM PUSH API SUCCESS BUT claimReferenceNo EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
+ log_message('error','MEDI_ASSIST - Claim Push API Failed | claimReferenceNo EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
return;
}
@@ -193,17 +193,17 @@ class MediAssistApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
if($response['status'] != true){
- log_message('error', 'Ecard Request FAILED | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
+ log_message('error','MEDI_ASSIST - Ecard Request FAILED | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
return null;
}
$ecardUrl = $response['data']['ecardUrl'] ?? null;
if(!empty($ecardUrl)){
- log_message('error', 'Ecard Request PUSH SUCCESS | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | ecardUrl: '.$ecardUrl);
+ log_message('error','MEDI_ASSIST - Ecard Request PUSH SUCCESS | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | ecardUrl: '.$ecardUrl);
return $ecardUrl;
} else {
- log_message('error', 'Ecard Request SUCCESS BUT ecardUrl EMPTY | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
+ log_message('error','MEDI_ASSIST - Ecard Request SUCCESS BUT ecardUrl EMPTY | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
return null;
}
@@ -242,7 +242,7 @@ class MediAssistApiController extends BaseController
$client_policy_id = $requestData['client_policy_id'] ?? null;
if (empty($policyNo)) {
- log_message('error', 'TPA ID PULL | policy_no missing in request');
+ log_message('error','MEDI_ASSIST - TPA ID Pull | policy_no missing in request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'policy_no required'];
}else{
@@ -251,7 +251,7 @@ class MediAssistApiController extends BaseController
}
if (empty($client_policy_id)) {
- log_message('error', 'TPA ID PULL | client_policy_id missing in request');
+ log_message('error','MEDI_ASSIST - TPA ID Pull | client_policy_id missing in request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'client_policy_id required'];
}else{
@@ -259,7 +259,7 @@ class MediAssistApiController extends BaseController
}
}
- log_message('error', "TPA ID PULL | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
+ log_message('error',"MEDI_ASSIST - TPA ID Pull | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
$employeePolicyModel = new EmployeePolicyModel();
$employeePolicyData = $employeePolicyModel
@@ -278,7 +278,7 @@ class MediAssistApiController extends BaseController
->findAll();
if (empty($employeePolicyData)) {
- log_message('error', 'TPA ID PULL FAILED | employeePolicyData is empty (tpa_id IS NULL from nhance) for this tpa id pull request');
+ log_message('error','MEDI_ASSIST - 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'];
}else{
@@ -301,8 +301,8 @@ class MediAssistApiController extends BaseController
"employeeId" => ""
];
- log_message('error', "TPA ID PULL | API Request (startIndex={$startIndex}): " . json_encode($body));
- log_message('error', "TPA ID PULL | API parems " . json_encode([$url, $method, $headers, $body]));
+ log_message('error',"MEDI_ASSIST - TPA ID Pull | API Request (startIndex={$startIndex}): " . json_encode($body));
+ log_message('error',"MEDI_ASSIST - TPA ID Pull | API parems " . json_encode([$url, $method, $headers, $body]));
$response = call_third_party_api($url, $method, $headers, $body);
@@ -312,12 +312,12 @@ class MediAssistApiController extends BaseController
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', "Files table status updated for the file id : {$requestData['file_id']}");
+ log_message('error',"MEDI_ASSIST - Files table status updated for the file id : {$requestData['file_id']}");
} else {
- log_message('error', "Failed to update file table status.");
+ log_message('error',"MEDI_ASSIST - Failed to update file table status.");
}
- log_message('error', 'TPA ID PULL API FAILED | API failed: ' . json_encode($response));
+ log_message('error','MEDI_ASSIST - TPA ID Pull API FAILED | API failed: ' . json_encode($response));
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'API call failed', 'data' => $response];
@@ -329,7 +329,7 @@ class MediAssistApiController extends BaseController
$data = $response['data'] ?? [];
if (!isset($data['benefDetails'])) {
- log_message('error', "TPA ID PULL FAILED |: 'benefDetails' missing in API response: " . json_encode($data));
+ log_message('error',"MEDI_ASSIST - TPA ID Pull FAILED |: 'benefDetails' missing in API response: " . json_encode($data));
break;
}
@@ -337,7 +337,7 @@ class MediAssistApiController extends BaseController
$totalCount = $count;
$fetchedCount = count($data['benefDetails']);
- log_message('error', "Fetched {$fetchedCount} records (startIndex={$startIndex}) of total {$count}");
+ log_message('error',"MEDI_ASSIST - Fetched {$fetchedCount} records (startIndex={$startIndex}) of total {$count}");
$allBenef = array_merge($allBenef, $data['benefDetails']);
@@ -376,7 +376,7 @@ class MediAssistApiController extends BaseController
$hasMatchForThisPolicy = true;
- // log_message('error', "✅ Match found: emp_code={$row['priBenefEmpCode']} policy={$row['polNo']}");
+ // log_message('error',"MEDI_ASSIST - ✅ Match found: emp_code={$row['priBenefEmpCode']} policy={$row['polNo']}");
$sql = "UPDATE employee_polices
SET tpa_id = ?
@@ -390,9 +390,9 @@ class MediAssistApiController extends BaseController
if ($this->db->affectedRows() > 0) {
$updated++;
- log_message('error', "✅ Updated tpa_id={$row['benefMediAssistID']} for emp_code={$row['priBenefEmpCode']} policy={$row['polNo']}");
+ log_message('error',"MEDI_ASSIST - ✅ Updated tpa_id={$row['benefMediAssistID']} for emp_code={$row['priBenefEmpCode']} policy={$row['polNo']}");
} else {
- log_message('error', "⚠️ No update (already set or not matched) for emp_code={$row['priBenefEmpCode']} policy={$row['polNo']}");
+ log_message('error',"MEDI_ASSIST - ⚠️ No update (already set or not matched) for emp_code={$row['priBenefEmpCode']} policy={$row['polNo']}");
}
}
@@ -423,7 +423,7 @@ class MediAssistApiController extends BaseController
// send e-card
if(!empty($employee_policy_ids)){
- log_message('error', "sendMailForDownloadingECard JOB PUSHED.");
+ log_message('error',"MEDI_ASSIST - sendMailForDownloadingECard JOB PUSHED.");
Jobs::addJob(['job_name' => 'sendMailForDownloadingECard', 'payload' => ['ids' => $employee_policy_ids, 'client_policy_id' => $client_policy_id]]);
}
@@ -432,13 +432,13 @@ class MediAssistApiController extends BaseController
$file_model = new BatchFileModel();
$file_model->where('id', $requestData['file_id'])->set('status', $batch_file_success)->update();
- log_message('error', "Files table status updated for the file id : {$requestData['file_id']}");
+ log_message('error',"MEDI_ASSIST - Files table status updated for the file id : {$requestData['file_id']}");
} else {
- log_message('error', "Failed to update file table status.");
+ log_message('error',"MEDI_ASSIST - Failed to update file table status.");
}
- log_message('error', "TPA ID PULL SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
+ log_message('error',"MEDI_ASSIST - TPA ID Pull SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
if($function_calling_type == "job"){
return [
@@ -462,9 +462,9 @@ class MediAssistApiController extends BaseController
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', "Files table status updated for the file id : {$requestData['file_id']}");
+ log_message('error',"MEDI_ASSIST - Files table status updated for the file id : {$requestData['file_id']}");
} else {
- log_message('error', "Failed to update file table status.");
+ log_message('error',"MEDI_ASSIST - Failed to update file table status.");
}
$errorData = [
@@ -478,7 +478,7 @@ class MediAssistApiController extends BaseController
'class' => $th->getTrace()[0]['class'] ?? null,
];
- log_message('error', 'Exception thrown while calling GetBenefDetails API: ' . json_encode($errorData));
+ log_message('error','MEDI_ASSIST - Exception thrown while calling GetBenefDetails API: ' . json_encode($errorData));
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'API call failed', 'data' => $errorData];
}else{
@@ -506,6 +506,8 @@ class MediAssistApiController extends BaseController
tm.id,
tm.tpa_no as memberId,
tm.tpa_claim_push_reference_no as claimRefNo,
+ tm.tpa_claim_id,
+ tm.claim_number,
cp.policy_no as policyNo,
cp.policy_start_date as startDate,
cp.policy_end_date as endDate,
@@ -521,6 +523,7 @@ class MediAssistApiController extends BaseController
return ['status' => false,'message' => 'Invalid Claim ID' ];
}
+
// REQUEST BODY
if($ticket['claimRefNo'] != null)
{
@@ -564,15 +567,17 @@ class MediAssistApiController extends BaseController
if ($response['status'] != true || empty($response['data']['claimsData'][0])) {
- log_message('error', 'CLAIM STATUS FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
+ log_message('error','MEDI_ASSIST - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
return ['status' => false,'message' => 'API call failed.','data' => $response ];
}
- // Extract claim status
+ // Extract Claim Status
$claimData = $response['data']['claimsData'][0];
$currentStatus = $claimData['claim_Current_Status'] ?? '';
$tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? '';
+ $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? '';
+ $tpa_ailments = ($claimData['ailment'] ?? '') . ' - ' . ($claimData['ailmenT_DESC'] ?? '');
// VALID STATUS LIST
$validStatuses = [
@@ -613,27 +618,40 @@ class MediAssistApiController extends BaseController
"DENIAL REVIEW AWAITED" => 66,
];
+ $updateArray = [
+ 'tpa_claim_status' => $currentStatus,
+ 'updated_at' => date('Y-m-d H:i:s'),
+ ];
- // Maping tpa claim status with local claim Status
- if (isset($validStatuses[$currentStatus]))
- {
- $updateArray = ['claim_status_id' => $validStatuses[$currentStatus] , 'tpa_claim_status' => $currentStatus , 'tpa_claim_id' => $tpa_claim_no, 'claim_number' => $tpa_claim_no, 'updated_at' => date('Y-m-d H:i:s')];
- }else{
- $updateArray = ['tpa_claim_status' => $currentStatus , 'tpa_claim_id' => $tpa_claim_no, 'claim_number' => $tpa_claim_no , 'updated_at' => date('Y-m-d H:i:s')];
+ if (isset($validStatuses[$currentStatus])) {
+ $updateArray['claim_status_id'] = $validStatuses[$currentStatus];
}
+ if (empty($ticket['tpa_claim_id']) || $ticket['tpa_claim_id'] === null) {
+ $updateArray['tpa_claim_id'] = $tpa_claim_no;
+ }
+ if (empty($ticket['claim_number']) || $ticket['claim_number'] === null) {
+ $updateArray['claim_number'] = $tpa_claim_no;
+ }
+ if (!empty($tpa_claim_type)) {
+ $updateArray['tpa_claim_type'] = $tpa_claim_type;
+ }
+ if (!empty($tpa_ailments)) {
+ $updateArray['tpa_ailments'] = $tpa_ailments;
+ }
+
// UPDATE ticket_master
$this->db->table('ticket_master')->where('id', $claimId)->update($updateArray);
// LOG UPDATE
- log_message('error', "CLAIM STATUS SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
+ log_message('error',"MEDI_ASSIST - Claim Status SUCCESS | Updated ticket ID $claimId with Claim Status: $currentStatus");
- return ['status' => true,'message' => 'Claim status updated.','updated_status' => $currentStatus,'api_response' => $response];
+ return ['status' => true,'message' => 'Claim Status updated.','updated_status' => $currentStatus,'api_response' => $response];
}
public function IRSubmission($claimId = null) // 585 this id for test
{
- log_message('error', "IRSubmission INIT for ticket_id={$claimId}");
+ log_message('error',"MEDI_ASSIST - IR Submission | INIT for ticket_id={$claimId}");
// 1. FETCH TICKET DETAILS
$ticket = $this->db->table('ticket_master tm')
@@ -654,7 +672,7 @@ class MediAssistApiController extends BaseController
->getRowArray();
if (!$ticket || empty($ticket['ClaimID'])) {
- log_message('error', "IRSubmission FAILED → ClaimID NOT FOUND for ticket_id={$claimId}");
+ log_message('error',"MEDI_ASSIST - IR Submission FAILED → ClaimID NOT FOUND for ticket_id={$claimId}");
return [
'status' => false,
@@ -683,17 +701,17 @@ class MediAssistApiController extends BaseController
$downloadUrl = base_url('fileDownload?file_path=') . $fileDir;
} else {
$downloadUrl = "";
- log_message('error', "File NOT FOUND on server → {$fileDir}");
+ log_message('error',"MEDI_ASSIST - IR Submission File NOT FOUND on server → {$fileDir}");
}
- log_message('error', "IRSubmission Attachment Ready: {$filename} | URL={$downloadUrl}");
+ log_message('error',"MEDI_ASSIST - IR Submission Attachment Ready: {$filename} | URL={$downloadUrl}");
$Attachments[] = [
"AttachmentName" => $filename,
"AttachmentPath" => $downloadUrl
];
} else {
- log_message('error', "IRSubmission Missing File URL → file_id={$file['id']}");
+ log_message('error',"MEDI_ASSIST - IR Submission Missing File URL → file_id={$file['id']}");
}
}
}
@@ -704,7 +722,7 @@ class MediAssistApiController extends BaseController
"Attachments" => $Attachments
];
- log_message('error', "IRSubmission Request Body => " . json_encode($body));
+ log_message('error',"MEDI_ASSIST - IR Submission Request Body => " . json_encode($body));
// 4. SEND API CALL
helper('api');
@@ -720,13 +738,13 @@ class MediAssistApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
- log_message('error', "IRSubmission API Response => " . json_encode($response));
+ log_message('error',"MEDI_ASSIST - IR Submission API Response => " . json_encode($response));
// 5. HANDLE RESPONSE
if (!$response['status']) {
log_message(
'error',
- "IRSubmission FAILED for ClaimID={$ticket['ClaimID']} → Response=" . json_encode($response)
+ "MEDI_ASSIST - IR Submission FAILED for ClaimID={$ticket['ClaimID']} → Response=" . json_encode($response)
);
return [
@@ -736,7 +754,7 @@ class MediAssistApiController extends BaseController
];
}
- log_message('error', "IRSubmission SUCCESS → ClaimID={$ticket['ClaimID']}");
+ log_message('error',"MEDI_ASSIST - IR Submission SUCCESS → ClaimID={$ticket['ClaimID']}");
return [
'status' => true,
@@ -750,7 +768,7 @@ class MediAssistApiController extends BaseController
$file_id = $array['file_id'];
$json = file_get_contents($array['json_file_path']);
$records = json_decode($json, true);
- // log_message('error','saveMediAssitAPIData' . json_encode($array));//die();
+ // log_message('error','MEDI_ASSIST - saveMediAssitAPIData' . json_encode($array));//die();
$file_model = new BatchFileModel();
$file_info = $file_model->where('id', $file_id)->find();
// dd($file_info);
@@ -787,7 +805,7 @@ class MediAssistApiController extends BaseController
'created_by' => $file_info[0]['created_by'] ?? null,
];
}
- // log_message('error','COUNT' . count($mappedRows));
+ // log_message('error','MEDI_ASSIST - COUNT' . count($mappedRows));
// print_rr($mappedRows);//die();
$result = $tpaApiDataModel->insertBatchWithChunkLog($mappedRows,500,('FILE_ID_'.$file_id));
// unlink($file_array['json_file_path']); // delete temp json file
@@ -829,7 +847,7 @@ class MediAssistApiController extends BaseController
// dd($TicketData);
if (!$TicketData) {
- log_message('error', "Claims not found to update status");
+ log_message('error',"MEDI_ASSIST - Claims not found to update Claim Status");
return $this->response->setJSON(['status' => false,'message' => 'Claims not found' ]);
}
@@ -871,14 +889,16 @@ class MediAssistApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
if ($response['status'] != true || empty($response['data']['claimsData'][0])) {
- log_message('error', 'CLAIM STATUS FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
+ log_message('error','MEDI_ASSIST - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
$error_data[$claimId][['status' => false,'message' => 'API call failed.','data' => $response]];
}
- // Extract claim status
+ // Extract Claim Status
$claimData = $response['data']['claimsData'][0];
$currentStatus = $claimData['claim_Current_Status'] ?? '';
$tpa_claim_no = $claimData['tpA_CLAIM_NO'] ?? '';
+ $tpa_claim_type = $claimData['typE_OF_CLAIM'] ?? '';
+ $tpa_ailments = ($claimData['ailment'] ?? '') . ' - ' . ($claimData['ailmenT_DESC'] ?? '');
// VALID STATUS LIST
$validStatuses = [
@@ -920,12 +940,20 @@ class MediAssistApiController extends BaseController
"DENIAL REVIEW AWAITED" => 66,
];
- // Maping tpa claim status with local claim Status
- if (isset($validStatuses[$currentStatus]))
- {
- $updateArray = ['claim_status_id' => $validStatuses[$currentStatus] , 'tpa_claim_status' => $currentStatus , 'tpa_claim_id' => $tpa_claim_no , 'claim_number' => $tpa_claim_no , 'updated_at' => date('Y-m-d H:i:s')];
- }else{
- $updateArray = ['tpa_claim_status' => $currentStatus , 'tpa_claim_id' => $tpa_claim_no , 'claim_number' => $tpa_claim_no, 'updated_at' => date('Y-m-d H:i:s')];
+ $updateArray = [
+ 'tpa_claim_status' => $currentStatus,
+ 'tpa_claim_id' => $tpa_claim_no,
+ 'claim_number' => $tpa_claim_no,
+ 'updated_at' => date('Y-m-d H:i:s'),
+ ];
+ if (isset($validStatuses[$currentStatus])) {
+ $updateArray['claim_status_id'] = $validStatuses[$currentStatus];
+ }
+ if (!empty($tpa_claim_type)) {
+ $updateArray['tpa_claim_type'] = $tpa_claim_type;
+ }
+ if (!empty($tpa_ailments)) {
+ $updateArray['tpa_ailments'] = $tpa_ailments;
}
// UPDATE ticket_master
@@ -933,13 +961,13 @@ class MediAssistApiController extends BaseController
$status_updated_count ++;
// LOG UPDATE
- log_message('error', "CLAIM STATUS SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
+ log_message('error',"MEDI_ASSIST - Claim Status SUCCESS | Updated ticket ID $claimId with Claim Status: $currentStatus");
}
return $this->response->setJSON([
'status' => true,
- 'message' => 'Claim status updated.',
+ 'message' => 'Claim Status updated.',
'updated_status' => $currentStatus,
'api_response' => $response,
'count' => $status_updated_count,
@@ -1002,7 +1030,7 @@ class MediAssistApiController extends BaseController
->getResultArray();
if (empty($policies)) {
- log_message('error', 'No policies found for claim sync');
+ log_message('error','MEDI_ASSIST - Sync TPA Claims | No policies found for claim sync');
return $this->response->setJSON([
'status' => false,
'message' => 'Policies not found'
@@ -1067,7 +1095,7 @@ class MediAssistApiController extends BaseController
if (empty($response['status']) || empty($response['data']['claimsData'])) {
- log_message('error','CLAIM STATUS FAILED | ' .'policyNo: ' . $policy['policyNo'] .' | ' . $chunkStart->format('Y-m-d') .' to ' . $chunkEnd->format('Y-m-d') .' | response: ' . json_encode($response) );
+ log_message('error','MEDI_ASSIST - Sync TPA Claims | ' .'policyNo: ' . $policy['policyNo'] .' | ' . $chunkStart->format('Y-m-d') .' to ' . $chunkEnd->format('Y-m-d') .' | response: ' . json_encode($response) );
$errorData[] = [
'policy_no' => $policy['policyNo'],
@@ -1153,7 +1181,7 @@ class MediAssistApiController extends BaseController
$claimStatusId = $validStatuses[$currentStatus] ?? null;
if (!$claimStatusId) {
- log_message('error', 'Unknown claim status: '.$currentStatus);
+ log_message('error','MEDI_ASSIST - Sync TPA Claims | Unknown Claim Status: '.$currentStatus);
continue;
}
@@ -1243,13 +1271,18 @@ class MediAssistApiController extends BaseController
// Payment
'utr_details' => $value['banK_CHEQUE_NO'] ?? null,
'settle_letter' => $value['settlement_LetterLink'] ?? null,
+
+ //others
+ 'tpa_claim_type' => $value['typE_OF_CLAIM'],
+ 'tpa_ailments' => ($value['ailment'] ?? '') . ' - ' . ($value['ailmenT_DESC'] ?? ''),
+
];
$this->db->table('ticket_master')->insert($claimData);
log_message(
'error',
- 'New claim created | Policy: '.$claimData['policy_no'].' | Claim: '.$claimData['claim_number']
+ 'MEDI_ASSIST - Sync TPA Claims | New claim created | Policy: '.$claimData['policy_no'].' | Claim: '.$claimData['claim_number']
);
}
@@ -1259,7 +1292,7 @@ class MediAssistApiController extends BaseController
return $this->response->setJSON([
'status' => true,
- 'message' => 'TPA claim status sync completed',
+ 'message' => 'TPA Claim Status sync completed',
'total_records' => count($finalResult),
'result' => $finalResult,
'errors' => $errorData
diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php
index e390e00d..c6b47973 100644
--- a/app/Controllers/PolicyTransactionController.php
+++ b/app/Controllers/PolicyTransactionController.php
@@ -5711,6 +5711,7 @@ class PolicyTransactionController extends BaseController
// 'agent_code' => $current_agent_data['agent_code'] ?? null,
'pos_id' => $current_agent_data['id'] ?? null,
'file_id' => $params['file_id'],
+ 'created_by' => $file['created_by'] ?? null,
'endorsement_no' => null,
'client_branch_id' => null,
'client_policy_id' => null,
@@ -5785,7 +5786,8 @@ class PolicyTransactionController extends BaseController
'pt_policy_issue_date' => change_date_format($policy_issue_date, 'd/M/Y', 'Y-m-d'),
- 'file_id' => $params['file_id']
+ 'file_id' => $params['file_id'],
+ 'created_by' => $file['created_by'] ?? null,
];
if(!empty($vehicle_id) && !empty($client_id)){
@@ -6027,10 +6029,12 @@ class PolicyTransactionController extends BaseController
if (empty($vehicle_id) && empty($client_id)) {
- foreach ($client_data as $c) {
- if (strcasecmp(trim($c['email']), $client_email) === 0) {
- $second_stage_client_id = $c['id'];
- break;
+ if(strtolower(trim($vehicle_number)) != 'new'){
+ foreach ($client_data as $c) {
+ if (strcasecmp(trim($c['email']), $client_email) === 0) {
+ $second_stage_client_id = $c['id'];
+ break;
+ }
}
}
@@ -6087,4 +6091,15 @@ class PolicyTransactionController extends BaseController
];
}
+ public function truncateBdsBulkUploadData()
+ {
+ $file_id = $this->request->getGet('file_id') ?? null;
+ if (empty($file_id)) {
+ return array('status' => false, 'message' => 'file_id is required');
+ }
+
+ $this->policyTransactionModel->select()->findAll();
+
+ }
+
}
diff --git a/app/Controllers/SalesController.php b/app/Controllers/SalesController.php
index 33a422f6..f79fd170 100644
--- a/app/Controllers/SalesController.php
+++ b/app/Controllers/SalesController.php
@@ -1,6 +1,6 @@
noteModel = new SalesLeadNoteModel();
}
+ public function index() {
+ $db = \Config\Database::connect();
+ // Fetch users for the assignment dropdowns
+ $data['users'] = $db->table('user_profiles')
+ ->select('id, first_name, last_name')
+ ->where('is_active', 1)
+ ->get()->getResultArray();
+
+ $this->loadLayout('sales/tracker_view', $data);
+ }
+
+ public function completeActivity($id) {
+ try {
+ $data = $this->request->getJSON(true);
+ $data['updated_by'] = $this->getUserId();
+
+ // 1. Mark current activity as completed
+ $this->activityModel->completeActivity((int)$id, [
+ 'completion_notes' => $data['completion_notes'],
+ 'updated_by' => $data['updated_by']
+ ]);
+
+ // 2. Handle follow-up if requested
+ if (!empty($data['schedule_followup']) && $data['schedule_followup'] === 'yes') {
+ $activity = $this->activityModel->find($id);
+ $this->activityModel->insert([
+ 'lead_id' => $activity['lead_id'],
+ 'activity_type' => $data['followup_type'],
+ 'notes' => $data['followup_notes'],
+ 'scheduled_date' => $data['followup_schedule'],
+ 'assigned_to' => $activity['assigned_to'],
+ 'status' => 'pending',
+ 'created_by' => $this->getUserId()
+ ]);
+ }
+
+ return $this->respond(['status' => 'success', 'message' => 'Activity updated']);
+ } catch (\Exception $e) {
+ return $this->failServerError($e->getMessage());
+ }
+ }
+
+
+ /**
+ * Corrected createLead to handle assigned_to as ID
+ */
+ public function createLead()
+ {
+ try {
+ $data = $this->request->getJSON(true);
+ $data['created_by'] = $this->getUserId();
+
+ // Ensure assigned_to is a valid integer from user_profiles
+ if (empty($data['assigned_to'])) {
+ return $this->fail('Please assign this lead to a user.');
+ }
+
+ if (!$this->leadModel->insert($data)) {
+ return $this->fail($this->leadModel->errors());
+ }
+
+ return $this->respondCreated(['status' => 'success', 'id' => $this->leadModel->getInsertID()]);
+ } catch (\Exception $e) {
+ return $this->failServerError($e->getMessage());
+ }
+ }
+
// ==================== LEAD APIs ====================
/**
@@ -81,46 +148,6 @@ class SalesController extends BaseController
}
}
- /**
- * Create new lead
- * POST /api/sales/leads
- */
- public function createLead()
- {
- try {
- $data = $this->request->getJSON(true);
-
- // Set created_by and updated_by from authenticated user
- $data['created_by'] = $this->getUserId();
- $data['updated_by'] = $this->getUserId();
-
- if (!$this->leadModel->insert($data)) {
- return $this->fail($this->leadModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
- }
-
- $leadId = $this->leadModel->getInsertID();
-
- // Insert contact persons if provided
- if (!empty($data['contact_persons'])) {
- foreach ($data['contact_persons'] as $contact) {
- $contact['lead_id'] = $leadId;
- $contact['created_by'] = $this->getUserId();
- $this->contactModel->insert($contact);
- }
- }
-
- $lead = $this->leadModel->getLeadComplete($leadId);
-
- return $this->respondCreated([
- 'status' => 'success',
- 'message' => 'Lead created successfully',
- 'data' => $lead
- ]);
- } catch (\Exception $e) {
- return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
-
/**
* Update lead
* PUT /api/sales/leads/{id}
@@ -467,55 +494,6 @@ class SalesController extends BaseController
}
}
- /**
- * Complete activity
- * POST /api/sales/activities/{id}/complete
- */
- public function completeActivity($id)
- {
- try {
- $activity = $this->activityModel->find((int)$id);
-
- if (!$activity) {
- return $this->failNotFound('Activity not found');
- }
-
- if ($activity['status'] === 'completed') {
- return $this->fail('Activity is already completed', ResponseInterface::HTTP_BAD_REQUEST);
- }
-
- $data = $this->request->getJSON(true);
- $data['updated_by'] = $this->getUserId();
-
- $this->activityModel->completeActivity((int)$id, $data);
-
- // Create follow-up activity if requested
- if (!empty($data['create_followup']) && $data['create_followup'] === true) {
- $followupData = [
- 'lead_id' => $activity['lead_id'],
- 'activity_type' => $data['followup_type'] ?? 'Call',
- 'notes' => $data['followup_notes'] ?? '',
- 'scheduled_date' => $data['followup_date'] ?? null,
- 'assigned_to' => $activity['assigned_to'],
- 'parent_activity_id' => $id,
- 'created_by' => $this->getUserId(),
- 'updated_by' => $this->getUserId(),
- ];
-
- $this->activityModel->insert($followupData);
- }
-
- $updatedActivity = $this->activityModel->find((int)$id);
-
- return $this->respond([
- 'status' => 'success',
- 'message' => 'Activity completed successfully',
- 'data' => $updatedActivity
- ]);
- } catch (\Exception $e) {
- return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
/**
* Delete activity
@@ -692,4 +670,123 @@ class SalesController extends BaseController
// For development/testing, you can return a default value
return 1;
}
+
+
+ // ==================== Dashboard ====================
+
+ public function branchLevelDashboard()
+ {
+ // Hardcoded branch ID as requested
+ $branchId = 1;
+
+ try {
+ // 1. Lead Statistics
+ $stats = $this->leadModel->getLeadStats(); // Using existing model method
+
+ // 2. Activity Statistics
+ $activityStats = [
+ 'total' => $this->activityModel->countAllResults(),
+ 'completed' => $this->activityModel->where('status', 'completed')->countAllResults(),
+ 'pending' => $this->activityModel->where('status', 'pending')->countAllResults(),
+ ];
+
+ // 3. Team Performance (Aggregating activity counts per user)
+ $db = \Config\Database::connect();
+ $teamPerformance = $db->table('user_profiles as u')
+ ->select('u.first_name, u.last_name, u.profile as role,
+ (SELECT COUNT(*) FROM sales_activities WHERE assigned_to = u.id) as total_acts,
+ (SELECT COUNT(*) FROM sales_activities WHERE assigned_to = u.id AND status = "completed") as done_acts')
+ ->where('u.nhance_branch_id', $branchId)
+ ->where('u.is_active', 1)
+ ->get()->getResultArray();
+
+ // 4. Recent Activities (Joining for Lead Names)
+ $recentActivities = $this->activityModel->select('sales_activities.*, sales_actual_leads.company_name')
+ ->join('sales_actual_leads', 'sales_actual_leads.lead_id = sales_activities.lead_id')
+ ->orderBy('sales_activities.scheduled_date', 'DESC')
+ ->limit(6)
+ ->findAll();
+
+ // 5. All Leads Overview
+ $leadsOverview = $this->leadModel->select('sales_actual_leads.*, user_profiles.first_name, user_profiles.last_name')
+ ->join('user_profiles', 'user_profiles.id = sales_actual_leads.assigned_to', 'left')
+ ->findAll();
+
+ $data = [
+ 'total_leads' => $stats['total'],
+ 'total_activities' => $activityStats['total'],
+ 'completed_acts' => $activityStats['completed'],
+ 'pipeline_value' => '15.0L', // Hardcoded placeholder from PDF [cite: 14]
+ 'team' => $teamPerformance,
+ 'recent_acts' => $recentActivities,
+ 'leads_overview' => $leadsOverview
+ ];
+
+ // dd($data);
+
+ $this->loadLayout('sales/branch_level_dashboard_view', $data);
+
+ // return view('sales/dashboard_view', $data);
+
+ } catch (\Exception $e) {
+ return $this->failServerError($e->getMessage());
+ }
+ }
+
+
+ public function salesManagerLevelDashboard()
+ {
+ $userId = 1;
+ $db = \Config\Database::connect();
+
+ try {
+ $target = $db->table('sales_target')
+ ->where('user_id', $userId)
+ ->where('fy_year', '2025-2026')
+ ->get()->getRowArray();
+
+ $targetAmount = $target['target_amount'] ?? 2500000.00;
+ $achievedAmount = 600000.00;
+ $remainingAmount = $targetAmount - $achievedAmount;
+ $achievementPercent = ($targetAmount > 0) ? round(($achievedAmount / $targetAmount) * 100) : 0;
+
+ $activitySummary = [
+ 'total' => $this->activityModel->where('assigned_to', $userId)->countAllResults(),
+ 'pending' => $this->activityModel->where(['assigned_to' => $userId, 'status' => 'pending'])->countAllResults(),
+ 'completed' => $this->activityModel->where(['assigned_to' => $userId, 'status' => 'completed'])->countAllResults(),
+ ];
+
+ $myLeadsCount = $this->leadModel->where('assigned_to', $userId)->countAllResults();
+
+ $upcomingActivities = $this->activityModel->select('sales_activities.*, sales_actual_leads.company_name')
+ ->join('sales_actual_leads', 'sales_actual_leads.lead_id = sales_activities.lead_id')
+ ->where(['sales_activities.assigned_to' => $userId, 'sales_activities.status' => 'pending'])
+ ->orderBy('scheduled_date', 'ASC')
+ ->limit(3)
+ ->findAll();
+
+ $recentLeads = $this->leadModel->where('assigned_to', $userId)
+ ->orderBy('created_at', 'DESC')
+ ->limit(5)
+ ->findAll();
+
+ $data = [
+ 'target' => $targetAmount,
+ 'achieved' => $achievedAmount,
+ 'remaining' => $remainingAmount,
+ 'percent' => $achievementPercent,
+ 'acts' => $activitySummary,
+ 'lead_count' => $myLeadsCount,
+ 'upcoming' => $upcomingActivities,
+ 'recent_leads' => $recentLeads,
+ 'user_name' => session()->get('first_name') ?? 'John Doe'
+ ];
+
+ // return view('sales/my_dashboard_view', $data);
+ $this->loadLayout('sales/sales_manager_level_dashboard', $data);
+
+ } catch (\Exception $e) {
+ return $this->failServerError($e->getMessage());
+ }
+ }
}
\ No newline at end of file
diff --git a/app/Controllers/TestingController.php b/app/Controllers/TestingController.php
index 7cfc5ab2..66957ea8 100644
--- a/app/Controllers/TestingController.php
+++ b/app/Controllers/TestingController.php
@@ -990,16 +990,24 @@ class TestingController extends BaseController
// 🔐 Move this to .env in real projects
$METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
- $policy_id = $this->request->getGet('client_policy');
+ $database_id = (int)$this->request->getGet('database_id') ?? 2;
+ $policy_id = $this->request->getGet('client_policy') ?? null;
+ $tpa_url = 'https://nsights.nhanceindia.in/public/dashboard/4babf324-6c1e-4c5a-adbb-1c80a0f545b1';
$policy_id = $policy_id ? $policy_id : 4687;
$payload = [
'resource' => [
// 'dashboard' => 1
- 'dashboard' => 2
+ 'dashboard' => $database_id
],
- 'params' => (object)['client_policy' => $policy_id], // MUST be object for Metabase
'exp' => time() + (10 * 60) // 10 minutes
];
+
+ if(!empty($policy_id)){
+ $payload['params'] = (object)['client_policy' => $policy_id]; // MUST be object for Metabase
+ }else{
+ $payload['params'] = (object)[]; // MUST be object for Metabase
+ }
+
// dd($payload);
$token = JWT::encode($payload, $METABASE_SECRET_KEY, 'HS256');
@@ -1025,6 +1033,31 @@ class TestingController extends BaseController
]);
}
+ public function testingquerys1(){
+ }
+ public function testingquerys()
+ {
+ $calendar = new \App\Libraries\GoogleCalendarService();
+
+ // Check if user is authenticated without passing tokens manually
+ if (!$calendar->isReady()) {
+ return $this->respond(['status' => 'failed', 'code' => '404' , 'message' => 'Google Access Token Expired'], 200);
+ }
+
+ $data = [
+ 'summary' => 'Client Follow up',
+ 'meeting_date' => '2026-02-22 10:00:00',
+ 'description' => 'Visit Client place',
+ 'emails' => ['surendarsuri30@gmail.com', 'vitvelz@gmail.com', 'venbalap2026@gmail.com', 'gowthamceline46@gmail.com']
+ ];
+
+ try {
+ $response = $calendar->createEvent($data);
+ return $this->respond(['status' => 'success', 'code' => '200' , 'message' => 'Follow-up Saved', 'response' => $response], 200);
+ } catch (\Exception $e) {
+ return $this->respond(['status' => 'failed', 'code' => '500' , 'message' => 'Error: ' . $e->getMessage()], 200);
+ }
+ }
}
diff --git a/app/Controllers/VidalApiController.php b/app/Controllers/VidalApiController.php
index c5274eff..04be9976 100644
--- a/app/Controllers/VidalApiController.php
+++ b/app/Controllers/VidalApiController.php
@@ -7,6 +7,7 @@ use App\Models\EmployeePolicyModel;
use App\Models\TpaApiDataModel;
use App\Controllers\BaseController;
+use App\Controllers\TicketController;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\API\ResponseTrait;
@@ -15,13 +16,20 @@ class VidalApiController extends BaseController
use ResponseTrait;
protected $db;
protected $vidal_primary_key;
+ protected $claim_type_array;
+ protected $ticketController;
public function __construct()
{
$this->db = \Config\Database::connect();
$this->vidal_primary_key = getenv('VIDAL_PRIMARY_KEY_CONSTANT');
+
+ $this->ticketController = new TicketController();
+ $this->claim_type_array = $this->ticketController->claimType;
}
+
+
function uploadFileToVidal($filePath,$filename)
{
@@ -29,7 +37,7 @@ class VidalApiController extends BaseController
$apiUrl = getenv('VIDAL_API_BASE_URL').'/files/upload-url';
$subscriptionKey = getenv('VIDAL_API_SUBSCRIPTION_KEY');
- log_message('error', "TPA CLAIM PUSH | Starting file upload process for filename: $filename | Path: $filePath");
+ log_message('error', "VIDAL - Claim Push | Starting file upload process for filename: $filename | Path: $filePath");
// Step 1: Get signed URL from Vidal API
// $filePath = '/opt/lampp/htdocs/nhance/writable/uploads/claim_files/1760013019_73d94af7b96ddc2e3d51.png';
@@ -39,7 +47,7 @@ class VidalApiController extends BaseController
"Ocp-Apim-Subscription-Key: $subscriptionKey"
];
- log_message('error', "TPA CLAIM PUSH | Requesting signed URL from Vidal API: $apiUrl | Payload: $payload");
+ log_message('error', "VIDAL - Claim Push | Requesting signed URL from Vidal API: $apiUrl | Payload: $payload");
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@@ -49,7 +57,7 @@ class VidalApiController extends BaseController
$response = curl_exec($ch);
if (curl_errno($ch)) {
- log_message('error', "Curl error while requesting signed URL: " . curl_error($ch));
+ log_message('error', "VIDAL - Claim Push Curl error while requesting signed URL: " . curl_error($ch));
return ["status" => false, "message" => curl_error($ch)];
}
curl_close($ch);
@@ -57,14 +65,14 @@ class VidalApiController extends BaseController
$responseData = json_decode($response, true);
if (!isset($responseData['data']['signedUrl']) || !isset($responseData['data']['fileId'])) {
- log_message('error', "TPA CLAIM PUSH | Invalid signed URL response received: " . json_encode($responseData));
+ log_message('error', "VIDAL - Claim Push | Invalid signed URL response received: " . json_encode($responseData));
return ["status" => false, "message" => "Invalid signed URL response", "response" => $responseData];
}
$signedUrl = $responseData['data']['signedUrl'];
$fileId = $responseData['data']['fileId'];
- log_message('error', "Received signed URL & fileId. fileId: $fileId");
+ log_message('error', "VIDAL - Claim Push | Received signed URL & fileId. fileId: $fileId");
// Step 2: Upload file to signed URL using PUT (Azure Blob)
$fileSize = filesize($filePath);
@@ -89,12 +97,12 @@ class VidalApiController extends BaseController
curl_close($ch2);
if ($curlErr) {
- log_message('error', "TPA CLAIM PUSH | Curl error during file upload: $curlErr");
+ log_message('error', "VIDAL - Claim Push | Curl error during file upload: $curlErr");
return ["status" => false, "message" => "File upload failed", "data" => $curlErr];
}
if ($httpCode !== 200 && $httpCode !== 201) {
- log_message('error', "TPA CLAIM PUSH | File upload failed with HTTP Code: $httpCode | Response: $uploadResponse");
+ log_message('error', "VIDAL - Claim Push | File upload failed with HTTP Code: $httpCode | Response: $uploadResponse");
return [
"status" => false,
"message" => "File upload failed",
@@ -132,6 +140,7 @@ class VidalApiController extends BaseController
tm.hospital_pin_code as hospitalPinCode,
tm.hospital_phone_no as hospitalPhoneNo,
tm.claim_amount as requestedAmount,
+ tm.claim_type,
tm.tpa_no as dependentUniqueId,
cp.policy_no as policyNo,
e.emp_code as memberId,
@@ -154,7 +163,7 @@ class VidalApiController extends BaseController
->getRowArray(); // single record
if (count($data) && $data['filePath'] == null) {
- log_message('error', "TPA CLAIM PUSH | Submit claim failed - Claim or File Missing");
+ log_message('error', "VIDAL - Claim Push | Submit claim failed - Claim or File Missing");
return $this->response->setJSON(['status' => false,'message' => 'Claim or File Missing', ]);
}
@@ -167,7 +176,7 @@ class VidalApiController extends BaseController
$upload = $this->uploadFileToVidal($filePath,$filename);
if ($upload['status'] !== true) {
- log_message('error', "TPA CLAIM PUSH | Submit claim failed - File upload failed");
+ log_message('error', "VIDAL - Claim Push | Submit claim failed - File upload failed");
return $this->response->setJSON([
'status' => false,
'message' => 'File upload failed',
@@ -185,11 +194,25 @@ class VidalApiController extends BaseController
'Ocp-Apim-Subscription-Key:' .getenv('VIDAL_API_SUBSCRIPTION_KEY').'',
];
+ $typeOfClaim = "Main hospitalization claim";
+ $allowedSubTypes = [
+ 'Hospitalization',
+ 'OPD',
+ 'Health check-up',
+ 'Dental benefit',
+ 'Day care',
+ 'Domiciliary'
+ ];
+ $mappedSubType = $this->claim_type_array[1][$data['claim_type'] ?? null] ?? null;
+ $claimSubType = in_array($mappedSubType, $allowedSubTypes, true)
+ ? $mappedSubType
+ : 'Hospitalization'; // safe default
+
$body = [
'policyNo' => $data['policyNo'],
'dependentUniqueId' => $data['dependentUniqueId'],
- 'typeOfClaim' => "Main hospitalization claim",
- 'claimSubType' => "OPD",
+ 'typeOfClaim' => $typeOfClaim,
+ 'claimSubType' => $claimSubType,
'requestedAmount' => $data['requestedAmount'],
'ailmentType' => "Non covid",
'admissionDate' => change_date_format($data['admissionDate'], 'Y-m-d', 'd-m-Y'),
@@ -212,7 +235,7 @@ class VidalApiController extends BaseController
];
// dd($body);
- log_message('error', 'TPA CLAIM PUSH | claimId: '.$claimId.' | payload: '.json_encode($body));
+ log_message('error', 'VIDAL - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
// $body = [
// 'policyNo' => "351500/D0534/PP/20-20/PC",
@@ -244,7 +267,7 @@ class VidalApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
if($response['status'] != true){
- log_message('error', 'TPA CLAIM PUSH FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
+ log_message('error', 'VIDAL - Claim Push FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
$this->db->table('ticket_master')
->where('id',$claimId)
->update([ 'tpa_push_response' => json_encode($response) ]);
@@ -260,7 +283,7 @@ class VidalApiController extends BaseController
if(!empty($claimNO) && !empty($claimInwardNO)){
- log_message('error', 'TPA CLAIM PUSH SUCCESS | claimId: '.$claimId.' | claimNO: '.$claimNO.' | claimInwardNO: '.$claimInwardNO);
+ log_message('error', 'VIDAL - Claim Push SUCCESS | claimId: '.$claimId.' | claimNO: '.$claimNO.' | claimInwardNO: '.$claimInwardNO);
$this->db->table('ticket_master')
->where('id',$claimId)
@@ -269,11 +292,11 @@ class VidalApiController extends BaseController
return;
} else {
- log_message('error', 'TPA CLAIM PUSH API SUCCESS BUT claimNO,claimInwardNO EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
+ log_message('error', 'VIDAL - Claim Push API SUCCESS BUT claimNO,claimInwardNO EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
return;
}
}else{
- log_message('error', 'TPA CLAIM PUSH API FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
+ log_message('error', 'VIDAL - Claim Push API FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
return;
}
}
@@ -463,22 +486,22 @@ class VidalApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
- // dd($response);
if ($response['status'] != true || empty($response['data']['data']['claims'][0])) {
- log_message('error', 'CLAIM STATUS FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
+ log_message('error', 'VIDAL - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
return ['status' => false, 'message' => 'API call failed.','data' => $response];
}
// Extract claim status
$claimData = $response['data']['data']['claims'][0];
+ $tpa_claim_no = $claimData['claimNumber'] ?? '';
$currentStatus = $claimData['status'] ?? '';
+ $tpa_claim_type = $claimData['claimType'] ?? '';
// VALID STATUS LIST
$validStatuses = [
-
"In-Progress" => 5,
"Required Information" => 4,
"Paid" => 11,
@@ -486,20 +509,25 @@ class VidalApiController extends BaseController
"Approved" => 8,
];
-
- // Maping tpa claim status with local claim Status
- if (isset($validStatuses[$currentStatus]))
- {
- $updateArray = ['claim_status_id' => $validStatuses[$currentStatus] , 'tpa_claim_status' => $currentStatus , 'updated_at' => date('Y-m-d H:i:s')];
- }else{
- $updateArray = ['tpa_claim_status' => $currentStatus , 'updated_at' => date('Y-m-d H:i:s')];
+ $updateArray = [
+ 'tpa_claim_status' => $currentStatus,
+ 'tpa_claim_id' => $tpa_claim_no,
+ // 'claim_number' => $tpa_claim_no, // already updated
+ 'updated_at' => date('Y-m-d H:i:s'),
+ ];
+ if (isset($validStatuses[$currentStatus])) {
+ $updateArray['claim_status_id'] = $validStatuses[$currentStatus];
}
+ if (!empty($tpa_claim_type)) {
+ $updateArray['tpa_claim_type'] = $tpa_claim_type;
+ }
+
// UPDATE ticket_master
$this->db->table('ticket_master')->where('id', $claimId)->update($updateArray);
// LOG UPDATE
- log_message('error', "CLAIM STATUS SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
+ log_message('error', "VIDAL - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
return ['status' => true,'message' => 'Claim status updated.','updated_status' => $currentStatus,'api_response' => $response];
}
@@ -540,7 +568,7 @@ class VidalApiController extends BaseController
// dd($TicketData);
if (!$TicketData) {
- log_message('error', "Claims not found to update status");
+ log_message('error', "VIDAL - Claim Status | Claims not found to update status");
return $this->response->setJSON(['status' => false,'message' => 'Claims not found' ]);
}
@@ -570,18 +598,19 @@ class VidalApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
if ($response['status'] != true || empty($response['data']['data']['claims'][0])) {
- log_message('error', 'CLAIM STATUS FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
+ log_message('error', 'VIDAL - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
$error_data[$claimId][['status' => false,'message' => 'API call failed.','data' => $response]];
}
// Extract claim status
$claimData = $response['data']['data']['claims'][0];
+ $tpa_claim_no = $claimData['claimNumber'] ?? '';
$currentStatus = $claimData['status'] ?? '';
+ $tpa_claim_type = $claimData['claimType'] ?? '';
// VALID STATUS LIST
$validStatuses = [
-
"In-Progress" => 5,
"Required Information" => 4,
"Paid" => 11,
@@ -589,20 +618,24 @@ class VidalApiController extends BaseController
"Approved" => 8,
];
-
- // Maping tpa claim status with local claim Status
- if (isset($validStatuses[$currentStatus]))
- {
- $updateArray = ['claim_status_id' => $validStatuses[$currentStatus] , 'tpa_claim_status' => $currentStatus , 'updated_at' => date('Y-m-d H:i:s')];
- }else{
- $updateArray = ['tpa_claim_status' => $currentStatus , 'updated_at' => date('Y-m-d H:i:s')];
+ $updateArray = [
+ 'tpa_claim_status' => $currentStatus,
+ 'tpa_claim_id' => $tpa_claim_no,
+ // 'claim_number' => $tpa_claim_no, // already updated
+ 'updated_at' => date('Y-m-d H:i:s'),
+ ];
+ if (isset($validStatuses[$currentStatus])) {
+ $updateArray['claim_status_id'] = $validStatuses[$currentStatus];
+ }
+ if (!empty($tpa_claim_type)) {
+ $updateArray['tpa_claim_type'] = $tpa_claim_type;
}
// UPDATE ticket_master
$this->db->table('ticket_master')->where('id', $claimId)->update($updateArray);
// LOG UPDATE
- log_message('error', "CLAIM STATUS SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
+ log_message('error', "VIDAL - Claim Status SUCCESS | Updated ticket ID $claimId with claim status: $currentStatus");
$status_updated_count ++;
@@ -654,17 +687,17 @@ class VidalApiController extends BaseController
// dd($response);
if($response['status'] != true){
- log_message('error', 'Ecard Request FAILED | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
+ log_message('error', 'VIDAL - Ecard Request FAILED | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
return null;
}
$ecardUrl = $response['data']['data']['dependents'][0]['ecardLink'] ?? null;
if(!empty($ecardUrl)){
- log_message('error', 'Ecard Request PUSH SUCCESS | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | ecardUrl: '.$ecardUrl);
+ log_message('error', 'VIDAL - Ecard Request PUSH SUCCESS | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | ecardUrl: '.$ecardUrl);
return $ecardUrl;
} else {
- log_message('error', 'Ecard Request SUCCESS BUT ecardUrl EMPTY | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
+ log_message('error', 'VIDAL - Ecard Request SUCCESS BUT ecardUrl EMPTY | employeeId: '.$employeeId.' | policyNo: '.$policyNo.' | response: '.json_encode($response));
return null;
}
@@ -692,7 +725,7 @@ class VidalApiController extends BaseController
$client_policy_id = $requestData['client_policy_id'] ?? null;
if (empty($policyNo)) {
- log_message('error', 'TPA ID PULL | policy_no missing in request');
+ log_message('error', 'VIDAL - TPA ID Pull | policy_no missing in request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'policy_no required'];
}else{
@@ -701,7 +734,7 @@ class VidalApiController extends BaseController
}
if (empty($client_policy_id)) {
- log_message('error', 'TPA ID PULL | client_policy_id missing in request');
+ log_message('error', 'VIDAL - TPA ID Pull | client_policy_id missing in request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'client_policy_id required'];
}else{
@@ -709,7 +742,7 @@ class VidalApiController extends BaseController
}
}
- log_message('error', "TPA ID PULL | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
+ log_message('error', "VIDAL - TPA ID Pull | called for policy_no: {$policyNo} , client_policy_id: {$client_policy_id}");
// Fetch file download dates
$batchFiles = $this->db->table('batch_files f')
@@ -723,7 +756,7 @@ class VidalApiController extends BaseController
// dd($batchFiles);
if (empty($batchFiles)) {
- log_message('error', 'TPA ID PULL FAILED | batchFiles is empty for this tpa id pull request');
+ log_message('error', 'VIDAL - TPA ID Pull FAILED | batchFiles is empty for this tpa id pull request');
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'batchFiles not found'];
}else{
@@ -749,7 +782,7 @@ class VidalApiController extends BaseController
// $body = [ 'empNO' => "Mem 1" ];
- log_message('error', "TPA ID PULL | API parems " . json_encode([$url, $method, $headers, $body]));
+ log_message('error', "VIDAL - TPA ID Pull | API parems " . json_encode([$url, $method, $headers, $body]));
$response = call_third_party_api($url, $method, $headers, $body);
@@ -759,12 +792,12 @@ class VidalApiController extends BaseController
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', "Files table status updated for the file id : {$requestData['file_id']}");
+ log_message('error', "VIDAL - TPA ID Pull | Files table status updated for the file id : {$requestData['file_id']}");
} else {
- log_message('error', "Failed to update file table status.");
+ log_message('error', "VIDAL - TPA ID Pull | Failed to update file table status.");
}
- log_message('error', 'TPA ID PULL API FAILED | API failed: ' . json_encode($response));
+ log_message('error', 'VIDAL - TPA ID Pull API FAILED | API failed: ' . json_encode($response));
if($function_calling_type == "job"){
return ['status' => false, 'message' => 'API call failed', 'data' => $response];
@@ -776,12 +809,12 @@ class VidalApiController extends BaseController
$data = $response['data']['data'] ?? [];
if (!isset($data['dependents'])) {
- log_message('error', "TPA ID PULL FAILED |: 'benefDetails' missing in API response: " . json_encode($data));
+ log_message('error', "VIDAL - TPA ID Pull FAILED |: 'benefDetails' missing in API response: " . json_encode($data));
break;
}
$fetchedCount = count($data['dependents']);
- log_message('error', "Fetched {$fetchedCount} records ");
+ log_message('error', "VIDAL - TPA ID Pull | Fetched {$fetchedCount} records ");
$allBenef = array_merge($allBenef, $data['dependents']);
}
@@ -848,9 +881,9 @@ class VidalApiController extends BaseController
if ($this->db->affectedRows() > 0) {
$updated++;
- log_message('error', "✅ Updated tpa_id={$row['enrollmentId']} for emp_code={$row['empNo']} policy={$row['policyNumber']}");
+ log_message('error', "VIDAL - TPA ID Pull | Updated tpa_id={$row['enrollmentId']} for emp_code={$row['empNo']} policy={$row['policyNumber']}");
} else {
- log_message('error', "⚠️ No update (already set or not matched) for emp_code={$row['empNo']} policy={$row['policyNumber']}");
+ log_message('error', "VIDAL - TPA ID Pull | No update (already set or not matched) for emp_code={$row['empNo']} policy={$row['policyNumber']}");
}
}
@@ -871,7 +904,7 @@ class VidalApiController extends BaseController
log_message(
'error',
- "❌ No match for Nhance = " . json_encode($nhanceSideData)
+ "VIDAL - TPA ID Pull | No match for Nhance = " . json_encode($nhanceSideData)
);
}
@@ -896,7 +929,7 @@ class VidalApiController extends BaseController
}
- log_message('error', "TPA ID PULL SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
+ log_message('error', "VIDAL - TPA ID Pull SUCCESS | completed. Total fetched={$totalCount}, updated={$updated}");
if($function_calling_type == "job"){
return [
@@ -945,8 +978,54 @@ class VidalApiController extends BaseController
}
}
+ public function saveVidalAPIData($array)
+ {
+ $file_id = $array['file_id'];
+ $json = file_get_contents($array['json_file_path']);
+ $records = json_decode($json, true);
+
+ // log_message('error','FHPL - saveFhplAPIData' . json_encode($array));//die();
+ $file_model = new BatchFileModel();
+ // $file_model = model(BatchFileModel::class);
+ $file_info = $file_model->where('id', $file_id)->find();
+
+ // $tpaApiDataModel = new TpaApiDataModel();
+ $tpaApiDataModel = model(TpaApiDataModel::class);
+ //deactivate old data
+ $tpaApiDataModel->set('is_active', 0)->where('file_id', $file_id)->update();
+
+ //covert tpa data to our model data
+ $mappedRows = [];
+
+ foreach ($records as $row) {
+
+ $mappedRows[] = [
+ 'file_id' => $file_id, // ← pass from controller
+ 'emp_code' => trim($row['empNo'] ?? ''),
+
+ 'name' => trim($row['name'] ?? ''),
+ 'dob' => !empty($row['dob'] ?? null) ? date('Y-m-d', strtotime(str_replace('/', '-', $row['dob']))) : null,
+
+ 'relation' => trim(strtolower($row['relationship'] ?? '')),
+ 'gender' => format_gender_v2($row['gender'] ?? null),
+ 'self' => strtolower($row['relationship'] ?? '') === 'self' ? 1 : 0,
+
+ 'tpa_id' => trim($row['enrollmentId'] ?? null),
+ 'age' => is_numeric($row['age'] ?? null) ? (int) $row['age'] : null,
+
+ 'is_active' => 1,
+ 'created_by' => $file_info[0]['created_by'] ?? null,
+ ];
+ }
+
+ // log_message('error','FHPL - COUNT' . count($mappedRows));
+ $result = $tpaApiDataModel->insertBatchWithChunkLog($mappedRows,500,('FILE_ID_'.$file_id));
+ // unlink($file_array['json_file_path']); // delete temp json file
+
+ return $result;
+ }
diff --git a/app/Filters/AuthApiRateLimitFilter.php b/app/Filters/AuthApiRateLimitFilter.php
new file mode 100644
index 00000000..944af97f
--- /dev/null
+++ b/app/Filters/AuthApiRateLimitFilter.php
@@ -0,0 +1,143 @@
+post('api/auth/verify-otp', 'AuthController::verifyOtp', ['filter' => 'authApiRateLimit']);
+ *
+ * Register in app/Config/Filters.php:
+ * 'AuthApiRateLimitFilter' => \App\Filters\AuthApiRateLimitFilter::class
+ */
+class AuthApiRateLimitFilter implements FilterInterface
+{
+ protected RateLimiterService $limiter;
+
+ public function __construct()
+ {
+ $this->limiter = new RateLimiterService();
+ }
+
+ // -------------------------------------------------------------------------
+ // BEFORE — runs before the controller
+ // -------------------------------------------------------------------------
+
+ public function before(RequestInterface $request, $arguments = null)
+ {
+ $fingerprint = generateFingerprint(exclude_ua: true);
+
+
+ // 1. IP-level check
+ $ipResult = $this->limiter->checkIp($fingerprint, 'authApi');
+ if ($ipResult) {
+ return $this->jsonResponse($ipResult);
+ }
+
+ // 2. User-level block check (identity may not be present yet on first hit)
+ $identity = $this->resolveIdentity($request);
+ if ($identity) {
+ $userResult = $this->limiter->checkUser($identity);
+ if ($userResult) {
+ return $this->jsonResponse($userResult);
+ }
+ }
+
+ // Store resolved identity in request for use in after()
+ if ($identity) {
+ $request->setGlobal('rateLimitIdentity', $identity);
+ }
+ $request->setGlobal('rateLimitFingerprint', $fingerprint);
+
+ return null; // pass through
+ }
+
+ // -------------------------------------------------------------------------
+ // AFTER — runs after the controller; records failures on bad responses
+ // -------------------------------------------------------------------------
+
+ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
+ {
+ // Only act on failed responses (4xx from auth failures)
+ $statusCode = $response->getStatusCode();
+ if ($statusCode < 400 || $statusCode === 429 || $statusCode === 403 || $statusCode === 451) {
+ return; // 2xx/3xx = success; 429/403/451 already handled
+ }
+
+ $fingerprint = $request->getGlobal('rateLimitFingerprint') ?? generateFingerprint(exclude_ua: true);
+
+ $identity = $request->getGlobal('rateLimitIdentity')
+ ?? $this->resolveIdentity($request);
+
+ // Record failure at IP level
+ $this->limiter->recordIpFailure($fingerprint);
+
+ // Record failure at user level
+ if ($identity) {
+ $this->limiter->recordUserFailure($identity, 'authApi');
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // HELPERS
+ // -------------------------------------------------------------------------
+
+ /**
+ * Extract identity from POST body or GET params.
+ * Looks for 'email' or 'mobile_number'.
+ */
+ protected function resolveIdentity(RequestInterface $request): ?string
+ {
+ // Try POST body first
+ $email = $request->getPost('email');
+ $mobile = $request->getPost('mobile_number');
+
+ // Fallback to GET params
+ if (! $email && ! $mobile) {
+ $email = $request->getGet('email');
+ $mobile = $request->getGet('mobile_number');
+ }
+
+ if ($email) {
+ return strtolower(trim($email));
+ }
+
+ if ($mobile) {
+ return trim($mobile);
+ }
+
+ return null;
+ }
+
+ /**
+ * Build and return a JSON response for blocked/throttled requests.
+ */
+ protected function jsonResponse(array $result): ResponseInterface
+ {
+ $response = service('response');
+ $response->setStatusCode($result['status']);
+ $response->setContentType('application/json');
+ $response->setBody(json_encode([
+ 'success' => false,
+ 'error' => [
+ 'code' => strtoupper('RATE_LIMIT_' . $result['level']),
+ 'message' => $result['message'],
+ 'type' => $result['type'] ?? 'request',
+ ],
+ ]));
+ return $response;
+ }
+}
diff --git a/app/Filters/GlobalPostFileUploadGuard.php b/app/Filters/GlobalPostFileUploadGuard.php
index 76117240..d5b3f4c8 100644
--- a/app/Filters/GlobalPostFileUploadGuard.php
+++ b/app/Filters/GlobalPostFileUploadGuard.php
@@ -30,7 +30,7 @@ class GlobalPostFileUploadGuard implements FilterInterface
'application/vnd.oasis.opendocument.text' => ['odt'],
'text/rtf' => ['rtf'],
'application/rtf' => ['rtf'],
- 'application/vnd.ms-excel' => ['xls'],
+ 'application/vnd.ms-excel' => ['xls', 'xlsx'],
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => ['xlsx'],
'application/vnd.oasis.opendocument.spreadsheet' => ['ods'],
'text/csv' => ['csv'],
diff --git a/app/Filters/JwtApiFilter.php b/app/Filters/JwtApiFilter.php
new file mode 100644
index 00000000..a3c7173d
--- /dev/null
+++ b/app/Filters/JwtApiFilter.php
@@ -0,0 +1,153 @@
+get('api/profile', 'ProfileController::index', ['filter' => 'jwtApiRateLimit']);
+ *
+ * Register in app/Config/Filters.php:
+ * 'JwtApiRateLimitFilter' => \App\Filters\JwtApiRateLimitFilter::class
+ */
+class JwtApiRateLimitFilter implements FilterInterface
+{
+ protected RateLimiterService $limiter;
+
+ public function __construct()
+ {
+ $this->limiter = new RateLimiterService();
+ }
+
+ // -------------------------------------------------------------------------
+ // BEFORE — runs before the controller
+ // -------------------------------------------------------------------------
+
+ public function before(RequestInterface $request, $arguments = null)
+ {
+ $fingerprint = generateFingerprint(exclude_ua: true);
+
+
+ // 1. IP-level throttle + block check
+ $ipResult = $this->limiter->checkIp($fingerprint, 'jwtApi');
+ if ($ipResult) {
+ return $this->jsonResponse($ipResult);
+ }
+
+ // 2. Resolve user identity from JWT
+ // Uses your existing JWT helper functions.
+ // If neither returns a value, fall back to IP-only limiting.
+ $identity = $this->resolveIdentityFromJwt();
+
+ if ($identity) {
+ // User-level throttle (request count based for JWT routes)
+ $userResult = $this->limiter->checkUserThrottle($identity, 'jwtApi');
+ if ($userResult) {
+ return $this->jsonResponse($userResult);
+ }
+ }
+
+ // Stash for after() use
+ $request->setGlobal('rateLimitFingerprint', $fingerprint);
+ if ($identity) {
+ $request->setGlobal('rateLimitIdentity', $identity);
+ }
+
+ return null; // pass through
+ }
+
+ // -------------------------------------------------------------------------
+ // AFTER — records IP failure on controller-level bad responses
+ // -------------------------------------------------------------------------
+
+ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
+ {
+ $statusCode = $response->getStatusCode();
+
+ // Only act on auth-related failures from the controller (401, 422, etc.)
+ // 429/403/451 are already handled by before(); skip 2xx/3xx.
+ if ($statusCode < 400 || in_array($statusCode, [429, 403, 451])) {
+ return;
+ }
+
+ $fingerprint = $request->getGlobal('rateLimitFingerprint') ?? generateFingerprint(exclude_ua: true);
+
+ $identity = $request->getGlobal('rateLimitIdentity') ?? $this->resolveIdentityFromJwt();
+
+ $this->limiter->recordIpFailure($fingerprint);
+
+ if ($identity) {
+ $this->limiter->recordUserFailure($identity, 'jwtApi');
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // HELPERS
+ // -------------------------------------------------------------------------
+
+ /**
+ * Resolve user identity from JWT using your existing helper functions.
+ * Tries email first, then mobile. Returns null if JWT is absent/invalid.
+ *
+ * IMPORTANT: Replace getEmailFromJWT() / getMobileFromJWT() with your
+ * actual function names if they differ.
+ */
+ protected function resolveIdentityFromJwt(): ?string
+ {
+ try {
+ // Try email from JWT
+ if (function_exists('getEmailFromJWT')) {
+ $email = getEmailFromJWT();
+ if ($email) {
+ return strtolower(trim($email));
+ }
+ }
+
+ // Try mobile from JWT
+ if (function_exists('getMobileFromJWT')) {
+ $mobile = getMobileFromJWT();
+ if ($mobile) {
+ return trim($mobile);
+ }
+ }
+ } catch (\Throwable $e) {
+ // JWT invalid or expired — fall through to IP-only limiting
+ log_message('debug', '[RateLimiter] JWT identity resolution failed: ' . $e->getMessage());
+ }
+
+ return null;
+ }
+
+ /**
+ * Build and return a JSON response for blocked/throttled requests.
+ */
+ protected function jsonResponse(array $result): ResponseInterface
+ {
+ $response = service('response');
+ $response->setStatusCode($result['status']);
+ $response->setContentType('application/json');
+ $response->setBody(json_encode([
+ 'success' => false,
+ 'error' => [
+ 'code' => strtoupper('RATE_LIMIT_' . $result['level']),
+ 'message' => $result['message'],
+ 'type' => $result['type'] ?? 'request',
+ ],
+ ]));
+ return $response;
+ }
+}
diff --git a/app/Helpers/HttpRequestHelper.php b/app/Helpers/HttpRequestHelper.php
index 3e072e8a..53268b39 100755
--- a/app/Helpers/HttpRequestHelper.php
+++ b/app/Helpers/HttpRequestHelper.php
@@ -15,6 +15,7 @@ class HttpRequestHelper
$data = [
'ip' => $request->getIPAddress(),
+ 'real_ip' => getRealClientIP(),
'platform' => $platform,
'browser' => $browser,
'method' => strtoupper($request->getMethod()),
diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php
index 178ec18a..467f0338 100755
--- a/app/Helpers/utility_helper.php
+++ b/app/Helpers/utility_helper.php
@@ -1069,23 +1069,43 @@ function getRealClientIP()
return $request->getIPAddress();
}
-function generateFingerprint()
+function generateFingerprint(bool $exclude_ua = false): string
{
$request = service('request');
$ua = $request->getUserAgent()->getAgentString();
$ip = getRealClientIP();
- // Use only subnet (first 3 blocks) to tolerate IP change
- $ipParts = explode('.', $ip);
- $ipSubnet = $ipParts[0] . '.' . $ipParts[1] . '.' . $ipParts[2];
+ // Normalize localhost
+ if ($ip === '127.0.0.1' || $ip === '::1') {
+ $ipGroup = 'localhost';
+ }
+ // IPv4 handling
+ elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
+ $parts = explode('.', $ip);
+ // Use /24 subnet (first 3 octets)
+ $ipGroup = $parts[0] . '.' . $parts[1] . '.' . $parts[2];
+ }
+ // IPv6 handling
+ elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ // Use first 4 blocks of IPv6 (rough /64 grouping)
+ $blocks = explode(':', $ip);
+ $ipGroup = implode(':', array_slice($blocks, 0, 4));
+ }
+ // Fallback
+ else {
+ $ipGroup = 'unknown';
+ }
- // $secret = env('app.sessionFingerprintSalt');
-
- // return hash('sha256', $ua . '|' . $ipSubnet . '|' . $secret);
- return hash('sha256', $ua . '|' . $ipSubnet );
+ if($exclude_ua){
+ return hash('sha256', $ipGroup);
+ }
+ return hash('sha256', $ua . '|' . $ipGroup);
}
+
+
+
if (!function_exists('convertGoogleDriveToDownloadLink')) {
function convertGoogleDriveToDownloadLink(?string $url): ?string
{
@@ -1144,7 +1164,116 @@ if (!function_exists('clear_cd_balance_session')) {
}
}
-
+if (!function_exists('format_gender_v2')) {
+ function format_gender_v2($gender) {
+ if (empty($gender)) return null;
+
+ $g = strtoupper(trim($gender));
+
+ // Direct-ah check pannuvom
+ if (str_starts_with($g, 'M')) return 'M'; // Male, M
+ if (str_starts_with($g, 'F')) return 'F'; // Female, F
+
+ // Others, Transgender, O - ivatrai 'O' ena return seiyum
+ if (str_starts_with($g, 'O') || str_starts_with($g, 'T')) {
+ return 'O';
+ }
+
+ return $g; // Vera ethuvum illaiyengil original-aiye return pannum
+ }
+}
+
+if (!function_exists('map_relationship')) {
+ /**
+ * Employee -> self, WIFE -> spouse ena maatri return seiyum.
+ */
+ function map_relationship($relation) {
+ if (empty($relation)) return '';
+
+ // Case prechanai varaamal irukka lowercase-kku maatri check seivom
+ $r = strtolower(trim($relation));
+
+ if ($r == 'employee') {
+ return 'self';
+ }
+ else if ($r == 'wife') {
+ return 'spouse';
+ }
+
+ // Matra anaithu relationship-um iruppathu polave (Original-aga) return aagum
+ return $relation;
+ }
+}
+
+
+/**
+ * Extract identity from POST body or GET params.
+ * Looks for 'email' or 'mobile_number'.
+ */
+ function resolveIdentity($request): ?string
+ {
+ // Try POST body first
+ $email = $request->getPost('email');
+ // print_r($email);die;
+ $mobile = $request->getPost('mobile_number');
+
+ // Fallback to GET params
+ if (! $email && ! $mobile) {
+ $email = $request->getGet('email');
+ $mobile = $request->getGet('mobile_number');
+ }
+ // Fallback to JSON params
+ if (! $email && ! $mobile) {
+ $req_data = $request->getJSON();
+ // print_r( $req_data);
+
+ $mobile = $req_data->mobile_number ?? null;
+ // return trim($mobile_number);
+
+ $email = $req_data->email ?? null;
+
+ if (!$email)
+ {
+ $email = $req_data->email_id ?? null;
+ }
+ // return trim($email);
+ }
+
+ if ($email) {
+ return strtolower(trim($email));
+ }
+
+ if ($mobile) {
+ return trim($mobile);
+ }
+
+ return null;
+ }
+
+
+ function recordRateLimitFailure(string $context = 'authApi'): void
+ {
+ /** @var IncomingRequest $request */
+ $request = \Config\Services::request();
+
+ $limiter = \Config\Services::limiter(); // or your custom limiter service
+
+ $fingerprint = $request->getVar('rateLimitFingerprint')
+ ?? generateFingerprint(exclude_ua: true);
+
+
+
+ $identity = $request->getVar('rateLimitIdentity')
+ ?? resolveIdentity($request);
+
+ // Record IP-level failure
+ $limiter->recordIpFailure($fingerprint);
+
+ // Record user-level failure
+ if (!empty($identity)) {
+ $limiter->recordUserFailure($identity, $context);
+ }
+ }
diff --git a/app/Libraries/GoogleCalendarService.php b/app/Libraries/GoogleCalendarService.php
new file mode 100644
index 00000000..8076a260
--- /dev/null
+++ b/app/Libraries/GoogleCalendarService.php
@@ -0,0 +1,205 @@
+client = new Client();
+ $this->client->setApplicationName($appName);
+ $this->client->setClientId($clientID);
+ $this->client->setClientSecret($clientSecret);
+ $this->client->setRedirectUri($redirectUri);
+ $this->client->addScope($scopesArray);
+ $this->client->setPrompt('consent');
+ $this->client->setAccessType('offline');
+
+ $accessToken = session()->get('access_token');
+ $refreshToken = session()->get('refresh_token'); // Session-la irunthu refresh token-a edukkurom
+
+ if ($accessToken) {
+ $this->client->setAccessToken($accessToken);
+
+ if ($this->client->isAccessTokenExpired()) {
+ if ($refreshToken) {
+ // Ippo session-la iruntha refresh token-a vechu puthu access token vaangurom
+ $newToken = $this->client->fetchAccessTokenWithRefreshToken($refreshToken);
+
+ // Romba mukkiyam: Puthu token-la refresh token thirumba varaathu,
+ // so pazhaya refresh token-aiye namma retain pannanum.
+ if (!isset($newToken['refresh_token'])) {
+ $newToken['refresh_token'] = $refreshToken;
+ }
+
+ session()->set('access_token', $newToken);
+ $this->client->setAccessToken($newToken);
+ } else {
+ // Refresh token illana, user marubadiyum login panna sollanum
+ return redirect()->to('/google-login');
+ }
+ }
+ }
+ }
+
+ public function isReady()
+ {
+ return $token = session()->get('access_token') && !$this->client->isAccessTokenExpired();
+ }
+
+ public function createEventForOrganizerOnly(array $data)
+ {
+ $this->service = new Calendar($this->client);
+
+ // Date kuda '10:00' add panrathu safe
+ $meeting_start = preg_match('/^\d{4}-\d{2}-\d{2}$/', $data['meeting_date']) ? $data['meeting_date'] . ' 10:00:00' : $data['meeting_date'];
+
+ $event = new Event([
+ 'summary' => $data['summary'],
+ 'description' => $data['description'] ?? '',
+ 'start' => [
+ 'dateTime' => date('c', strtotime($meeting_start)), // Ippo 10 AM-nu fix aagidum
+ 'timeZone' => 'Asia/Kolkata',
+ ],
+ 'end' => [
+ 'dateTime' => date('c', strtotime($meeting_start . ' +30 minutes')),
+ 'timeZone' => 'Asia/Kolkata',
+ ],
+ 'reminders' => [
+ 'useDefault' => false,
+ 'overrides' => [
+ ['method' => 'email', 'minutes' => 1440], // Munthuna naal 10 AM
+ ['method' => 'popup', 'minutes' => 60], // Event annaki 9 AM
+ ],
+ ],
+ ]);
+
+ return $this->service->events->insert('primary', $event);
+ }
+
+ public function createEvent(array $data)
+ {
+ $this->service = new Calendar($this->client);
+ $responses = [];
+
+ try {
+
+ $meetingStartRaw = (preg_match('/^\d{4}-\d{2}-\d{2}$/', $data['meeting_date']))
+ ? $data['meeting_date'] . ' 10:00:00'
+ : $data['meeting_date'];
+
+ $startTime = date('c', strtotime($meetingStartRaw));
+ $endTime = date('c', strtotime(date('Y-m-d', strtotime($meetingStartRaw)) . ' 23:59:59'));
+
+ // 2. Prepare Attendees
+ $attendees = [];
+ if (!empty($data['emails']) && is_array($data['emails'])) {
+ foreach ($data['emails'] as $email) {
+ $attendees[] = ['email' => $email];
+ }
+ }
+
+ // 3. Define the Event
+ $event = new Event([
+ 'summary' => $data['summary'],
+ 'description' => $data['description'] ?? '',
+ 'start' => ['dateTime' => $startTime, 'timeZone' => 'Asia/Kolkata'],
+ 'end' => ['dateTime' => $endTime, 'timeZone' => 'Asia/Kolkata'],
+ 'attendees' => $attendees,
+ 'reminders' => [
+ 'useDefault' => false,
+ 'overrides' => [
+ ['method' => 'email', 'minutes' => 1440],
+ ['method' => 'popup', 'minutes' => 60],
+ ],
+ ],
+ ]);
+
+ $optParams = ['sendUpdates' => 'all'];
+
+ $calendarId = 'primary';
+ $result = $this->service->events->insert($calendarId, $event, $optParams);
+
+ $responses['status'] = 'success';
+ $responses['event_id'] = $result->getId();
+ $responses['raw_response'] = $result;
+
+ } catch (\Exception $e) {
+
+ $error_data = [
+ 'error' => $e->getMessage(),
+ 'data' => $data,
+ 'trace' => $e->getTraceAsString()
+ ];
+
+ // Log only on failure
+ log_message('error', 'Google Calendar Event Creation Failed' . json_encode($error_data ?? []));
+
+ $responses['status'] = 'error';
+ $responses['message'] = $e->getMessage();
+ $responses['error_data'] = $error_data;
+ }
+
+ return $responses;
+ }
+
+ public function createStaffEvent(array $data)
+ {
+ $results = [];
+
+ $meetingStartRaw = (preg_match('/^\d{4}-\d{2}-\d{2}$/', $data['meeting_date']))
+ ? $data['meeting_date'] . ' 10:00:00'
+ : $data['meeting_date'];
+
+ $startTime = date('c', strtotime($meetingStartRaw));
+ $endTime = date('c', strtotime(date('Y-m-d', strtotime($meetingStartRaw)) . ' 23:59:59'));
+
+
+ // Event Object create panrom (Common for all staff)
+ $event = new Event([
+ 'summary' => $data['summary'],
+ 'description' => $data['description'] ?? '',
+ 'start' => ['dateTime' => $startTime, 'timeZone' => 'Asia/Kolkata'],
+ 'end' => ['dateTime' => $endTime, 'timeZone' => 'Asia/Kolkata'],
+ 'reminders' => [
+ 'useDefault' => false,
+ 'overrides' => [
+ ['method' => 'email', 'minutes' => 1440],
+ ['method' => 'popup', 'minutes' => 60],
+ ],
+ ],
+ ]);
+
+ // Loop through each staff email in the array
+ foreach ($data['emails'] as $email) {
+ try {
+
+ $this->client->setSubject($email);
+
+ $staffService = new Calendar($this->client);
+
+ $results[$email] = $staffService->events->insert('primary', $event);
+
+ } catch (\Exception $e) {
+ $results[$email] = 'Error: ' . $e->getMessage();
+ }
+ }
+
+ return $results;
+ }
+}
\ No newline at end of file
diff --git a/app/Libraries/GoogleSheetLib.php b/app/Libraries/GoogleSheetLib.php
new file mode 100644
index 00000000..5bdb9464
--- /dev/null
+++ b/app/Libraries/GoogleSheetLib.php
@@ -0,0 +1,80 @@
+client = new Google_Client();
+
+ // Service account JSON
+ $this->client->setAuthConfig(
+ ROOTPATH . 'gdrive-demo-394007-5b1d856b0c5b.json'
+ );
+
+ // IMPORTANT for service account
+ $this->client->useApplicationDefaultCredentials();
+
+ // Required scopes
+ $this->client->addScope([
+ Google_Service_Drive::DRIVE,
+ Google_Service_Sheets::SPREADSHEETS
+ ]);
+
+ // Init services
+ $this->sheets = new Google_Service_Sheets($this->client);
+ $this->drive = new Google_Service_Drive($this->client);
+ }
+
+ /* ===================== READ ===================== */
+
+ public function read(string $spreadsheetId, string $range = 'Sheet1')
+ {
+ $response = $this->sheets
+ ->spreadsheets_values
+ ->get($spreadsheetId, $range);
+
+ return $response->getValues() ?? [];
+ }
+
+ /* ===================== WRITE ===================== */
+
+ public function write(string $spreadsheetId, array $values, string $range = 'Sheet1')
+ {
+ $body = new Google_Service_Sheets_ValueRange([
+ 'values' => $values
+ ]);
+
+ $this->sheets
+ ->spreadsheets_values
+ ->update(
+ $spreadsheetId,
+ $range,
+ $body,
+ ['valueInputOption' => 'RAW']
+ );
+
+ return true;
+ }
+
+ /* ===================== DOWNLOAD ===================== */
+
+ public function downloadExcel(string $spreadsheetId)
+ {
+ $response = $this->drive->files->export(
+ $spreadsheetId,
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ ['alt' => 'media']
+ );
+
+ return $response->getBody()->getContents();
+ }
+}
diff --git a/app/Libraries/RateLimiterService.php b/app/Libraries/RateLimiterService.php
new file mode 100644
index 00000000..90094907
--- /dev/null
+++ b/app/Libraries/RateLimiterService.php
@@ -0,0 +1,383 @@
+config = config('RateLimiter');
+ $this->cache = \Config\Services::cache();
+ }
+
+ // =========================================================================
+ // PUBLIC — IP LEVEL
+ // =========================================================================
+
+ /**
+ * Check & throttle by fingerprint (IP+UA based).
+ * Returns null on pass, or an array ['level'=>..., 'message'=>...] on block.
+ */
+ public function checkIp(string $fingerprint, string $routeType = 'jwtApi'): ?array
+ {
+ // 1. Is the IP already blocked?
+ $blockInfo = $this->getIpBlock($fingerprint);
+ if ($blockInfo) {
+ // Count hit while blocked → maybe escalate
+ $this->recordIpBlockHit($fingerprint, $blockInfo['level']);
+ return $this->blockedResponse('ip', $blockInfo['level']);
+ }
+
+ // 2. Throttle check
+ $cfg = $this->config->ipBlock;
+ $countKey = $this->config->cacheKeys['ip_count'] . $fingerprint;
+ $count = (int) ($this->cache->get($countKey) ?? 0);
+
+ if ($count === 0) {
+ $this->cache->save($countKey, 1, $cfg['window']);
+ } else {
+ $this->cache->save($countKey, $count + 1, $cfg['window']);
+ }
+
+ if (($count + 1) > $cfg['limit']) {
+ // Over limit → record violation
+ $violated = $this->incrementIpViolation($fingerprint);
+ if ($violated >= $cfg['violation_soft']) {
+ $this->blockIp($fingerprint, 'soft');
+ return $this->blockedResponse('ip', 'soft');
+ }
+ return [
+ 'level' => 'throttle',
+ 'message' => 'Too many requests. Please slow down.',
+ 'status' => $this->config->statusCodes['throttle'],
+ ];
+ }
+
+ return null;
+ }
+
+ /**
+ * Record a "bad outcome" for IP (e.g. controller calls this after failed auth).
+ * Same escalation path as throttle violations.
+ */
+ public function recordIpFailure(string $fingerprint): ?array
+ {
+ $blockInfo = $this->getIpBlock($fingerprint);
+ if ($blockInfo) {
+ $this->recordIpBlockHit($fingerprint, $blockInfo['level']);
+ return $this->blockedResponse('ip', $blockInfo['level']);
+ }
+
+ $violated = $this->incrementIpViolation($fingerprint);
+ $cfg = $this->config->ipBlock;
+
+ if ($violated >= $cfg['violation_soft']) {
+ $this->blockIp($fingerprint, 'soft');
+ return $this->blockedResponse('ip', 'soft');
+ }
+
+ return null;
+ }
+
+ /**
+ * Manually block an IP at a given level.
+ */
+ public function blockIp(string $fingerprint, string $level = 'soft'): void
+ {
+ $cfg = $this->config->ipBlock;
+ $blockKey = $this->config->cacheKeys['ip_block'] . $fingerprint;
+
+ $duration = $this->blockDuration($cfg, $level);
+
+ $data = [
+ 'level' => $level,
+ 'blocked_at' => time(),
+ 'fingerprint'=> $fingerprint,
+ 'ip' => getRealClientIP(),
+ ];
+
+ // Duration 0 = store for 10 years (permanent until manual unblock)
+ $ttl = $duration > 0 ? $duration : (10 * 365 * 24 * 3600);
+ $this->cache->save($blockKey, $data, $ttl);
+ }
+
+ /**
+ * Manually unblock an IP. Clears block, violations, and counters.
+ */
+ public function unblockIp(string $fingerprint): void
+ {
+ $keys = $this->config->cacheKeys;
+ $this->cache->delete($keys['ip_block'] . $fingerprint);
+ $this->cache->delete($keys['ip_violations'] . $fingerprint);
+ $this->cache->delete($keys['ip_count'] . $fingerprint);
+ $this->cache->delete($keys['ip_block_hits'] . $fingerprint);
+ }
+
+ /**
+ * Get current IP block info or null if not blocked.
+ */
+ public function getIpBlock(string $fingerprint): ?array
+ {
+ $blockKey = $this->config->cacheKeys['ip_block'] . $fingerprint;
+ $data = $this->cache->get($blockKey);
+ return $data ?: null;
+ }
+
+ // =========================================================================
+ // PUBLIC — USER LEVEL
+ // =========================================================================
+
+ /**
+ * Check if a user (by email or mobile) is blocked.
+ * Returns null on pass, or block response array on block.
+ */
+ public function checkUser(string $identity): ?array
+ {
+ $blockInfo = $this->getUserBlock($identity);
+ if ($blockInfo) {
+ $this->recordUserBlockHit($identity, $blockInfo['level']);
+ return $this->blockedResponse('user', $blockInfo['level']);
+ }
+ return null;
+ }
+
+ /**
+ * Record a failed attempt for a user identity.
+ * Called from controller after() or manually after a failed verification.
+ * Handles escalation: free → soft → medium → hard
+ */
+ public function recordUserFailure(string $identity, string $routeType = 'authApi'): ?array
+ {
+ $blockInfo = $this->getUserBlock($identity);
+
+ if ($blockInfo) {
+ // Already blocked — count hit and maybe escalate
+ $this->recordUserBlockHit($identity, $blockInfo['level']);
+ return $this->blockedResponse('user', $blockInfo['level']);
+ }
+
+ // Not blocked yet — increment violation count
+ $violated = $this->incrementUserViolation($identity, $routeType);
+ $cfg = $this->config->userBlock;
+ $routeCfg = $this->config->{$routeType};
+
+ if ($violated >= $routeCfg['violation_soft']) {
+ $this->blockUser($identity, 'soft');
+ return $this->blockedResponse('user', 'soft');
+ }
+
+ return null;
+ }
+
+ /**
+ * Manually block a user identity at a given level.
+ */
+ public function blockUser(string $identity, string $level = 'soft'): void
+ {
+ $cfg = $this->config->userBlock;
+ $blockKey = $this->config->cacheKeys['user_block'] . $this->hashIdentity($identity);
+
+ $duration = $this->blockDuration($cfg, $level);
+ $ttl = $duration > 0 ? $duration : (10 * 365 * 24 * 3600);
+
+ $data = [
+ 'level' => $level,
+ 'blocked_at' => time(),
+ 'identity' => $identity,
+ ];
+
+ $this->cache->save($blockKey, $data, $ttl);
+ }
+
+ /**
+ * Manually unblock a user identity. Independent — does NOT touch IP block.
+ */
+ public function unblockUser(string $identity): void
+ {
+ $keys = $this->config->cacheKeys;
+ $hashed = $this->hashIdentity($identity);
+
+ $this->cache->delete($keys['user_block'] . $hashed);
+ $this->cache->delete($keys['user_violations'] . $hashed);
+ $this->cache->delete($keys['user_count'] . $hashed);
+ $this->cache->delete($keys['user_block_hits'] . $hashed);
+ }
+
+ /**
+ * Get current user block info or null if not blocked.
+ */
+ public function getUserBlock(string $identity): ?array
+ {
+ $blockKey = $this->config->cacheKeys['user_block'] . $this->hashIdentity($identity);
+ $data = $this->cache->get($blockKey);
+ return $data ?: null;
+ }
+
+ // =========================================================================
+ // USER THROTTLE (for JWT API routes — request count based)
+ // =========================================================================
+
+ /**
+ * Throttle check for a known user on JWT routes.
+ * Increments request counter; if over limit records violation.
+ */
+ public function checkUserThrottle(string $identity, string $routeType = 'jwtApi'): ?array
+ {
+ $blockCheck = $this->checkUser($identity);
+ if ($blockCheck) {
+ return $blockCheck;
+ }
+
+ $cfg = $this->config->{$routeType};
+ $hashed = $this->hashIdentity($identity);
+ $countKey = $this->config->cacheKeys['user_count'] . $hashed;
+ $count = (int) ($this->cache->get($countKey) ?? 0);
+
+ if ($count === 0) {
+ $this->cache->save($countKey, 1, $cfg['window']);
+ } else {
+ $this->cache->save($countKey, $count + 1, $cfg['window']);
+ }
+
+ if (($count + 1) > $cfg['limit']) {
+ $violated = $this->incrementUserViolation($identity, $routeType);
+ if ($violated >= $cfg['violation_soft']) {
+ $this->blockUser($identity, 'soft');
+ return $this->blockedResponse('user', 'soft');
+ }
+ return [
+ 'level' => 'throttle',
+ 'message' => 'Too many requests. Please slow down.',
+ 'status' => $this->config->statusCodes['throttle'],
+ ];
+ }
+
+ return null;
+ }
+
+ // =========================================================================
+ // PRIVATE HELPERS
+ // =========================================================================
+
+ /**
+ * Increment IP violation counter and return new count.
+ */
+ protected function incrementIpViolation(string $fingerprint): int
+ {
+ $key = $this->config->cacheKeys['ip_violations'] . $fingerprint;
+ $count = (int) ($this->cache->get($key) ?? 0) + 1;
+ // Keep violation record for the block window duration
+ $this->cache->save($key, $count, $this->config->ipBlock['window'] * 10);
+ return $count;
+ }
+
+ /**
+ * Record a hit while IP is already blocked; escalate if thresholds met.
+ */
+ protected function recordIpBlockHit(string $fingerprint, string $currentLevel): void
+ {
+ $cfg = $this->config->ipBlock;
+ $hitKey = $this->config->cacheKeys['ip_block_hits'] . $fingerprint;
+ $hits = (int) ($this->cache->get($hitKey) ?? 0) + 1;
+ $this->cache->save($hitKey, $hits, 10 * 365 * 24 * 3600);
+
+ if ($currentLevel === 'soft' && $hits >= $cfg['medium_trigger']) {
+ $this->cache->delete($hitKey);
+ $this->blockIp($fingerprint, 'medium');
+ } elseif ($currentLevel === 'medium' && $hits >= $cfg['hard_trigger']) {
+ $this->cache->delete($hitKey);
+ $this->blockIp($fingerprint, 'hard');
+ }
+ }
+
+ /**
+ * Increment user violation counter and return new count.
+ */
+ protected function incrementUserViolation(string $identity, string $routeType): int
+ {
+ $hashed = $this->hashIdentity($identity);
+ $key = $this->config->cacheKeys['user_violations'] . $hashed;
+ $count = (int) ($this->cache->get($key) ?? 0) + 1;
+ $window = $this->config->{$routeType}['window'] ?? 180;
+ $this->cache->save($key, $count, $window * 10);
+ return $count;
+ }
+
+ /**
+ * Record a hit while user is already blocked; escalate if thresholds met.
+ */
+ protected function recordUserBlockHit(string $identity, string $currentLevel): void
+ {
+ $cfg = $this->config->userBlock;
+ $hashed = $this->hashIdentity($identity);
+ $hitKey = $this->config->cacheKeys['user_block_hits'] . $hashed;
+ $hits = (int) ($this->cache->get($hitKey) ?? 0) + 1;
+ $this->cache->save($hitKey, $hits, 10 * 365 * 24 * 3600);
+
+ if ($currentLevel === 'soft' && $hits >= $cfg['medium_trigger']) {
+ $this->cache->delete($hitKey);
+ $this->blockUser($identity, 'medium');
+ } elseif ($currentLevel === 'medium' && $hits >= $cfg['hard_trigger']) {
+ $this->cache->delete($hitKey);
+ $this->blockUser($identity, 'hard');
+ }
+ }
+
+ /**
+ * Resolve block duration from config based on level.
+ */
+ protected function blockDuration(array $cfg, string $level): int
+ {
+ return match ($level) {
+ 'soft' => $cfg['soft_duration'],
+ 'medium' => $cfg['medium_duration'],
+ 'hard' => $cfg['hard_duration'],
+ default => 0,
+ };
+ }
+
+ /**
+ * Build a standardised blocked response array.
+ */
+ protected function blockedResponse(string $type, string $level): array
+ {
+ $messages = [
+ 'soft' => 'Your access has been temporarily suspended. Please contact support.',
+ 'medium' => 'Your access has been restricted due to repeated violations.',
+ 'hard' => 'Your access has been permanently blocked. Please contact support.',
+ ];
+
+ return [
+ 'level' => $level,
+ 'type' => $type,
+ 'message' => $messages[$level] ?? 'Access denied.',
+ 'status' => $this->config->statusCodes[$level],
+ ];
+ }
+
+ /**
+ * Hash user identity (email or mobile) for cache key safety.
+ */
+ protected function hashIdentity(string $identity): string
+ {
+ return hash('sha256', strtolower(trim($identity)));
+ }
+}
diff --git a/app/Models/PolicyTransactionModel.php b/app/Models/PolicyTransactionModel.php
index fe7872f7..8c6d875d 100644
--- a/app/Models/PolicyTransactionModel.php
+++ b/app/Models/PolicyTransactionModel.php
@@ -3,6 +3,7 @@
namespace App\Models;
use CodeIgniter\Model;
+ use Kint;
class PolicyTransactionModel extends Model
{
@@ -3168,9 +3169,10 @@
pt.installment,
nhance_branch.branch_name as nhance_branch,
- DATE_FORMAT(pt.policy_issue_date, '%d %b %Y') AS policy_issue_date,
+ DATE_FORMAT(pcsd.pt_policy_issue_date, '%d %b %Y') AS policy_issue_date,
DATE_FORMAT(pcsd.pt_policy_issue_date, '%b %Y') AS policy_issue_month,
- pt.month as statement_month,
+ DATE_FORMAT(pcsd.pt_policy_issue_date, '%b %Y') AS statement_year_month,
+ pcsd.pt_policy_issue_date as statement_month,
'no statement uploaded' AS statement_uploaded,
@@ -3331,8 +3333,9 @@
pt.installment,
nhance_branch.branch_name as nhance_branch,
- DATE_FORMAT(pt.policy_issue_date, '%d %b %Y') AS policy_issue_date,
+ DATE_FORMAT(pcsd.pt_policy_issue_date, '%d %b %Y') AS policy_issue_date,
DATE_FORMAT(IF(insq.month IS NULL, pcsd.pt_policy_issue_date, insq.month),'%b %Y') AS policy_issue_month,
+ DATE_FORMAT(insq.month, '%b %Y') AS statement_year_month,
insq.month as statement_month,
'statement uploaded' AS statement_uploaded,
@@ -3392,7 +3395,7 @@
(pcsd.agreed_tp_per + pcsd.agreed_tep_per) AS agreed_tp_or_ter_per,
CASE
- WHEN insq.month = pt.month THEN pcsd.exp_amt
+ WHEN DATE_FORMAT(insq.month, '%Y-%m') = DATE_FORMAT(pcsd.pt_policy_issue_date, '%Y-%m') THEN pcsd.exp_amt
ELSE 0
END AS total_irda_amt_2,
@@ -3521,8 +3524,9 @@
pt.installment,
nhance_branch.branch_name as nhance_branch,
- DATE_FORMAT(pt.policy_issue_date, '%d %b %Y') AS policy_issue_date,
+ DATE_FORMAT(pcsd.pt_policy_issue_date, '%d %b %Y') AS policy_issue_date,
DATE_FORMAT(IF(insq.month IS NULL, pcsd.pt_policy_issue_date, insq.month),'%b %Y') AS policy_issue_month,
+ DATE_FORMAT(insq.month, '%b %Y') AS statement_year_month,
insq.month as statement_month,
'statement uploaded' AS statement_uploaded,
@@ -3704,7 +3708,7 @@
// $countofalldata = count($result);
- // dd($result);
+ // Kint::dump($result);
// dd($this->db->getLastQuery()->getQuery());
$keys = [];
@@ -3732,7 +3736,7 @@
// ✅ Stable key (NO reward flag)
$key = implode('|', [
- $row['statement_month'],
+ $row['statement_year_month'],
$row['insurer_name'],
$row['policy_no'],
$endorsement_number,
@@ -3753,7 +3757,7 @@
// Reindex final output
$result = array_values($filtered);
- // dd($countofalldata, $result);
+ // dd($result);
// --------------------------------------------------------------------------------------------------------
@@ -3776,7 +3780,7 @@
}
}
- // dd($totalIrdaMap);
+ // dd($totalBilled, $totalIrdaMap);
$ptSeen = [];
$final = [];
@@ -3785,8 +3789,10 @@
$ptId = $row['pt_id'].'-'.$row['insurer_id'];
if (!isset($ptSeen[$ptId])) {
// First entry → set unbilled amount
- $row['unbilled_amount'] = (float) (($totalIrdaMap[$ptId] ?? 0) - ($totalBilled[$ptId] ?? 0)) ?? '0.00';
-
+ $row['unbilled_amount'] = round(
+ (float) (($totalIrdaMap[$ptId] ?? 0) - ($totalBilled[$ptId] ?? 0)),
+ 2
+ );
$ptSeen[$ptId] = true;
} else {
// Other entries → zero
diff --git a/app/Models/SalesActivityModel.php b/app/Models/SalesActivityModel.php
index dc70086c..80b8aef6 100644
--- a/app/Models/SalesActivityModel.php
+++ b/app/Models/SalesActivityModel.php
@@ -60,52 +60,52 @@ class SalesActivityModel extends Model
protected $skipValidation = false;
/**
- * Get activities by lead with user details
+ * Get sales_activities by lead with user details
*/
public function getActivitiesByLead($leadId, $status = null)
{
- $builder = $this->select('activities.*, user_profiles.username as assigned_to_name')
- ->join('user_profiles', 'user_profiles.id = activities.assigned_to', 'left')
- ->where('activities.lead_id', $leadId);
+ $builder = $this->select('sales_activities.*, user_profiles.first_name as assigned_to_name')
+ ->join('user_profiles', 'user_profiles.id = sales_activities.assigned_to', 'left')
+ ->where('sales_activities.lead_id', $leadId);
if ($status) {
- $builder->where('activities.status', $status);
+ $builder->where('sales_activities.status', $status);
}
- return $builder->orderBy('activities.scheduled_date', 'DESC')->findAll();
+ return $builder->orderBy('sales_activities.scheduled_date', 'DESC')->findAll();
}
/**
- * Get all activities with filters
+ * Get all sales_activities with filters
*/
public function getActivitiesWithFilters($filters = [], $limit = 10, $offset = 0)
{
- $builder = $this->select('activities.*, actual_leads.company_name, user_profiles.username as assigned_to_name')
- ->join('actual_leads', 'actual_leads.lead_id = activities.lead_id', 'left')
- ->join('user_profiles', 'user_profiles.id = activities.assigned_to', 'left');
+ $builder = $this->select('sales_activities.*, actual_leads.company_name, user_profiles.first_name as assigned_to_name')
+ ->join('actual_leads', 'actual_leads.lead_id = sales_activities.lead_id', 'left')
+ ->join('user_profiles', 'user_profiles.id = sales_activities.assigned_to', 'left');
if (!empty($filters['status'])) {
- $builder->where('activities.status', $filters['status']);
+ $builder->where('sales_activities.status', $filters['status']);
}
if (!empty($filters['activity_type'])) {
- $builder->where('activities.activity_type', $filters['activity_type']);
+ $builder->where('sales_activities.activity_type', $filters['activity_type']);
}
if (!empty($filters['assigned_to'])) {
- $builder->where('activities.assigned_to', $filters['assigned_to']);
+ $builder->where('sales_activities.assigned_to', $filters['assigned_to']);
}
if (!empty($filters['date_from'])) {
- $builder->where('activities.scheduled_date >=', $filters['date_from']);
+ $builder->where('sales_activities.scheduled_date >=', $filters['date_from']);
}
if (!empty($filters['date_to'])) {
- $builder->where('activities.scheduled_date <=', $filters['date_to']);
+ $builder->where('sales_activities.scheduled_date <=', $filters['date_to']);
}
return [
- 'data' => $builder->orderBy('activities.scheduled_date', 'DESC')
+ 'data' => $builder->orderBy('sales_activities.scheduled_date', 'DESC')
->limit($limit, $offset)->findAll(),
'total' => $builder->countAllResults(false)
];
@@ -125,7 +125,7 @@ class SalesActivityModel extends Model
}
/**
- * Get pending activities count by user
+ * Get pending sales_activities count by user
*/
public function getPendingActivitiesCount($userId)
{
@@ -136,18 +136,18 @@ class SalesActivityModel extends Model
}
/**
- * Get upcoming activities for a user
+ * Get upcoming sales_activities for a user
*/
public function getUpcomingActivities($userId, $days = 7, $limit = 10)
{
$endDate = date('Y-m-d H:i:s', strtotime("+{$days} days"));
- return $this->select('activities.*, actual_leads.company_name')
- ->join('actual_leads', 'actual_leads.lead_id = activities.lead_id', 'left')
- ->where('activities.assigned_to', $userId)
- ->where('activities.status', 'pending')
- ->where('activities.scheduled_date <=', $endDate)
- ->orderBy('activities.scheduled_date', 'ASC')
+ return $this->select('sales_activities.*, actual_leads.company_name')
+ ->join('actual_leads', 'actual_leads.lead_id = sales_activities.lead_id', 'left')
+ ->where('sales_activities.assigned_to', $userId)
+ ->where('sales_activities.status', 'pending')
+ ->where('sales_activities.scheduled_date <=', $endDate)
+ ->orderBy('sales_activities.scheduled_date', 'ASC')
->limit($limit)
->findAll();
}
@@ -157,10 +157,10 @@ class SalesActivityModel extends Model
*/
public function getActivityTimeline($leadId)
{
- return $this->select('activities.*, user_profiles.username as assigned_to_name')
- ->join('user_profiles', 'user_profiles.id = activities.assigned_to', 'left')
- ->where('activities.lead_id', $leadId)
- ->orderBy('activities.scheduled_date', 'DESC')
+ return $this->select('sales_activities.*, user_profiles.first_name as assigned_to_name')
+ ->join('user_profiles', 'user_profiles.id = sales_activities.assigned_to', 'left')
+ ->where('sales_activities.lead_id', $leadId)
+ ->orderBy('sales_activities.scheduled_date', 'DESC')
->findAll();
}
}
\ No newline at end of file
diff --git a/app/Models/SalesActualLeadModel.php b/app/Models/SalesActualLeadModel.php
index 6b8aee8f..25603740 100644
--- a/app/Models/SalesActualLeadModel.php
+++ b/app/Models/SalesActualLeadModel.php
@@ -6,7 +6,7 @@ use CodeIgniter\Model;
/**
* Lead Model
- * Handles all operations related to actual_leads table
+ * Handles all operations related to sales_actual_leads table
*/
class SalesActualLeadModel extends Model
{
@@ -63,9 +63,9 @@ class SalesActualLeadModel extends Model
*/
public function getLeadWithUser($leadId)
{
- return $this->select('actual_leads.*, user_profiles.username as assigned_to_name, user_profiles.email as assigned_to_email')
- ->join('user_profiles', 'user_profiles.id = actual_leads.assigned_to', 'left')
- ->where('actual_leads.lead_id', $leadId)
+ return $this->select('sales_actual_leads.*, user_profiles.first_name as assigned_to_name, user_profiles.email as assigned_to_email')
+ ->join('user_profiles', 'user_profiles.id = sales_actual_leads.assigned_to', 'left')
+ ->where('sales_actual_leads.lead_id', $leadId)
->first();
}
@@ -74,22 +74,22 @@ class SalesActualLeadModel extends Model
*/
public function getLeadsWithFilters($filters = [], $limit = 10, $offset = 0)
{
- $builder = $this->select('actual_leads.*, user_profiles.username as assigned_to_name')
- ->join('user_profiles', 'user_profiles.id = actual_leads.assigned_to', 'left');
+ $builder = $this->select('sales_actual_leads.*, user_profiles.first_name as assigned_to_name')
+ ->join('user_profiles', 'user_profiles.id = sales_actual_leads.assigned_to', 'left');
if (!empty($filters['status'])) {
- $builder->where('actual_leads.status', $filters['status']);
+ $builder->where('sales_actual_leads.status', $filters['status']);
}
if (!empty($filters['assigned_to'])) {
- $builder->where('actual_leads.assigned_to', $filters['assigned_to']);
+ $builder->where('sales_actual_leads.assigned_to', $filters['assigned_to']);
}
if (!empty($filters['search'])) {
$builder->groupStart()
- ->like('actual_leads.company_name', $filters['search'])
- ->orLike('actual_leads.email', $filters['search'])
- ->orLike('actual_leads.phone', $filters['search'])
+ ->like('sales_actual_leads.company_name', $filters['search'])
+ ->orLike('sales_actual_leads.email', $filters['search'])
+ ->orLike('sales_actual_leads.phone', $filters['search'])
->groupEnd();
}
diff --git a/app/Models/SalesLeadNoteModel.php b/app/Models/SalesLeadNoteModel.php
index c8d9654f..60e612a4 100644
--- a/app/Models/SalesLeadNoteModel.php
+++ b/app/Models/SalesLeadNoteModel.php
@@ -53,10 +53,10 @@ class SalesLeadNoteModel extends Model
*/
public function getNotesByLead($leadId)
{
- return $this->select('lead_notes.*, user_profiles.username')
- ->join('user_profiles', 'user_profiles.id = lead_notes.user_id', 'left')
- ->where('lead_notes.lead_id', $leadId)
- ->orderBy('lead_notes.created_at', 'DESC')
+ return $this->select('sales_lead_notes.*, user_profiles.first_name')
+ ->join('user_profiles', 'user_profiles.id = sales_lead_notes.created_by', 'left')
+ ->where('sales_lead_notes.lead_id', $leadId)
+ ->orderBy('sales_lead_notes.created_at', 'DESC')
->findAll();
}
@@ -65,10 +65,10 @@ class SalesLeadNoteModel extends Model
*/
public function getNotesByUser($userId, $limit = 20, $offset = 0)
{
- return $this->select('lead_notes.*, actual_leads.company_name')
- ->join('actual_leads', 'actual_leads.lead_id = lead_notes.lead_id', 'left')
- ->where('lead_notes.user_id', $userId)
- ->orderBy('lead_notes.created_at', 'DESC')
+ return $this->select('sales_lead_notes.*, actual_leads.company_name')
+ ->join('actual_leads', 'actual_leads.lead_id = sales_lead_notes.lead_id', 'left')
+ ->where('sales_lead_notes.created_by', $userId)
+ ->orderBy('sales_lead_notes.created_at', 'DESC')
->limit($limit, $offset)
->findAll();
}
diff --git a/app/Models/TpaConfigModel.php b/app/Models/TpaConfigModel.php
new file mode 100644
index 00000000..10ddc35a
--- /dev/null
+++ b/app/Models/TpaConfigModel.php
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/app/Views/claim_files_upload.php b/app/Views/claim_files_upload.php
index 7b9cd814..9132e7e5 100644
--- a/app/Views/claim_files_upload.php
+++ b/app/Views/claim_files_upload.php
@@ -91,7 +91,7 @@
Submit
+ id="g_drive_file_upload_sbt_btn">Save
diff --git a/app/Views/client_basic_info.php b/app/Views/client_basic_info.php
index 055a0e33..a8de6ec7 100755
--- a/app/Views/client_basic_info.php
+++ b/app/Views/client_basic_info.php
@@ -287,6 +287,8 @@ input:checked + .slider:before {
var message = (PrimaryKey === '') ? 'Client General Info Created successfully' : 'Client General Info Updated successfully';
toastr.success(message, 'Success');
$submitButton.prop('disabled', false);
+ let client_name = res.data.client_name ? (' - ' + res.data.client_name) : '';
+ $('#client_heading').text(client_name);
}, 1000);
}
diff --git a/app/Views/client_onboarding.php b/app/Views/client_onboarding.php
index d8d5eb68..c63e00a6 100755
--- a/app/Views/client_onboarding.php
+++ b/app/Views/client_onboarding.php
@@ -273,9 +273,9 @@
-
Client Onboarding Client Onboarding
+ } ?>
">
diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php
index 5811354c..b18e9021 100755
--- a/app/Views/client_policy.php
+++ b/app/Views/client_policy.php
@@ -291,7 +291,7 @@ input:checked + .slider_blue::before {
-->
- Disclaimer*
+ Disclaimer
diff --git a/app/Views/gsheet_editor.php b/app/Views/gsheet_editor.php
new file mode 100644
index 00000000..93f40957
--- /dev/null
+++ b/app/Views/gsheet_editor.php
@@ -0,0 +1,73 @@
+
+
+
+
Google Sheet Editor
+
+
+
+
+
Google Sheet Editor
+
+
💾 Save
+
⬇ Download
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/logs/view.php b/app/Views/logs/view.php
index de031e03..1e7b7cfb 100644
--- a/app/Views/logs/view.php
+++ b/app/Views/logs/view.php
@@ -2,482 +2,126 @@
-
= esc($title) ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- = count(array_filter($logEntries, fn($e) => stripos($e['message'], 'TPA CLAIM PUSH SUCCESS') !== false)) ?>
-
-
Claim success
-
-
-
- = count(array_filter($logEntries, fn($e) => stripos($e['message'], 'TPA CLAIM PUSH FAILED') !== false)) ?>
-
-
Claim failed
-
-
-
- = count(array_filter($logEntries, fn($e) => stripos($e['message'], 'TPA ID PULL SUCCESS') !== false)) ?>
-
-
Tpa no pull success
-
-
-
- = count(array_filter($logEntries, fn($e) => stripos($e['message'], 'TPA ID PULL FAILED') !== false)) ?>
-
-
Tpa no pull Failed
-
-
-
- = count(array_filter($logEntries, fn($e) => stripos($e['message'], 'CLAIM STATUS SUCCESS') !== false)) ?>
-
-
Claim status fetch success
-
-
-
- = count(array_filter($logEntries, fn($e) => stripos($e['message'], 'CLAIM STATUS FAILED') !== false)) ?>
-
-
Claim status fetch failed
-
-
-
- = count(array_filter($logEntries, fn($e) => stripos($e['message'], 'Ecard Request PUSH SUCCESS') !== false)) ?>
-
-
Ecard Request
-
-
-
-
-
-
-
-
-
- Filter:
- All
- Critical
- Error
- Warning
- Info
- Debug
-
-
-
-
-
-
-
No Log Entries Found
-
This log file is empty or couldn't be parsed.
-
-
-
-
-
-
-
-
= esc($entry['message']) ?>
-
-
-
-
+
+
-
+
+
+
+
+
No Logs Found
+
Try adjusting your TPA filters or search term.
+
+
+
+
+
+
+ = esc($entry['level']) ?>
+ = esc($entry['date']) ?>
+
+
= esc($entry['message']) ?>
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/Views/policy_grid.php b/app/Views/policy_grid.php
index 4c519a97..61518cf8 100755
--- a/app/Views/policy_grid.php
+++ b/app/Views/policy_grid.php
@@ -151,7 +151,7 @@
@@ -371,9 +371,11 @@ $('body').on('click', '.btnPolicyModel', function()
$('.loader-mask').fadeIn();
if (policy_type_string == 'GPA' || policy_type_id == 6 || policy_type_id == 7) {
- $('#add_new_rack_rate_tab_div').hide();
+ $('.savebuttonChange').text('Submit');
+ $('#add_new_rack_rate_tab_div').hide('');
$('#rack_rate_one').hide();
} else {
+ $('.savebuttonChange').text('Save');
$('#add_new_rack_rate_tab_div').show();
$('#rack_rate_one').show();
}
@@ -3413,7 +3415,7 @@ function appendNewTab(tabNameData = null, data = null)
diff --git a/app/Views/policy_transaction_inception_form.php b/app/Views/policy_transaction_inception_form.php
index 5f6ae488..84613a8d 100644
--- a/app/Views/policy_transaction_inception_form.php
+++ b/app/Views/policy_transaction_inception_form.php
@@ -2713,13 +2713,10 @@
if(allocg != 'EB'){
tp = parseFloat($('#tp_premium_' + input).val()) || 0;
}
- // do not remove this commented item
- // if(bap == 'Motor'){
- // tp = parseFloat($('#tp_premium_' + input).val()) || 0;
- // }
var tep = 0;
- if(bap == 'Fire' || bap == 'Marine Cargo' || bap == 'Marine Hull'){
+ // if(bap == 'Fire' || bap == 'Marine Cargo' || bap == 'Marine Hull'){
+ if(allocg != 'EB'){
tep = parseFloat($('#ter_premium_' + input).val()) || 0;
}
@@ -2732,7 +2729,8 @@
}
var cotep = 0;
- if(bap == 'Fire' || bap == 'Marine Cargo' || bap == 'Marine Hull'){
+ // if(bap == 'Fire' || bap == 'Marine Cargo' || bap == 'Marine Hull'){
+ if(allocg != 'EB'){
cotep = parseFloat($('#co_ter_premium_' + input).val()) || 0;
}
diff --git a/app/Views/sales/branch_level_dashboard_view.php b/app/Views/sales/branch_level_dashboard_view.php
new file mode 100644
index 00000000..3a9d13cc
--- /dev/null
+++ b/app/Views/sales/branch_level_dashboard_view.php
@@ -0,0 +1,177 @@
+
+
+
+
+
+
+
+
4
+
Total Leads
+
↑ 12% this month
+
+
+
6
+
Total Activities
+
↑ 5% this month
+
+
+
1
+
Completed Activities
+
↑ 15% this month
+
+
+
₹15.0L
+
Pipeline Value
+
↑ 18% this month
+
+
+
+
+
+
+
+
+
+ Company
+ Activity & Assigned
+ Date
+ Status
+
+
+
+
+ Venba Infotech
+
+ CALL
+ John Doe
+
+ 20 Feb 2026
+ Completed
+
+
+ Acme Corporation
+
+ EMAIL
+ John Doe
+
+ 20 Feb 2026
+ Pending
+
+
+
+
+
+
+
+
Sales Team Performance
+
+
V
+
+
Venkat 3.0
+
Sales Manager
+
+
+
+
+
P
+
+
Pavi_the_Staff V
+
Sales Staff
+
+
+
+
+
+
+
Activity Breakdown
+
Call42%
+
Email25%
+
Meeting18%
+
Visit10%
+
Demo5%
+
+
+
+
+
+
+
+
+
+ Company
+ Status
+ Assigned To
+ Activities
+ Opportunities
+
+
+
+
+ Venba Infotech
+ New
+ John Doe
+ 1
+ 1
+
+
+ Acme Corporation
+ Potential
+ John Doe
+ 1
+ 0
+
+
+
+
+
\ No newline at end of file
diff --git a/app/Views/sales/sales_manager_level_dashboard.php b/app/Views/sales/sales_manager_level_dashboard.php
new file mode 100644
index 00000000..5b75fc42
--- /dev/null
+++ b/app/Views/sales/sales_manager_level_dashboard.php
@@ -0,0 +1,93 @@
+
+
+
+
+
+
My Dashboard
+
Welcome back, = $user_name ?>
+
+
+
+
+
+
+
+
YEARLY TARGET 2025
+
₹= number_format($target / 100000, 1) ?>L
+
Apr 2025 - Mar 2026
+
+
+ = $percent ?>%
+
+
+
+
+ Achieved ₹= number_format($achieved / 100000, 1) ?>L
+ Remaining ₹= number_format($remaining / 100000, 1) ?>L
+
+
+
+
= $acts['total'] ?> My Activities
+
= $acts['pending'] ?> Pending
+
= $acts['completed'] ?> Completed
+
= $lead_count ?> My Leads
+
+
+
+
+
+
+
My Upcoming Activities
+ = $acts['pending'] ?> pending
+
+
+
+
+
= $u['company_name'] ?>
+
= strtoupper($u['activity_type'] ?? 'EMAIL') ?> - = date('d Mar Y', strtotime($u['scheduled_date'])) ?>
+
+
✓ Done
+
+
+
+
+
+
My Recent Leads
+
+
+
+
= substr($rl['company_name'], 0, 1) ?>
+
+
= $rl['company_name'] ?>
+
= $rl['email'] ?>
+
+
+
= $rl['status'] ?>
+
+
+
+
+
\ No newline at end of file
diff --git a/app/Views/sales/tracker_view.php b/app/Views/sales/tracker_view.php
new file mode 100644
index 00000000..b317712c
--- /dev/null
+++ b/app/Views/sales/tracker_view.php
@@ -0,0 +1,356 @@
+
+
+
+
+
+ + Add Lead
+
+
+
+
All
+
New
+
Potential
+
Prospects
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Activity Timeline
+ + Add Activity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Outcome Notes
+
+
+
+ Next Follow-up?
+
+ No
+ Yes
+
+
+
+ Submit Outcome
+
+
+
+
+
\ No newline at end of file
diff --git a/app/Views/ticket_auto_query.php b/app/Views/ticket_auto_query.php
index a6651e8d..d26a84c1 100644
--- a/app/Views/ticket_auto_query.php
+++ b/app/Views/ticket_auto_query.php
@@ -49,7 +49,7 @@
- Submit
+ Save
diff --git a/app/Views/ticket_form_gmc.php b/app/Views/ticket_form_gmc.php
index 5d1ae008..782cc30d 100644
--- a/app/Views/ticket_form_gmc.php
+++ b/app/Views/ticket_form_gmc.php
@@ -501,7 +501,7 @@
-
Submit
+
= !isset($ticket_data) ? "Submit" : "Save" ?>
Approve Claim Rejection
diff --git a/app/Views/ticket_form_gpa.php b/app/Views/ticket_form_gpa.php
index 3da118d5..8604bc0b 100644
--- a/app/Views/ticket_form_gpa.php
+++ b/app/Views/ticket_form_gpa.php
@@ -326,7 +326,7 @@
Submit
+ id="btnSubmit">= !isset($ticket_data) ? "Submit" : "Save" ?>
Rejected Approve
diff --git a/app/Views/ticket_form_motor.php b/app/Views/ticket_form_motor.php
index 8d891cec..68ba84b2 100644
--- a/app/Views/ticket_form_motor.php
+++ b/app/Views/ticket_form_motor.php
@@ -340,7 +340,7 @@
Submit
+ id="btnSubmit">= !isset($ticket_data) ? "Submit" : "Save" ?>
Rejected Approve
diff --git a/app/Views/ticket_note.php b/app/Views/ticket_note.php
index 97c37331..05033b69 100644
--- a/app/Views/ticket_note.php
+++ b/app/Views/ticket_note.php
@@ -13,7 +13,7 @@
- Submit
+ Save
diff --git a/app/Views/view_deposit.php b/app/Views/view_deposit.php
index c0b9272e..3a290002 100755
--- a/app/Views/view_deposit.php
+++ b/app/Views/view_deposit.php
@@ -461,9 +461,34 @@
location.reload();
},
error: function(xhr, status, error) {
- toastr.error("Transaction save failed", "Error");
+
console.error(xhr.responseText);
console.error(status, error);
+
+ if (xhr.status === 400) {
+ let response = JSON.parse(xhr.responseText);
+ let errorMessages = "";
+ let seenMessages = []; // Array to store unique messages
+ if (response.errors) {
+ $.each(response.errors, function (field, message) {
+ if (!seenMessages.includes(message)) {
+ errorMessages += `• ${message} `;
+ seenMessages.push(message); // Mark this message as "seen"
+ }
+ });
+ toastr.error(errorMessages, 'Validation Error', { "allowHtml": true });
+ } else {
+ toastr.warning(response.message || 'Validation failed', 'Warning');
+ }
+ } else if (xhr.status === 403) {
+ let response = JSON.parse(xhr.responseText);
+ toastr.error(response.message, 'Security Policy');
+ } else if (xhr.status === 500) {
+ toastr.error('Something went wrong . Please try again later.', 'Server Error');
+ } else {
+ toastr.error('An unexpected error occurred. Please try again later.', 'Error');
+ }
+
location.reload(); // Uncomment if you need to reload the page on error
}
});
diff --git a/gdrive-demo-394007-5b1d856b0c5b.json b/gdrive-demo-394007-5b1d856b0c5b.json
new file mode 100644
index 00000000..d2c85363
--- /dev/null
+++ b/gdrive-demo-394007-5b1d856b0c5b.json
@@ -0,0 +1,13 @@
+{
+ "type": "service_account",
+ "project_id": "gdrive-demo-394007",
+ "private_key_id": "5b1d856b0c5b13e52b5210d381ce7ae02204f666",
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9tqkwe8XEuvDJ\ngDAKHn7FzFgkmor9sEZPkjofVJ1dK0RpD1mMVw38BzzMsEo8Y8aojNKj9FcgJPI+\nMiSwvoHDVGxPuyz2Q7o8BS7WdM83Sn69CBGn+0s+YjsyQ5pQBeu1YZ3erjckyA1M\nX0a0qXSFRm7dN0pwDIk0SP9/pl5iAKEtakuXn/Q+lSIpHz6OUgQy8bCjn91poMtF\nhL1YR/7k8ZttjQiFSCTzQ6e3IJmVbqY9UZ2hc4zVicLVSLM2x17M1CCVrsXoceOj\nQoYEeCqP2qJjGA29CB66xpXetuOFcll/ZHiNBhSekOBbJIKFG8WfTKaFn4hu2HX6\nzbJLse5FAgMBAAECggEAXK8qxWcS3eQ+0xLvZWI0qUoGHgvqr7o4/5L/FmNuZiBH\nUdSP+UJmsKSQjafq/Mn6OkpidntfPXMPbldtGXRZTSanq+RUORQpnj0h/uAehHK+\nrHeOuLTKs/Wl2g6xCzt5RqokSLBwfGXIKXG6x3SqWppoe2cR1OArAAJR4PlUzyeM\nP0HkZcVMDrXkshpbi/7yk1Yol5CTJjUrXT4cH2eFSih+eu5UxI/uEdxu86XnaB+V\nBDS94nSQffaMem3YLRSQpPWMHJts3NM2eoxpVy3NqbyHH0Jzr47T5+pdnk5AZX8v\nMu7L0FYgUmGli8W9/jV43lUi9z147EpNC1ugySICGQKBgQDeT3i9mBO1HQB+3y05\n4ao9YKWtR7RHTIiMBkekRs58xxWIq75+bsJtLMy0GsHOJHbpdfDU2AtcasYXVm/L\nc960AR7Qm0mdhQi5CG7XfFTvkc+RhsFoCAYOnbdInr1D+s7NsyOgdYvzh9HYIiJ/\nm8MzeGQia/4tlO+UNq7UK0sfowKBgQDadpe0OCynXEiziSY/aBT9mrjplXJSJUeR\nX5/pUrBV++mYt+LJU0Q+4op0Qf+PUJwp72O1v3T9h4ox2BcrYUMI17dJZ5HG46BG\n6Sjh+mZzLCTN9L6AVgRzK/5CUpsL+oPpClzGQK+1uJ+YKZD086YBuQi2JiG6uBxk\n7VLzATZ49wKBgQC3ZHgGb95SGoq+Hv4AMdluqLwEJpLh/pDmcofHTWIqLVHmXUfY\npSZfSgXUzf3zQMGX9mOmMlOs+ahQuE2hWQTvGb2B+ZjRCV4Yxowp17d5qp/BPZlv\naK8Wf6Ujk1AvNEhGCPHq/Q1m6TSDSCWNf8GYREjW3J/immrJqhKvlMd0YQKBgQCM\nf2CpQsdVCwCmljnG5YU6ZFsvvjE7q0YPtFP/lnJZmh1tXjW4DJkDaGZqxlc5MDp+\nrbqOlIcE1jqGO9cKyw51jWYPC1CxfIsDj8f/LS7eOzGgUxqBJtDN0SlANigI2CAl\nq8hmqAtY71eUYIcdQeUtjnaPzo46q1V3gzmplsoVmQKBgDCzaBbFY1bKW+xPPC98\nutYS7cGYtTq241zafSXx/qmpZB2QwFsR3rmZ9msCEBb3TY4Ew+hUi7+SP3ycSU1s\nkwIO/9DaZhFBRA9jbwbu4zdB2Niamfo79epqJ8vhJ6TA2d5xRSGbHWkGymWV/e0p\na74mh5hQ0lqI4MSeArFrJwwF\n-----END PRIVATE KEY-----\n",
+ "client_email": "gsheet@gdrive-demo-394007.iam.gserviceaccount.com",
+ "client_id": "108808196910972902964",
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+ "token_uri": "https://oauth2.googleapis.com/token",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/gsheet%40gdrive-demo-394007.iam.gserviceaccount.com",
+ "universe_domain": "googleapis.com"
+}