Merge branch 'dev' of bitbucket.org:jubilian/nhance into dev
This commit is contained in:
commit
6e6c0e9186
15
.env.sample
15
.env.sample
@ -116,6 +116,21 @@ VIDAL_PRIMARY_KEY_CONSTANT =
|
|||||||
|
|
||||||
MEDI_ASSIST_PRIMARY_KEY_CONSTANT =
|
MEDI_ASSIST_PRIMARY_KEY_CONSTANT =
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# TPA PRIMARY KEY CONSTANTS LIVE
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
|
||||||
|
MEDI_ASSIST_PRIMARY_KEY_CONSTANT_LIVE =
|
||||||
|
ICICI_PRIMARY_KEY_CONSTANT_LIVE =
|
||||||
|
ABHI_PRIMARY_KEY_CONSTANT_LIVE =
|
||||||
|
R_CARE_PRIMARY_KEY_CONSTANT_LIVE =
|
||||||
|
FHPL_PRIMARY_KEY_CONSTANT_LIVE =
|
||||||
|
VIDAL_PRIMARY_KEY_CONSTANT_LIVE =
|
||||||
|
VOLO_PRIMARY_KEY_CONSTANT_LIVE =
|
||||||
|
|
||||||
|
# When true, claims-collection-report falls back to ticket_master only if the
|
||||||
|
# policy TPA has no mapped dump table (or dump table missing). Dump TPAs always use claim_report.
|
||||||
|
CLAIM_REPORT_FALLBACK_TO_TICKET_MASTER = false
|
||||||
|
|
||||||
FHPL_TOKEN_URL =
|
FHPL_TOKEN_URL =
|
||||||
FHPL_BASE_URL =
|
FHPL_BASE_URL =
|
||||||
|
|||||||
@ -151,6 +151,7 @@ $routes->group("/client", ["filter" => "authMVC"], function ($routes) {
|
|||||||
$routes->get('createtransaction', 'ClientController::createtransaction');
|
$routes->get('createtransaction', 'ClientController::createtransaction');
|
||||||
$routes->post('save_deposit', 'ClientController::saveDeposit');
|
$routes->post('save_deposit', 'ClientController::saveDeposit');
|
||||||
$routes->post('update_deposit_amount', 'ClientController::updateDepositAmount');
|
$routes->post('update_deposit_amount', 'ClientController::updateDepositAmount');
|
||||||
|
$routes->post('update_deposit_description', 'ClientController::updateDepositDescription');
|
||||||
$routes->post("saveApiData", "ClientController::saveApiData");
|
$routes->post("saveApiData", "ClientController::saveApiData");
|
||||||
$routes->get("generateToken","ClientController::sendToken");
|
$routes->get("generateToken","ClientController::sendToken");
|
||||||
// $routes->get('view_Deposit/(:num)/(:num)','ClientController/view_Deposit/$1/$2');
|
// $routes->get('view_Deposit/(:num)/(:num)','ClientController/view_Deposit/$1/$2');
|
||||||
@ -484,6 +485,15 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) {
|
|||||||
$routes->match(['get', 'post'], 'decryptVisitSso', 'ApiServiceController::decryptVisitSso'); // disabled for now do not remove this
|
$routes->match(['get', 'post'], 'decryptVisitSso', 'ApiServiceController::decryptVisitSso'); // disabled for now do not remove this
|
||||||
$routes->get("getInsurerClaimFormDownloadUrl", "EmployeeRestController::getInsurerClaimFormDownloadUrl");
|
$routes->get("getInsurerClaimFormDownloadUrl", "EmployeeRestController::getInsurerClaimFormDownloadUrl");
|
||||||
|
|
||||||
|
// $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->group('claims-collection-v2', static function ($routes) {
|
$routes->group('claims-collection-v2', static function ($routes) {
|
||||||
$routes->get('preview', 'ClaimsCollectionV2DashboardController::preview');
|
$routes->get('preview', 'ClaimsCollectionV2DashboardController::preview');
|
||||||
$routes->get('preview/(:num)', 'ClaimsCollectionV2DashboardController::preview/$1');
|
$routes->get('preview/(:num)', 'ClaimsCollectionV2DashboardController::preview/$1');
|
||||||
@ -493,6 +503,16 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) {
|
|||||||
$routes->get('debug/(:num)', 'ClaimsCollectionV2DashboardController::debug/$1');
|
$routes->get('debug/(:num)', 'ClaimsCollectionV2DashboardController::debug/$1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$routes->group('claims-collection-report', static function ($routes) {
|
||||||
|
$routes->get('preview', 'ClaimReportDashboardController::preview');
|
||||||
|
$routes->get('preview/(:num)', 'ClaimReportDashboardController::preview/$1');
|
||||||
|
$routes->get('kpi/(:segment)', 'ClaimReportDashboardController::kpi/$1');
|
||||||
|
$routes->get('all', 'ClaimReportDashboardController::all');
|
||||||
|
$routes->get('debug', 'ClaimReportDashboardController::debug');
|
||||||
|
$routes->get('debug/(:num)', 'ClaimReportDashboardController::debug/$1');
|
||||||
|
$routes->get('sync', 'ClaimReportDashboardController::sync');
|
||||||
|
});
|
||||||
|
|
||||||
$routes->group('enrollment-collection-v1', static function ($routes) {
|
$routes->group('enrollment-collection-v1', static function ($routes) {
|
||||||
$routes->get('preview', 'EnrollmentCollectionV1DashboardController::preview');
|
$routes->get('preview', 'EnrollmentCollectionV1DashboardController::preview');
|
||||||
$routes->get('preview/(:num)', 'EnrollmentCollectionV1DashboardController::preview/$1');
|
$routes->get('preview/(:num)', 'EnrollmentCollectionV1DashboardController::preview/$1');
|
||||||
@ -726,7 +746,7 @@ $routes->group("employeeRest", ['filter' => ['ratelimit' , 'appSignature'] ], fu
|
|||||||
|
|
||||||
//samulss oauth login api's
|
//samulss oauth login api's
|
||||||
$routes->get("getTokenforSamulssOAuthLogin", "RestAuthenticationController::getTokenforSamulssOAuthLogin");
|
$routes->get("getTokenforSamulssOAuthLogin", "RestAuthenticationController::getTokenforSamulssOAuthLogin");
|
||||||
|
$routes->get("downloadEmployeeListExcel", "EmployeeRestController::downloadEmployeeListExcel");
|
||||||
});
|
});
|
||||||
|
|
||||||
$routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratelimit' , 'appSignature', 'authJWT']], function ($routes) {
|
$routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratelimit' , 'appSignature', 'authJWT']], function ($routes) {
|
||||||
@ -822,6 +842,15 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel
|
|||||||
$routes->post("bulkEcardDownloadAsZip", "EmployeeRestController::bulkEcardDownloadAsZip");
|
$routes->post("bulkEcardDownloadAsZip", "EmployeeRestController::bulkEcardDownloadAsZip");
|
||||||
$routes->get("downloadSampleExcel/(:any)", "EmployeeController::downloadSampleExcelFile/$1");
|
$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->group('claims-collection-v2', static function ($routes) {
|
$routes->group('claims-collection-v2', static function ($routes) {
|
||||||
$routes->get('preview', 'ClaimsCollectionV2DashboardController::preview');
|
$routes->get('preview', 'ClaimsCollectionV2DashboardController::preview');
|
||||||
$routes->get('preview/(:num)', 'ClaimsCollectionV2DashboardController::preview/$1');
|
$routes->get('preview/(:num)', 'ClaimsCollectionV2DashboardController::preview/$1');
|
||||||
@ -831,6 +860,15 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel
|
|||||||
$routes->get('debug/(:num)', 'ClaimsCollectionV2DashboardController::debug/$1');
|
$routes->get('debug/(:num)', 'ClaimsCollectionV2DashboardController::debug/$1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$routes->group('claims-collection-report', static function ($routes) {
|
||||||
|
$routes->get('preview', 'ClaimReportDashboardController::preview');
|
||||||
|
$routes->get('preview/(:num)', 'ClaimReportDashboardController::preview/$1');
|
||||||
|
$routes->get('kpi/(:segment)', 'ClaimReportDashboardController::kpi/$1');
|
||||||
|
$routes->get('all', 'ClaimReportDashboardController::all');
|
||||||
|
$routes->get('debug', 'ClaimReportDashboardController::debug');
|
||||||
|
$routes->get('debug/(:num)', 'ClaimReportDashboardController::debug/$1');
|
||||||
|
});
|
||||||
|
|
||||||
$routes->group('enrollment-collection-v1', static function ($routes) {
|
$routes->group('enrollment-collection-v1', static function ($routes) {
|
||||||
$routes->get('preview', 'EnrollmentCollectionV1DashboardController::preview');
|
$routes->get('preview', 'EnrollmentCollectionV1DashboardController::preview');
|
||||||
$routes->get('preview/(:num)', 'EnrollmentCollectionV1DashboardController::preview/$1');
|
$routes->get('preview/(:num)', 'EnrollmentCollectionV1DashboardController::preview/$1');
|
||||||
|
|||||||
@ -898,6 +898,7 @@ class ApiServiceController extends BaseController
|
|||||||
->where('client_policy.tpa_id', $tpa_id)
|
->where('client_policy.tpa_id', $tpa_id)
|
||||||
->where('batch_files.is_active', 1)
|
->where('batch_files.is_active', 1)
|
||||||
->where('batch_files.event_type', 'api')
|
->where('batch_files.event_type', 'api')
|
||||||
|
->where('batch_files.client_policy_id', $policy_id)
|
||||||
->where('batch_files.icici_status_flag !=', 'COMPLETED')
|
->where('batch_files.icici_status_flag !=', 'COMPLETED')
|
||||||
->countAllResults();
|
->countAllResults();
|
||||||
|
|
||||||
|
|||||||
557
app/Controllers/ClaimReportDashboardController.php
Normal file
557
app/Controllers/ClaimReportDashboardController.php
Normal file
@ -0,0 +1,557 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controllers;
|
||||||
|
|
||||||
|
use App\Models\ClaimReportDashboardModel;
|
||||||
|
use App\Models\ClaimsCollectionV2DashboardModel;
|
||||||
|
use App\Models\ClaimDumpFileModel;
|
||||||
|
use CodeIgniter\API\ResponseTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Claims Collection dashboard API using claim_report.
|
||||||
|
* ticket_master fallback is env-gated (CLAIM_REPORT_FALLBACK_TO_TICKET_MASTER)
|
||||||
|
* and only applies when the policy TPA has no dump table.
|
||||||
|
*/
|
||||||
|
class ClaimReportDashboardController extends BaseController
|
||||||
|
{
|
||||||
|
use ResponseTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve policy id from request; optional $fallback (e.g. route default for debug only).
|
||||||
|
*/
|
||||||
|
protected function resolvePolicyId(?int $fallback = null): int
|
||||||
|
{
|
||||||
|
$id = (int) (
|
||||||
|
$this->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 or Metabase 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 ClaimReportDashboardModel();
|
||||||
|
$metabaseId = array_search($kpiMethod, ClaimsCollectionV2DashboardModel::KPI_MAP, true);
|
||||||
|
|
||||||
|
return $this->respond([
|
||||||
|
'status' => true,
|
||||||
|
'policy_id' => $policyId,
|
||||||
|
'claims_source' => $model->resolveClaimsTable($policyId),
|
||||||
|
'kpi_id' => $metabaseId !== false ? (int) $metabaseId : null,
|
||||||
|
'kpi' => $kpiMethod,
|
||||||
|
'label' => ClaimsCollectionV2DashboardModel::KPI_LABELS[$kpiMethod] ?? $kpiMethod,
|
||||||
|
'rows' => $model->getKpi($kpiMethod, $policyId),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON: all KPIs.
|
||||||
|
*/
|
||||||
|
public function all()
|
||||||
|
{
|
||||||
|
$policyId = $this->resolvePolicyId();
|
||||||
|
|
||||||
|
if ($policyId <= 0) {
|
||||||
|
return $this->respond([
|
||||||
|
'status' => false,
|
||||||
|
'message' => 'client_policy or client_policy_id is required.',
|
||||||
|
], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$generatedAt = (new ClaimDumpFileModel())->getGeneratedAtForPolicy($policyId);
|
||||||
|
// if ($generatedAt === null) {
|
||||||
|
// return $this->respond([
|
||||||
|
// 'status' => false,
|
||||||
|
// 'message' => 'claim_dump_date is mandatory. No claim dump date found for this policy.',
|
||||||
|
// ], 422);
|
||||||
|
// }
|
||||||
|
|
||||||
|
$model = new ClaimReportDashboardModel();
|
||||||
|
$data = $model->getAllKpis($policyId);
|
||||||
|
$source = $data['_meta']['claims_source'] ?? $model->resolveClaimsTable($policyId);
|
||||||
|
unset($data['_meta']);
|
||||||
|
|
||||||
|
return $this->respond([
|
||||||
|
'status' => true,
|
||||||
|
'policy_id' => $policyId,
|
||||||
|
'claims_source' => $source,
|
||||||
|
'generated_at' => $generatedAt,
|
||||||
|
'data' => $data,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin preview UI — KPI grid for manual testing.
|
||||||
|
*/
|
||||||
|
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-report' : 'util/claims-collection-report';
|
||||||
|
|
||||||
|
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'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync TPA dump tables → claim_report.
|
||||||
|
* Only rows where ticket_id IS NOT NULL and is_active = 1 are copied.
|
||||||
|
* Idempotent: existing (client_policy_id, claim_number) rows are skipped.
|
||||||
|
* No request parameters required.
|
||||||
|
*
|
||||||
|
* GET /util/claims-collection-report/sync
|
||||||
|
*/
|
||||||
|
public function sync()
|
||||||
|
{
|
||||||
|
@set_time_limit(0);
|
||||||
|
@ini_set('max_execution_time', '0');
|
||||||
|
|
||||||
|
$db = db_connect();
|
||||||
|
|
||||||
|
if (!$db->tableExists('claim_report')) {
|
||||||
|
return $this->respond([
|
||||||
|
'status' => false,
|
||||||
|
'message' => 'Table claim_report does not exist. Run migrations first.',
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// env_key => [dump_table, claim_number_col, dump_col => claim_report_col mapping]
|
||||||
|
$tpaTableMap = [
|
||||||
|
'VIDAL_PRIMARY_KEY_CONSTANT' => [
|
||||||
|
'table' => 'claims_dump_vidal',
|
||||||
|
'claim_col' => 'insurer_claim_number',
|
||||||
|
'mapping' => [
|
||||||
|
'insurer_claim_number' => 'claim_number',
|
||||||
|
'employee_number' => 'emp_code',
|
||||||
|
'date_of_admission' => 'doa',
|
||||||
|
'date_of_discharge' => 'dod',
|
||||||
|
'claim_amount' => 'claim_amount',
|
||||||
|
'approved_amount' => 'approved_amount',
|
||||||
|
'sum_insured' => 'si_amt',
|
||||||
|
'claim_status' => 'tpa_claim_status',
|
||||||
|
'hospital_name' => 'hospital_name',
|
||||||
|
'hospital_address' => 'hospital_address',
|
||||||
|
'hospital_city' => 'hospital_city',
|
||||||
|
'hospital_state' => 'hospital_state',
|
||||||
|
'hospital_pincode' => 'hospital_pin_code',
|
||||||
|
'type_of_claim' => 'tpa_claim_type',
|
||||||
|
'diagnosis' => 'tpa_ailments',
|
||||||
|
'tpa_claim_number' => 'tpa_no',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'ABHI_PRIMARY_KEY_CONSTANT' => [
|
||||||
|
'table' => 'claims_dump_abhi',
|
||||||
|
'claim_col' => 'abhi_claim_no',
|
||||||
|
'mapping' => [
|
||||||
|
'abhi_claim_no' => 'claim_number',
|
||||||
|
'member_code' => 'emp_code',
|
||||||
|
'doa' => 'doa',
|
||||||
|
'dod' => 'dod',
|
||||||
|
'intimation_date' => 'date_of_intimat',
|
||||||
|
'claim_status' => 'tpa_claim_status',
|
||||||
|
'claimed_amount' => 'claim_amount',
|
||||||
|
'hospital_name' => 'hospital_name',
|
||||||
|
'hospital_city' => 'hospital_city',
|
||||||
|
'hospital_state' => 'hospital_state',
|
||||||
|
'settled_date' => 'settled_date',
|
||||||
|
'healthcard_id' => 'tpa_no',
|
||||||
|
'claim_type' => 'tpa_claim_type',
|
||||||
|
'diagnosis' => 'tpa_ailments',
|
||||||
|
'abhi_amount_less_coins_current_month' => 'approved_amount',
|
||||||
|
'patient_age' => 'age',
|
||||||
|
'gender' => 'gender',
|
||||||
|
'relation' => 'relation',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'MEDI_ASSIST_PRIMARY_KEY_CONSTANT' => [
|
||||||
|
'table' => 'claims_dump_medi_assist',
|
||||||
|
'claim_col' => 'claim_id',
|
||||||
|
'mapping' => [
|
||||||
|
'claim_id' => 'claim_number',
|
||||||
|
'pribenef_employee_code' => 'emp_code',
|
||||||
|
'date_of_admission' => 'doa',
|
||||||
|
'date_of_discharge' => 'dod',
|
||||||
|
'intimation_date' => 'date_of_intimat',
|
||||||
|
'settled_date' => 'settled_date',
|
||||||
|
'processed_date' => 'approved_date',
|
||||||
|
'claim_status' => 'tpa_claim_status',
|
||||||
|
'claim_amount' => 'claim_amount',
|
||||||
|
'claim_approved_amount' => 'approved_amount',
|
||||||
|
'hospital_name' => 'hospital_name',
|
||||||
|
'hospital_address' => 'hospital_address',
|
||||||
|
'hospital_city' => 'hospital_city',
|
||||||
|
'hospital_state' => 'hospital_state',
|
||||||
|
'hospital_pincode' => 'hospital_pin_code',
|
||||||
|
'claim_type' => 'tpa_claim_type',
|
||||||
|
'primary_ailment_name' => 'tpa_ailments',
|
||||||
|
'benef_sum_insured' => 'si_amt',
|
||||||
|
'benef_gender' => 'gender',
|
||||||
|
'benef_age' => 'age',
|
||||||
|
'benef_relation' => 'relation',
|
||||||
|
'incurred_amount' => 'incurred_amount',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'FHPL_PRIMARY_KEY_CONSTANT' => [
|
||||||
|
'table' => 'claims_dump_fhpl',
|
||||||
|
'claim_col' => 'claim_id',
|
||||||
|
'mapping' => [
|
||||||
|
'claim_id' => 'claim_number',
|
||||||
|
'employee_id' => 'emp_code',
|
||||||
|
'admission_date' => 'doa',
|
||||||
|
'discharge_date' => 'dod',
|
||||||
|
'claim_received_date' => 'date_of_intimat',
|
||||||
|
'claim_passed_date' => 'approved_date',
|
||||||
|
'settled_date' => 'settled_date',
|
||||||
|
'current_claim_status' => 'tpa_claim_status',
|
||||||
|
'claim_amount' => 'claim_amount',
|
||||||
|
'settled_amount' => 'approved_amount',
|
||||||
|
'incurred_amount' => 'incurred_amount',
|
||||||
|
'coverage_amount' => 'si_amt',
|
||||||
|
'provider_name' => 'hospital_name',
|
||||||
|
'provider_address' => 'hospital_address',
|
||||||
|
'provider_state' => 'hospital_state',
|
||||||
|
'provider_place' => 'hospital_city',
|
||||||
|
'provider_pincode' => 'hospital_pin_code',
|
||||||
|
'claim_type' => 'tpa_claim_type',
|
||||||
|
'diagnosis' => 'tpa_ailments',
|
||||||
|
'uhid_no' => 'tpa_no',
|
||||||
|
'gender' => 'gender',
|
||||||
|
'years' => 'age',
|
||||||
|
'relationship' => 'relation',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'R_CARE_PRIMARY_KEY_CONSTANT' => [
|
||||||
|
'table' => 'claims_dump_reliance',
|
||||||
|
'claim_col' => 'cl_inward_no',
|
||||||
|
'mapping' => [
|
||||||
|
'cl_inward_no' => 'claim_number',
|
||||||
|
'employee_member_id' => 'emp_code',
|
||||||
|
'doa_opd_treatment_from' => 'doa',
|
||||||
|
'dod_opd_treatment_to' => 'dod',
|
||||||
|
'approved_date' => 'approved_date',
|
||||||
|
'cheque_neft_date' => 'settled_date',
|
||||||
|
'claimed_amount' => 'claim_amount',
|
||||||
|
'net_sanction_amount' => 'approved_amount',
|
||||||
|
'final_status' => 'tpa_claim_status',
|
||||||
|
'hospital_name' => 'hospital_name',
|
||||||
|
'hospital_state' => 'hospital_state',
|
||||||
|
'hospital_district' => 'hospital_city',
|
||||||
|
'uhid' => 'tpa_no',
|
||||||
|
'diagnosis' => 'tpa_ailments',
|
||||||
|
'member_reimbursement_cl_type' => 'tpa_claim_type',
|
||||||
|
'gender' => 'gender',
|
||||||
|
'age' => 'age',
|
||||||
|
'relation' => 'relation',
|
||||||
|
'sum_insured' => 'si_amt',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'ICICI_PRIMARY_KEY_CONSTANT' => [
|
||||||
|
'table' => 'claims_dump_icici',
|
||||||
|
'claim_col' => 'claim_number',
|
||||||
|
'mapping' => [
|
||||||
|
'claim_number' => 'claim_number',
|
||||||
|
'employee_member_id' => 'emp_code',
|
||||||
|
'doa' => 'doa',
|
||||||
|
'dod' => 'dod',
|
||||||
|
'payment_date' => 'settled_date',
|
||||||
|
'claimed_amount' => 'claim_amount',
|
||||||
|
'net_sanct_amt' => 'approved_amount',
|
||||||
|
'updated_status' => 'tpa_claim_status',
|
||||||
|
'hospital_name' => 'hospital_name',
|
||||||
|
'hospital_city' => 'hospital_city',
|
||||||
|
'hospital_state' => 'hospital_state',
|
||||||
|
'type_of_claim' => 'tpa_claim_type',
|
||||||
|
'diagnosis' => 'tpa_ailments',
|
||||||
|
'uhid' => 'tpa_no',
|
||||||
|
'sum_insured' => 'si_amt',
|
||||||
|
'gender' => 'gender',
|
||||||
|
'age' => 'age',
|
||||||
|
'relation' => 'relation',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Build tpa_id → config map from env
|
||||||
|
$tpaMap = [];
|
||||||
|
foreach ($tpaTableMap as $envKey => $cfg) {
|
||||||
|
$tpaId = (int) env($envKey);
|
||||||
|
if ($tpaId > 0) {
|
||||||
|
$tpaMap[$tpaId] = $cfg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalFound = 0;
|
||||||
|
$totalInserted = 0;
|
||||||
|
$totalSkipped = 0;
|
||||||
|
$totalFailed = 0;
|
||||||
|
$tpaResults = [];
|
||||||
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
foreach ($tpaMap as $tpaId => $cfg) {
|
||||||
|
$dumpTable = $cfg['table'];
|
||||||
|
$claimCol = $cfg['claim_col'];
|
||||||
|
$mapping = $cfg['mapping'];
|
||||||
|
|
||||||
|
if (!$db->tableExists($dumpTable)) {
|
||||||
|
$tpaResults[] = [
|
||||||
|
'tpa_id' => $tpaId,
|
||||||
|
'table' => $dumpTable,
|
||||||
|
'status' => 'skipped',
|
||||||
|
'detail' => 'Dump table does not exist.',
|
||||||
|
'found' => 0,
|
||||||
|
'inserted' => 0,
|
||||||
|
'skipped' => 0,
|
||||||
|
'failed' => 0,
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all active dump rows with a ticket_id (all columns)
|
||||||
|
$dumpRows = $db->table($dumpTable)
|
||||||
|
->where('is_active', 1)
|
||||||
|
->where('ticket_id IS NOT NULL', null, false)
|
||||||
|
->get()
|
||||||
|
->getResultArray();
|
||||||
|
|
||||||
|
// Pre-load all related ticket_master rows in one query
|
||||||
|
$ticketIds = array_filter(array_column($dumpRows, 'ticket_id'));
|
||||||
|
$ticketsById = [];
|
||||||
|
if (!empty($ticketIds)) {
|
||||||
|
$ticketRows = $db->table('ticket_master')
|
||||||
|
->whereIn('id', array_values(array_unique($ticketIds)))
|
||||||
|
->get()
|
||||||
|
->getResultArray();
|
||||||
|
foreach ($ticketRows as $tm) {
|
||||||
|
$ticketsById[(int) $tm['id']] = $tm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$found = count($dumpRows);
|
||||||
|
$inserted = 0;
|
||||||
|
$skipped = 0;
|
||||||
|
$failed = 0;
|
||||||
|
$totalFound += $found;
|
||||||
|
|
||||||
|
foreach ($dumpRows as $row) {
|
||||||
|
$claimNumber = trim((string) ($row[$claimCol] ?? ''));
|
||||||
|
$clientPolicyId = (int) ($row['client_policy_id'] ?? 0);
|
||||||
|
|
||||||
|
if ($claimNumber === '' || $clientPolicyId <= 0) {
|
||||||
|
$skipped++;
|
||||||
|
$totalSkipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch linked ticket_master row for emp_id / insured_emp_id
|
||||||
|
$ticket = $ticketsById[(int) ($row['ticket_id'] ?? 0)] ?? null;
|
||||||
|
|
||||||
|
// Check if already exists in claim_report
|
||||||
|
$existing = $db->table('claim_report')
|
||||||
|
->where('client_policy_id', $clientPolicyId)
|
||||||
|
->where('claim_number', $claimNumber)
|
||||||
|
->get()
|
||||||
|
->getRowArray();
|
||||||
|
|
||||||
|
// Base row metadata from dump; employee/system IDs always from ticket_master
|
||||||
|
$reportRow = [
|
||||||
|
'tpa_id' => $tpaId,
|
||||||
|
'client_id' => $row['client_id'] ?? ($ticket['client_id'] ?? null),
|
||||||
|
'file_id' => $row['file_id'] ?? ($ticket['file_id'] ?? null),
|
||||||
|
'ticket_id' => $row['ticket_id'],
|
||||||
|
'source_table' => $dumpTable,
|
||||||
|
'source_row_id' => $row['id'],
|
||||||
|
'is_active' => 1,
|
||||||
|
'updated_at' => $now,
|
||||||
|
'emp_id' => $ticket['emp_id'] ?? null,
|
||||||
|
'insured_emp_id' => $ticket['insured_emp_id'] ?? null,
|
||||||
|
'claim_status_id' => $ticket['claim_status_id'] ?? null,
|
||||||
|
];
|
||||||
|
|
||||||
|
// 1) Fill ALL claim_report data fields from ticket_master first
|
||||||
|
$ticketCols = [
|
||||||
|
'emp_code', 'tpa_no',
|
||||||
|
'gender', 'age', 'relation',
|
||||||
|
'claim_amount', 'approved_amount', 'si_amt', 'incurred_amount',
|
||||||
|
'tpa_claim_status', 'tpa_claim_type', 'tpa_ailments',
|
||||||
|
'doa', 'dod', 'date_of_intimat', 'settled_date', 'approved_date',
|
||||||
|
'hospital_name', 'hospital_city', 'hospital_state',
|
||||||
|
'hospital_pin_code', 'hospital_address',
|
||||||
|
'claim_dump_date',
|
||||||
|
];
|
||||||
|
if ($ticket) {
|
||||||
|
foreach ($ticketCols as $col) {
|
||||||
|
$ticketVal = $ticket[$col] ?? null;
|
||||||
|
// ticket_master uses "relationship"; claim_report uses "relation"
|
||||||
|
if ($col === 'relation' && ($ticketVal === null || $ticketVal === '')) {
|
||||||
|
$ticketVal = $ticket['relationship'] ?? null;
|
||||||
|
}
|
||||||
|
if ($ticketVal !== null && $ticketVal !== '') {
|
||||||
|
$reportRow[$col] = $ticketVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Dump table fills only fields still null/empty after ticket_master
|
||||||
|
foreach ($mapping as $dumpCol => $reportCol) {
|
||||||
|
$current = $reportRow[$reportCol] ?? null;
|
||||||
|
if ($current !== null && $current !== '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (array_key_exists($dumpCol, $row) && $row[$dumpCol] !== null && $row[$dumpCol] !== '') {
|
||||||
|
$reportRow[$reportCol] = $row[$dumpCol];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// incurred_amount final fallback
|
||||||
|
if (empty($reportRow['incurred_amount'])) {
|
||||||
|
$reportRow['incurred_amount'] = $reportRow['approved_amount'] ?? $reportRow['claim_amount'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
// Update existing row with full data
|
||||||
|
$ok = $db->table('claim_report')
|
||||||
|
->where('client_policy_id', $clientPolicyId)
|
||||||
|
->where('claim_number', $claimNumber)
|
||||||
|
->update($reportRow);
|
||||||
|
if ($ok) {
|
||||||
|
$skipped++;
|
||||||
|
$totalSkipped++;
|
||||||
|
} else {
|
||||||
|
$failed++;
|
||||||
|
$totalFailed++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New insert
|
||||||
|
$reportRow['client_policy_id'] = $clientPolicyId;
|
||||||
|
$reportRow['claim_number'] = $claimNumber;
|
||||||
|
$reportRow['created_at'] = $now;
|
||||||
|
|
||||||
|
$ok = $db->table('claim_report')->insert($reportRow);
|
||||||
|
|
||||||
|
if ($ok) {
|
||||||
|
$inserted++;
|
||||||
|
$totalInserted++;
|
||||||
|
} else {
|
||||||
|
$failed++;
|
||||||
|
$totalFailed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$tpaResults[] = [
|
||||||
|
'tpa_id' => $tpaId,
|
||||||
|
'table' => $dumpTable,
|
||||||
|
'status' => 'done',
|
||||||
|
'found' => $found,
|
||||||
|
'inserted' => $inserted,
|
||||||
|
'skipped' => $skipped,
|
||||||
|
'failed' => $failed,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->respond([
|
||||||
|
'status' => $totalFailed === 0,
|
||||||
|
'message' => $totalFailed === 0 ? 'Sync completed successfully.' : 'Sync completed with some failures.',
|
||||||
|
'summary' => [
|
||||||
|
'total_found' => $totalFound,
|
||||||
|
'total_inserted' => $totalInserted,
|
||||||
|
'total_skipped' => $totalSkipped,
|
||||||
|
'total_failed' => $totalFailed,
|
||||||
|
],
|
||||||
|
'tpa_results' => $tpaResults,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin check only: raw JSON on screen (no dashboard UI).
|
||||||
|
*/
|
||||||
|
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 ClaimReportDashboardModel();
|
||||||
|
$data = $model->getAllKpis($policyId);
|
||||||
|
$source = $data['_meta']['claims_source'] ?? $model->resolveClaimsTable($policyId);
|
||||||
|
unset($data['_meta']);
|
||||||
|
|
||||||
|
$body = json_encode([
|
||||||
|
'status' => true,
|
||||||
|
'policy_id' => $policyId,
|
||||||
|
'claims_source' => $source,
|
||||||
|
'data' => $data,
|
||||||
|
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
return $this->response
|
||||||
|
->setHeader('Content-Type', 'application/json; charset=UTF-8')
|
||||||
|
->setBody($body);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Controllers;
|
namespace App\Controllers;
|
||||||
|
|
||||||
use App\Models\ClaimsCollectionV2DashboardModel;
|
use App\Models\ClaimsCollectionV2DashboardModel;
|
||||||
|
use App\Models\ClaimDumpFileModel;
|
||||||
use CodeIgniter\API\ResponseTrait;
|
use CodeIgniter\API\ResponseTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,11 +110,20 @@ class ClaimsCollectionV2DashboardController extends BaseController
|
|||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$generatedAt = (new ClaimDumpFileModel())->getGeneratedAtForPolicy($policyId);
|
||||||
|
// if ($generatedAt === null) {
|
||||||
|
// return $this->respond([
|
||||||
|
// 'status' => false,
|
||||||
|
// 'message' => 'claim_dump_date is mandatory. No claim dump date found for this policy.',
|
||||||
|
// ], 422);
|
||||||
|
// }
|
||||||
|
|
||||||
$model = new ClaimsCollectionV2DashboardModel();
|
$model = new ClaimsCollectionV2DashboardModel();
|
||||||
|
|
||||||
return $this->respond([
|
return $this->respond([
|
||||||
'status' => true,
|
'status' => true,
|
||||||
'policy_id' => $policyId,
|
'policy_id' => $policyId,
|
||||||
|
'generated_at' => $generatedAt,
|
||||||
'data' => $model->getAllKpis($policyId),
|
'data' => $model->getAllKpis($policyId),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1005,6 +1005,73 @@ class ClientController extends AdminController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateDepositDescription()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'deposit_id' => 'required|is_natural_no_zero',
|
||||||
|
'description' => 'required|string|min_length[1]|max_length[1000]',
|
||||||
|
'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);
|
||||||
|
$description = trim((string) ($postData['description'] ?? ''));
|
||||||
|
$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.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$updated = $depositModel->update($depositId, [
|
||||||
|
'description' => $description,
|
||||||
|
'updated_by' => $loggedInUserID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($updated === false) {
|
||||||
|
return $this->response
|
||||||
|
->setStatusCode(500)
|
||||||
|
->setJSON([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Failed to update description.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response->setJSON([
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => 'Description updated successfully.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function editClientOnboarding($id = null)
|
public function editClientOnboarding($id = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@ -605,8 +605,16 @@ class EmployeeRestController extends AdminController
|
|||||||
public function getEmployeeAndDependenceByClientId()
|
public function getEmployeeAndDependenceByClientId()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$search = trim((string) $this->request->getGet('search'));
|
||||||
|
|
||||||
$empData = $this->employeePolicyModel->getEmployeePolicy(client_id: $this->request->getGet('client_id'), policy_id: $this->request->getGet('client_policy_id'), status: 0, branch_id: $this->request->getGet('client_branch_id'), status_type: 'inactive');
|
$empData = $this->employeePolicyModel->getEmployeePolicy(
|
||||||
|
client_id: $this->request->getGet('client_id'),
|
||||||
|
policy_id: $this->request->getGet('client_policy_id'),
|
||||||
|
status: 0,
|
||||||
|
branch_id: $this->request->getGet('client_branch_id'),
|
||||||
|
status_type: 'inactive',
|
||||||
|
search: $search
|
||||||
|
);
|
||||||
|
|
||||||
if ($empData) {
|
if ($empData) {
|
||||||
return $this->respond(['status' => 'success', 'code' => 200, 'data' => $empData], 200);
|
return $this->respond(['status' => 'success', 'code' => 200, 'data' => $empData], 200);
|
||||||
@ -687,6 +695,105 @@ class EmployeeRestController extends AdminController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download all employees for client/branch/policy as Excel
|
||||||
|
* (Emp Code, Name, TPA ID, Relationship, Date Of Birth, Gender, Mobile, Email, Status).
|
||||||
|
*
|
||||||
|
* Query params: client_id, policy_id (or client_policy_id), branch_id (or client_branch_id)
|
||||||
|
*/
|
||||||
|
public function downloadEmployeeListExcel()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$clientId = $this->request->getGet('client_id');
|
||||||
|
$policyId = $this->request->getGet('policy_id') ?: $this->request->getGet('client_policy_id');
|
||||||
|
$branchId = $this->request->getGet('branch_id') ?: $this->request->getGet('client_branch_id');
|
||||||
|
|
||||||
|
if (empty($clientId) || empty($policyId) || empty($branchId)) {
|
||||||
|
return $this->respond([
|
||||||
|
'status' => 'failed',
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'client_id, policy_id and branch_id are required',
|
||||||
|
'data' => [],
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
$empData = $this->employeePolicyModel->getEmployeePolicy(
|
||||||
|
client_id: $clientId,
|
||||||
|
policy_id: $policyId,
|
||||||
|
status: 0,
|
||||||
|
branch_id: $branchId,
|
||||||
|
status_type: 'inactive'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!count($empData)) {
|
||||||
|
return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Emp Code',
|
||||||
|
'Name',
|
||||||
|
'TPA ID',
|
||||||
|
'Relationship',
|
||||||
|
'Date Of Birth',
|
||||||
|
'Gender',
|
||||||
|
'Mobile',
|
||||||
|
'Email',
|
||||||
|
'Status',
|
||||||
|
];
|
||||||
|
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
|
||||||
|
$column = 'A';
|
||||||
|
foreach ($headers as $header) {
|
||||||
|
$sheet->setCellValue($column . '1', $header);
|
||||||
|
$column++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = 2;
|
||||||
|
foreach ($empData as $employee) {
|
||||||
|
$gender = strtoupper(trim((string) ($employee['gender'] ?? '')));
|
||||||
|
if ($gender === 'MALE' || $gender === 'M') {
|
||||||
|
$gender = 'M';
|
||||||
|
} elseif ($gender === 'FEMALE' || $gender === 'F') {
|
||||||
|
$gender = 'F';
|
||||||
|
} elseif ($gender !== '') {
|
||||||
|
$gender = strtoupper(substr($gender, 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
$dob = $employee['formatted_dob'] ?? '';
|
||||||
|
if ($dob === '' && !empty($employee['dob'])) {
|
||||||
|
$ts = strtotime((string) $employee['dob']);
|
||||||
|
$dob = $ts ? date('d/m/Y', $ts) : (string) $employee['dob'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$sheet->setCellValue('A' . $row, $employee['emp_code'] ?? '');
|
||||||
|
$sheet->setCellValue('B' . $row, $employee['name'] ?? '');
|
||||||
|
$sheet->setCellValue('C' . $row, $employee['tpa_id'] ?? '');
|
||||||
|
$sheet->setCellValue('D' . $row, $employee['relationship'] ?? '');
|
||||||
|
$sheet->setCellValue('E' . $row, $dob);
|
||||||
|
$sheet->setCellValue('F' . $row, $gender);
|
||||||
|
$sheet->setCellValueExplicit('G' . $row, (string) ($employee['mobile'] ?? ''), \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
|
||||||
|
$sheet->setCellValue('H' . $row, $employee['email_corporate'] ?? '');
|
||||||
|
$sheet->setCellValue('I' . $row, $employee['emp_status'] ?? ($employee['status'] ?? ''));
|
||||||
|
$row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$policyName = preg_replace('/[^A-Za-z0-9_\- ]/', '', (string) ($empData[0]['policy_name'] ?? 'Employees'));
|
||||||
|
$filename = trim($policyName) !== '' ? $policyName . '-Employees.xlsx' : 'Employees.xlsx';
|
||||||
|
|
||||||
|
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||||
|
header('Content-Disposition: attachment;filename="' . $filename . '"');
|
||||||
|
header('Cache-Control: max-age=0');
|
||||||
|
|
||||||
|
$writer = new Xlsx($spreadsheet);
|
||||||
|
$writer->save('php://output');
|
||||||
|
exit;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//not in use
|
//not in use
|
||||||
public function getClientPolicy()
|
public function getClientPolicy()
|
||||||
{
|
{
|
||||||
@ -4290,6 +4397,7 @@ class EmployeeRestController extends AdminController
|
|||||||
|
|
||||||
$TicketMasterModel = new TicketMasterModel();
|
$TicketMasterModel = new TicketMasterModel();
|
||||||
$ticket_data = $TicketMasterModel->get_ticket_data($emp_id, $returnType, $ticket_type, $ticket_id);
|
$ticket_data = $TicketMasterModel->get_ticket_data($emp_id, $returnType, $ticket_type, $ticket_id);
|
||||||
|
// print_r($ticket_data);die;
|
||||||
|
|
||||||
if (! empty($ticket_data)) {
|
if (! empty($ticket_data)) {
|
||||||
|
|
||||||
|
|||||||
@ -238,14 +238,15 @@ class ICICILombardController extends AdminController
|
|||||||
];
|
];
|
||||||
|
|
||||||
$response = call_third_party_api($url, $method, $headers, $body);
|
$response = call_third_party_api($url, $method, $headers, $body);
|
||||||
|
log_message('error', 'ICICI - generateAuthToken API URL: ' . json_encode(["url" => $url, "method" => $method, "headers" => $headers, "body" => $body], JSON_PRETTY_PRINT));
|
||||||
|
log_message('error', 'ICICI - generateAuthToken API response: ' . json_encode($response, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
if($response['status'] != true){
|
if($response['status'] != true){
|
||||||
return $this->response->setJSON([
|
return [
|
||||||
'status' => false,
|
'status' => false,
|
||||||
'message' => 'Token generation failed.',
|
'message' => 'Token generation failed.',
|
||||||
'data' => $response
|
'data' => $response
|
||||||
]);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug removed: return token response to caller.
|
// Debug removed: return token response to caller.
|
||||||
|
|||||||
@ -4073,7 +4073,7 @@ class PolicyTransactionController extends BaseController
|
|||||||
|
|
||||||
if ($date_type == 'statement_month' && $start_date && $end_date) {
|
if ($date_type == 'statement_month' && $start_date && $end_date) {
|
||||||
$start_date = (string) date('Y-m-01', strtotime($start_date));
|
$start_date = (string) date('Y-m-01', strtotime($start_date));
|
||||||
$end_date = (string) date('Y-m-31', strtotime($end_date));
|
$end_date = (string) date('Y-m-t', strtotime($end_date));
|
||||||
}
|
}
|
||||||
|
|
||||||
$normalize = static function ($value) {
|
$normalize = static function ($value) {
|
||||||
@ -4367,7 +4367,7 @@ class PolicyTransactionController extends BaseController
|
|||||||
$insurer_branch_id = $this->request->getGet('insurer_branch_id');
|
$insurer_branch_id = $this->request->getGet('insurer_branch_id');
|
||||||
|
|
||||||
$start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : change_date_format($start_date, 'd-m-Y', 'Y-m-01');
|
$start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : change_date_format($start_date, 'd-m-Y', 'Y-m-01');
|
||||||
$end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : change_date_format($end_date, 'd-m-Y', 'Y-m-31');
|
$end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : change_date_format($end_date, 'd-m-Y', 'Y-m-t');
|
||||||
// dd([$start_date,$end_date]);
|
// dd([$start_date,$end_date]);
|
||||||
|
|
||||||
|
|
||||||
@ -6135,7 +6135,7 @@ class PolicyTransactionController extends BaseController
|
|||||||
// Handle statement month range
|
// Handle statement month range
|
||||||
if ($date_type == 'statement_month') {
|
if ($date_type == 'statement_month') {
|
||||||
$start_date = (string) date('Y-m-01', strtotime($start_date));
|
$start_date = (string) date('Y-m-01', strtotime($start_date));
|
||||||
$end_date = (string) date('Y-m-31', strtotime($end_date));
|
$end_date = (string) date('Y-m-t', strtotime($end_date));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure default values
|
// Ensure default values
|
||||||
|
|||||||
@ -0,0 +1,207 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class CreateClaimReportTable extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->forge->addField([
|
||||||
|
'id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'auto_increment' => true,
|
||||||
|
],
|
||||||
|
'tpa_id' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'client_id' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'client_policy_id' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => false,
|
||||||
|
],
|
||||||
|
'file_id' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'ticket_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'source_table' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 64,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'source_row_id' => [
|
||||||
|
'type' => 'BIGINT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'claim_number' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 191,
|
||||||
|
'null' => false,
|
||||||
|
],
|
||||||
|
'emp_code' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 100,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'tpa_no' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 100,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'emp_id' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'insured_emp_id' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'claim_amount' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 50,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'approved_amount' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 50,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'incurred_amount' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 50,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'si_amt' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 50,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'tpa_claim_status' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 191,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'claim_status_id' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'tpa_claim_type' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 100,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'tpa_ailments' => [
|
||||||
|
'type' => 'TEXT',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'doa' => [
|
||||||
|
'type' => 'DATE',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'dod' => [
|
||||||
|
'type' => 'DATE',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'date_of_intimat' => [
|
||||||
|
'type' => 'DATE',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'settled_date' => [
|
||||||
|
'type' => 'DATE',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'approved_date' => [
|
||||||
|
'type' => 'DATE',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'claim_dump_date' => [
|
||||||
|
'type' => 'DATETIME',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'hospital_name' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 255,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'hospital_city' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 150,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'hospital_state' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 150,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'hospital_pin_code' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 20,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'hospital_address' => [
|
||||||
|
'type' => 'TEXT',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'gender' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 30,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'age' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 20,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'relation' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 50,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'is_active' => [
|
||||||
|
'type' => 'TINYINT',
|
||||||
|
'constraint' => 1,
|
||||||
|
'default' => 1,
|
||||||
|
],
|
||||||
|
'created_at' => [
|
||||||
|
'type' => 'DATETIME',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
'updated_at' => [
|
||||||
|
'type' => 'DATETIME',
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->forge->addKey('id', true);
|
||||||
|
$this->forge->addUniqueKey(['client_policy_id', 'claim_number'], 'uq_claim_report_policy_claim');
|
||||||
|
$this->forge->addKey(['client_policy_id', 'is_active'], false, false, 'idx_claim_report_policy_active');
|
||||||
|
$this->forge->addKey('ticket_id', false, false, 'idx_claim_report_ticket');
|
||||||
|
$this->forge->addKey(['source_table', 'source_row_id'], false, false, 'idx_claim_report_source');
|
||||||
|
|
||||||
|
$this->forge->createTable('claim_report', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropTable('claim_report', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
app/Database/claim_report.sql
Normal file
49
app/Database/claim_report.sql
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
-- claim_report: normalized claims analytics table (UNIQUE client_policy_id + claim_number)
|
||||||
|
-- Prefer: php spark migrate
|
||||||
|
-- Manual fallback if migrations are not used in this environment.
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `claim_report` (
|
||||||
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`tpa_id` INT UNSIGNED NULL,
|
||||||
|
`client_id` INT UNSIGNED NULL,
|
||||||
|
`client_policy_id` INT UNSIGNED NOT NULL,
|
||||||
|
`file_id` INT UNSIGNED NULL,
|
||||||
|
`ticket_id` BIGINT UNSIGNED NULL,
|
||||||
|
`source_table` VARCHAR(64) NULL,
|
||||||
|
`source_row_id` BIGINT UNSIGNED NULL,
|
||||||
|
`claim_number` VARCHAR(191) NOT NULL,
|
||||||
|
`emp_code` VARCHAR(100) NULL,
|
||||||
|
`tpa_no` VARCHAR(100) NULL,
|
||||||
|
`emp_id` INT UNSIGNED NULL,
|
||||||
|
`insured_emp_id` INT UNSIGNED NULL,
|
||||||
|
`claim_amount` VARCHAR(50) NULL,
|
||||||
|
`approved_amount` VARCHAR(50) NULL,
|
||||||
|
`incurred_amount` VARCHAR(50) NULL,
|
||||||
|
`si_amt` VARCHAR(50) NULL,
|
||||||
|
`tpa_claim_status` VARCHAR(191) NULL,
|
||||||
|
`claim_status_id` INT UNSIGNED NULL,
|
||||||
|
`tpa_claim_type` VARCHAR(100) NULL,
|
||||||
|
`tpa_ailments` TEXT NULL,
|
||||||
|
`doa` DATE NULL,
|
||||||
|
`dod` DATE NULL,
|
||||||
|
`date_of_intimat` DATE NULL,
|
||||||
|
`settled_date` DATE NULL,
|
||||||
|
`approved_date` DATE NULL,
|
||||||
|
`claim_dump_date` DATETIME NULL,
|
||||||
|
`hospital_name` VARCHAR(255) NULL,
|
||||||
|
`hospital_city` VARCHAR(150) NULL,
|
||||||
|
`hospital_state` VARCHAR(150) NULL,
|
||||||
|
`hospital_pin_code` VARCHAR(20) NULL,
|
||||||
|
`hospital_address` TEXT NULL,
|
||||||
|
`gender` VARCHAR(30) NULL,
|
||||||
|
`age` VARCHAR(20) NULL,
|
||||||
|
`relation` VARCHAR(50) NULL,
|
||||||
|
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||||
|
`created_at` DATETIME NULL,
|
||||||
|
`updated_at` DATETIME NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uq_claim_report_policy_claim` (`client_policy_id`, `claim_number`),
|
||||||
|
KEY `idx_claim_report_policy_active` (`client_policy_id`, `is_active`),
|
||||||
|
KEY `idx_claim_report_ticket` (`ticket_id`),
|
||||||
|
KEY `idx_claim_report_source` (`source_table`, `source_row_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
@ -113,6 +113,8 @@ class AbhiClaimImportService extends BaseTpaClaimImportService
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra dump → claim_report fields beyond ticketMasterMapping.
|
||||||
protected $statusMapping = [
|
protected $statusMapping = [
|
||||||
'Settled' => 11,
|
'Settled' => 11,
|
||||||
'Rejected' => 8,
|
'Rejected' => 8,
|
||||||
|
|||||||
@ -175,6 +175,8 @@ class FhplClaimImportService extends BaseTpaClaimImportService
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra dump → claim_report fields beyond ticketMasterMapping.
|
||||||
protected $statusMapping = [
|
protected $statusMapping = [
|
||||||
'Settled' => 11,
|
'Settled' => 11,
|
||||||
'Rejected' => 8,
|
'Rejected' => 8,
|
||||||
|
|||||||
@ -104,6 +104,8 @@ class IciciClaimImportService extends BaseTpaClaimImportService
|
|||||||
'diagnosis' => 'tpa_ailments',
|
'diagnosis' => 'tpa_ailments',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra dump → claim_report fields beyond ticketMasterMapping.
|
||||||
protected $statusMapping = [
|
protected $statusMapping = [
|
||||||
'PAID' => 11,
|
'PAID' => 11,
|
||||||
'SETTLED' => 11,
|
'SETTLED' => 11,
|
||||||
|
|||||||
@ -155,6 +155,8 @@ class MediAssistClaimImportService extends BaseTpaClaimImportService
|
|||||||
'primary_ailment_name' => 'tpa_ailments',
|
'primary_ailment_name' => 'tpa_ailments',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra dump → claim_report fields beyond ticketMasterMapping.
|
||||||
protected $statusMapping = [
|
protected $statusMapping = [
|
||||||
'Settled' => 11,
|
'Settled' => 11,
|
||||||
'Rejected' => 8,
|
'Rejected' => 8,
|
||||||
|
|||||||
@ -92,6 +92,8 @@ class RcareClaimImportService extends BaseTpaClaimImportService
|
|||||||
'uhid' => 'tpa_no',
|
'uhid' => 'tpa_no',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra dump → claim_report fields beyond ticketMasterMapping.
|
||||||
protected $statusMapping = [
|
protected $statusMapping = [
|
||||||
'CL Paid with Settlement Letter' => 11,
|
'CL Paid with Settlement Letter' => 11,
|
||||||
'Settled' => 11,
|
'Settled' => 11,
|
||||||
|
|||||||
@ -348,6 +348,8 @@ class VidalClaimImportService extends BaseTpaClaimImportService
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra dump → claim_report fields beyond ticketMasterMapping.
|
||||||
protected $statusMapping = [
|
protected $statusMapping = [
|
||||||
'Settled' => 11,
|
'Settled' => 11,
|
||||||
'Rejected' => 8,
|
'Rejected' => 8,
|
||||||
|
|||||||
@ -57,4 +57,35 @@ class ClaimDumpFileModel extends Model
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Latest claim_dump_date for a policy, formatted as dd-mm-yyyy.
|
||||||
|
* Returns null when no dump file has a claim_dump_date.
|
||||||
|
*/
|
||||||
|
public function getGeneratedAtForPolicy(int $policyId): ?string
|
||||||
|
{
|
||||||
|
if ($policyId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = $this->select('claim_dump_date')
|
||||||
|
->where('client_policy_id', $policyId)
|
||||||
|
->where('is_active', 1)
|
||||||
|
->where('claim_dump_date IS NOT NULL', null, false)
|
||||||
|
->where("TRIM(claim_dump_date) != ''", null, false)
|
||||||
|
->orderBy('claim_dump_date', 'DESC')
|
||||||
|
->orderBy('id', 'DESC')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$raw = trim((string) ($row['claim_dump_date'] ?? ''));
|
||||||
|
if ($raw === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ts = strtotime($raw);
|
||||||
|
if ($ts === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return date('d-m-Y', $ts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
109
app/Models/ClaimReportDashboardModel.php
Normal file
109
app/Models/ClaimReportDashboardModel.php
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Claims Collection dashboard backed by claim_report.
|
||||||
|
* Falls back to ticket_master only for non-dump TPAs when env flag is true.
|
||||||
|
* Reuses V2 KPI SQL; claim fact tables are rewritten at query time.
|
||||||
|
*/
|
||||||
|
class ClaimReportDashboardModel extends ClaimsCollectionV2DashboardModel
|
||||||
|
{
|
||||||
|
/** @var array<int, string> */
|
||||||
|
protected array $claimsTableCache = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve claim fact table for a policy.
|
||||||
|
*
|
||||||
|
* - TPA dump table exists → always claim_report (even if empty; never ticket_master).
|
||||||
|
* - Dump table missing / TPA unmapped → ticket_master only when
|
||||||
|
* CLAIM_REPORT_FALLBACK_TO_TICKET_MASTER=true; otherwise claim_report.
|
||||||
|
*/
|
||||||
|
public function resolveClaimsTable(int $policyId): string
|
||||||
|
{
|
||||||
|
if (isset($this->claimsTableCache[$policyId])) {
|
||||||
|
return $this->claimsTableCache[$policyId];
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = \Config\Database::connect($this->DBGroup);
|
||||||
|
$fallbackEnabled = $this->isTicketMasterFallbackEnabled();
|
||||||
|
|
||||||
|
if ($policyId <= 0) {
|
||||||
|
return $this->claimsTableCache[$policyId] = $fallbackEnabled
|
||||||
|
? 'ticket_master'
|
||||||
|
: 'claim_report';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table missing — cannot query claim_report; ticket_master is the only option.
|
||||||
|
if (!$db->tableExists('claim_report')) {
|
||||||
|
return $this->claimsTableCache[$policyId] = 'ticket_master';
|
||||||
|
}
|
||||||
|
|
||||||
|
$policy = $db->table('client_policy')
|
||||||
|
->select('tpa_id')
|
||||||
|
->where('id', $policyId)
|
||||||
|
->get()
|
||||||
|
->getRowArray();
|
||||||
|
|
||||||
|
$tpaId = (int) ($policy['tpa_id'] ?? 0);
|
||||||
|
$dumpTable = $this->getTpaDumpTableMap()[$tpaId] ?? null;
|
||||||
|
|
||||||
|
// Mapped dump TPA with existing dump table → claim_report only.
|
||||||
|
if ($dumpTable !== null && $db->tableExists($dumpTable)) {
|
||||||
|
return $this->claimsTableCache[$policyId] = 'claim_report';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-dump / missing dump table → env-gated ticket_master fallback.
|
||||||
|
return $this->claimsTableCache[$policyId] = $fallbackEnabled
|
||||||
|
? 'ticket_master'
|
||||||
|
: 'claim_report';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isTicketMasterFallbackEnabled(): bool
|
||||||
|
{
|
||||||
|
return filter_var(
|
||||||
|
env('CLAIM_REPORT_FALLBACK_TO_TICKET_MASTER', false),
|
||||||
|
FILTER_VALIDATE_BOOLEAN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
protected function getTpaDumpTableMap(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
(int) env('VIDAL_PRIMARY_KEY_CONSTANT') => 'claims_dump_vidal',
|
||||||
|
(int) env('ABHI_PRIMARY_KEY_CONSTANT') => 'claims_dump_abhi',
|
||||||
|
(int) env('MEDI_ASSIST_PRIMARY_KEY_CONSTANT') => 'claims_dump_medi_assist',
|
||||||
|
(int) env('FHPL_PRIMARY_KEY_CONSTANT') => 'claims_dump_fhpl',
|
||||||
|
(int) env('R_CARE_PRIMARY_KEY_CONSTANT') => 'claims_dump_reliance',
|
||||||
|
(int) env('ICICI_PRIMARY_KEY_CONSTANT') => 'claims_dump_icici',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function runKpiQuery(string $sql, int $policyId): array
|
||||||
|
{
|
||||||
|
$sql = str_replace(['\\t', '\\n', '\\r'], ["\t", "\n", "\r"], $sql);
|
||||||
|
|
||||||
|
$claimsTable = $this->resolveClaimsTable($policyId);
|
||||||
|
if ($claimsTable !== 'ticket_master') {
|
||||||
|
$sql = preg_replace('/\bticket_master\b/', $claimsTable, $sql) ?? $sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = \Config\Database::connect($this->DBGroup);
|
||||||
|
$query = $db->query($sql, ['policy_id' => $policyId]);
|
||||||
|
|
||||||
|
return $query->getResultArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllKpis(int $policyId): array
|
||||||
|
{
|
||||||
|
$out = parent::getAllKpis($policyId);
|
||||||
|
$out['_meta'] = [
|
||||||
|
'claims_source' => $this->resolveClaimsTable($policyId),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
app/Models/ClaimReportModel.php
Normal file
58
app/Models/ClaimReportModel.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use CodeIgniter\Model;
|
||||||
|
|
||||||
|
class ClaimReportModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'claim_report';
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
protected $useAutoIncrement = true;
|
||||||
|
protected $returnType = 'array';
|
||||||
|
protected $useSoftDeletes = false;
|
||||||
|
protected $protectFields = true;
|
||||||
|
protected $useTimestamps = true;
|
||||||
|
protected $createdField = 'created_at';
|
||||||
|
protected $updatedField = 'updated_at';
|
||||||
|
|
||||||
|
protected $allowedFields = [
|
||||||
|
'tpa_id',
|
||||||
|
'client_id',
|
||||||
|
'client_policy_id',
|
||||||
|
'file_id',
|
||||||
|
'ticket_id',
|
||||||
|
'source_table',
|
||||||
|
'source_row_id',
|
||||||
|
'claim_number',
|
||||||
|
'emp_code',
|
||||||
|
'tpa_no',
|
||||||
|
'emp_id',
|
||||||
|
'insured_emp_id',
|
||||||
|
'claim_amount',
|
||||||
|
'approved_amount',
|
||||||
|
'incurred_amount',
|
||||||
|
'si_amt',
|
||||||
|
'tpa_claim_status',
|
||||||
|
'claim_status_id',
|
||||||
|
'tpa_claim_type',
|
||||||
|
'tpa_ailments',
|
||||||
|
'doa',
|
||||||
|
'dod',
|
||||||
|
'date_of_intimat',
|
||||||
|
'settled_date',
|
||||||
|
'approved_date',
|
||||||
|
'claim_dump_date',
|
||||||
|
'hospital_name',
|
||||||
|
'hospital_city',
|
||||||
|
'hospital_state',
|
||||||
|
'hospital_pin_code',
|
||||||
|
'hospital_address',
|
||||||
|
'gender',
|
||||||
|
'age',
|
||||||
|
'relation',
|
||||||
|
'is_active',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -222,7 +222,7 @@ class EmployeePolicyModel extends Model
|
|||||||
// return $res;
|
// return $res;
|
||||||
// } // remarks do not remove
|
// } // remarks do not remove
|
||||||
|
|
||||||
public function getEmployeePolicy($client_id = 0, $policy_id = 0, $status = [], $branch_id = 0, $emp_code = "", $emp_name = "", $status_type = '')
|
public function getEmployeePolicy($client_id = 0, $policy_id = 0, $status = [], $branch_id = 0, $emp_code = "", $emp_name = "", $status_type = '', $search = '')
|
||||||
{
|
{
|
||||||
// dd($status);
|
// dd($status);
|
||||||
$ecard_download_link = "
|
$ecard_download_link = "
|
||||||
@ -364,6 +364,10 @@ class EmployeePolicyModel extends Model
|
|||||||
$result->where('employee_polices.status !=', 'inactive');
|
$result->where('employee_polices.status !=', 'inactive');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($search)) {
|
||||||
|
$this->applyEmployeeGlobalSearch($result, $search);
|
||||||
|
}
|
||||||
|
|
||||||
$res = $result->findAll();
|
$res = $result->findAll();
|
||||||
|
|
||||||
// dd($this->db->getLastQuery());
|
// dd($this->db->getLastQuery());
|
||||||
@ -371,6 +375,31 @@ class EmployeePolicyModel extends Model
|
|||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global search across employee + policy fields (OR + LIKE).
|
||||||
|
* Searches: emp_code, name, mobile, email, tpa_id, dob, relationship, status.
|
||||||
|
*/
|
||||||
|
protected function applyEmployeeGlobalSearch($builder, string $search)
|
||||||
|
{
|
||||||
|
$search = trim($search);
|
||||||
|
if ($search === '') {
|
||||||
|
return $builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $builder->groupStart()
|
||||||
|
->like('emp.emp_code', $search)
|
||||||
|
->orLike('emp.name', $search)
|
||||||
|
->orLike('emp.mobile', $search)
|
||||||
|
->orLike('emp.email_corporate', $search)
|
||||||
|
->orLike('employee_polices.tpa_id', $search)
|
||||||
|
->orLike('emp.dob', $search)
|
||||||
|
->orLike("DATE_FORMAT(emp.dob, '%d/%m/%Y')", $search)
|
||||||
|
->orLike('emp.relationship', $search)
|
||||||
|
->orLike('employee_polices.status', $search)
|
||||||
|
->orLike('emp.emp_status', $search)
|
||||||
|
->groupEnd();
|
||||||
|
}
|
||||||
|
|
||||||
public function getEmployeePolicyForEcard($policy_id = 0)
|
public function getEmployeePolicyForEcard($policy_id = 0)
|
||||||
{
|
{
|
||||||
$result = $this->select([
|
$result = $this->select([
|
||||||
|
|||||||
@ -857,7 +857,7 @@ class TicketMasterModel extends Model
|
|||||||
")
|
")
|
||||||
->join('ticket_messages tms', 'ticket_master.id = tms.ticket_id', 'left')
|
->join('ticket_messages tms', 'ticket_master.id = tms.ticket_id', 'left')
|
||||||
->where('ticket_master.is_active', 1);
|
->where('ticket_master.is_active', 1);
|
||||||
$query->whereIn('sender', ['staff', 'user']);
|
// $query->whereIn('sender', ['staff', 'user']);
|
||||||
$query->where('ticket_master.emp_id', $emp_id);
|
$query->where('ticket_master.emp_id', $emp_id);
|
||||||
|
|
||||||
if (! empty($ticket_id)) {
|
if (! empty($ticket_id)) {
|
||||||
@ -871,7 +871,7 @@ class TicketMasterModel extends Model
|
|||||||
$query->groupBy('ticket_master.id');
|
$query->groupBy('ticket_master.id');
|
||||||
$data = $query->findAll();
|
$data = $query->findAll();
|
||||||
// dd($data, db_connect()->getLastQuery());
|
// dd($data, db_connect()->getLastQuery());
|
||||||
// print_r($this->db->getLastQuery());die;
|
// print_r($this->db->getLastQuery()->getQuery());die;
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,6 +60,11 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
#scroll-horizontal-datatable tbody td.deposit-description-cell {
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: clip;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
#scroll-horizontal-datatable_wrapper .dataTables_scrollHead table thead th,
|
#scroll-horizontal-datatable_wrapper .dataTables_scrollHead table thead th,
|
||||||
#scroll-horizontal-datatable thead th {
|
#scroll-horizontal-datatable thead th {
|
||||||
padding: 5px 11px !important;
|
padding: 5px 11px !important;
|
||||||
@ -111,6 +116,17 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
background-color: #f4f5f7 !important;
|
background-color: #f4f5f7 !important;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
.deposit-description-cell .deposit-inline-cell {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.deposit-description-input {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-height: 30px;
|
||||||
|
resize: vertical;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
.deposit-balance-wrap {
|
.deposit-balance-wrap {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -386,7 +402,8 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
data-row-id="<?= (int) $row->id ?>"
|
data-row-id="<?= (int) $row->id ?>"
|
||||||
data-transaction-type="<?= esc((string) $row->transaction_type, 'attr') ?>"
|
data-transaction-type="<?= esc((string) $row->transaction_type, 'attr') ?>"
|
||||||
data-credit="<?= esc((string) $creditAmount, 'attr') ?>"
|
data-credit="<?= esc((string) $creditAmount, 'attr') ?>"
|
||||||
data-debit="<?= esc((string) $debitAmount, 'attr') ?>">
|
data-debit="<?= esc((string) $debitAmount, 'attr') ?>"
|
||||||
|
data-description="<?= esc((string) ($row->description ?? ''), 'attr') ?>">
|
||||||
<td><?php echo date('d/m/Y h:i A', strtotime($row->created_at)); ?></td>
|
<td><?php echo date('d/m/Y h:i A', strtotime($row->created_at)); ?></td>
|
||||||
<td><?php echo isset($row->record_date)? date('d-M-Y', strtotime($row->record_date)):'-' ?></td>
|
<td><?php echo isset($row->record_date)? date('d-M-Y', strtotime($row->record_date)):'-' ?></td>
|
||||||
<td><?php echo $row->unit ?? ' - '; ?></td>
|
<td><?php echo $row->unit ?? ' - '; ?></td>
|
||||||
@ -431,13 +448,13 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="deposit-description-cell"
|
<td class="deposit-description-cell">
|
||||||
data-toggle="tooltip"
|
<div class="deposit-inline-cell">
|
||||||
data-bs-toggle="tooltip"
|
<textarea class="form-control form-control-sm deposit-description-input"
|
||||||
data-placement="top"
|
rows="2"
|
||||||
data-bs-placement="top"
|
title="<?= esc((string) ($row->description ?? ''), 'attr') ?>"
|
||||||
title="<?= esc((string) ($row->description ?? ''), 'attr') ?>">
|
aria-label="Description"><?= esc((string) ($row->description ?? '')) ?></textarea>
|
||||||
<?php echo $row->description; ?>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><?php echo $row->username; ?></td>
|
<td><?php echo $row->username; ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -690,6 +707,12 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
}
|
}
|
||||||
return ($(node).text() || '').trim();
|
return ($(node).text() || '').trim();
|
||||||
}
|
}
|
||||||
|
if (column === 9) {
|
||||||
|
var $descInput = $(node).find('.deposit-description-input');
|
||||||
|
if ($descInput.length) {
|
||||||
|
return ($descInput.val() || '').trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (typeof data === 'string' && data.indexOf('<') !== -1) {
|
if (typeof data === 'string' && data.indexOf('<') !== -1) {
|
||||||
return $('<div>').html(data).text().trim();
|
return $('<div>').html(data).text().trim();
|
||||||
}
|
}
|
||||||
@ -1102,6 +1125,13 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
var originalDebit = parseFloat($row.attr('data-debit')) || 0;
|
var originalDebit = parseFloat($row.attr('data-debit')) || 0;
|
||||||
var inputCredit = creditInputVal === '' ? 0 : parseFloat(creditInputVal);
|
var inputCredit = creditInputVal === '' ? 0 : parseFloat(creditInputVal);
|
||||||
var inputDebit = debitInputVal === '' ? 0 : parseFloat(debitInputVal);
|
var inputDebit = debitInputVal === '' ? 0 : parseFloat(debitInputVal);
|
||||||
|
var descriptionVal = ($row.find('.deposit-description-input').val() || '').trim();
|
||||||
|
var originalDescription = ($row.attr('data-description') || '').trim();
|
||||||
|
|
||||||
|
if (descriptionVal !== originalDescription) {
|
||||||
|
pending = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isNaN(inputCredit) || isNaN(inputDebit)) {
|
if (isNaN(inputCredit) || isNaN(inputDebit)) {
|
||||||
return;
|
return;
|
||||||
@ -1130,6 +1160,12 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
updateTopSaveButtonVisibility();
|
updateTopSaveButtonVisibility();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on('input change', '.deposit-description-input', function () {
|
||||||
|
var $input = $(this);
|
||||||
|
$input.attr('title', ($input.val() || '').trim());
|
||||||
|
updateTopSaveButtonVisibility();
|
||||||
|
});
|
||||||
|
|
||||||
function collectChanges() {
|
function collectChanges() {
|
||||||
var changes = [];
|
var changes = [];
|
||||||
var hasValidationError = false;
|
var hasValidationError = false;
|
||||||
@ -1190,12 +1226,52 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function collectDescriptionChanges() {
|
||||||
|
var changes = [];
|
||||||
|
var hasValidationError = false;
|
||||||
|
$('#scroll-horizontal-datatable tbody tr').each(function () {
|
||||||
|
var $row = $(this);
|
||||||
|
var $input = $row.find('.deposit-description-input');
|
||||||
|
if (!$input.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var current = ($input.val() || '').trim();
|
||||||
|
var original = ($row.attr('data-description') || '').trim();
|
||||||
|
if (current === original) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (current === '') {
|
||||||
|
toastr.warning('Description cannot be empty.');
|
||||||
|
hasValidationError = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (current.length > 1000) {
|
||||||
|
toastr.warning('Description must not exceed 1000 characters.');
|
||||||
|
hasValidationError = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
changes.push({
|
||||||
|
rowId: $row.data('row-id'),
|
||||||
|
description: current,
|
||||||
|
$row: $row
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasValidationError) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
window.saveDepositInlineChanges = function () {
|
window.saveDepositInlineChanges = function () {
|
||||||
var changes = collectChanges();
|
var changes = collectChanges();
|
||||||
if (!Array.isArray(changes) || changes.length === 0) {
|
var descriptionChanges = collectDescriptionChanges();
|
||||||
if (changes !== false) {
|
if (changes === false || descriptionChanges === false) {
|
||||||
toastr.info('No changes to save.');
|
return;
|
||||||
}
|
}
|
||||||
|
if ((!Array.isArray(changes) || changes.length === 0) &&
|
||||||
|
(!Array.isArray(descriptionChanges) || descriptionChanges.length === 0)) {
|
||||||
|
toastr.info('No changes to save.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1204,8 +1280,9 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
var cdAcPk = $('#cd_ac_pk').val();
|
var cdAcPk = $('#cd_ac_pk').val();
|
||||||
|
|
||||||
var completed = 0;
|
var completed = 0;
|
||||||
function saveNext(index) {
|
var totalChanges = changes.length + descriptionChanges.length;
|
||||||
if (index >= changes.length) {
|
|
||||||
|
function finishSave() {
|
||||||
toastr.success('Saved ' + completed + ' change(s) successfully.');
|
toastr.success('Saved ' + completed + ' change(s) successfully.');
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (typeof window.storeCurrentDepositTablePage === 'function') {
|
if (typeof window.storeCurrentDepositTablePage === 'function') {
|
||||||
@ -1213,6 +1290,51 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
}, 250);
|
}, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDescriptionNext(index) {
|
||||||
|
if (index >= descriptionChanges.length) {
|
||||||
|
finishSave();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var change = descriptionChanges[index];
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '<?= base_url() . "client/update_deposit_description" ?>',
|
||||||
|
data: {
|
||||||
|
deposit_id: change.rowId,
|
||||||
|
description: change.description,
|
||||||
|
client_id: clientId,
|
||||||
|
insurer_id: insurerId,
|
||||||
|
cd_ac_pk: cdAcPk
|
||||||
|
},
|
||||||
|
success: function () {
|
||||||
|
change.$row.attr('data-description', change.description);
|
||||||
|
change.$row.find('.deposit-description-input').attr('title', change.description);
|
||||||
|
completed++;
|
||||||
|
saveDescriptionNext(index + 1);
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
if (xhr.status === 400 && xhr.responseText) {
|
||||||
|
try {
|
||||||
|
var response = JSON.parse(xhr.responseText);
|
||||||
|
toastr.error(response.message || 'Validation failed.');
|
||||||
|
} catch (e) {
|
||||||
|
toastr.error('Validation failed.');
|
||||||
|
}
|
||||||
|
} else if (xhr.status === 404) {
|
||||||
|
toastr.error('Transaction not found for this account.');
|
||||||
|
} else {
|
||||||
|
toastr.error('Unable to update description right now.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveAmountNext(index) {
|
||||||
|
if (index >= changes.length) {
|
||||||
|
saveDescriptionNext(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1237,7 +1359,7 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
setRowDisplay(change.$row, 0, change.amount);
|
setRowDisplay(change.$row, 0, change.amount);
|
||||||
}
|
}
|
||||||
completed++;
|
completed++;
|
||||||
saveNext(index + 1);
|
saveAmountNext(index + 1);
|
||||||
},
|
},
|
||||||
error: function (xhr) {
|
error: function (xhr) {
|
||||||
if (xhr.status === 400 && xhr.responseText) {
|
if (xhr.status === 400 && xhr.responseText) {
|
||||||
@ -1256,7 +1378,12 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
saveNext(0);
|
if (totalChanges === 0) {
|
||||||
|
toastr.info('No changes to save.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveAmountNext(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).on('keydown', '.deposit-inline-input', function (e) {
|
$(document).on('keydown', '.deposit-inline-input', function (e) {
|
||||||
@ -1268,6 +1395,15 @@ $vd_col_width_px = nhance_dt_column_widths_px($vd_header_labels, $vd_col_max_len
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on('keydown', '.deposit-description-input', function (e) {
|
||||||
|
if (e.key === 'Enter' && !e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (typeof window.saveDepositInlineChanges === 'function') {
|
||||||
|
window.saveDepositInlineChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
updateTopSaveButtonVisibility();
|
updateTopSaveButtonVisibility();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
378
tests/smoke_get_employee_and_dependence_by_client_id.php
Normal file
378
tests/smoke_get_employee_and_dependence_by_client_id.php
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Smoke test: EmployeeRestController::getEmployeeAndDependenceByClientId (+ global search)
|
||||||
|
*
|
||||||
|
* Covers baseline list and search across:
|
||||||
|
* emp_code, name, mobile, email, tpa_id, dob, relationship, status
|
||||||
|
*
|
||||||
|
* Run:
|
||||||
|
* php tests/smoke_get_employee_and_dependence_by_client_id.php
|
||||||
|
* php tests/smoke_get_employee_and_dependence_by_client_id.php [client_id] [client_policy_id] [client_branch_id]
|
||||||
|
*
|
||||||
|
* client_id may be numeric or 32-char MD5 hash.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
|
||||||
|
define('FCPATH', __DIR__ . '/../public/');
|
||||||
|
chdir(FCPATH);
|
||||||
|
|
||||||
|
require FCPATH . '../app/Config/Paths.php';
|
||||||
|
$paths = new Config\Paths();
|
||||||
|
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php';
|
||||||
|
require_once SYSTEMPATH . 'Config/DotEnv.php';
|
||||||
|
(new CodeIgniter\Config\DotEnv(ROOTPATH))->load();
|
||||||
|
|
||||||
|
defined('ENVIRONMENT') || define('ENVIRONMENT', env('CI_ENVIRONMENT', 'development'));
|
||||||
|
|
||||||
|
$boot = APPPATH . 'Config/Boot/' . ENVIRONMENT . '.php';
|
||||||
|
if (is_file($boot)) {
|
||||||
|
require_once $boot;
|
||||||
|
}
|
||||||
|
|
||||||
|
use App\Controllers\EmployeeRestController;
|
||||||
|
use CodeIgniter\HTTP\IncomingRequest;
|
||||||
|
use CodeIgniter\HTTP\URI;
|
||||||
|
use CodeIgniter\HTTP\UserAgent;
|
||||||
|
use Config\Services;
|
||||||
|
|
||||||
|
$pass = 0;
|
||||||
|
$fail = 0;
|
||||||
|
$skip = 0;
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
function ok(string $label, bool $cond, string $detail = ''): void
|
||||||
|
{
|
||||||
|
global $pass, $fail, $results;
|
||||||
|
if ($cond) {
|
||||||
|
$pass++;
|
||||||
|
$results[] = '[PASS] ' . $label . ($detail !== '' ? " — {$detail}" : '');
|
||||||
|
} else {
|
||||||
|
$fail++;
|
||||||
|
$results[] = '[FAIL] ' . $label . ($detail !== '' ? " — {$detail}" : '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function skip(string $label, string $detail = ''): void
|
||||||
|
{
|
||||||
|
global $skip, $results;
|
||||||
|
$skip++;
|
||||||
|
$results[] = '[SKIP] ' . $label . ($detail !== '' ? " — {$detail}" : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{http:int,body:array,raw:string,error:?string}
|
||||||
|
*/
|
||||||
|
function invokeGetEmployeeAndDependenceByClientId(array $query): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$uri = new URI('http://localhost/nhance_v2/employeeRest/getEmployeeAndDependenceByClientId');
|
||||||
|
if ($query !== []) {
|
||||||
|
$uri->setQuery(http_build_query($query));
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = new IncomingRequest(
|
||||||
|
config('App'),
|
||||||
|
$uri,
|
||||||
|
null,
|
||||||
|
new UserAgent()
|
||||||
|
);
|
||||||
|
$request->setMethod('get');
|
||||||
|
$request->setGlobal('get', $query);
|
||||||
|
|
||||||
|
$controller = new EmployeeRestController();
|
||||||
|
$response = Services::response();
|
||||||
|
$logger = Services::logger();
|
||||||
|
$controller->initController($request, $response, $logger);
|
||||||
|
|
||||||
|
$resp = $controller->getEmployeeAndDependenceByClientId();
|
||||||
|
$raw = $resp->getBody();
|
||||||
|
$body = json_decode($raw, true);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'http' => $resp->getStatusCode(),
|
||||||
|
'body' => is_array($body) ? $body : [],
|
||||||
|
'raw' => (string) $raw,
|
||||||
|
'error' => null,
|
||||||
|
];
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
return [
|
||||||
|
'http' => 500,
|
||||||
|
'body' => [],
|
||||||
|
'raw' => '',
|
||||||
|
'error' => $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowMatchesSearch(array $row, string $search): bool
|
||||||
|
{
|
||||||
|
$needle = mb_strtolower(trim($search));
|
||||||
|
if ($needle === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$haystacks = [
|
||||||
|
(string) ($row['emp_code'] ?? ''),
|
||||||
|
(string) ($row['name'] ?? ''),
|
||||||
|
(string) ($row['mobile'] ?? ''),
|
||||||
|
(string) ($row['email_corporate'] ?? ''),
|
||||||
|
(string) ($row['tpa_id'] ?? ''),
|
||||||
|
(string) ($row['dob'] ?? ''),
|
||||||
|
(string) ($row['formatted_dob'] ?? ''),
|
||||||
|
(string) ($row['relationship'] ?? ''),
|
||||||
|
(string) ($row['status'] ?? ''),
|
||||||
|
(string) ($row['emp_status'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($haystacks as $hay) {
|
||||||
|
if ($hay !== '' && mb_stripos($hay, $needle) !== false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Fixtures ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
$db = db_connect('default');
|
||||||
|
|
||||||
|
$cliClientId = $argv[1] ?? null;
|
||||||
|
$cliClientPolicyId = isset($argv[2]) && ctype_digit((string) $argv[2]) ? (int) $argv[2] : null;
|
||||||
|
$cliClientBranchId = isset($argv[3]) && ctype_digit((string) $argv[3]) ? (int) $argv[3] : null;
|
||||||
|
|
||||||
|
$fixtureSql = "
|
||||||
|
SELECT
|
||||||
|
emp.client_id,
|
||||||
|
MD5(emp.client_id) AS client_id_md5,
|
||||||
|
emp.client_branch_id,
|
||||||
|
ep.client_policy_id,
|
||||||
|
emp.emp_code,
|
||||||
|
emp.name,
|
||||||
|
emp.mobile,
|
||||||
|
emp.email_corporate,
|
||||||
|
ep.tpa_id,
|
||||||
|
emp.dob,
|
||||||
|
DATE_FORMAT(emp.dob, '%d/%m/%Y') AS formatted_dob,
|
||||||
|
emp.relationship,
|
||||||
|
ep.status,
|
||||||
|
emp.emp_status
|
||||||
|
FROM employee_polices ep
|
||||||
|
INNER JOIN employees emp ON emp.id = ep.employee_id
|
||||||
|
WHERE ep.is_active = 1
|
||||||
|
AND emp.is_active = 1
|
||||||
|
AND ep.status IN ('active', 'inactive')
|
||||||
|
";
|
||||||
|
|
||||||
|
$bindings = [];
|
||||||
|
if ($cliClientId !== null && $cliClientId !== '') {
|
||||||
|
if (is_string($cliClientId) && preg_match('/^[a-f0-9]{32}$/i', $cliClientId)) {
|
||||||
|
$fixtureSql .= ' AND MD5(emp.client_id) = ?';
|
||||||
|
$bindings[] = $cliClientId;
|
||||||
|
} else {
|
||||||
|
$fixtureSql .= ' AND emp.client_id = ?';
|
||||||
|
$bindings[] = (int) $cliClientId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($cliClientPolicyId !== null) {
|
||||||
|
$fixtureSql .= ' AND ep.client_policy_id = ?';
|
||||||
|
$bindings[] = $cliClientPolicyId;
|
||||||
|
}
|
||||||
|
if ($cliClientBranchId !== null) {
|
||||||
|
$fixtureSql .= ' AND emp.client_branch_id = ?';
|
||||||
|
$bindings[] = $cliClientBranchId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer a row that has searchable fields populated (mobile/email/tpa_id).
|
||||||
|
$fixtureSql .= '
|
||||||
|
ORDER BY
|
||||||
|
(emp.mobile IS NOT NULL AND emp.mobile <> "") DESC,
|
||||||
|
(emp.email_corporate IS NOT NULL AND emp.email_corporate <> "") DESC,
|
||||||
|
(ep.tpa_id IS NOT NULL AND ep.tpa_id <> "") DESC,
|
||||||
|
ep.id DESC
|
||||||
|
LIMIT 1
|
||||||
|
';
|
||||||
|
|
||||||
|
$fixture = $db->query($fixtureSql, $bindings)->getRowArray();
|
||||||
|
|
||||||
|
if (!$fixture) {
|
||||||
|
echo "No fixture rows found for employee_polices + employees.\n";
|
||||||
|
echo "Pass args: php tests/smoke_get_employee_and_dependence_by_client_id.php [client_id] [client_policy_id] [client_branch_id]\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$baseQuery = [
|
||||||
|
'client_id' => (string) $fixture['client_id_md5'],
|
||||||
|
'client_policy_id' => (string) $fixture['client_policy_id'],
|
||||||
|
'client_branch_id' => (string) $fixture['client_branch_id'],
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "Fixture:\n";
|
||||||
|
echo json_encode([
|
||||||
|
'client_id' => $fixture['client_id'],
|
||||||
|
'client_id_md5' => $fixture['client_id_md5'],
|
||||||
|
'client_policy_id' => $fixture['client_policy_id'],
|
||||||
|
'client_branch_id' => $fixture['client_branch_id'],
|
||||||
|
'emp_code' => $fixture['emp_code'],
|
||||||
|
'name' => $fixture['name'],
|
||||||
|
'mobile' => $fixture['mobile'],
|
||||||
|
'email_corporate' => $fixture['email_corporate'],
|
||||||
|
'tpa_id' => $fixture['tpa_id'],
|
||||||
|
'dob' => $fixture['dob'],
|
||||||
|
'formatted_dob' => $fixture['formatted_dob'],
|
||||||
|
'relationship' => $fixture['relationship'],
|
||||||
|
'status' => $fixture['status'],
|
||||||
|
'emp_status' => $fixture['emp_status'],
|
||||||
|
], JSON_PRETTY_PRINT) . "\n\n";
|
||||||
|
|
||||||
|
// ─── Baseline (no search) ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
$baseline = invokeGetEmployeeAndDependenceByClientId($baseQuery);
|
||||||
|
ok(
|
||||||
|
'Baseline call has no PHP error',
|
||||||
|
$baseline['error'] === null,
|
||||||
|
(string) ($baseline['error'] ?? '')
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
'Baseline returns success/200 with non-empty data',
|
||||||
|
($baseline['body']['status'] ?? '') === 'success'
|
||||||
|
&& (int) ($baseline['body']['code'] ?? 0) === 200
|
||||||
|
&& is_array($baseline['body']['data'] ?? null)
|
||||||
|
&& count($baseline['body']['data']) > 0,
|
||||||
|
'http=' . $baseline['http'] . ' count=' . count($baseline['body']['data'] ?? []) . ' body_status=' . ($baseline['body']['status'] ?? '')
|
||||||
|
);
|
||||||
|
|
||||||
|
$baselineRows = is_array($baseline['body']['data'] ?? null) ? $baseline['body']['data'] : [];
|
||||||
|
$baselineCount = count($baselineRows);
|
||||||
|
|
||||||
|
// Empty search should behave like no search
|
||||||
|
$emptySearch = invokeGetEmployeeAndDependenceByClientId($baseQuery + ['search' => '']);
|
||||||
|
ok(
|
||||||
|
'Empty search returns same count as baseline',
|
||||||
|
($emptySearch['error'] ?? null) === null
|
||||||
|
&& count($emptySearch['body']['data'] ?? []) === $baselineCount,
|
||||||
|
'baseline=' . $baselineCount . ' empty_search=' . count($emptySearch['body']['data'] ?? [])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Nonsense search → failed/404 empty
|
||||||
|
$nonsense = invokeGetEmployeeAndDependenceByClientId($baseQuery + ['search' => '___no_such_value_zzz_999___']);
|
||||||
|
ok(
|
||||||
|
'Nonsense search returns failed/404 empty data',
|
||||||
|
($nonsense['body']['status'] ?? '') === 'failed'
|
||||||
|
&& (int) ($nonsense['body']['code'] ?? 0) === 404
|
||||||
|
&& ($nonsense['body']['data'] ?? null) === [],
|
||||||
|
json_encode($nonsense['body'])
|
||||||
|
);
|
||||||
|
|
||||||
|
// ─── Per-field search cases ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
$searchCases = [
|
||||||
|
'emp_code' => (string) ($fixture['emp_code'] ?? ''),
|
||||||
|
'name' => (string) ($fixture['name'] ?? ''),
|
||||||
|
'mobile' => (string) ($fixture['mobile'] ?? ''),
|
||||||
|
'email' => (string) ($fixture['email_corporate'] ?? ''),
|
||||||
|
'tpa_id' => (string) ($fixture['tpa_id'] ?? ''),
|
||||||
|
'dob' => (string) ($fixture['dob'] ?? ''),
|
||||||
|
'formatted_dob'=> (string) ($fixture['formatted_dob'] ?? ''),
|
||||||
|
'relationship' => (string) ($fixture['relationship'] ?? ''),
|
||||||
|
'status' => (string) ($fixture['status'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($searchCases as $field => $value) {
|
||||||
|
$value = trim($value);
|
||||||
|
if ($value === '') {
|
||||||
|
skip("Search by {$field}", 'fixture value empty');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a short distinctive fragment when the value is long (e.g. name/email)
|
||||||
|
$term = $value;
|
||||||
|
if (in_array($field, ['name', 'email'], true) && mb_strlen($value) > 4) {
|
||||||
|
$term = mb_substr($value, 0, max(3, (int) floor(mb_strlen($value) / 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$resp = invokeGetEmployeeAndDependenceByClientId($baseQuery + ['search' => $term]);
|
||||||
|
$rows = is_array($resp['body']['data'] ?? null) ? $resp['body']['data'] : [];
|
||||||
|
|
||||||
|
ok(
|
||||||
|
"Search by {$field} returns success with rows",
|
||||||
|
($resp['error'] ?? null) === null
|
||||||
|
&& ($resp['body']['status'] ?? '') === 'success'
|
||||||
|
&& (int) ($resp['body']['code'] ?? 0) === 200
|
||||||
|
&& count($rows) > 0,
|
||||||
|
'term=' . $term . ' count=' . count($rows) . ' err=' . ($resp['error'] ?? '')
|
||||||
|
);
|
||||||
|
|
||||||
|
$allMatch = true;
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
if (!rowMatchesSearch($row, $term)) {
|
||||||
|
$allMatch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok(
|
||||||
|
"Search by {$field}: every returned row matches term",
|
||||||
|
$allMatch && count($rows) > 0,
|
||||||
|
'term=' . $term . ' rows=' . count($rows)
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(
|
||||||
|
"Search by {$field}: result count <= baseline",
|
||||||
|
count($rows) <= $baselineCount,
|
||||||
|
'filtered=' . count($rows) . ' baseline=' . $baselineCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partial emp_code (if long enough)
|
||||||
|
$empCode = trim((string) ($fixture['emp_code'] ?? ''));
|
||||||
|
if (mb_strlen($empCode) >= 3) {
|
||||||
|
$partial = mb_substr($empCode, 0, 3);
|
||||||
|
$resp = invokeGetEmployeeAndDependenceByClientId($baseQuery + ['search' => $partial]);
|
||||||
|
$rows = is_array($resp['body']['data'] ?? null) ? $resp['body']['data'] : [];
|
||||||
|
ok(
|
||||||
|
'Partial emp_code search returns matching rows',
|
||||||
|
($resp['body']['status'] ?? '') === 'success' && count($rows) > 0,
|
||||||
|
'term=' . $partial . ' count=' . count($rows)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
skip('Partial emp_code search', 'emp_code too short');
|
||||||
|
}
|
||||||
|
|
||||||
|
// MD5 client_id already used above; also verify numeric client_id works without search
|
||||||
|
$numericQuery = [
|
||||||
|
'client_id' => (string) $fixture['client_id'],
|
||||||
|
'client_policy_id' => (string) $fixture['client_policy_id'],
|
||||||
|
'client_branch_id' => (string) $fixture['client_branch_id'],
|
||||||
|
];
|
||||||
|
$numeric = invokeGetEmployeeAndDependenceByClientId($numericQuery);
|
||||||
|
ok(
|
||||||
|
'Numeric client_id baseline returns success',
|
||||||
|
($numeric['body']['status'] ?? '') === 'success'
|
||||||
|
&& count($numeric['body']['data'] ?? []) > 0,
|
||||||
|
'count=' . count($numeric['body']['data'] ?? [])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Optional: if a search term was passed as 4th argv, dump raw result
|
||||||
|
if (isset($argv[4]) && trim((string) $argv[4]) !== '') {
|
||||||
|
$manualTerm = trim((string) $argv[4]);
|
||||||
|
$manual = invokeGetEmployeeAndDependenceByClientId($baseQuery + ['search' => $manualTerm]);
|
||||||
|
echo "\nManual search term={$manualTerm}\n";
|
||||||
|
echo json_encode([
|
||||||
|
'http' => $manual['http'],
|
||||||
|
'error' => $manual['error'],
|
||||||
|
'status'=> $manual['body']['status'] ?? null,
|
||||||
|
'code' => $manual['body']['code'] ?? null,
|
||||||
|
'count' => count($manual['body']['data'] ?? []),
|
||||||
|
'first' => ($manual['body']['data'][0] ?? null),
|
||||||
|
], JSON_PRETTY_PRINT) . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\nSmoke test summary: {$pass} passed, {$fail} failed, {$skip} skipped\n";
|
||||||
|
foreach ($results as $line) {
|
||||||
|
echo $line . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
exit($fail > 0 ? 1 : 0);
|
||||||
Loading…
Reference in New Issue
Block a user