diff --git a/app/Config/Acl.php b/app/Config/Acl.php
index ce46852c..8b0476ea 100644
--- a/app/Config/Acl.php
+++ b/app/Config/Acl.php
@@ -44,7 +44,7 @@ class Acl
'#^/sendDataToTPA#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID, MANAGER_ROLE_ID]],
'#^/swagger#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID, MANAGER_ROLE_ID]],
'#^/viewClaimFile#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID]],
-
+ '#^/employee/tpaReportsDashboard#' => ['roles' => [ACCOUNT_MANAGER_ROLE_ID]],
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 4b2155c4..78a80888 100755
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -35,6 +35,7 @@ $routes->get('/fedeploy', 'DeployController::fedeploy_view', ['filter' => 'authM
$routes->post('/fedeploy', 'DeployController::fedeploy', ['filter' => 'authMVC']);
$routes->get('/visitOffBoardCheck', 'EmployeeController::visitOffBoardCheck');
$routes->get('/metaDashboardDemo', 'TestingController::metaDashboardDemo');
+$routes->get('/apacheSuperSetDemo', 'TestingController::apacheSuperSetDemo');
$routes->get('/metaTpaDashboardDemo', 'TestingController::metaTpaDashboardDemo');
// Reminder Mail Notification
@@ -137,6 +138,7 @@ $routes->group("/client", ["filter" => "authMVC"], function ($routes) {
$routes->get('view_deposit/(:num)', 'ClientController::view_Deposit/$1');
$routes->get('createtransaction', 'ClientController::createtransaction');
$routes->post('save_deposit', 'ClientController::saveDeposit');
+ $routes->post('update_deposit_amount', 'ClientController::updateDepositAmount');
$routes->post("saveApiData", "ClientController::saveApiData");
$routes->get("generateToken","ClientController::sendToken");
// $routes->get('view_Deposit/(:num)/(:num)','ClientController/view_Deposit/$1/$2');
@@ -240,7 +242,7 @@ $routes->group("/employee", ["filter" => "authMVC"], function ($routes) {
$routes->get("bulkGenerateEcardAndStoreinS3", "EmployeeController::bulkGenerateEcardAndStoreinS3");
$routes->get('clearCdSession', 'EmployeeController::clearCdSession');
$routes->get('checkSessionStatus', 'EmployeeController::checkSessionStatus');
-
+ $routes->get("tpaReportsDashboard", "EmployeeController::tpaReportsDashboard");
});
@@ -460,6 +462,15 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) {
$routes->get('insertSampleTpaApiData/(:any)', 'TestingController::insertSampleTpaApiData/$1');
$routes->get('listEmployeeCountByClientPolicy', 'TestingController::listEmployeeCountByClientPolicy');
$routes->get('testMediAssistWellness','TestingController::testMediAssistWellness');
+
+ $routes->group('claims-collection-v2', static function ($routes) {
+ $routes->get('preview', 'ClaimsCollectionV2DashboardController::preview');
+ $routes->get('preview/(:num)', 'ClaimsCollectionV2DashboardController::preview/$1');
+ $routes->get('kpi/(:segment)', 'ClaimsCollectionV2DashboardController::kpi/$1');
+ $routes->get('all', 'ClaimsCollectionV2DashboardController::all');
+ $routes->get('debug', 'ClaimsCollectionV2DashboardController::debug');
+ $routes->get('debug/(:num)', 'ClaimsCollectionV2DashboardController::debug/$1');
+ });
});
$routes->post("policy_tranction/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail");
@@ -767,6 +778,15 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel
$routes->get("downloadPolicyFiles", "EmployeeRestController::downloadPolicyFiles");
$routes->post("bulkEcardDownloadAsZip", "EmployeeRestController::bulkEcardDownloadAsZip");
$routes->get("downloadSampleExcel/(:any)", "EmployeeController::downloadSampleExcelFile/$1");
+
+ $routes->group('claims-collection-v2', static function ($routes) {
+ $routes->get('preview', 'ClaimsCollectionV2DashboardController::preview');
+ $routes->get('preview/(:num)', 'ClaimsCollectionV2DashboardController::preview/$1');
+ $routes->get('kpi/(:segment)', 'ClaimsCollectionV2DashboardController::kpi/$1');
+ $routes->get('all', 'ClaimsCollectionV2DashboardController::all');
+ $routes->get('debug', 'ClaimsCollectionV2DashboardController::debug');
+ $routes->get('debug/(:num)', 'ClaimsCollectionV2DashboardController::debug/$1');
+ });
});
$routes->post("bulkEcardDownloadAsZip", "EmployeeRestController::bulkEcardDownloadAsZip");
@@ -804,6 +824,7 @@ $routes->group("/ticket", ["filter" => "authMVC"], function ($routes) {
$routes->get('feedback-list','TicketController::feedbackList');
$routes->match(['get', 'post'], 'claim-upload','TicketController::claimDumpUpload');
$routes->get('remove','TicketController::removeTicket');
+ $routes->get('tpa-claim-push-logs','TicketController::getTpaClaimPushLogs');
$routes->get('new/(:any)','TicketController::ticket_form/$1');
$routes->post('create','TicketController::createTicket');
$routes->post('update','TicketController::updateTicket');
diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php
index 18eac66a..735cbfb0 100644
--- a/app/Controllers/ApiServiceController.php
+++ b/app/Controllers/ApiServiceController.php
@@ -50,7 +50,9 @@ class ApiServiceController extends BaseController
// Push Claims
public function pushClaims($claimId)
{
-
+ helper('tpa_claim_push_log');
+ init_tpa_claim_push_logs($claimId);
+
$data = $this->db->table('ticket_master tm')
->select('tm.id,tm.tpa_id ')->where('tm.id', $claimId)->get()->getRowArray(); // single record
@@ -79,7 +81,7 @@ class ApiServiceController extends BaseController
$voloApiController = new VoloApiController();
return $voloApiController->SubmitClaim($claimId);
}else{
- log_message('error', "This ticket id ( {$claimId} ) TPA has no API service enabled. TPA ID : {$tpaID}");
+ tpa_claim_push_log($claimId, "This ticket id ( {$claimId} ) TPA has no API service enabled. TPA ID : {$tpaID}");
}
}
diff --git a/app/Controllers/ClaimsCollectionV2DashboardController.php b/app/Controllers/ClaimsCollectionV2DashboardController.php
new file mode 100644
index 00000000..e49739d1
--- /dev/null
+++ b/app/Controllers/ClaimsCollectionV2DashboardController.php
@@ -0,0 +1,166 @@
+request->getGet('client_policy')
+ ?? $this->request->getGet('client_policy_id')
+ ?? $this->request->getPost('client_policy')
+ ?? $this->request->getPost('client_policy_id')
+ ?? 0
+ );
+
+ if ($id > 0) {
+ return $id;
+ }
+
+ if ($fallback !== null && $fallback > 0) {
+ return $fallback;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Resolve KPI by Metabase numeric id or method slug.
+ */
+ protected function resolveKpiMethod(string $kpiKey): ?string
+ {
+ $kpiKey = trim($kpiKey);
+ if ($kpiKey === '') {
+ return null;
+ }
+
+ if (in_array($kpiKey, ClaimsCollectionV2DashboardModel::KPI_MAP, true)) {
+ return $kpiKey;
+ }
+
+ if (ctype_digit($kpiKey)) {
+ $id = (int) $kpiKey;
+ return ClaimsCollectionV2DashboardModel::KPI_MAP[$id] ?? null;
+ }
+
+ return null;
+ }
+
+ /**
+ * JSON: single KPI by slug (e.g. incurred_ratio) or Metabase id (e.g. 207).
+ * Requires client_policy or client_policy_id.
+ */
+ public function kpi(string $kpiMethod = '')
+ {
+ $policyId = $this->resolvePolicyId();
+
+ if ($policyId <= 0) {
+ return $this->respond([
+ 'status' => false,
+ 'message' => 'client_policy or client_policy_id is required.',
+ ], 422);
+ }
+
+ $kpiMethod = $this->resolveKpiMethod($kpiMethod);
+ if ($kpiMethod === null) {
+ return $this->respond([
+ 'status' => false,
+ 'message' => 'Unknown KPI. Pass Metabase id or method slug.',
+ 'allowed' => ClaimsCollectionV2DashboardModel::KPI_MAP,
+ ], 404);
+ }
+
+ $model = new ClaimsCollectionV2DashboardModel();
+ $metabaseId = array_search($kpiMethod, ClaimsCollectionV2DashboardModel::KPI_MAP, true);
+
+ return $this->respond([
+ 'status' => true,
+ 'policy_id' => $policyId,
+ 'kpi_id' => $metabaseId !== false ? (int) $metabaseId : null,
+ 'kpi' => $kpiMethod,
+ 'label' => ClaimsCollectionV2DashboardModel::KPI_LABELS[$kpiMethod] ?? $kpiMethod,
+ 'rows' => $model->getKpi($kpiMethod, $policyId),
+ ]);
+ }
+
+ /**
+ * JSON: all KPIs. Requires client_policy or client_policy_id.
+ */
+ public function all()
+ {
+ $policyId = $this->resolvePolicyId();
+
+ if ($policyId <= 0) {
+ return $this->respond([
+ 'status' => false,
+ 'message' => 'client_policy or client_policy_id is required.',
+ ], 422);
+ }
+
+ $model = new ClaimsCollectionV2DashboardModel();
+
+ return $this->respond([
+ 'status' => true,
+ 'policy_id' => $policyId,
+ 'data' => $model->getAllKpis($policyId),
+ ]);
+ }
+
+ /**
+ * Admin preview UI (authMVC only) — KPI grid for manual testing.
+ * Default policy id only in method signature; override via query or /preview/{id}.
+ */
+ public function preview(int $policyId = 4687)
+ {
+ $policyId = $this->resolvePolicyId($policyId);
+ $path = $this->request->getUri()->getPath();
+ $isJwt = stripos($path, 'employeeRest') !== false;
+ $prefix = $isJwt ? 'employeeRest/claims-collection-v2' : 'util/claims-collection-v2';
+
+ return view('claims_collection_v2_dashboard', [
+ 'policy_id' => $policyId,
+ 'kpi_map' => ClaimsCollectionV2DashboardModel::KPI_MAP,
+ 'kpi_labels' => ClaimsCollectionV2DashboardModel::KPI_LABELS,
+ 'api_all_url' => base_url($prefix . '/all'),
+ 'api_kpi_url' => base_url($prefix . '/kpi'),
+ ]);
+ }
+
+ /**
+ * Admin check only: raw JSON on screen (no dashboard UI).
+ * Default policy id only here; override via ?client_policy= or /debug/{id}.
+ */
+ public function debug(int $policyId = 4687)
+ {
+ $policyId = $this->resolvePolicyId($policyId);
+
+ if ($policyId <= 0) {
+ return $this->response
+ ->setStatusCode(422)
+ ->setBody('client_policy or client_policy_id is required.');
+ }
+
+ $model = new ClaimsCollectionV2DashboardModel();
+ $body = json_encode([
+ 'status' => true,
+ 'policy_id' => $policyId,
+ 'data' => $model->getAllKpis($policyId),
+ ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
+
+ return $this->response
+ ->setHeader('Content-Type', 'application/json; charset=UTF-8')
+ ->setBody($body);
+ }
+}
diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php
index 56087644..4c9edd8d 100755
--- a/app/Controllers/ClientController.php
+++ b/app/Controllers/ClientController.php
@@ -902,6 +902,109 @@ class ClientController extends AdminController
return $this->response->setJSON(['success' => $response['success']]);
}
+ public function updateDepositAmount()
+ {
+ $rules = [
+ 'deposit_id' => 'required|is_natural_no_zero',
+ 'amount' => 'required|numeric|greater_than_equal_to[0]',
+ 'transaction_type' => 'required|in_list[Credit,Debit]',
+ 'client_id' => 'required',
+ 'insurer_id' => 'required|is_natural_no_zero',
+ 'cd_ac_pk' => 'required|is_natural_no_zero',
+ ];
+
+ if (! $this->validate($rules)) {
+ return $this->response
+ ->setStatusCode(400)
+ ->setJSON([
+ 'status' => 'error',
+ 'message' => 'Input validation failed',
+ 'errors' => $this->validator->getErrors(),
+ ]);
+ }
+
+ $postData = sanitizeInputArrayAdvanced($this->request->getPost());
+ $depositId = (int) ($postData['deposit_id'] ?? 0);
+ $clientId = $postData['client_id'] ?? null;
+ $insurerId = (int) ($postData['insurer_id'] ?? 0);
+ $cdAcPk = (int) ($postData['cd_ac_pk'] ?? 0);
+ $amount = (float) ($postData['amount'] ?? 0);
+ $transactionType = $postData['transaction_type'] ?? 'Credit';
+ $loggedInUserID = get_session_userid();
+
+ $depositModel = new ClientDepositModel();
+
+ $targetRow = $depositModel
+ ->where('id', $depositId)
+ ->where('client_id', $clientId)
+ ->where('insurer_id', $insurerId)
+ ->where('cd_ac_pk', $cdAcPk)
+ ->where('is_active', 1)
+ ->first();
+
+ if (empty($targetRow)) {
+ return $this->response
+ ->setStatusCode(404)
+ ->setJSON([
+ 'status' => 'error',
+ 'message' => 'Transaction not found for this account.',
+ ]);
+ }
+
+ $existingType = $targetRow['transaction_type'] ?? '';
+ if ($existingType !== $transactionType) {
+ return $this->response
+ ->setStatusCode(400)
+ ->setJSON([
+ 'status' => 'error',
+ 'message' => 'Only ' . $existingType . ' value can be edited for this transaction.',
+ ]);
+ }
+
+ $db = \Config\Database::connect();
+ $db->transBegin();
+
+ $depositModel->update($depositId, [
+ 'amount' => $amount,
+ 'transaction_type' => $transactionType,
+ 'updated_by' => $loggedInUserID,
+ ]);
+
+ $rows = $depositModel
+ ->where('client_id', $clientId)
+ ->where('insurer_id', $insurerId)
+ ->where('cd_ac_pk', $cdAcPk)
+ ->where('is_active', 1)
+ ->orderBy('id', 'ASC')
+ ->findAll();
+
+ $runningBalance = 0.0;
+ foreach ($rows as $row) {
+ $rowAmount = (float) ($row['amount'] ?? 0);
+ $runningBalance += (($row['transaction_type'] ?? '') === 'Credit') ? $rowAmount : -$rowAmount;
+ $depositModel->update((int) $row['id'], [
+ 'balance' => $runningBalance,
+ 'updated_by' => $loggedInUserID,
+ ]);
+ }
+
+ if ($db->transStatus() === false) {
+ $db->transRollback();
+ return $this->response
+ ->setStatusCode(500)
+ ->setJSON([
+ 'status' => 'error',
+ 'message' => 'Failed to update transaction.',
+ ]);
+ }
+
+ $db->transCommit();
+ return $this->response->setJSON([
+ 'status' => 'success',
+ 'message' => 'Transaction updated successfully.',
+ ]);
+ }
+
public function editClientOnboarding($id = null)
{
@@ -6652,7 +6755,7 @@ class ClientController extends AdminController
// Check in Enrollment (client_policy)
$client_policy_data = $this->clientPolicyModel
->where('is_active', 1)
- ->where('policy_status', 1)
+ // ->where('policy_status', 1)
->where('TRIM(policy_no)', $policy_no)
->first();
diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php
index c345330c..d209ca84 100755
--- a/app/Controllers/EmployeeController.php
+++ b/app/Controllers/EmployeeController.php
@@ -55,6 +55,8 @@ use Dompdf\Dompdf;
use Dompdf\Options;
use Kint;
+use Firebase\JWT\JWT;
+
class EmployeeController extends AdminController
{
@@ -7339,4 +7341,75 @@ class EmployeeController extends AdminController
}
}
+
+ public function tpaReportsDashboard()
+ {
+ $METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
+ $policy_id = $this->request->getGet('client_policy') ?? null;
+
+ if ($this->request->getGet('api') != 1) {
+ $data = [
+ 'tab_name' => 'TPA Reports',
+ 'page_name' => 'TPA Reports',
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ 'dashboardApiUrl' => base_url('/employee/tpaReportsDashboard'),
+ ];
+
+ return $this->loadLayout('meta_dashboard_demo_one', $data);
+ }
+
+ if (empty($policy_id)) {
+ return $this->respond([
+ 'status' => 'failed',
+ 'message' => 'Client policy is required.',
+ 'data' => [],
+ ]);
+ }
+
+ $client_policy_data = $this->clientPolicyModel
+ ->select('tpa.dashboard_id')
+ ->join('tpa', 'client_policy.tpa_id = tpa.id')
+ ->where('client_policy.id', $policy_id)
+ ->first();
+
+ $database_id = isset($client_policy_data['dashboard_id']) ? (int) $client_policy_data['dashboard_id'] : null;
+
+ if (empty($database_id)) {
+
+ if ($this->request->getGet('api') == 1) {
+ return $this->respond([
+ 'status' => 'failed',
+ 'message' => 'There is no dashboard for this TPA.',
+ 'data' => []
+ ]);
+ }
+
+ return view('errors/404', [
+ 'message' => 'There is no dashboard for this TPA.'
+ ]);
+ }
+
+ $payload = [
+ 'resource' => [
+ 'dashboard' => $database_id
+ ],
+ 'exp' => time() + (10 * 60), // 10 minutes
+ 'params' => (object) ['client_policy' => $policy_id ], // MUST be object for Metabase
+
+ ];
+
+ $token = JWT::encode($payload, $METABASE_SECRET_KEY, 'HS256');
+ // dd($token);
+
+ return $this->respond([
+ 'status' => 'success',
+ 'message' => 'Form data received successfully!',
+ 'data' => [
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ ],
+ ]);
+ }
+
+
}
diff --git a/app/Controllers/FhplApiController.php b/app/Controllers/FhplApiController.php
index 6d684e1c..16bc30ed 100644
--- a/app/Controllers/FhplApiController.php
+++ b/app/Controllers/FhplApiController.php
@@ -70,7 +70,7 @@ class FhplApiController extends BaseController
public function SubmitClaim($claimId = null) // 515
{
- helper('api');
+ helper(['api', 'tpa_claim_push_log']);
$data = $this->db->table('ticket_master tm')
->select('
@@ -99,7 +99,7 @@ class FhplApiController extends BaseController
if (count($data) && $data['filePath'] == null) {
- log_message('error', "FHPL - Claim Push FAILED | claimId: '.$claimId.' - Claim or File Missing");
+ tpa_claim_push_log($claimId, "FHPL - Claim Push FAILED | claimId: {$claimId} - Claim or File Missing");
return ['status' => false, 'message' => 'Claim Push FAILED | Claim or File Missing'];
}
@@ -109,7 +109,7 @@ class FhplApiController extends BaseController
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename;
if (!file_exists($pdfPath)) {
- log_message('error', "FHPL - Claim Push FAILED | claimId: '.$claimId.' - PDF not found on server");
+ tpa_claim_push_log($claimId, "FHPL - Claim Push FAILED | claimId: {$claimId} - PDF not found on server");
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server'];
}
@@ -119,7 +119,7 @@ class FhplApiController extends BaseController
// Generate FHPL Token
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['access_token'])) {
- log_message('error', "FHPL - Claim Push FAILED | claimId: '.$claimId.' - FHPL Token generation failed");
+ tpa_claim_push_log($claimId, "FHPL - Claim Push FAILED | claimId: {$claimId} - FHPL Token generation failed");
return ['status' => false, 'message' => 'Claim Push FAILED | FHPL Token generation failed'];
}
$token = $tokenResponse['data']['access_token'];
@@ -154,14 +154,14 @@ class FhplApiController extends BaseController
"Content-Type: application/json"
];
- log_message('error', 'FHPL - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
+ tpa_claim_push_log($claimId, 'FHPL - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
$response = call_third_party_api($url, 'POST', $headers, $body);
- log_message('error', 'FHPL - Claim Push RESPONSE | ' . json_encode($response));
+ tpa_claim_push_log($claimId, 'FHPL - Claim Push RESPONSE | ' . json_encode($response));
if($response['status'] != true){
- log_message('error', 'FHPL - Claim Push FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
+ tpa_claim_push_log($claimId, '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) ]);
@@ -193,15 +193,15 @@ class FhplApiController extends BaseController
->where('id', $file_id)
->update([ 'is_file_sent_to_tpa' => 1 ]);
- log_message('error','HEALTH_INDIA - Claim Push | Updating claim_files table for file_id: '.$file_id);
+ tpa_claim_push_log($claimId, 'FHPL - Claim Push | Updating claim_files table for file_id: '.$file_id);
}else{
- log_message('error','HEALTH_INDIA - Claim Push | No file_id found to update claim_files table.');
+ tpa_claim_push_log($claimId, 'FHPL - Claim Push | No file_id found to update claim_files table.');
}
- log_message('error', 'FHPL - Claim Push SUCCESS | claimId: '.$claimId.' | claimNO: '.$fhplClaimNo);
+ tpa_claim_push_log($claimId, 'FHPL - Claim Push SUCCESS | claimId: '.$claimId.' | claimNO: '.$fhplClaimNo);
return ['status' => true, 'message' => 'Claim Push SUCCESS', 'response' => $response];
}else {
- log_message('error', 'FHPL - Claim Push API SUCCESS BUT claimsInfo EMPTY | response: '.json_encode($response));
+ tpa_claim_push_log($claimId, 'FHPL - Claim Push API SUCCESS BUT claimsInfo EMPTY | response: '.json_encode($response));
return ['status' => false, 'message' => 'Claim Push API SUCCESS BUT claimsInfo EMPTY'];
}
}
diff --git a/app/Controllers/HealthIndiaApiController.php b/app/Controllers/HealthIndiaApiController.php
index 46b67043..485e81d9 100644
--- a/app/Controllers/HealthIndiaApiController.php
+++ b/app/Controllers/HealthIndiaApiController.php
@@ -84,9 +84,9 @@ class HealthIndiaApiController extends BaseController
public function SubmitClaim($claimId = null)
{
- helper('api');
+ helper(['api', 'tpa_claim_push_log']);
- log_message('error', 'HEALTH_INDIA - Claim Push | Started for claimId: ' . $claimId);
+ tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push | Started for claimId: ' . $claimId);
$data = $this->db->table('ticket_master tm')
->select('
@@ -121,12 +121,12 @@ class HealthIndiaApiController extends BaseController
// dd($data);
if (!$data) {
- log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Claim not found");
+ tpa_claim_push_log($claimId, "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Claim not found");
return ['status' => false, 'message' => 'Claim Push FAILED | Claim not found'];
}
if ($data['filePath'] == null) {
- log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - File Missing");
+ tpa_claim_push_log($claimId, "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - File Missing");
return ['status' => false, 'message' => 'Claim Push FAILED | File Missing'];
}
@@ -136,7 +136,7 @@ class HealthIndiaApiController extends BaseController
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename;
if (!file_exists($pdfPath)) {
- log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - PDF not found on server at path: {$pdfPath}");
+ tpa_claim_push_log($claimId, "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - PDF not found on server at path: {$pdfPath}");
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server'];
}
@@ -146,7 +146,7 @@ class HealthIndiaApiController extends BaseController
// Generate Health India Token
$tokenResponse = $this->generateAuthToken();
if (empty($tokenResponse['data']['result'][0]['access_token'])) {
- log_message('error', "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Token generation failed");
+ tpa_claim_push_log($claimId, "HEALTH_INDIA - Claim Push FAILED | claimId: {$claimId} - Token generation failed");
return;
}
$token = $tokenResponse['data']['result'][0]['access_token'];
@@ -206,14 +206,14 @@ class HealthIndiaApiController extends BaseController
"Content-Type: application/json"
];
- log_message('error', 'HEALTH_INDIA - Claim Push | claimId: ' . $claimId . ' | URL: ' . $url );
+ tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push | claimId: ' . $claimId . ' | URL: ' . $url);
$response = call_third_party_api($url, 'POST', $headers, $body);
// dd($response);
if ($response['status'] != true) {
- log_message('error', 'HEALTH_INDIA - Claim Push FAILED | claimId: ' . $claimId . ' | response: ' . json_encode($response));
+ tpa_claim_push_log($claimId, '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)]);
@@ -240,15 +240,15 @@ class HealthIndiaApiController extends BaseController
->where('id', $file_id)
->update([ 'is_file_sent_to_tpa' => 1 ]);
- log_message('error','HEALTH_INDIA - Claim Push | Updating claim_files table for file_id: '.$file_id);
+ tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push | Updating claim_files table for file_id: '.$file_id);
}else{
- log_message('error','HEALTH_INDIA - Claim Push | No file_id found to update claim_files table.');
+ tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push | No file_id found to update claim_files table.');
}
- log_message('error', 'HEALTH_INDIA - Claim Push SUCCESS | claimId: ' . $claimId . ' | CCN: ' . $ccn . ' | CCN_EXT: ' . $ccnExt);
+ tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push SUCCESS | claimId: ' . $claimId . ' | CCN: ' . $ccn . ' | CCN_EXT: ' . $ccnExt);
return ['status' => true, 'message' => 'Claim Push SUCCESS', 'response' => $response];
} else {
- log_message('error', 'HEALTH_INDIA - Claim Push API SUCCESS BUT CCN EMPTY | claimId: ' . $claimId . ' | response: ' . json_encode($response));
+ tpa_claim_push_log($claimId, 'HEALTH_INDIA - Claim Push API SUCCESS BUT CCN EMPTY | claimId: ' . $claimId . ' | response: ' . json_encode($response));
return ['status' => false, 'message' => 'Claim Push API SUCCESS BUT CCN EMPTY'];
}
diff --git a/app/Controllers/MediAssistApiController.php b/app/Controllers/MediAssistApiController.php
index cb39d93c..a05b8853 100644
--- a/app/Controllers/MediAssistApiController.php
+++ b/app/Controllers/MediAssistApiController.php
@@ -30,7 +30,7 @@ class MediAssistApiController extends BaseController
public function SubmitClaim ($claimId = null)
{
- helper('api');
+ helper(['api', 'tpa_claim_push_log']);
// $url = ''. getenv('MEDI_ASSIST_API_BASE_URL').'/SubmitClaim';
$url = getenv('MEDI_ASSIST_API_BASE_URL_CLAIMSUBMIT');
@@ -133,14 +133,14 @@ class MediAssistApiController extends BaseController
// ]
// ];
- log_message('error','MEDI_ASSIST - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
+ tpa_claim_push_log($claimId, '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','MEDI_ASSIST - Claim Push FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
+ tpa_claim_push_log($claimId, '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) ]);
@@ -153,7 +153,7 @@ class MediAssistApiController extends BaseController
if(!empty($claimRef)){
- log_message('error','MEDI_ASSIST - Claim Push SUCCESS | claimId: '.$claimId.' | claimReferenceNo: '.$claimRef);
+ tpa_claim_push_log($claimId, 'MEDI_ASSIST - Claim Push SUCCESS | claimId: '.$claimId.' | claimReferenceNo: '.$claimRef);
// Update claim reference number in ticket_master
$this->db->table('ticket_master')
@@ -167,15 +167,15 @@ class MediAssistApiController extends BaseController
->where('id', $file_id)
->update([ 'is_file_sent_to_tpa' => 1 ]);
- log_message('error','MEDI_ASSIST - Claim Push | Updating claim_files table for file_id: '.$file_id);
+ tpa_claim_push_log($claimId, 'MEDI_ASSIST - Claim Push | Updating claim_files table for file_id: '.$file_id);
}else{
- log_message('error','MEDI_ASSIST - Claim Push | No file_id found to update claim_files table.');
+ tpa_claim_push_log($claimId, 'MEDI_ASSIST - Claim Push | No file_id found to update claim_files table.');
}
return ['status' => true, 'message' => 'Claim Push SUCCESS', 'response' => $response];
} else {
- log_message('error','MEDI_ASSIST - Claim Push API Failed | claimReferenceNo EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
+ tpa_claim_push_log($claimId, 'MEDI_ASSIST - Claim Push API Failed | claimReferenceNo EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
return ['status' => false, 'message' => 'Claim Push API Failed', 'response' => $response];
}
diff --git a/app/Controllers/TestingController.php b/app/Controllers/TestingController.php
index eecbfb45..4de8ff71 100644
--- a/app/Controllers/TestingController.php
+++ b/app/Controllers/TestingController.php
@@ -365,7 +365,7 @@ class TestingController extends BaseController
$insurerBranchModel = new InsurerBranchModel();
$insurer_branch = $insurerBranchModel->getInsurerBranchesWithInsurerNames();
- $dataArray = $data['pt_co_share_details']; // Example
+ $dataArray = $data['pt_co_share_details'] ?? []; // Example
$cd_ac_pk = 'CD12345';
$role_id = 1;
$team_id = ['6'];
@@ -1099,6 +1099,64 @@ class TestingController extends BaseController
public function metaDashboardDemo()
{
+ // 🔐 Move this to .env in real projects
+ $METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
+ $database_id = (int) ($this->request->getGet('database_id') ?? 2);
+ $policy_id = $this->request->getGet('client_policy') ?? null;
+ $payload = [
+ 'resource' => [
+ // 'dashboard' => 1
+ 'dashboard' => $database_id
+ ],
+ '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');
+
+ // // You can either return token only
+ // return $this->response->setJSON([
+ // 'token' => $token,
+ // 'iframe_url' => "https://your-metabase-domain/embed/dashboard/{$token}#bordered=true&titled=true"
+ // ]);
+ if ($this->request->getGet('api') == 1) {
+ if (empty($policy_id)) {
+ return $this->respond([
+ 'status' => 'failed',
+ 'message' => 'Client policy is required.',
+ 'data' => [],
+ ]);
+ }
+
+ return $this->respond([
+ 'status' => 'success',
+ 'message' => 'Dashboard token generated.',
+ 'data' => [
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ ],
+ ]);
+ }
+
+ $data = [
+ 'tab_name' => 'Metabase Dashboard',
+ 'page_name' => 'Metabase Dashboard',
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ 'dashboardApiUrl' => base_url('/metaDashboardDemo'),
+ ];
+
+ return $this->loadLayout('meta_dashboard_demo_one', $data);
+ }
+ public function apacheSuperSetDemo()
+ {
+
+ // echo 'Dta';die;
// 🔐 Move this to .env in real projects
$METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
$database_id = (int)$this->request->getGet('database_id') ?? 2;
@@ -1108,7 +1166,7 @@ class TestingController extends BaseController
$payload = [
'resource' => [
// 'dashboard' => 1
- 'dashboard' => $database_id
+ 'dashboard' => 2
],
'exp' => time() + (10 * 60), // 10 minutes
];
@@ -1138,16 +1196,11 @@ class TestingController extends BaseController
]);
}
- return view('meta_dashboard_demo_one', [
+ return view('apache_dashboard_demo_one', [
'metabaseToken' => $token,
'metabaseUrl' => 'https://nsights.nhanceindia.in',
]);
}
-
- public function testingquerys1(){
-
- }
-
public function testingquerys()
{
$calendar = new \App\Libraries\GoogleCalendarService();
@@ -1175,7 +1228,26 @@ class TestingController extends BaseController
public function metaTpaDashboardDemo()
{
$METABASE_SECRET_KEY = getenv('METABASE_SECRET_KEY');
- $policy_id = $this->request->getGet('client_policy') ?? 4687;
+ $policy_id = $this->request->getGet('client_policy') ?? null;
+
+ if ($this->request->getGet('api') != 1) {
+ $data = [
+ 'tab_name' => 'TPA Reports',
+ 'page_name' => 'TPA Reports',
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ 'dashboardApiUrl' => base_url('/metaTpaDashboardDemo'),
+ ];
+
+ return $this->loadLayout('meta_dashboard_demo_one', $data);
+ }
+
+ if (empty($policy_id)) {
+ return $this->respond([
+ 'status' => 'failed',
+ 'message' => 'Client policy is required.',
+ 'data' => [],
+ ]);
+ }
$client_policy_data = $this->ClientPolicyModel
->select('tpa.dashboard_id')
@@ -1212,20 +1284,13 @@ class TestingController extends BaseController
$token = JWT::encode($payload, $METABASE_SECRET_KEY, 'HS256');
// dd($token);
- if ($this->request->getGet('api') == 1) {
- return $this->respond([
- 'status' => 'success',
- 'message' => 'Form data received successfully!',
- 'data' => [
- 'metabaseToken' => $token,
- 'metabaseUrl' => 'https://nsights.nhanceindia.in'
- ]
- ]);
- }
-
- return view('meta_dashboard_demo_one', [
- 'metabaseToken' => $token,
- 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ return $this->respond([
+ 'status' => 'success',
+ 'message' => 'Form data received successfully!',
+ 'data' => [
+ 'metabaseToken' => $token,
+ 'metabaseUrl' => 'https://nsights.nhanceindia.in',
+ ],
]);
}
diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php
index 4421fb71..a3e0e01c 100644
--- a/app/Controllers/TicketController.php
+++ b/app/Controllers/TicketController.php
@@ -509,6 +509,7 @@ class TicketController extends BaseController
'tm.is_head_approved',
'tcs.claim_status AS status',
'tm.claim_number AS claim_no',
+ 'tm.tpa_claim_push_reference_no',
'tm.tpa_id',
'tm.tpa_no',
'tm.emp_name',
@@ -650,6 +651,7 @@ class TicketController extends BaseController
'tm.ticket_type_id',
'tcs.claim_status AS status',
'tm.claim_number AS claim_no',
+ 'tm.tpa_claim_push_reference_no',
'tm.claim_status_id',
'tm.claim_created_by',
'tm.is_head_approved',
@@ -2535,6 +2537,43 @@ class TicketController extends BaseController
}
+ public function getTpaClaimPushLogs()
+ {
+ $ticketId = $this->request->getGet('ticket_id');
+
+ if (empty($ticketId)) {
+ return $this->respond([
+ 'status' => false,
+ 'message' => 'ticket_id is required',
+ ], 400);
+ }
+
+ $ticket = $this->ticketMasterModel
+ ->select('id, tpa_claim_push_logs')
+ ->where('id', $ticketId)
+ ->where('is_active', 1)
+ ->first();
+
+ if (!$ticket) {
+ return $this->respond([
+ 'status' => false,
+ 'message' => 'Claim not found',
+ ], 404);
+ }
+
+ $logs = trim((string) ($ticket['tpa_claim_push_logs'] ?? ''));
+
+ return $this->respond([
+ 'status' => true,
+ 'message' => 'TPA claim push logs fetched successfully',
+ 'data' => [
+ 'ticket_id' => (int) $ticketId,
+ 'logs' => $logs,
+ 'has_logs' => $logs !== '',
+ ],
+ ], 200);
+ }
+
//---- Email Trigger Part----------------------------------------------------------------------------------------------
public function constructMailContent($ticket_id, $status_id = null)
diff --git a/app/Controllers/VidalApiController.php b/app/Controllers/VidalApiController.php
index 889ae745..0fec2c73 100644
--- a/app/Controllers/VidalApiController.php
+++ b/app/Controllers/VidalApiController.php
@@ -41,13 +41,14 @@ class VidalApiController extends BaseController
- function uploadFileToVidal($filePath,$filename)
+ function uploadFileToVidal($filePath, $filename, $claimId = null)
{
+ helper('tpa_claim_push_log');
// $apiUrl = "https://devapigw.vidalhealthtpa.com/partner-integration/api/files/upload-url";
$apiUrl = getenv('VIDAL_API_BASE_URL').'/files/upload-url';
$subscriptionKey = getenv('VIDAL_API_SUBSCRIPTION_KEY');
- log_message('error', "VIDAL - Claim Push | Starting file upload process for filename: $filename | Path: $filePath");
+ tpa_claim_push_log($claimId, "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';
@@ -57,7 +58,7 @@ class VidalApiController extends BaseController
"Ocp-Apim-Subscription-Key: $subscriptionKey"
];
- log_message('error', "VIDAL - Claim Push | Requesting signed URL from Vidal API: $apiUrl | Payload: $payload");
+ tpa_claim_push_log($claimId, "VIDAL - Claim Push | Requesting signed URL from Vidal API: $apiUrl | Payload: $payload");
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@@ -67,7 +68,7 @@ class VidalApiController extends BaseController
$response = curl_exec($ch);
if (curl_errno($ch)) {
- log_message('error', "VIDAL - Claim Push Curl error while requesting signed URL: " . curl_error($ch));
+ tpa_claim_push_log($claimId, "VIDAL - Claim Push Curl error while requesting signed URL: " . curl_error($ch));
return ["status" => false, "message" => curl_error($ch)];
}
curl_close($ch);
@@ -75,14 +76,14 @@ class VidalApiController extends BaseController
$responseData = json_decode($response, true);
if (!isset($responseData['data']['signedUrl']) || !isset($responseData['data']['fileId'])) {
- log_message('error', "VIDAL - Claim Push | Invalid signed URL response received: " . json_encode($responseData));
+ tpa_claim_push_log($claimId, "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', "VIDAL - Claim Push | Received signed URL & fileId. fileId: $fileId");
+ tpa_claim_push_log($claimId, "VIDAL - Claim Push | Received signed URL & fileId. fileId: $fileId");
// Step 2: Upload file to signed URL using PUT (Azure Blob)
$fileSize = filesize($filePath);
@@ -107,12 +108,12 @@ class VidalApiController extends BaseController
curl_close($ch2);
if ($curlErr) {
- log_message('error', "VIDAL - Claim Push | Curl error during file upload: $curlErr");
+ tpa_claim_push_log($claimId, "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', "VIDAL - Claim Push | File upload failed with HTTP Code: $httpCode | Response: $uploadResponse");
+ tpa_claim_push_log($claimId, "VIDAL - Claim Push | File upload failed with HTTP Code: $httpCode | Response: $uploadResponse");
return [
"status" => false,
"message" => "File upload failed",
@@ -133,7 +134,7 @@ class VidalApiController extends BaseController
public function SubmitClaim ($claimId = null) //515
{
- helper('api');
+ helper(['api', 'tpa_claim_push_log']);
// Fetch the data from DB
$data = $this->db->table('ticket_master tm')
@@ -174,7 +175,7 @@ class VidalApiController extends BaseController
->getRowArray(); // single record
if (count($data) && $data['filePath'] == null) {
- log_message('error', "VIDAL - Claim Push | Submit claim failed - Claim or File Missing");
+ tpa_claim_push_log($claimId, "VIDAL - Claim Push | Submit claim failed - Claim or File Missing");
return ['status' => false, 'message' => 'Claim Push FAILED | Claim or File Missing'];
}
@@ -185,9 +186,9 @@ class VidalApiController extends BaseController
// dd($data);
// Upload file first
- $upload = $this->uploadFileToVidal($filePath,$filename);
+ $upload = $this->uploadFileToVidal($filePath, $filename, $claimId);
if ($upload['status'] !== true) {
- log_message('error', "VIDAL - Claim Push | Submit claim failed - File upload failed");
+ tpa_claim_push_log($claimId, "VIDAL - Claim Push | Submit claim failed - File upload failed");
return $this->response->setJSON([
'status' => false,
'message' => 'File upload failed',
@@ -247,7 +248,7 @@ class VidalApiController extends BaseController
];
// dd($body);
- log_message('error', 'VIDAL - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
+ tpa_claim_push_log($claimId, 'VIDAL - Claim Push | claimId: '.$claimId.' | payload: '.json_encode($body));
// $body = [
// 'policyNo' => "351500/D0534/PP/20-20/PC",
@@ -279,7 +280,7 @@ class VidalApiController extends BaseController
$response = call_third_party_api($url, $method, $headers, $body);
if($response['status'] != true){
- log_message('error', 'VIDAL - Claim Push FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
+ tpa_claim_push_log($claimId, '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) ]);
@@ -295,7 +296,7 @@ class VidalApiController extends BaseController
if(!empty($claimNO) && !empty($claimInwardNO)){
- log_message('error', 'VIDAL - Claim Push SUCCESS | claimId: '.$claimId.' | claimNO: '.$claimNO.' | claimInwardNO: '.$claimInwardNO);
+ tpa_claim_push_log($claimId, 'VIDAL - Claim Push SUCCESS | claimId: '.$claimId.' | claimNO: '.$claimNO.' | claimInwardNO: '.$claimInwardNO);
$this->db->table('ticket_master')
->where('id',$claimId)
@@ -308,19 +309,19 @@ class VidalApiController extends BaseController
->where('id', $tpa_sent_file_id)
->update([ 'is_file_sent_to_tpa' => 1 ]);
- log_message('error','MEDI_ASSIST - Claim Push | Updating claim_files table for file_id: '.$tpa_sent_file_id);
+ tpa_claim_push_log($claimId, 'VIDAL - Claim Push | Updating claim_files table for file_id: '.$tpa_sent_file_id);
}else{
- log_message('error','MEDI_ASSIST - Claim Push | No file_id found to update claim_files table.');
+ tpa_claim_push_log($claimId, 'VIDAL - Claim Push | No file_id found to update claim_files table.');
}
return ['status' => true, 'message' => 'Claim Push SUCCESS'];
} else {
- log_message('error', 'VIDAL - Claim Push API SUCCESS BUT claimNO,claimInwardNO EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
+ tpa_claim_push_log($claimId, 'VIDAL - Claim Push API SUCCESS BUT claimNO,claimInwardNO EMPTY | claimId: '.$claimId.' | response: '.json_encode($response));
return ['status' => false, 'message' => 'Claim Push API SUCCESS BUT claimNO,claimInwardNO EMPTY'];
}
}else{
- log_message('error', 'VIDAL - Claim Push API FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
+ tpa_claim_push_log($claimId, 'VIDAL - Claim Push API FAILED | claimId: '.$claimId.' | response: '.json_encode($response));
return ['status' => false, 'message' => 'Claim Push API FAILED'];
}
diff --git a/app/Controllers/VoloApiController.php b/app/Controllers/VoloApiController.php
index b1bc0a4b..c256ecfa 100644
--- a/app/Controllers/VoloApiController.php
+++ b/app/Controllers/VoloApiController.php
@@ -682,7 +682,7 @@ class VoloApiController extends BaseController
*/
public function SubmitClaim($claimId = null)
{
- helper('api');
+ helper(['api', 'tpa_claim_push_log']);
$data = $this->db->table('ticket_master tm')
->select('
@@ -702,12 +702,12 @@ class VoloApiController extends BaseController
->getRowArray();
if (!$data) {
- log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | claim not found');
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | claim not found');
return ['status' => false, 'message' => 'Claim Push FAILED | Claim not found'];
}
if (empty($data['filePath'])) {
- log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | file missing');
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | file missing');
return ['status' => false, 'message' => 'Claim Push FAILED | File Missing'];
}
@@ -715,7 +715,7 @@ class VoloApiController extends BaseController
$filename = basename($data['filePath']);
$pdfPath = WRITEPATH . 'uploads/claim_files/' . $filename;
if (!is_readable($pdfPath)) {
- log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | PDF not readable');
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | PDF not readable');
return ['status' => false, 'message' => 'Claim Push FAILED | PDF not found on server'];
}
@@ -723,13 +723,13 @@ class VoloApiController extends BaseController
$entityId = $this->resolveEntityId($data['policyNo'] ?? '');
if ($entityId === null) {
- log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | entity id not resolved');
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | entity id not resolved');
return ['status' => false, 'message' => 'Claim Push FAILED | entity id not resolved'];
}
$hospitalId = getenv('VOLO_DEFAULT_HOSPITAL_ID');
if ($hospitalId === false || $hospitalId === '') {
- log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | VOLO_DEFAULT_HOSPITAL_ID not set');
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | VOLO_DEFAULT_HOSPITAL_ID not set');
return ['status' => false, 'message' => 'Claim Push FAILED | hospital id not configured'];
}
@@ -754,12 +754,12 @@ class VoloApiController extends BaseController
'insurerPolicyNumber' => (string) ($data['policyNo'] ?? ''),
];
- log_message('error', 'VOLO - Claim Push | claimId: ' . $claimId . ' | payload: ' . json_encode($payload));
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push | claimId: ' . $claimId . ' | payload: ' . json_encode($payload));
$response = $this->intimateClaim($payload);
if (empty($response['status'])) {
- log_message('error', 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | ' . json_encode($response));
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push FAILED | claimId: ' . $claimId . ' | ' . json_encode($response));
$this->db->table('ticket_master')
->where('id', $claimId)
->update(['tpa_push_response' => json_encode($response)]);
@@ -781,7 +781,7 @@ class VoloApiController extends BaseController
'tpa_claim_id' => $ref,
'updated_at' => date('Y-m-d H:i:s'),
]);
- log_message('error', 'VOLO - Claim Push SUCCESS | claimId: ' . $claimId . ' | ref: ' . $ref);
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push SUCCESS | claimId: ' . $claimId . ' | ref: ' . $ref);
// Update claim files table that file is sent to tpa for this claim
if(!empty($file_id)){
@@ -790,15 +790,15 @@ class VoloApiController extends BaseController
->where('id', $file_id)
->update([ 'is_file_sent_to_tpa' => 1 ]);
- log_message('error','VOLO - Claim Push | Updating claim_files table for file_id: '.$file_id);
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push | Updating claim_files table for file_id: '.$file_id);
}else{
- log_message('error','VOLO - Claim Push | No file_id found to update claim_files table.');
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push | No file_id found to update claim_files table.');
}
return ['status' => true, 'message' => 'Claim Push SUCCESS', 'response' => $response];
}
- log_message('error', 'VOLO - Claim Push empty reference | claimId: ' . $claimId . ' | ' . json_encode($response));
+ tpa_claim_push_log($claimId, 'VOLO - Claim Push empty reference | claimId: ' . $claimId . ' | ' . json_encode($response));
return ['status' => false, 'message' => 'Claim Push API response missing reference', 'response' => $response];
}
diff --git a/app/Helpers/MailHelper.php b/app/Helpers/MailHelper.php
index 6c16ca8a..0999dc4b 100755
--- a/app/Helpers/MailHelper.php
+++ b/app/Helpers/MailHelper.php
@@ -183,12 +183,24 @@ use App\Models\JobModel;
class MailHelper
{
+ private const SYSTEM_EMAIL_FOOTER = '
+ This is a system-generated email. Please do not reply.
+
';
public static function send_email_smtp($params)
{
$myLogger = \Config\Services::mylogger();
$emaill = $params['mail'];
$subject = $params['subject'];
$message = $params['message'];
+ $message .= self::SYSTEM_EMAIL_FOOTER;
if (isset($params['bcc'])) {
$bcc = $params['bcc'];
} else {
@@ -206,7 +218,8 @@ class MailHelper
$curl = curl_init();
$postData = [
'from' => [
- 'address' => $from_address
+ 'address' => $from_address,
+ 'name' => 'Nhance India Insurance'
],
'to' => [
[
@@ -315,6 +328,9 @@ class MailHelper
$subject = $params['subject'];
$message = $params['message'];
+ $message .= self::SYSTEM_EMAIL_FOOTER;
+
+ // echo $message;die;
$attachments = isset($params['attachments']) ? $params['attachments'] : [];
$common = isset($params['common']) ? $params['common'] : '';
$bcc = isset($params['bcc']) ? $params['bcc'] : '';
@@ -328,7 +344,8 @@ class MailHelper
$postData = [
'from' => [
- 'address' => $from_address
+ 'address' => $from_address,
+ 'name' => "Nhance India Insurance"
],
'to' => $emails,
'subject' => $subject,
diff --git a/app/Helpers/tpa_claim_push_log_helper.php b/app/Helpers/tpa_claim_push_log_helper.php
new file mode 100644
index 00000000..cf9b2cc9
--- /dev/null
+++ b/app/Helpers/tpa_claim_push_log_helper.php
@@ -0,0 +1,48 @@
+table('ticket_master')
+ ->where('id', $claimId)
+ ->update(['tpa_claim_push_logs' => "[{$started}] Claim push started\n"]);
+ }
+}
+
+if (!function_exists('tpa_claim_push_log')) {
+ /**
+ * Write to application log and append the same line to ticket_master.tpa_claim_push_logs.
+ */
+ function tpa_claim_push_log($claimId, string $message, string $level = 'error'): void
+ {
+ log_message($level, $message);
+
+ if ($claimId === null || $claimId === '') {
+ return;
+ }
+
+ $timestamp = date('Y-m-d H:i:s');
+ $line = "[{$timestamp}] {$message}\n";
+
+ $db = \Config\Database::connect();
+ $row = $db->table('ticket_master')
+ ->select('tpa_claim_push_logs')
+ ->where('id', $claimId)
+ ->get()
+ ->getRowArray();
+
+ $existing = $row['tpa_claim_push_logs'] ?? '';
+ $db->table('ticket_master')
+ ->where('id', $claimId)
+ ->update(['tpa_claim_push_logs' => $existing . $line]);
+ }
+}
diff --git a/app/Models/ClaimsCollectionV2DashboardModel.php b/app/Models/ClaimsCollectionV2DashboardModel.php
new file mode 100644
index 00000000..447dcee0
--- /dev/null
+++ b/app/Models/ClaimsCollectionV2DashboardModel.php
@@ -0,0 +1,2182 @@
+ PHP method name.
+ */
+ public const KPI_MAP = [
+ 181 => 'policy_exposure_summary',
+ 185 => 'premium_as_on_date',
+ 186 => 'claims_experience_summary',
+ 190 => 'claim_amount_by_gender',
+ 191 => 'age_band',
+ 194 => 'top_5_hospitals_by_incurred_amount',
+ 197 => 'claims_incidence_rate',
+ 198 => 'policy_start_date',
+ 199 => 'policy_end_date',
+ 200 => 'insurer',
+ 201 => 'tpa',
+ 203 => 'earned_premium',
+ 204 => 'total_claims',
+ 206 => 'incurred_amount',
+ 207 => 'incurred_ratio',
+ 208 => 'projected_claims',
+ 209 => 'projected_ratio',
+ 213 => 'total_reimbursement_amount',
+ 214 => 'total_reimbursement_amt_pct',
+ 215 => 'cashless_claim_amt',
+ 216 => 'cashless_claim_amt_pct',
+ 217 => 'total_incurred_by_city',
+ 219 => 'claim_amount_by_claim_status',
+ 220 => 'hospitals_in_detail',
+ 221 => 'hospital_city_wise_si_limit_pregnancy',
+ 224 => 's_pregnancy_normal_delivery_exceeded_amt',
+ 225 => 's_pregnancy_c_sec_avg_exceeded_amt',
+ 228 => 'cataract_exceeded_claim_amount',
+ 229 => 'cataract_avg_exceeded_amount',
+ 230 => 'hospital_city_wise_si_limit_cataract',
+ 231 => 'total_incurred_by_cliam_status',
+ 232 => 'inception_emp_lives',
+ 233 => 'current_emp_lives',
+ 234 => 'claim_value_by_month',
+ ];
+
+ /**
+ * Human-readable KPI labels (Metabase name).
+ */
+ public const KPI_LABELS = [
+ 'policy_exposure_summary' => 'POLICY & EXPOSURE SUMMARY',
+ 'premium_as_on_date' => 'PREMIUM AS ON DATE',
+ 'claims_experience_summary' => 'CLAIMS EXPERIENCE SUMMARY',
+ 'claim_amount_by_gender' => 'Claim Amount by Gender',
+ 'age_band' => 'Age Band',
+ 'top_5_hospitals_by_incurred_amount' => 'Top 5 Hospitals by Incurred amount',
+ 'claims_incidence_rate' => 'Claims Incidence Rate',
+ 'policy_start_date' => 'Policy Start Date',
+ 'policy_end_date' => 'Policy End Date',
+ 'insurer' => 'Insurer',
+ 'tpa' => 'TPA',
+ 'earned_premium' => 'Earned Premium',
+ 'total_claims' => 'Total Claims',
+ 'incurred_amount' => 'Incurred Amount',
+ 'incurred_ratio' => 'Incurred Ratio',
+ 'projected_claims' => 'Projected Claims',
+ 'projected_ratio' => 'Projected Ratio',
+ 'total_reimbursement_amount' => 'Total Reimbursement Amount',
+ 'total_reimbursement_amt_pct' => 'Total Reimbursement Amt %',
+ 'cashless_claim_amt' => 'Cashless Claim Amt',
+ 'cashless_claim_amt_pct' => 'Cashless Claim Amt %',
+ 'total_incurred_by_city' => 'Total Incurred by city',
+ 'claim_amount_by_claim_status' => 'Claim Amount by Claim Status',
+ 'hospitals_in_detail' => 'Hospitals in detail',
+ 'hospital_city_wise_si_limit_pregnancy' => 'Hospital city wise SI Limit - Pregnancy',
+ 's_pregnancy_normal_delivery_exceeded_amt' => 'S-PREGNANCY - NORMAL DELIVERY Exceeded Amt',
+ 's_pregnancy_c_sec_avg_exceeded_amt' => 'S-Pregnancy C-Sec avg exceeded amt',
+ 'cataract_exceeded_claim_amount' => 'Cataract exceeded claim amount',
+ 'cataract_avg_exceeded_amount' => 'Cataract avg exceeded amount',
+ 'hospital_city_wise_si_limit_cataract' => 'Hospital city wise SI Limit - Cataract',
+ 'total_incurred_by_cliam_status' => 'Total Incurred by Cliam Status ',
+ 'inception_emp_lives' => 'Inception Employees & Lives',
+ 'current_emp_lives' => 'Current Employees & Lives',
+ 'claim_value_by_month' => 'Claim Value by Month',
+ ];
+
+ protected function runKpiQuery(string $sql, int $policyId): array
+ {
+ // Metabase export may contain literal \t / \n in CSV — normalize for MySQL.
+ $sql = str_replace(['\\t', '\\n', '\\r'], ["\t", "\n", "\r"], $sql);
+
+ $db = \Config\Database::connect($this->DBGroup);
+ $query = $db->query($sql, ['policy_id' => $policyId]);
+
+ return $query->getResultArray();
+ }
+
+ public function getKpi(string $method, int $policyId): array
+ {
+ if (!method_exists($this, $method)) {
+ return [];
+ }
+ return $this->{$method}($policyId);
+ }
+
+ public function getAllKpis(int $policyId): array
+ {
+ $out = [];
+ foreach (self::KPI_MAP as $id => $method) {
+ $out[$method] = [
+ 'id' => (int) $id,
+ 'label' => self::KPI_LABELS[$method] ?? $method,
+ 'rows' => $this->getKpi($method, $policyId),
+ ];
+ }
+ return $out;
+ }
+
+ /** Metabase #181: POLICY & EXPOSURE SUMMARY */
+ public function policy_exposure_summary(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ cp.policy_start_date,
+ cp.policy_end_date,
+ i.name AS insurer_name,
+ t.name AS tpa_name
+FROM client_policy cp
+LEFT JOIN insurers i ON i.id = cp.insurer_id
+LEFT JOIN tpa t ON t.id = cp.tpa_id
+WHERE cp.id = :policy_id:
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #185: PREMIUM AS ON DATE */
+ public function premium_as_on_date(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ CONCAT('💰 ', FORMAT(
+ COALESCE(SUM(
+ CASE
+ WHEN LOWER(e.change_event) = '%inception%'
+ THEN ep.rata_premimum
+ WHEN LOWER(e.change_event) NOT LIKE '%inception%'
+ AND (ep.date_of_exit IS NULL OR ep.date_of_exit = '')
+ THEN ep.rata_premimum
+ WHEN ep.date_of_exit IS NOT NULL
+ AND ep.date_of_exit != ''
+ AND ep.claim_status = 0
+ THEN -ep.rata_premimum
+ ELSE 0
+ END
+ ), 0)
+ , 0)) AS premium_as_on_date
+
+FROM employee_polices ep
+JOIN employees e ON e.id = ep.employee_id
+WHERE ep.client_policy_id = :policy_id:
+ AND ep.is_active = 1;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #186: CLAIMS EXPERIENCE SUMMARY */
+ public function claims_experience_summary(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ /* run days */
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ) AS run_days,
+
+ /* earned premium */
+ FORMAT(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) AS earned_premium,
+
+ /* claims reported */
+ FORMAT(COUNT(tm.id), 0) AS claims_reported,
+\t\t/* incurred claims count */
+\tFORMAT(
+\t SUM(
+\t CASE
+\t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1
+\t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1
+\t ELSE 0
+\t END
+\t )
+, 0) AS incurred_claims,
+
+ /* incurred amount */
+ FORMAT(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ , 0) AS incurred_amount,
+
+ /* incurred ratio */
+ CONCAT(
+ ROUND(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) * 100
+ , 2)
+ , '%') AS incurred_ratio,
+
+ /* rejection rate */
+ CONCAT(
+ ROUND(
+ SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END)
+ / NULLIF(COUNT(tm.id), 0) * 100
+ , 2)
+ , '%') AS rejection_rate,
+
+ /* projected claims */
+ FORMAT(
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ , 0) AS projected_claims,
+
+ /* projected ratio */
+ CONCAT(
+ ROUND(
+ (
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ )
+ / NULLIF(prem.premium_as_on_date, 0) * 100
+ , 2)
+ , '%') AS projected_ratio
+
+FROM client_policy cp
+
+JOIN (
+ SELECT
+ ep2.client_policy_id,
+ COALESCE(SUM(
+ CASE
+ WHEN e2.change_event = 'inception'
+ THEN ep2.rata_premimum
+ WHEN e2.change_event != 'inception'
+ AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '')
+ THEN ep2.rata_premimum
+ WHEN ep2.date_of_exit IS NOT NULL
+ AND ep2.date_of_exit != ''
+ AND ep2.claim_status = 0
+ THEN -ep2.rata_premimum
+ ELSE 0
+ END
+ ), 0) AS premium_as_on_date
+ FROM employee_polices ep2
+ JOIN employees e2 ON e2.id = ep2.employee_id
+ WHERE ep2.client_policy_id = :policy_id:
+ AND ep2.is_active = 1
+ GROUP BY ep2.client_policy_id
+) prem ON prem.client_policy_id = cp.id
+
+JOIN ticket_master tm
+ ON tm.client_policy_id = cp.id
+ AND tm.is_active = 1
+
+JOIN ticket_claim_status tcs
+ ON tcs.id = tm.claim_status_id
+
+WHERE cp.id = :policy_id:
+
+GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #190: Claim Amount by Gender */
+ public function claim_amount_by_gender(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(e.gender, 'Unknown') AS gender,
+ COUNT(tm.id) AS claim_count,
+ CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%')
+ AS count_pct,
+
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ AS claim_value,
+ CONCAT(ROUND(
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(totals.total_value, 0) * 100
+ , 2), '%') AS value_pct
+FROM ticket_master tm
+JOIN employees e ON e.id = tm.emp_id
+JOIN (
+ SELECT
+ COUNT(id) AS total_count,
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id: AND is_active = 1
+) totals ON 1=1
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+GROUP BY e.gender, totals.total_count, totals.total_value
+ORDER BY claim_count DESC;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #191: Age Band */
+ public function age_band(int $policyId): array
+ {
+ $sql = <<<'SQL'
+WITH age_slabs AS (
+ SELECT '0-18' AS age_band, 0 AS min_age, 18 AS max_age UNION ALL
+ SELECT '19-25', 19, 25 UNION ALL
+ SELECT '26-35', 26, 35 UNION ALL
+ SELECT '36-45', 36, 45 UNION ALL
+ SELECT '46-55', 46, 55 UNION ALL
+ SELECT '56-65', 56, 65 UNION ALL
+ SELECT '66-75', 66, 75 UNION ALL
+ SELECT '75+', 76, 200
+),
+
+base AS (
+ SELECT
+ TIMESTAMPDIFF(YEAR, e.dob, cp.policy_end_date) AS age,
+ tm.claim_amount
+ FROM ticket_master tm
+ JOIN employees e ON e.id = tm.insured_emp_id
+\tJOIN client_policy cp ON tm.client_policy_id = cp.id
+ WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+),
+
+totals AS (
+ SELECT
+ COUNT(*) AS total_count,
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+)
+
+SELECT
+ s.age_band,
+
+ COUNT(b.age) AS claim_count,
+
+ ROUND(COUNT(b.age) / NULLIF(t.total_count, 0) * 100, 2) AS count_pct,
+
+ COALESCE(SUM(CAST(NULLIF(b.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value,
+
+ ROUND(
+ COALESCE(SUM(CAST(NULLIF(b.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(t.total_value, 0) * 100
+ , 2) AS value_pct
+
+FROM age_slabs s
+
+LEFT JOIN base b
+ ON b.age BETWEEN s.min_age AND s.max_age
+
+CROSS JOIN totals t
+
+GROUP BY s.age_band, s.min_age, t.total_count, t.total_value
+
+ORDER BY s.min_age;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #194: Top 5 Hospitals by Incurred amount */
+ public function top_5_hospitals_by_incurred_amount(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(tm.hospital_name, 'Not Specified') AS hospital_name,
+ COALESCE(tm.hospital_city, '-') AS hospital_city,
+ COALESCE(tm.hospital_state, '-') AS hospital_state,
+
+ COUNT(tm.id) AS claim_count,
+
+ ROUND(
+ COUNT(tm.id) / totals.total_count * 100,
+ 2
+ ) AS count_pct,
+
+ COALESCE(
+ SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))),
+ 0
+ ) AS claim_value,
+
+ ROUND(
+ COALESCE(
+ SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))),
+ 0
+ ) / NULLIF(totals.total_value, 0) * 100,
+ 2
+ ) AS value_pct
+
+FROM ticket_master tm
+
+JOIN (
+ SELECT
+ COUNT(id) AS total_count,
+
+ COALESCE(
+ SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))),
+ 0
+ ) AS total_value
+
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+) totals ON 1=1
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND tm.hospital_name IS NOT NULL
+
+GROUP BY
+ tm.hospital_name,
+ tm.hospital_city,
+ tm.hospital_state,
+ totals.total_count,
+ totals.total_value
+
+ORDER BY claim_count DESC
+
+LIMIT 5;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #197: Claims Incidence Rate */
+ public function claims_incidence_rate(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ CONCAT(
+ ROUND(
+ COUNT(tm.id) / NULLIF(lives.current_lives, 0) * 100
+ , 2)
+ , '%') AS claims_incidence_rate
+FROM ticket_master tm
+JOIN (
+ SELECT COUNT(DISTINCT ep.employee_id) AS current_lives
+ FROM employee_polices ep
+ JOIN employees e ON e.id = ep.employee_id
+ WHERE ep.client_policy_id = :policy_id:
+ AND ep.status = 'active'
+ AND ep.is_active = 1
+ AND e.emp_status = 'active'
+ AND e.is_active = 1
+) lives ON 1=1
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #198: Policy Start Date */
+ public function policy_start_date(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ CONCAT(DATE_FORMAT(cp.policy_start_date, '%d %b, %Y'), ' 📅') AS policy_start_date,
+ -- cp.policy_start_date,
+ cp.policy_end_date,
+ i.name AS insurer_name,
+ t.name AS tpa_name
+FROM client_policy cp
+LEFT JOIN insurers i ON i.id = cp.insurer_id
+LEFT JOIN tpa t ON t.id = cp.tpa_id
+WHERE cp.id = :policy_id:
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #199: Policy End Date */
+ public function policy_end_date(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ cp.policy_start_date,CONCAT(DATE_FORMAT(cp.policy_end_date, '%d %b, %Y'), ' 📅') AS policy_end_date,
+ -- cp.policy_end_date,
+ i.name AS insurer_name,
+ t.name AS tpa_name
+FROM client_policy cp
+LEFT JOIN insurers i ON i.id = cp.insurer_id
+LEFT JOIN tpa t ON t.id = cp.tpa_id
+WHERE cp.id = :policy_id:
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #200: Insurer */
+ public function insurer(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ cp.policy_start_date,
+ cp.policy_end_date,
+ i.name AS insurer_name,
+ t.short_name AS tpa_name
+FROM client_policy cp
+LEFT JOIN insurers i ON i.id = cp.insurer_id
+LEFT JOIN tpa t ON t.id = cp.tpa_id
+WHERE cp.id = :policy_id:
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #201: TPA */
+ public function tpa(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ cp.policy_start_date,
+ cp.policy_end_date,
+ i.name AS insurer_name,
+ t.name AS tpa_name
+FROM client_policy cp
+LEFT JOIN insurers i ON i.id = cp.insurer_id
+LEFT JOIN tpa t ON t.id = cp.tpa_id
+WHERE cp.id = :policy_id:
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #203: Earned Premium */
+ public function earned_premium(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+
+
+ /* earned premium */
+
+ CONCAT('💵 ', FORMAT( (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ ,0))AS earned_premium
+FROM client_policy cp
+
+JOIN (
+ SELECT
+ ep2.client_policy_id,
+ COALESCE(SUM(
+ CASE
+ WHEN e2.change_event = 'inception'
+ THEN ep2.rata_premimum
+ WHEN e2.change_event != 'inception'
+ AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '')
+ THEN ep2.rata_premimum
+ WHEN ep2.date_of_exit IS NOT NULL
+ AND ep2.date_of_exit != ''
+ AND ep2.claim_status = 0
+ THEN -ep2.rata_premimum
+ ELSE 0
+ END
+ ), 0) AS premium_as_on_date
+ FROM employee_polices ep2
+ JOIN employees e2 ON e2.id = ep2.employee_id
+ WHERE ep2.client_policy_id = :policy_id:
+ AND ep2.is_active = 1
+ GROUP BY ep2.client_policy_id
+) prem ON prem.client_policy_id = cp.id
+
+JOIN ticket_master tm
+ ON tm.client_policy_id = cp.id
+ AND tm.is_active = 1
+
+JOIN ticket_claim_status tcs
+ ON tcs.id = tm.claim_status_id
+
+WHERE cp.id = :policy_id:
+
+GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #204: Total Claims */
+ public function total_claims(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ /* run days */
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ) AS run_days,
+
+ /* earned premium */
+ FORMAT(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) AS earned_premium,
+
+ /* claims reported */
+ FORMAT(COUNT(tm.id), 0) AS claims_reported,
+\t\t/* incurred claims count */
+\tFORMAT(
+\t SUM(
+\t CASE
+\t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1
+\t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1
+\t ELSE 0
+\t END
+\t )
+, 0) AS incurred_claims,
+
+ /* incurred amount */
+ FORMAT(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ , 0) AS incurred_amount,
+
+ /* incurred ratio */
+ CONCAT(
+ ROUND(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) * 100
+ , 2)
+ , '%') AS incurred_ratio,
+
+ /* rejection rate */
+ CONCAT(
+ ROUND(
+ SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END)
+ / NULLIF(COUNT(tm.id), 0) * 100
+ , 2)
+ , '%') AS rejection_rate,
+
+ /* projected claims */
+ FORMAT(
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ , 0) AS projected_claims,
+
+ /* projected ratio */
+ CONCAT(
+ ROUND(
+ (
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ )
+ / NULLIF(prem.premium_as_on_date, 0) * 100
+ , 2)
+ , '%') AS projected_ratio
+
+FROM client_policy cp
+
+JOIN (
+ SELECT
+ ep2.client_policy_id,
+ COALESCE(SUM(
+ CASE
+ WHEN e2.change_event = 'inception'
+ THEN ep2.rata_premimum
+ WHEN e2.change_event != 'inception'
+ AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '')
+ THEN ep2.rata_premimum
+ WHEN ep2.date_of_exit IS NOT NULL
+ AND ep2.date_of_exit != ''
+ AND ep2.claim_status = 0
+ THEN -ep2.rata_premimum
+ ELSE 0
+ END
+ ), 0) AS premium_as_on_date
+ FROM employee_polices ep2
+ JOIN employees e2 ON e2.id = ep2.employee_id
+ WHERE ep2.client_policy_id = :policy_id:
+ AND ep2.is_active = 1
+ GROUP BY ep2.client_policy_id
+) prem ON prem.client_policy_id = cp.id
+
+JOIN ticket_master tm
+ ON tm.client_policy_id = cp.id
+ AND tm.is_active = 1
+
+JOIN ticket_claim_status tcs
+ ON tcs.id = tm.claim_status_id
+
+WHERE cp.id = :policy_id:
+
+GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #206: Incurred Amount */
+ public function incurred_amount(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ /* run days */
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ) AS run_days,
+
+ /* earned premium */
+ FORMAT(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) AS earned_premium,
+
+ /* claims reported */
+ FORMAT(COUNT(tm.id), 0) AS claims_reported,
+\t\t/* incurred claims count */
+\tFORMAT(
+\t SUM(
+\t CASE
+\t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1
+\t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1
+\t ELSE 0
+\t END
+\t )
+, 0) AS incurred_claims,
+
+ /* incurred amount */
+ FORMAT(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ , 0) AS incurred_amount,
+
+ /* incurred ratio */
+ CONCAT(
+ ROUND(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) * 100
+ , 2)
+ , '%') AS incurred_ratio,
+
+ /* rejection rate */
+ CONCAT(
+ ROUND(
+ SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END)
+ / NULLIF(COUNT(tm.id), 0) * 100
+ , 2)
+ , '%') AS rejection_rate,
+
+ /* projected claims */
+ FORMAT(
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ , 0) AS projected_claims,
+
+ /* projected ratio */
+ CONCAT(
+ ROUND(
+ (
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ )
+ / NULLIF(prem.premium_as_on_date, 0) * 100
+ , 2)
+ , '%') AS projected_ratio
+
+FROM client_policy cp
+
+JOIN (
+ SELECT
+ ep2.client_policy_id,
+ COALESCE(SUM(
+ CASE
+ WHEN e2.change_event = 'inception'
+ THEN ep2.rata_premimum
+ WHEN e2.change_event != 'inception'
+ AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '')
+ THEN ep2.rata_premimum
+ WHEN ep2.date_of_exit IS NOT NULL
+ AND ep2.date_of_exit != ''
+ AND ep2.claim_status = 0
+ THEN -ep2.rata_premimum
+ ELSE 0
+ END
+ ), 0) AS premium_as_on_date
+ FROM employee_polices ep2
+ JOIN employees e2 ON e2.id = ep2.employee_id
+ WHERE ep2.client_policy_id = :policy_id:
+ AND ep2.is_active = 1
+ GROUP BY ep2.client_policy_id
+) prem ON prem.client_policy_id = cp.id
+
+JOIN ticket_master tm
+ ON tm.client_policy_id = cp.id
+ AND tm.is_active = 1
+
+JOIN ticket_claim_status tcs
+ ON tcs.id = tm.claim_status_id
+
+WHERE cp.id = :policy_id:
+
+GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #207: Incurred Ratio */
+ public function incurred_ratio(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ /* run days */
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ) AS run_days,
+
+ /* earned premium */
+ FORMAT(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) AS earned_premium,
+
+ /* claims reported */
+ FORMAT(COUNT(tm.id), 0) AS claims_reported,
+\t\t/* incurred claims count */
+\tFORMAT(
+\t SUM(
+\t CASE
+\t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1
+\t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1
+\t ELSE 0
+\t END
+\t )
+, 0) AS incurred_claims,
+
+ /* incurred amount */
+ FORMAT(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ , 0) AS incurred_amount,
+
+ /* incurred ratio */
+ CONCAT('💹 ',
+ ROUND(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) * 100
+ , 2)
+ , '%') AS incurred_ratio,
+
+ /* rejection rate */
+ CONCAT(
+ ROUND(
+ SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END)
+ / NULLIF(COUNT(tm.id), 0) * 100
+ , 2)
+ , '%') AS rejection_rate,
+
+ /* projected claims */
+ FORMAT(
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ , 0) AS projected_claims,
+
+ /* projected ratio */
+ CONCAT(
+ ROUND(
+ (
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ )
+ / NULLIF(prem.premium_as_on_date, 0) * 100
+ , 2)
+ , '%') AS projected_ratio
+
+FROM client_policy cp
+
+JOIN (
+ SELECT
+ ep2.client_policy_id,
+ COALESCE(SUM(
+ CASE
+ WHEN e2.change_event = 'inception'
+ THEN ep2.rata_premimum
+ WHEN e2.change_event != 'inception'
+ AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '')
+ THEN ep2.rata_premimum
+ WHEN ep2.date_of_exit IS NOT NULL
+ AND ep2.date_of_exit != ''
+ AND ep2.claim_status = 0
+ THEN -ep2.rata_premimum
+ ELSE 0
+ END
+ ), 0) AS premium_as_on_date
+ FROM employee_polices ep2
+ JOIN employees e2 ON e2.id = ep2.employee_id
+ WHERE ep2.client_policy_id = :policy_id:
+ AND ep2.is_active = 1
+ GROUP BY ep2.client_policy_id
+) prem ON prem.client_policy_id = cp.id
+
+JOIN ticket_master tm
+ ON tm.client_policy_id = cp.id
+ AND tm.is_active = 1
+
+JOIN ticket_claim_status tcs
+ ON tcs.id = tm.claim_status_id
+
+WHERE cp.id = :policy_id:
+
+GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #208: Projected Claims */
+ public function projected_claims(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ /* run days */
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ) AS run_days,
+
+ /* earned premium */
+ FORMAT(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) AS earned_premium,
+
+ /* claims reported */
+ FORMAT(COUNT(tm.id), 0) AS claims_reported,
+\t\t/* incurred claims count */
+\tFORMAT(
+\t SUM(
+\t CASE
+\t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1
+\t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1
+\t ELSE 0
+\t END
+\t )
+, 0) AS incurred_claims,
+
+ /* incurred amount */
+ FORMAT(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ , 0) AS incurred_amount,
+
+ /* incurred ratio */
+ CONCAT(
+ ROUND(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) * 100
+ , 2)
+ , '%') AS incurred_ratio,
+
+ /* rejection rate */
+ CONCAT(
+ ROUND(
+ SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END)
+ / NULLIF(COUNT(tm.id), 0) * 100
+ , 2)
+ , '%') AS rejection_rate,
+
+ /* projected claims */
+
+ CONCAT('🎯 ', FORMAT(
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ , 0)) AS projected_claims,
+
+ /* projected ratio */
+ CONCAT(
+ ROUND(
+ (
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ )
+ / NULLIF(prem.premium_as_on_date, 0) * 100
+ , 2)
+ , '%') AS projected_ratio
+
+FROM client_policy cp
+
+JOIN (
+ SELECT
+ ep2.client_policy_id,
+ COALESCE(SUM(
+ CASE
+ WHEN e2.change_event = 'inception'
+ THEN ep2.rata_premimum
+ WHEN e2.change_event != 'inception'
+ AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '')
+ THEN ep2.rata_premimum
+ WHEN ep2.date_of_exit IS NOT NULL
+ AND ep2.date_of_exit != ''
+ AND ep2.claim_status = 0
+ THEN -ep2.rata_premimum
+ ELSE 0
+ END
+ ), 0) AS premium_as_on_date
+ FROM employee_polices ep2
+ JOIN employees e2 ON e2.id = ep2.employee_id
+ WHERE ep2.client_policy_id = :policy_id:
+ AND ep2.is_active = 1
+ GROUP BY ep2.client_policy_id
+) prem ON prem.client_policy_id = cp.id
+
+JOIN ticket_master tm
+ ON tm.client_policy_id = cp.id
+ AND tm.is_active = 1
+
+JOIN ticket_claim_status tcs
+ ON tcs.id = tm.claim_status_id
+
+WHERE cp.id = :policy_id:
+
+GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #209: Projected Ratio */
+ public function projected_ratio(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ /* run days */
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ) AS run_days,
+
+ /* earned premium */
+ FORMAT(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) AS earned_premium,
+
+ /* claims reported */
+ FORMAT(COUNT(tm.id), 0) AS claims_reported,
+\t\t/* incurred claims count */
+\tFORMAT(
+\t SUM(
+\t CASE
+\t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1
+\t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1
+\t ELSE 0
+\t END
+\t )
+, 0) AS incurred_claims,
+
+ /* incurred amount */
+ FORMAT(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ , 0) AS incurred_amount,
+
+ /* incurred ratio */
+ CONCAT(
+ ROUND(
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ (prem.premium_as_on_date / 365)
+ * DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ )
+ , 0) * 100
+ , 2)
+ , '%') AS incurred_ratio,
+
+ /* rejection rate */
+ CONCAT(
+ ROUND(
+ SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END)
+ / NULLIF(COUNT(tm.id), 0) * 100
+ , 2)
+ , '%') AS rejection_rate,
+
+ /* projected claims */
+ FORMAT(
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ , 0) AS projected_claims,
+
+ /* projected ratio */
+ CONCAT('💹 ',
+ ROUND(
+ (
+ (
+ COALESCE(SUM(
+ CASE
+ WHEN tcs.claim_status IN ('Settled', 'Paid')
+ THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied')
+ THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ), 0)
+ / NULLIF(
+ DATEDIFF(
+ MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)),
+ cp.policy_start_date
+ ), 0
+ )
+ * 365
+ ) * 1.10
+ )
+ / NULLIF(prem.premium_as_on_date, 0) * 100
+ , 2)
+ , '%') AS projected_ratio
+
+FROM client_policy cp
+
+JOIN (
+ SELECT
+ ep2.client_policy_id,
+ COALESCE(SUM(
+ CASE
+ WHEN e2.change_event = 'inception'
+ THEN ep2.rata_premimum
+ WHEN e2.change_event != 'inception'
+ AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '')
+ THEN ep2.rata_premimum
+ WHEN ep2.date_of_exit IS NOT NULL
+ AND ep2.date_of_exit != ''
+ AND ep2.claim_status = 0
+ THEN -ep2.rata_premimum
+ ELSE 0
+ END
+ ), 0) AS premium_as_on_date
+ FROM employee_polices ep2
+ JOIN employees e2 ON e2.id = ep2.employee_id
+ WHERE ep2.client_policy_id = :policy_id:
+ AND ep2.is_active = 1
+ GROUP BY ep2.client_policy_id
+) prem ON prem.client_policy_id = cp.id
+
+JOIN ticket_master tm
+ ON tm.client_policy_id = cp.id
+ AND tm.is_active = 1
+
+JOIN ticket_claim_status tcs
+ ON tcs.id = tm.claim_status_id
+
+WHERE cp.id = :policy_id:
+
+GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #213: Total Reimbursement Amount */
+ public function total_reimbursement_amount(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value,
+
+ ROUND(
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(totals.total_value, 0) * 100
+ , 2) AS value_pct
+
+FROM ticket_master tm
+
+JOIN (
+ SELECT
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+) totals ON 1=1
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND (
+ tm.tpa_claim_type IS NULL
+ OR TRIM(LOWER(tm.tpa_claim_type)) IN ('unknown', 'reimbursement', '')
+ );
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #214: Total Reimbursement Amt % */
+ public function total_reimbursement_amt_pct(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value,
+
+ ROUND(
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(totals.total_value, 0) * 100
+ , 2) AS value_pct
+
+FROM ticket_master tm
+
+JOIN (
+ SELECT
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+) totals ON 1=1
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND (
+ tm.tpa_claim_type IS NULL
+ OR TRIM(LOWER(tm.tpa_claim_type)) IN ('unknown', 'reimbursement', '')
+ );
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #215: Cashless Claim Amt */
+ public function cashless_claim_amt(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value,
+
+ ROUND(
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(totals.total_value, 0) * 100
+ , 2) AS value_pct
+
+FROM ticket_master tm
+
+JOIN (
+ SELECT
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+) totals ON 1=1
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND TRIM(LOWER(tm.tpa_claim_type)) = 'cashless';
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #216: Cashless Claim Amt % */
+ public function cashless_claim_amt_pct(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value,
+
+ ROUND(
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(totals.total_value, 0) * 100
+ , 2) AS value_pct
+
+FROM ticket_master tm
+
+JOIN (
+ SELECT
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+) totals ON 1=1
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND TRIM(LOWER(tm.tpa_claim_type)) = 'cashless';
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #217: Total Incurred by city */
+ public function total_incurred_by_city(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(tm.hospital_name, 'Not Specified') AS hospital_name,
+ COALESCE(tm.hospital_city, '-') AS hospital_city,
+ COALESCE(tm.hospital_state, '-') AS hospital_state,
+
+ COUNT(tm.id) AS claim_count,
+
+ ROUND(
+ COUNT(tm.id) / totals.total_count * 100,
+ 2
+ ) AS count_pct,
+
+ COALESCE(
+ SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))),
+ 0
+ ) AS claim_value,
+
+ ROUND(
+ COALESCE(
+ SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))),
+ 0
+ ) / NULLIF(totals.total_value, 0) * 100,
+ 2
+ ) AS value_pct
+
+FROM ticket_master tm
+
+JOIN (
+ SELECT
+ COUNT(id) AS total_count,
+
+ COALESCE(
+ SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))),
+ 0
+ ) AS total_value
+
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+) totals ON 1=1
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND tm.hospital_name IS NOT NULL
+
+GROUP BY
+ tm.hospital_name,
+ tm.hospital_city,
+ tm.hospital_state,
+ totals.total_count,
+ totals.total_value
+
+ORDER BY claim_count DESC
+
+LIMIT 5;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #219: Claim Amount by Claim Status */
+ public function claim_amount_by_claim_status(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(tcs.display_name, 'Unknown') AS claim_status,
+ COUNT(tm.id) AS claim_count,
+ CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%')
+ AS count_pct,
+
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ AS claim_value,
+ CONCAT(ROUND(
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(totals.total_value, 0) * 100
+ , 2), '%') AS value_pct
+FROM ticket_master tm
+JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id
+JOIN (
+ SELECT
+ COUNT(id) AS total_count,
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id: AND is_active = 1
+) totals ON 1=1
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+GROUP BY tcs.display_name, totals.total_count, totals.total_value
+ORDER BY claim_count DESC;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #220: Hospitals in detail */
+ public function hospitals_in_detail(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(NULLIF(TRIM(tm.hospital_name), ''), 'Not Specified') AS hospital_name,
+
+ COALESCE(NULLIF(TRIM(tm.hospital_city), ''), '-') AS hospital_city,
+
+ COALESCE(NULLIF(TRIM(tm.hospital_state), ''), '-') AS hospital_state,
+
+ COUNT(tm.id) AS claim_count,
+
+ CAST(
+ GREATEST(
+ ROUND(
+ (
+ COUNT(tm.id) / NULLIF(totals.total_count, 0)
+ ) * 100,
+ 2
+ ),
+ 0.01
+ ) AS DECIMAL(10,2)
+ ) AS count_pct,
+
+ CAST(
+ COALESCE(
+ SUM(
+ CASE
+ WHEN TRIM(tm.claim_amount) REGEXP '^[0-9]+(\\\\.[0-9]+)?$'
+ THEN CAST(TRIM(tm.claim_amount) AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ),
+ 0
+ ) AS DECIMAL(15,2)
+ ) AS claim_value,
+
+ CAST(
+ GREATEST(
+ ROUND(
+ (
+ COALESCE(
+ SUM(
+ CASE
+ WHEN TRIM(tm.claim_amount) REGEXP '^[0-9]+(\\\\.[0-9]+)?$'
+ THEN CAST(TRIM(tm.claim_amount) AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ),
+ 0
+ ) / NULLIF(totals.total_value, 0)
+ ) * 100,
+ 2
+ ),
+ 0.01
+ ) AS DECIMAL(10,2)
+ ) AS value_pct
+
+FROM ticket_master tm
+
+JOIN (
+ SELECT
+ COUNT(id) AS total_count,
+
+ CAST(
+ COALESCE(
+ SUM(
+ CASE
+ WHEN TRIM(claim_amount) REGEXP '^[0-9]+(\\\\.[0-9]+)?$'
+ THEN CAST(TRIM(claim_amount) AS DECIMAL(15,2))
+ ELSE 0
+ END
+ ),
+ 0
+ ) AS DECIMAL(15,2)
+ ) AS total_value
+
+ FROM ticket_master
+
+ WHERE client_policy_id = :policy_id:
+ AND is_active = 1
+
+) totals ON 1 = 1
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND NULLIF(TRIM(tm.hospital_name), '') IS NOT NULL
+
+GROUP BY
+ tm.hospital_name,
+ tm.hospital_city,
+ tm.hospital_state
+
+ORDER BY claim_count DESC;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #221: Hospital city wise SI Limit - Pregnancy */
+ public function hospital_city_wise_si_limit_pregnancy(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(tm.hospital_city, 'Not Specified') AS hospital_city,
+\tCOALESCE(tm.hospital_name, 'Not Specified') AS hospital_name,
+ COUNT(tm.id) AS `Claim Count`,
+
+ FORMAT(
+ COALESCE(
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),
+ 0),
+ 0) AS `SUM OF CLAIMED AMOUNT`,
+
+ CASE
+ WHEN COALESCE(
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),
+ 0)
+ >
+ COALESCE(
+ SUM(
+ CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2))
+ ),
+ 0)
+ THEN 'Exceeded'
+ ELSE 'Within Limit'
+ END AS `CLAIM STATUS LIMIT`
+
+FROM ticket_master tm
+
+INNER JOIN employee_polices ep
+ ON ep.employee_id = tm.emp_id
+ AND ep.client_policy_id = tm.client_policy_id
+ AND ep.is_active = 1
+ AND ep.status = 'active'
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND tm.hospital_name IS NOT NULL
+
+ /* Pregnancy Related Conditions */
+ AND (
+ LOWER(tm.tpa_ailments) LIKE '%pregnancy%'
+ OR LOWER(tm.tpa_ailments) LIKE '%maternal%'
+ OR LOWER(tm.tpa_ailments) LIKE '%gestational%'
+ OR LOWER(tm.tpa_ailments) LIKE '%delivery%'
+ OR LOWER(tm.tpa_ailments) LIKE '%cesarean%'
+ OR LOWER(tm.tpa_ailments) LIKE '%caesarean%'
+ OR LOWER(tm.tpa_ailments) LIKE '%c-section%'
+ OR LOWER(tm.tpa_ailments) LIKE '%spontaneous delivery%'
+ OR LOWER(tm.tpa_ailments) LIKE '%normal delivery%'
+ OR LOWER(tm.tpa_ailments) LIKE '%forceps%'
+ OR LOWER(tm.tpa_ailments) LIKE '%vaccum extractor%'
+ )
+
+GROUP BY tm.hospital_city,tm.hospital_name
+
+ORDER BY
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ) DESC;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #224: S-PREGNANCY - NORMAL DELIVERY Exceeded Amt */
+ public function s_pregnancy_normal_delivery_exceeded_amt(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ 'SINGLE PREGNANCY - NORMAL DELIVERY' AS diagnosis,
+
+ COALESCE(
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),0) AS exceeded_claim_amount
+
+FROM ticket_master tm
+
+INNER JOIN employee_polices ep
+ ON ep.employee_id = tm.emp_id
+ AND ep.client_policy_id = tm.client_policy_id
+ AND ep.is_active = 1
+ AND ep.status = 'active'
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+
+ AND (
+ LOWER(tm.tpa_ailments) LIKE '%spontaneous delivery%'
+ OR LOWER(tm.tpa_ailments) LIKE '%normal delivery%'
+ OR LOWER(tm.tpa_ailments) LIKE '%forceps%'
+ OR LOWER(tm.tpa_ailments) LIKE '%vaccum extractor%'
+ )
+
+ AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ >
+ CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2));
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #225: S-Pregnancy C-Sec avg exceeded amt */
+ public function s_pregnancy_c_sec_avg_exceeded_amt(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ 'SINGLE PREGNANCY - CAESAREAN DELIVERY' AS diagnosis,
+
+ COALESCE(
+ AVG(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),
+ 2) AS avg_exceeded_amount
+
+FROM ticket_master tm
+
+INNER JOIN employee_polices ep
+ ON ep.employee_id = tm.emp_id
+ AND ep.client_policy_id = tm.client_policy_id
+ AND ep.is_active = 1
+ AND ep.status = 'active'
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+
+ AND (
+ LOWER(tm.tpa_ailments) LIKE '%cesarean%'
+ OR LOWER(tm.tpa_ailments) LIKE '%caesarean%'
+ OR LOWER(tm.tpa_ailments) LIKE '%c-section%'
+ )
+
+ AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ >
+ CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2));
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #228: Cataract exceeded claim amount */
+ public function cataract_exceeded_claim_amount(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ 'CATARACT' AS diagnosis,
+
+
+ COALESCE(
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),
+ 0) AS exceeded_claim_amount
+
+FROM ticket_master tm
+
+INNER JOIN employee_polices ep
+ ON ep.employee_id = tm.emp_id
+ AND ep.client_policy_id = tm.client_policy_id
+ AND ep.is_active = 1
+ AND ep.status = 'active'
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+
+ AND LOWER(tm.tpa_ailments) LIKE '%cataract%'
+
+ AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ >
+ CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2));
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #229: Cataract avg exceeded amount */
+ public function cataract_avg_exceeded_amount(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ 'CATARACT' AS diagnosis,
+
+ FORMAT(
+ COALESCE(
+ AVG(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),
+ 0),
+ 2) AS avg_exceeded_claim_amount
+
+FROM ticket_master tm
+
+INNER JOIN employee_polices ep
+ ON ep.employee_id = tm.emp_id
+ AND ep.client_policy_id = tm.client_policy_id
+ AND ep.is_active = 1
+ AND ep.status = 'active'
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+
+ AND LOWER(tm.tpa_ailments) LIKE '%cataract%'
+
+ AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ >
+ CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2));
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #230: Hospital city wise SI Limit - Cataract */
+ public function hospital_city_wise_si_limit_cataract(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+\tCOALESCE(tm.hospital_city, 'Not Specified') AS hospital_city,
+ COALESCE(tm.hospital_name, 'Not Specified') AS hospital_name,
+
+ COUNT(tm.id) AS claim_count,
+
+ FORMAT(
+ COALESCE(
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),
+ 0),
+ 0) AS `SUM OF CLAIMED AMOUNT`,
+
+ CASE
+ WHEN COALESCE(
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ),
+ 0)
+ >
+ COALESCE(
+ SUM(
+ CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2))
+ ),
+ 0)
+ THEN 'Exceeded'
+ ELSE 'Within Limit'
+ END AS `CLAIM STATUS LIMIT`
+
+FROM ticket_master tm
+
+INNER JOIN employee_polices ep
+ ON ep.employee_id = tm.emp_id
+ AND ep.client_policy_id = tm.client_policy_id
+ AND ep.is_active = 1
+ AND ep.status = 'active'
+
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+ AND tm.hospital_name IS NOT NULL
+
+ /* Cataract Related */
+ AND LOWER(tm.tpa_ailments) LIKE '%cataract%'
+
+GROUP BY tm.hospital_city,tm.hospital_name
+
+ORDER BY
+ SUM(
+ CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2))
+ ) DESC;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #231: Total Incurred by Cliam Status */
+ public function total_incurred_by_cliam_status(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COALESCE(tcs.display_name, 'Unknown') AS `Claim Status`,
+ -- COUNT(tm.id) AS claim_count,
+ -- CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%')
+ -- AS count_pct,
+
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ AS `Total Incurred Amount`,
+ CONCAT(ROUND(
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ / NULLIF(totals.total_value, 0) * 100
+ , 2), '%') AS `Value PCT`
+FROM ticket_master tm
+JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id
+JOIN (
+ SELECT
+ COUNT(id) AS total_count,
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id: AND is_active = 1
+) totals ON 1=1
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+GROUP BY tcs.display_name, totals.total_count, totals.total_value
+-- ORDER BY claim_count DESC;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #232: Inception Employees & Lives */
+ public function inception_emp_lives(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COUNT(DISTINCT CASE
+ WHEN e.relationship = 'Self' THEN e.id
+ END) AS inception_emp,
+
+ COUNT(DISTINCT e.id) AS inception_lives
+
+FROM employee_polices ep
+JOIN employees e ON e.id = ep.employee_id
+WHERE ep.client_policy_id = :policy_id:
+ AND LOWER(e.change_event) LIKE '%inception%'
+ AND ep.is_active = 1
+ AND e.is_active = 1;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #233: Current Employees & Lives */
+ public function current_emp_lives(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ COUNT(DISTINCT CASE
+ WHEN e.relationship = 'Self' THEN e.id
+ END) AS current_emp,
+
+ COUNT(DISTINCT e.id) AS current_lives,
+
+ ROUND(
+ COUNT(DISTINCT e.id)
+ / NULLIF(COUNT(DISTINCT CASE
+ WHEN e.relationship = 'Self' THEN e.id
+ END), 0)
+ , 2) AS avg_family_size
+
+FROM employee_polices ep
+JOIN employees e ON e.id = ep.employee_id
+WHERE ep.client_policy_id = :policy_id:
+ AND ep.status = 'active'
+ AND ep.is_active = 1
+ AND e.emp_status = 'active'
+ AND e.is_active = 1;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+ /** Metabase #234: Claim Value by Month */
+ public function claim_value_by_month(int $policyId): array
+ {
+ $sql = <<<'SQL'
+SELECT
+ DATE_FORMAT(tm.created_at, '%b %Y') AS claim_month,
+ DATE_FORMAT(tm.created_at, '%Y-%m') AS month_sort,
+ -- COUNT(tm.id) AS claim_count,
+ -- CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%') AS count_pct,
+
+ COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ AS claim_value
+ -- CONCAT(ROUND(
+ -- COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0)
+ -- / NULLIF(totals.total_value, 0) * 100
+ -- , 2), '%') AS value_pct
+FROM ticket_master tm
+JOIN (
+ SELECT
+ COUNT(id) AS total_count,
+ COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value
+ FROM ticket_master
+ WHERE client_policy_id = :policy_id: AND is_active = 1
+) totals ON 1=1
+WHERE tm.client_policy_id = :policy_id:
+ AND tm.is_active = 1
+GROUP BY
+ DATE_FORMAT(tm.created_at, '%b %Y'),
+ DATE_FORMAT(tm.created_at, '%Y-%m'),
+ totals.total_count,
+ totals.total_value
+ORDER BY month_sort;
+SQL;
+ return $this->runKpiQuery($sql, $policyId);
+ }
+
+}
diff --git a/app/Models/ClientPolicyModel.php b/app/Models/ClientPolicyModel.php
index c3acb681..b650d585 100755
--- a/app/Models/ClientPolicyModel.php
+++ b/app/Models/ClientPolicyModel.php
@@ -311,6 +311,24 @@ class ClientPolicyModel extends Model
// Fetch the deposit data based on client and insurer IDs
$query = $this->db->table('cash_deposit')
->select('cash_deposit.*')
+ ->select("
+ (select old_value from auditing_history where pk = cash_deposit.id and field_name = 'amount' and table_name = 'cash_deposit' order by id desc limit 1) as old_amt,
+ (select new_value from auditing_history where pk = cash_deposit.id and field_name = 'amount' and table_name = 'cash_deposit' order by id desc limit 1) as new_amt,
+ (select created_by from auditing_history where pk = cash_deposit.id and field_name = 'amount' and table_name = 'cash_deposit' order by id desc limit 1) as amt_updated_by,
+ (select created_at from auditing_history where pk = cash_deposit.id and field_name = 'amount' and table_name = 'cash_deposit' order by id desc limit 1) as amt_updated_at,
+ (
+ select up.first_name
+ from user_profiles up
+ where up.id = (
+ select created_by
+ from auditing_history
+ where pk = cash_deposit.id and field_name = 'amount' and table_name = 'cash_deposit'
+ order by id desc
+ limit 1
+ )
+ limit 1
+ ) as amt_updated_by_name
+ ")
->select('insurers.name as insurer_name, insurers.short_name as insurer_short')
->select('clients.client_name as clientname, clients.short_name as clientshort, client_policy.policy_no')
->select('cd_master.cd_ac_no as cd_master_account_no')
diff --git a/app/Views/apache_dashboard_demo_one.php b/app/Views/apache_dashboard_demo_one.php
new file mode 100644
index 00000000..fe1da55a
--- /dev/null
+++ b/app/Views/apache_dashboard_demo_one.php
@@ -0,0 +1,113 @@
+
+
+
+
+
+ Claims Overview
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/Views/batch_list.php b/app/Views/batch_list.php
index 5ebdebc5..61d395e7 100755
--- a/app/Views/batch_list.php
+++ b/app/Views/batch_list.php
@@ -34,7 +34,7 @@ if (!empty($batch_list) && is_array($batch_list)) {
$countStr = ($file['count'] ?? null) === null ? '-' : (string) $file['count'];
$batch_col_max_len[9] = max($batch_col_max_len[9], mb_strlen($countStr));
$batch_col_max_len[10] = max($batch_col_max_len[10], mb_strlen((string) format_indian_number($file['amount'])));
- $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd M Y h:i a')
+ $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd/m/Y h:i a')
. ' by '
. get_username($file['created_by'] ?? '');
$batch_col_max_len[11] = max($batch_col_max_len[11], mb_strlen($userTime));
@@ -350,7 +350,7 @@ for ($i = 0; $i < $batch_col_count; $i++) {
|
- by
+ by
|
diff --git a/app/Views/bds_dump_file_list.php b/app/Views/bds_dump_file_list.php
index b56448fa..2ea6207a 100644
--- a/app/Views/bds_dump_file_list.php
+++ b/app/Views/bds_dump_file_list.php
@@ -49,7 +49,7 @@
|
- ' . $file['user_name'] . '' ?> |
+ ' . $file['user_name'] . '' ?> |
= $file['status'] ?>
diff --git a/app/Views/cd_master_add_modal.php b/app/Views/cd_master_add_modal.php
index e73b807f..29597a75 100644
--- a/app/Views/cd_master_add_modal.php
+++ b/app/Views/cd_master_add_modal.php
@@ -107,13 +107,50 @@
var isCdMasterPage = ;
console.log("isCdMasterPage", isCdMasterPage);
+ function formatCdOpeningDateForInput(inputDate) {
+ if (!inputDate || String(inputDate).trim() === '') {
+ return '';
+ }
+ var str = String(inputDate).trim();
+ var iso = str.match(/^(\d{4})-(\d{2})-(\d{2})/);
+ if (iso) {
+ return iso[3] + '/' + iso[2] + '/' + iso[1];
+ }
+ var dmy = str.match(/^(\d{1,2})[-\/](\d{1,2})[-\/](\d{4})$/);
+ if (dmy) {
+ var day = ('0' + dmy[1]).slice(-2);
+ var month = ('0' + dmy[2]).slice(-2);
+ return day + '/' + month + '/' + dmy[3];
+ }
+ return str;
+ }
+
+ function cdOpeningDateForSubmit(inputDate) {
+ var formatted = formatCdOpeningDateForInput(inputDate);
+ if (!formatted) {
+ return inputDate || '';
+ }
+ var parts = formatted.split('/');
+ return parts[0] + '-' + parts[1] + '-' + parts[2];
+ }
+
+ var openingDatePicker;
+
$(document).ready(function(){
- var openingDatePicker = flatpickr("#opening_date", {
- dateFormat: "d-m-Y",
+ openingDatePicker = flatpickr("#opening_date", {
+ dateFormat: "d/m/Y",
allowInput: false
});
+ $('#con-close-modal').on('shown.bs.modal', function() {
+ var val = $('#opening_date').val();
+ if (val) {
+ var formatted = formatCdOpeningDateForInput(val);
+ openingDatePicker.setDate(formatted, false);
+ }
+ });
+
if(isCdMasterPage == true){
$('#cd_client_id').select2();
$('#insurer_id_for_cd').select2();
@@ -172,6 +209,10 @@
}
let formData = new FormData($('#CDMasterForm')[0]);
+ var openingDate = formData.get('opening_date');
+ if (openingDate) {
+ formData.set('opening_date', cdOpeningDateForSubmit(openingDate));
+ }
console.log("formData", formData);
let url = '= base_url('master/cash_deposite/create') ?>';
diff --git a/app/Views/cd_master_list.php b/app/Views/cd_master_list.php
index 1314066a..1bd8dc4e 100755
--- a/app/Views/cd_master_list.php
+++ b/app/Views/cd_master_list.php
@@ -15,12 +15,12 @@ foreach ($CD_Master_Data as $index => $row) {
$cdm_col_max_len[1] = max($cdm_col_max_len[1], mb_strlen($clientCell));
$cdm_col_max_len[2] = max($cdm_col_max_len[2], mb_strlen((string) ($row['insurer_name'] ?? '')));
$cdm_col_max_len[3] = max($cdm_col_max_len[3], mb_strlen((string) ($row['insurer_branch_name'] ?? '')));
- $od = ! empty($row['opening_date']) ? date('d-m-Y', strtotime((string) $row['opening_date'])) : '';
+ $od = ! empty($row['opening_date']) ? date('d/m/Y', strtotime((string) $row['opening_date'])) : '';
$cdm_col_max_len[4] = max($cdm_col_max_len[4], mb_strlen($od));
$cdm_col_max_len[5] = max($cdm_col_max_len[5], mb_strlen((string) ($row['cd_ac_no'] ?? '')));
$cdm_col_max_len[6] = max($cdm_col_max_len[6], mb_strlen((string) ($row['opening_bal'] ?? '')));
$du = ! empty($row['created_at'])
- ? (date('d-M-Y h:i A', strtotime((string) $row['created_at'])) . ' by ' . ($row['user_name'] ?? ''))
+ ? (date('d/m/Y h:i A', strtotime((string) $row['created_at'])) . ' by ' . ($row['user_name'] ?? ''))
: '';
$cdm_col_max_len[7] = max($cdm_col_max_len[7], mb_strlen($du));
$cdm_col_max_len[8] = max($cdm_col_max_len[8], 4);
@@ -118,10 +118,10 @@ $cdm_col_width_px = nhance_dt_column_widths_px($cdm_header_labels, $cdm_col_max_
| ( = $row['short_name'] ?> ) |
|
|
- |
+ |
|
|
- by |
+ by |
diff --git a/app/Views/claim_dump_file_list.php b/app/Views/claim_dump_file_list.php
index ee00683e..63d7cedf 100644
--- a/app/Views/claim_dump_file_list.php
+++ b/app/Views/claim_dump_file_list.php
@@ -161,7 +161,7 @@
|
- ' . $file['user_name'] . '' ?> |
+ ' . $file['user_name'] . '' ?> |
= $file['status'] ?>
@@ -262,7 +262,7 @@
diff --git a/app/Views/claims_collection_v2_dashboard.php b/app/Views/claims_collection_v2_dashboard.php
new file mode 100644
index 00000000..54093024
--- /dev/null
+++ b/app/Views/claims_collection_v2_dashboard.php
@@ -0,0 +1,103 @@
+
+
+
+
+
+ Claims Collection V2 Dashboard
+
+
+
+
+Claims Collection V2
+
+
+
+
+
+
+
+
+ $method): ?>
+
+ #= (int) $metabaseId ?> · = esc($kpi_labels[$method] ?? $method) ?>
+ = esc($method) ?>
+ Click “Load all KPIs” or open single KPI API.
+
+
+
+
+
+
+
diff --git a/app/Views/client_basic_info.php b/app/Views/client_basic_info.php
index efbbb33a..58a16e1a 100755
--- a/app/Views/client_basic_info.php
+++ b/app/Views/client_basic_info.php
@@ -236,7 +236,7 @@ input:checked + .slider:before {
class="text-danger">*
|
diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php
index 9e654e80..26bcab2c 100755
--- a/app/Views/client_policy.php
+++ b/app/Views/client_policy.php
@@ -209,7 +209,7 @@ input:checked + .slider_blue::before {
data-parsley-pattern="^[1-9][0-9]*$"
data-parsley-pattern-message="Please select a valid Policy Type.">
-
+
@@ -230,7 +230,7 @@ input:checked + .slider_blue::before {
-
+
@@ -241,7 +241,7 @@ input:checked + .slider_blue::before {
-
+
@@ -454,7 +454,7 @@ input:checked + .slider_blue::before {
const showExpired = $('#chk-show-expired').is(':checked');
var startDatePicker = flatpickr("#start_date", {
- dateFormat: "d-m-Y",
+ dateFormat: "d/m/Y",
defaultDate: today,
allowInput: false,
onChange: function(selectedDates, dateStr, instance) {
@@ -467,7 +467,7 @@ input:checked + .slider_blue::before {
// Initialize Flatpickr for the start date with today's date
var openDatePicker = flatpickr("#open_date", {
- dateFormat: "d-m-Y",
+ dateFormat: "d/m/Y",
defaultDate: today,
allowInput: false,
});
@@ -478,14 +478,14 @@ input:checked + .slider_blue::before {
closeDate.setDate(closeDate.getDate() - 1); // Set end date to last day of next year
var endDatePicker = flatpickr("#end_date", {
- dateFormat: "d-m-Y",
+ dateFormat: "d/m/Y",
defaultDate: closeDate,
allowInput: false
});
// Initialize Flatpickr for the end date with the calculated end date
var closeDatePicker = flatpickr("#close_date", {
- dateFormat: "d-m-Y",
+ dateFormat: "d/m/Y",
defaultDate: today,
allowInput: false
});
@@ -566,7 +566,7 @@ input:checked + .slider_blue::before {
${policy_name_data} |
${item.branch_name ? item.branch_name : ' - '} |
${tpaValue} |
- ${(item.policy_start_date)} / ${(item.policy_end_date)} |
+ ${formatPolicyDisplayDate(item.policy_start_date)} - ${formatPolicyDisplayDate(item.policy_end_date)} |
${checkDateStatus(item.policy_end_date, 1)} |
@@ -751,6 +751,12 @@ input:checked + .slider_blue::before {
$('.loader-mask').fadeIn();
var formData = new FormData($('#policy_form')[0]);
+ ['policy_start_date', 'policy_end_date', 'open_date', 'close_date'].forEach(function(fieldName) {
+ var val = formData.get(fieldName);
+ if (val) {
+ formData.set(fieldName, policyFormDateForSubmit(val));
+ }
+ });
var policy_form_action = $('#policy_form_action').val();
console.log(formData+'form data');
$.ajax({
@@ -853,7 +859,7 @@ input:checked + .slider_blue::before {
| ${item.branch_name ? item.branch_name : ' - '} |
${tpaValue} |
- ${(item.policy_start_date)} / ${(item.policy_end_date)} |
+ ${formatPolicyDisplayDate(item.policy_start_date)} - ${formatPolicyDisplayDate(item.policy_end_date)} |
${checkDateStatus(item.policy_end_date, 1)} |
@@ -1512,31 +1518,74 @@ input:checked + .slider_blue::before {
});
- //for date convert to indian formate like this 'yyyy-mm-dd' to this 'dd-mm-yyyy'
- function rearrangeDateFormat(inputDate) {
-
- console.log('inputDate', inputDate)
- // Check if inputDate is a string and not empty
- if (typeof inputDate === 'string' && inputDate.trim() !== '') {
- var dateComponents = inputDate.split("-");
-
- // Check if dateComponents has the expected number of parts
- if (dateComponents.length === 3) {
- var rearrangedDate = dateComponents[2] + "-" + dateComponents[1] + "-" + dateComponents[0];
- return rearrangedDate;
- } else {
- // Handle unexpected date format
- return '';
- }
- } else {
- // Handle the case where inputDate is not a valid string
- return '';
+ function parsePolicyDate(inputDate) {
+ if (!inputDate || (typeof inputDate === 'string' && inputDate.trim() === '')) {
+ return null;
}
+ var str = String(inputDate).trim();
+ var dmyMon = str.match(/^(\d{1,2})\/([A-Za-z]{3})\/(\d{4})$/i);
+ if (dmyMon) {
+ return new Date(str);
+ }
+ var dmy = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
+ if (dmy) {
+ return new Date(parseInt(dmy[3], 10), parseInt(dmy[2], 10) - 1, parseInt(dmy[1], 10));
+ }
+ var iso = str.match(/^(\d{4})-(\d{2})-(\d{2})/);
+ if (iso) {
+ return new Date(parseInt(iso[1], 10), parseInt(iso[2], 10) - 1, parseInt(iso[3], 10));
+ }
+ var dmyDash = str.match(/^(\d{1,2})-([A-Za-z]{3}|\d{1,2})-(\d{4})$/i);
+ if (dmyDash) {
+ if (/^[A-Za-z]{3}$/i.test(dmyDash[2])) {
+ return new Date(str);
+ }
+ return new Date(parseInt(dmyDash[3], 10), parseInt(dmyDash[2], 10) - 1, parseInt(dmyDash[1], 10));
+ }
+ var parsed = new Date(str);
+ return isNaN(parsed.getTime()) ? null : parsed;
+ }
+
+ var policyMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+
+ function formatPolicyDisplayDate(inputDate) {
+ var d = parsePolicyDate(inputDate);
+ if (!d) {
+ return (inputDate && String(inputDate).trim() !== '') ? String(inputDate) : '';
+ }
+ return d.getDate() + '/' + policyMonthNames[d.getMonth()] + '/' + d.getFullYear();
+ }
+
+ function formatPolicyFormDate(inputDate) {
+ var d = parsePolicyDate(inputDate);
+ if (!d) {
+ return (inputDate && String(inputDate).trim() !== '') ? String(inputDate) : '';
+ }
+ var day = ('0' + d.getDate()).slice(-2);
+ var month = ('0' + (d.getMonth() + 1)).slice(-2);
+ return day + '/' + month + '/' + d.getFullYear();
+ }
+
+ function policyFormDateForSubmit(inputDate) {
+ var formatted = formatPolicyFormDate(inputDate);
+ if (!formatted) {
+ return inputDate || '';
+ }
+ var parts = formatted.split('/');
+ return parts[0] + '-' + parts[1] + '-' + parts[2];
+ }
+
+ // Convert API/storage dates to d/m/Y for form inputs
+ function rearrangeDateFormat(inputDate) {
+ return formatPolicyFormDate(inputDate);
}
function checkDateStatus(inputDate, bg = false) {
- var givenDate = new Date(inputDate);
+ var givenDate = parsePolicyDate(inputDate);
+ if (!givenDate) {
+ return bg ? '' : '';
+ }
var currentDate = new Date();
if (bg != false) {
@@ -2763,7 +2812,7 @@ $(document).ready(function () {
${policy_name_data} |
${item.branch_name ? item.branch_name : ' - '} |
${tpaValue} |
- ${(item.policy_start_date)} / ${(item.policy_end_date)} |
+ ${formatPolicyDisplayDate(item.policy_start_date)} - ${formatPolicyDisplayDate(item.policy_end_date)} |
${checkDateStatus(item.policy_end_date, 1)} |
@@ -2809,7 +2858,7 @@ $(document).ready(function () {
| ${policy_name_data} |
${item.branch_name ? item.branch_name : ' - '} |
${tpaValue} |
- ${(item.policy_start_date)} / ${(item.policy_end_date)} |
+ ${formatPolicyDisplayDate(item.policy_start_date)} - ${formatPolicyDisplayDate(item.policy_end_date)} |
${checkDateStatus(item.policy_end_date, 1)} |
diff --git a/app/Views/commission_file_upload.php b/app/Views/commission_file_upload.php
index 685074c2..ac13bac9 100644
--- a/app/Views/commission_file_upload.php
+++ b/app/Views/commission_file_upload.php
@@ -182,7 +182,7 @@
| |
|
|
- ' . $row['created_user_name'] . '' ?>
+ | ' . $row['created_user_name'] . '' ?>
|
diff --git a/app/Views/expense_list.php b/app/Views/expense_list.php
index a46c51cd..1ec1df19 100644
--- a/app/Views/expense_list.php
+++ b/app/Views/expense_list.php
@@ -252,7 +252,7 @@ $ex_col_width_px = nhance_dt_column_widths_px($ex_header_labels, $ex_col_max_len
= number_format((float) ($row['amount'] ?? 0), 2); ?> |
- = date('d-m-Y', strtotime($row['expense_date'])); ?>
+ = date('d/m/Y', strtotime($row['expense_date'])); ?>
|
diff --git a/app/Views/file_list.php b/app/Views/file_list.php
index dc389326..95633200 100755
--- a/app/Views/file_list.php
+++ b/app/Views/file_list.php
@@ -23,7 +23,7 @@ if (!empty($fileList) && is_array($fileList)) {
);
$fl_col_max_len[4] = max($fl_col_max_len[4], mb_strlen($policy_display));
$fl_col_max_len[5] = max($fl_col_max_len[5], mb_strlen((string) ($file['action'] ?? '')));
- $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd M Y h:i a')
+ $userTime = change_date_format($file['created_at'] ?? '', 'Y-m-d H:i:s', 'd/m/Y h:i a')
. ' by '
. ($file['first_name'] ?? '');
$fl_col_max_len[6] = max($fl_col_max_len[6], mb_strlen($userTime));
@@ -203,7 +203,7 @@ $fl_col_width_px = nhance_dt_column_widths_px($fl_header_labels, $fl_col_max_len
| - |
|
- ' . $file['first_name'] . '' ?>
+ | ' . $file['first_name'] . '' ?>
|
|
|
|
- ' . $file['first_name'] . '' ?> |
+ ' . $file['first_name'] . '' ?> |
|
|
diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php
index 36ead7b7..7a0e9ff2 100755
--- a/app/Views/layout/header.php
+++ b/app/Views/layout/header.php
@@ -2017,6 +2017,11 @@ body[data-sidebar-size="condensed"] .footer {
Retail Endorsement
+
+
+ TPA Reports
+
+
diff --git a/app/Views/meta_dashboard_demo_one.php b/app/Views/meta_dashboard_demo_one.php
index 4652f9e9..fa558443 100644
--- a/app/Views/meta_dashboard_demo_one.php
+++ b/app/Views/meta_dashboard_demo_one.php
@@ -1,33 +1,345 @@
-
-
-
-
- Metabase Dashboard
+
-
+
+
-
-
-
-
+ $elBranch.on('change', function () {
+ const branchId = $(this).val();
+ const clientId = $elClient.val();
+ rebuildSelect($elPolicy, 'Select', !branchId);
+ clearDashboard();
+ setStatus(branchId ? '' : 'Select branch and policy to load the dashboard.');
-
-
+ if (!branchId || !clientId) {
+ return;
+ }
+
+ const policiesForClient = policyByClient[clientId] || [];
+ const policies = policiesForClient.filter(function (p) {
+ return String(p.client_branch_id) === String(branchId);
+ });
+
+ rebuildSelect($elPolicy, 'Select', policies.length === 0, policies, function (p) { return p.id; }, function (p) {
+ const type = p.policy_type || '';
+ const no = p.policy_no || '';
+ return (type && no) ? (type + ' - ' + no) : (no || type || ('Policy ' + p.id));
+ });
+ if (policies.length === 0) {
+ setStatus('No policies found for this branch.', 'error');
+ }
+ });
+
+ $elPolicy.on('change', function () {
+ fetchDashboard($(this).val());
+ });
+
+ initSelect2($elClient, false);
+ initSelect2($elBranch, true);
+ initSelect2($elPolicy, true);
+ loadFilterData();
+ });
+
diff --git a/app/Views/non_eb_claim_list.php b/app/Views/non_eb_claim_list.php
index f4622ffe..2136c661 100644
--- a/app/Views/non_eb_claim_list.php
+++ b/app/Views/non_eb_claim_list.php
@@ -64,7 +64,7 @@
| = $row['nhance_claim_ref_no'] ?: 'N/A'; ?> |
= $row['short_name'] ?: ($row['client_name'] ?? 'N/A'); ?> |
= $row['insurer_short_name'] ?: ($row['insurer_name'] ?: 'N/A'); ?> |
- = !empty($row['loss_date']) ? date('d-m-Y', strtotime($row['loss_date'])) : 'N/A'; ?> |
+ = !empty($row['loss_date']) ? date('d/m/Y', strtotime($row['loss_date'])) : 'N/A'; ?> |
= $row['nature_of_loss'] ?: 'N/A'; ?> |
= $row['acm_name'] ?? ''; ?> |
diff --git a/app/Views/policy_transaction_endorsement_form.php b/app/Views/policy_transaction_endorsement_form.php
index e203c8cb..d78428db 100644
--- a/app/Views/policy_transaction_endorsement_form.php
+++ b/app/Views/policy_transaction_endorsement_form.php
@@ -181,7 +181,7 @@
}
-
+
| |