diff --git a/app/Config/Acl.php b/app/Config/Acl.php
index 2960595f..b4d85eac 100644
--- a/app/Config/Acl.php
+++ b/app/Config/Acl.php
@@ -32,6 +32,8 @@ class Acl
'#^/metaTpaDashboardDemo#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]],
'#^/sales/dashboard#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, STAFF_ROLE_ID]],
'#^/sales#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, STAFF_ROLE_ID]],
+ '#^/expense#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, STAFF_ROLE_ID]],
+
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index d9a05733..cf88f2b9 100755
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -444,7 +444,9 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) {
$routes->get('proceedExcelFileDataValidation', 'EmployeeController::proceedExcelFileDataValidation');
$routes->get('checkTpaApiEnable', 'EmployeeRestController::checkTpaApiEnable');
$routes->get('generateDemographyDataTable', 'LeadsController::generateDemographyDataTable');
- $routes->post('insufficientCdBalanceHrMailSend', 'EmployeeController::insufficientCdBalanceHrMailSend');
+ $routes->post('insufficientCdBalanceHrMailSend', 'EmployeeController::insufficientCdBalanceHrMailSend');
+ $routes->get('getTpaClaimDumpErrorData/(:any)', 'TicketServiceController::getTpaClaimDumpErrorData/$1');
+
});
$routes->post("policy_tranction/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail");
@@ -915,6 +917,8 @@ $routes->group('sales', function($routes) {
$routes->get('loadactivities', 'SalesController::loadactivities');
+ $routes->get('loadtargets', 'SalesController::loadtargets');
+
$routes->get('page/(:segment)', 'SalesController::noPage/$1');
// Get all leads with filters
@@ -995,6 +999,13 @@ $routes->group('sales', function($routes) {
// Delete note
$routes->delete('notes/(:num)', 'SalesController::deleteNote/$1');
+ // ==================== TARGETS ROUTES ====================
+ $routes->get('targets', 'SalesController::getTargets');
+ $routes->get('targets/user/(:num)', 'SalesController::getTargetByUser/$1');
+ $routes->get('targets/fy/(:segment)','SalesController::getTargetByFY/$1');
+ $routes->post('targets', 'SalesController::createTarget');
+ $routes->put('targets/(:num)', 'SalesController::updateTarget/$1');
+ $routes->delete('targets/(:num)', 'SalesController::deleteTarget/$1');
//Dashboard
$routes->get('dashboard', 'SalesController::dashboard');
@@ -1002,4 +1013,13 @@ $routes->group('sales', function($routes) {
$routes->get('salesManagerLevelDashboard', 'SalesController::salesManagerLevelDashboard');
});
+// Expence Module Route Group
+$routes->group('expense', ["filter" => "authMVC", 'namespace' => 'App\Controllers'], static function($routes) {
+ $routes->get('/', 'ExpenseController::index');
+ $routes->post('save', 'ExpenseController::save');
+ $routes->get('get/(:num)', 'ExpenseController::getExpense/$1');
+ $routes->post('delete/(:num)', 'ExpenseController::delete/$1');
+ $routes->get('client-policies', 'ExpenseController::clientPolicies');
+});
+
diff --git a/app/Controllers/AppContentManagementController.php b/app/Controllers/AppContentManagementController.php
index a53d90d0..c3bcde67 100755
--- a/app/Controllers/AppContentManagementController.php
+++ b/app/Controllers/AppContentManagementController.php
@@ -62,32 +62,40 @@ class AppContentManagementController extends AdminController
$data = $this->request->getPost();
$sanitized_post_data = sanitizeInputArrayAdvanced($data);
- $id = ((int) $sanitized_post_data['add_image_id']) ?? null;
+ $id = (int)($sanitized_post_data['add_image_id'] ?? 0);
$rules = [
- 'client_id' => [
- 'rules' => 'required|integer',
+ 'add_image_id' => [
+ 'rules' => 'permit_empty|integer|is_natural',
'errors' => [
- 'required' => 'Client is required',
- 'integer' => 'Invalid client selected'
+ 'integer' => 'Image ID must be a valid number',
+ 'is_natural' => 'Image ID must be a non-negative number'
+ ]
+ ],
+ 'client_id' => [
+ 'rules' => 'required|integer|is_natural_no_zero',
+ 'errors' => [
+ 'required' => 'Client is required',
+ 'integer' => 'Invalid client selected',
+ 'is_natural_no_zero' => 'Invalid client selected'
+ ]
+ ],
+ 'advertise_image' => [
+ 'rules' => ($id === 0 ? 'uploaded[advertise_image]|' : '')
+ . 'is_image[advertise_image]'
+ . '|mime_in[advertise_image,image/jpg,image/jpeg,image/png]'
+ . '|max_size[advertise_image,200]'
+ . '|min_dims[advertise_image,1640,664]'
+ . '|max_dims[advertise_image,1640,664]',
+ 'errors' => [
+ 'uploaded' => 'Image is required',
+ 'is_image' => 'File must be an image',
+ 'mime_in' => 'Only JPG, JPEG, PNG allowed',
+ 'max_size' => 'Image size must not exceed 200 KB',
+ 'min_dims' => 'Image dimensions must be exactly 1640x664 pixels',
+ 'max_dims' => 'Image dimensions must be exactly 1640x664 pixels',
]
],
- ];
- $rules['advertise_image'] = [
- 'rules' => ($id === 0 ? 'uploaded[advertise_image]|' : '') // required only for ADD
- . 'is_image[advertise_image]'
- . '|mime_in[advertise_image,image/jpg,image/jpeg,image/png]'
- . '|max_size[advertise_image,200]'
- . '|min_dims[advertise_image,1640,664]'
- . '|max_dims[advertise_image,1640,664]',
- 'errors' => [
- 'uploaded' => 'Image is required',
- 'is_image' => 'File must be an image',
- 'mime_in' => 'Only JPG, JPEG, PNG allowed',
- 'max_size' => 'Image size must not exceed 200 KB',
- 'min_dims' => 'Image dimensions must be exactly 1640x664 pixels',
- 'max_dims' => 'Image dimensions must be exactly 1640x664 pixels',
- ]
];
if (!$this->validate($rules)) {
return $this->response->setStatusCode(400)->setJSON([
@@ -100,7 +108,12 @@ class AppContentManagementController extends AdminController
$file = $this->request->getFile('advertise_image');
- $client_id = $sanitized_post_data['client_id'] ?? null;
+ $client_id = (int)($sanitized_post_data['client_id'] ?? 0);
+
+ $clientExists = $this->clientModel->where('id', $client_id)->where('is_active', 1)->first();
+ if (!$clientExists) {
+ return $this->respond(['status' => false, 'message' => 'Invalid client selected.'], 400);
+ }
if (!$file || !$file->isValid()) {
return $this->respond(['status' => false, 'message' => 'No file uploaded or invalid file.'], 400);
@@ -119,12 +132,15 @@ class AppContentManagementController extends AdminController
$file->move($uploadPath, $fileName);
- $id = $sanitized_post_data['add_image_id'] ?? null;
$details = ['name' => $fileName,'client_id'=>$client_id];
- if ($id == 0) {
+ if ($id === 0) {
$this->addImgModel->insert($details);
} else {
+ $existingRecord = $this->addImgModel->find($id);
+ if (!$existingRecord) {
+ return $this->respond(['status' => false, 'message' => 'Record not found for update.'], 404);
+ }
$this->addImgModel->update($id, $details);
}
@@ -138,14 +154,34 @@ class AppContentManagementController extends AdminController
public function remove_advertise_image()
{
try {
- $id = $this->request->getPost('add_image_id');
+ $rules = [
+ 'add_image_id' => [
+ 'rules' => 'required|integer|is_natural_no_zero',
+ 'errors' => [
+ 'required' => 'Image ID is required',
+ 'integer' => 'Image ID must be a valid number',
+ 'is_natural_no_zero' => 'Image ID must be a positive number'
+ ]
+ ]
+ ];
- if (!$id) {
- return $this->respond(['status' => false, 'message' => 'ID missing'], 400);
+ if (!$this->validate($rules)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => false,
+ 'message' => 'Input validation failed',
+ 'code' => 400,
+ 'errors' => $this->validator->getErrors()
+ ]);
}
- $data = ['is_active' => 0];
- $this->addImgModel->update($id, $data);
+ $id = (int)$this->request->getPost('add_image_id');
+
+ $existing = $this->addImgModel->find($id);
+ if (!$existing) {
+ return $this->respond(['status' => false, 'message' => 'Record not found'], 404);
+ }
+
+ $this->addImgModel->update($id, ['is_active' => 0]);
return $this->respond(['status' => true, 'message' => 'Deleted successfully']);
@@ -158,19 +194,27 @@ class AppContentManagementController extends AdminController
// Preview image Went Edit.
public function showAdvertiseImage($filename)
{
- // $path = WRITEPATH . 'uploads/advertiseImage/' . $filename;
- $path = ROOTPATH . 'public/uploads/add_image_upload/' . $filename;
+ $filename = basename($filename);
- if (!file_exists($path)) {
+ if (!preg_match('/^[a-zA-Z0-9_\-]+\.(jpg|jpeg|png|gif|webp)$/i', $filename)) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
- // return $this->response->setStatusCode(404, 'File not found');
}
- $mime = mime_content_type($path);
- // header('Content-Type: ' . $mimeType);
- // readfile($path);
- // exit;
- return $this->response->setHeader('Content-Type', $mime)->setBody(file_get_contents($path));
+ $path = ROOTPATH . 'public/uploads/add_image_upload/' . $filename;
+ $realPath = realpath($path);
+ $allowedDir = realpath(ROOTPATH . 'public/uploads/add_image_upload');
+
+ if (!$realPath || strpos($realPath, $allowedDir) !== 0 || !file_exists($realPath)) {
+ throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
+ }
+
+ $mime = mime_content_type($realPath);
+ $allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
+ if (!in_array($mime, $allowedMimes, true)) {
+ throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
+ }
+
+ return $this->response->setHeader('Content-Type', $mime)->setBody(file_get_contents($realPath));
}
@@ -183,39 +227,51 @@ class AppContentManagementController extends AdminController
if ($this->request->getMethod() === 'post') {
$rules = [
- 'type' => [
- 'rules' => 'required|max_length[255]',
+ 'fe_id' => [
+ 'rules' => 'permit_empty|integer|is_natural',
'errors' => [
- 'required' => 'Type is required',
- 'max_length' => 'Type cannot exceed 255 characters'
+ 'integer' => 'ID must be a valid number',
+ 'is_natural' => 'ID must be a non-negative number'
+ ]
+ ],
+ 'type' => [
+ 'rules' => 'required|max_length[255]|regex_match[/^[a-zA-Z0-9_ \-]+$/]',
+ 'errors' => [
+ 'required' => 'Type is required',
+ 'max_length' => 'Type cannot exceed 255 characters',
+ 'regex_match' => 'Type contains invalid characters'
]
],
'content_section' => [
- 'rules' => 'required|max_length[255]',
+ 'rules' => 'required|max_length[255]|regex_match[/^[a-zA-Z0-9_ \-]+$/]',
'errors' => [
- 'required' => 'Content Section is required',
- 'max_length' => 'Content Section cannot exceed 255 characters'
+ 'required' => 'Content Section is required',
+ 'max_length' => 'Content Section cannot exceed 255 characters',
+ 'regex_match' => 'Content Section contains invalid characters'
]
],
'heading' => [
- 'rules' => 'required|max_length[255]',
+ 'rules' => 'required|max_length[255]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/]+$/]',
'errors' => [
- 'required' => 'Heading is required',
- 'max_length' => 'Heading cannot exceed 255 characters'
+ 'required' => 'Heading is required',
+ 'max_length' => 'Heading cannot exceed 255 characters',
+ 'regex_match' => 'Heading contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed'
]
],
'content' => [
- 'rules' => 'required|max_length[5000]',
+ 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]',
'errors' => [
- 'required' => 'Content is required',
- 'max_length' => 'Content cannot exceed 5000 characters'
+ 'required' => 'Content is required',
+ 'max_length' => 'Content cannot exceed 5000 characters',
+ 'regex_match' => 'Content contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed'
]
],
'notes' => [
- 'rules' => 'required|max_length[1500]',
+ 'rules' => 'required|max_length[1500]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]',
'errors' => [
- 'required' => 'Notes are required',
- 'max_length' => 'Notes cannot exceed 1500 characters'
+ 'required' => 'Notes are required',
+ 'max_length' => 'Notes cannot exceed 1500 characters',
+ 'regex_match' => 'Notes contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed'
]
]
];
@@ -230,8 +286,14 @@ class AppContentManagementController extends AdminController
}
$request_post_data = $this->request->getPost();
$data = sanitizeInputArrayAdvanced($request_post_data);
- $id = $data['fe_id'];
-
+ $id = $data['fe_id'] ?? null;
+
+ if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => false, 'message' => 'Invalid ID format', 'code' => 400
+ ]);
+ }
+ $id = !empty($id) ? (int)$id : null;
unset($data['fe_id']);
@@ -244,6 +306,12 @@ class AppContentManagementController extends AdminController
$status = $this->feContentModel->insert($data);
$text = "Created";
} else {
+ $existing = $this->feContentModel->find($id);
+ if (!$existing) {
+ return $this->response->setStatusCode(404)->setJSON([
+ 'status' => false, 'message' => 'Record not found', 'code' => 404
+ ]);
+ }
$status = $this->feContentModel->update($id, $data);
$text = "Updated";
}
@@ -260,6 +328,13 @@ class AppContentManagementController extends AdminController
$id = $this->request->getGet('fe_id') ?? null;
if (!empty($id)) {
+
+ if (!ctype_digit((string)$id) || (int)$id <= 0) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => false, 'code' => 400, 'message' => 'Invalid ID format'
+ ]);
+ }
+ $id = (int)$id;
$data['fe_list'] = $this->feContentModel->where('id', $id)->orderBy('id', 'DESC')->findAll();
@@ -276,16 +351,24 @@ class AppContentManagementController extends AdminController
} elseif ($method === 'delete') {
- // $input = $this->request->getRawInput();
- $id = $this->request->getGet('fe_id'); // ✅ THIS
- $id = $id ?? null;
+ $id = $this->request->getGet('fe_id') ?? null;
- if (empty($id)) {
+ if (empty($id) || !ctype_digit((string)$id) || (int)$id <= 0) {
+ return $this->respond([
+ 'status' => false,
+ 'code' => 400,
+ 'message' => 'Valid numeric ID is required for deletion'
+ ], 400);
+ }
+ $id = (int)$id;
+
+ $existing = $this->feContentModel->find($id);
+ if (!$existing) {
return $this->respond([
'status' => false,
'code' => 404,
- 'message' => 'No ID provided for deletion'
- ], 200);
+ 'message' => 'Record not found'
+ ], 404);
}
$update_status = $this->feContentModel->where('id', $id)->set(['is_active' => 0])->update();
@@ -309,10 +392,15 @@ class AppContentManagementController extends AdminController
}
+ private const ALLOWED_RETURN_TYPES = ['api', 'web'];
+
public function FAQ()
{
$method = strtolower($this->request->getMethod());
$returnType = strtolower($this->request->getGet('return_type') ?? 'api');
+ if (!in_array($returnType, self::ALLOWED_RETURN_TYPES, true)) {
+ $returnType = 'api';
+ }
$ref = ['timestamp' => date('Y-m-d H:i:s')];
try {
@@ -320,33 +408,64 @@ class AppContentManagementController extends AdminController
if ($method === 'post') {
$rules = [
'category' => [
- 'rules' => 'required',
+ 'rules' => 'required|max_length[100]|alpha_numeric_space',
'errors' => [
- 'required' => 'Category is required'
+ 'required' => 'Category is required',
+ 'max_length' => 'Category cannot exceed 100 characters',
+ 'alpha_numeric_space' => 'Category contains invalid characters'
]
],
'question' => [
- 'rules' => 'required',
+ 'rules' => 'required|max_length[1000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]',
'errors' => [
- 'required' => 'Question is required'
+ 'required' => 'Question is required',
+ 'max_length' => 'Question cannot exceed 1000 characters',
+ 'regex_match' => 'Question contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed'
]
],
'answer' => [
- 'rules' => 'required',
+ 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]',
'errors' => [
- 'required' => 'Answer is required'
+ 'required' => 'Answer is required',
+ 'max_length' => 'Answer cannot exceed 5000 characters',
+ 'regex_match' => 'Answer contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed'
]
]
];
+
+ if (!$this->validate($rules)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => 'error',
+ 'message' => 'Input validation failed',
+ 'code' => 400,
+ 'errors' => $this->validator->getErrors(),
+ 'ref' => $ref
+ ]);
+ }
+
$request_post_data = $this->request->getPost();
$sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data);
$data = array_filter($sanitized_post_data, fn($v) => $v !== '' && $v !== null);
- $id = $data['faq_id'];
+ $id = $data['faq_id'] ?? null;
+
+ if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => 'error', 'message' => 'Invalid FAQ ID format', 'code' => 400, 'ref' => $ref
+ ]);
+ }
+ $id = !empty($id) ? (int)$id : null;
+ unset($data['faq_id']);
if (empty($id)) {
$status = $this->faqModel->insert($data);
$msg = "Created";
} else {
+ $existing = $this->faqModel->find($id);
+ if (!$existing) {
+ return $this->response->setStatusCode(404)->setJSON([
+ 'status' => 'error', 'message' => 'FAQ not found', 'code' => 404, 'ref' => $ref
+ ]);
+ }
$status = $this->faqModel->update($id, $data);
$msg = "Updated";
}
@@ -372,10 +491,17 @@ class AppContentManagementController extends AdminController
$id = $this->request->getGet('faq_id');
if (!empty($id)) {
+ if (!ctype_digit((string)$id) || (int)$id <= 0) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => 'error', 'message' => 'Invalid FAQ ID format', 'code' => 400, 'ref' => $ref
+ ]);
+ }
+ $id = (int)$id;
+
if($returnType === 'web'){
- $row = $this->faqModel->find((int)$id);
+ $row = $this->faqModel->find($id);
}else{
- $row = $this->faqModel->where('is_active', 1)->find((int)$id);
+ $row = $this->faqModel->where('is_active', 1)->find($id);
}
$data['faq_list'] = $row ? [$row] : [];
@@ -417,7 +543,15 @@ class AppContentManagementController extends AdminController
// --- 3. DELETE: SOFT DELETE ---
elseif ($method === 'delete') {
$id = $this->request->getGet('faq_id');
- $status = (!empty($id)) ? $this->faqModel->update($id, ['is_active' => 0]) : false;
+
+ if (empty($id) || !ctype_digit((string)$id) || (int)$id <= 0) {
+ return $this->response->setJSON([
+ 'status' => 'error', 'message' => 'Valid numeric FAQ ID is required', 'code' => 400, 'ref' => $ref
+ ])->setStatusCode(400);
+ }
+ $id = (int)$id;
+
+ $status = $this->faqModel->find($id) ? $this->faqModel->update($id, ['is_active' => 0]) : false;
return $this->response->setJSON([
'status' => $status ? ($returnType === 'web' ? true : 'success') : ($returnType === 'web' ? false : 'error'),
@@ -429,12 +563,12 @@ class AppContentManagementController extends AdminController
}
} catch (\Throwable $e) {
- $msg = $e->getMessage();
+ log_message('error', 'FAQ error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
return $this->response->setJSON([
'status' => $returnType === 'web' ? false : 'error',
'code' => 500,
- 'message' => $msg,
- 'ref' => ['file' => $e->getFile(), 'line' => $e->getLine()]
+ 'message' => 'An internal error occurred. Please try again later.',
+ 'ref' => $ref
])->setStatusCode(500);
}
}
diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php
index 62989198..6d2064fa 100755
--- a/app/Controllers/ClientController.php
+++ b/app/Controllers/ClientController.php
@@ -142,24 +142,38 @@ class ClientController extends AdminController
return $this->response->setJSON(['isDuplicate' => $isDuplicate]);
}
+ private const ALLOWED_DUPLICATE_CHECK_TABLES = [
+ 'clients', 'client_branch', 'level_contacts', 'insurers', 'insurer_branch',
+ 'tpa', 'tpa_branch', 'policies', 'client_policy', 'user_profiles',
+ ];
+
public function checkDuplicateTableFieldValue()
{
$table = $this->request->getPost('table');
$field = $this->request->getPost('field');
$value = $this->request->getPost('value');
- // Load the database if not already loaded
- $db = db_connect();
+ if (!in_array($table, self::ALLOWED_DUPLICATE_CHECK_TABLES, true)) {
+ return $this->response->setJSON(['isDuplicate' => false, 'error' => 'Invalid table']);
+ }
+
+ $db = db_connect();
+ $tableFields = $db->getFieldNames($table);
- // Perform the query
$builder = $db->table($table);
if (is_array($value)) {
- $isDuplicate = $builder->where($value)->where('is_active', 1)->countAllResults() > 0;
+ $filteredValue = array_intersect_key($value, array_flip($tableFields));
+ if (empty($filteredValue)) {
+ return $this->response->setJSON(['isDuplicate' => false, 'error' => 'Invalid fields']);
+ }
+ $isDuplicate = $builder->where($filteredValue)->where('is_active', 1)->countAllResults() > 0;
} else {
+ if (!in_array($field, $tableFields, true)) {
+ return $this->response->setJSON(['isDuplicate' => false, 'error' => 'Invalid field']);
+ }
$isDuplicate = $builder->where($field, $value)->where('is_active', 1)->countAllResults() > 0;
}
- // Return the result
return $this->response->setJSON(['isDuplicate' => $isDuplicate]);
}
@@ -6955,16 +6969,21 @@ class ClientController extends AdminController
// $response = $ticketServiceController->getClaimExcelErrorData(["file_id" => 41]);
// $response = $ticketServiceController->claimDumpOnBoardProcess(["file_id" => 17]);
// $response = $ticketServiceController->extractExcelData("claims_dump_form_client.xlsx");
+
// $response = $ticketServiceController->tpaClaimDumpImporter(["file_id" => 51]); //abhi
// $response = $ticketServiceController->tpaClaimDumpImporter(["file_id" => 50]); //fhpl
// $response = $ticketServiceController->tpaClaimDumpImporter(["file_id" => 53]); //icici
// $response = $ticketServiceController->tpaClaimDumpImporter(["file_id" => 54]); //mediassist
// $response = $ticketServiceController->tpaClaimDumpImporter(["file_id" => 52]); //reliance
// $response = $ticketServiceController->tpaClaimDumpImporter(["file_id" => 48]); //vidal
- // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 48]); //vidal
- // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 54]); //mediassist
- // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 4]); //abhi
+ // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 51]); //abhi
+ // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 50]); //fhpl
+ // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 53]); //icici
+ // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 54]); //mediassist
+ // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 52]); //reliance
+ // $response = $ticketServiceController->tpaClaimDumpToTicketMasterImporters(["file_id" => 48]); //vidal
+ // $response = $ticketServiceController->getTpaClaimDumpErrorData(["file_id" => 48]);
// dd($response);
// ---------- TICKET CONTROLLER --------------------------------------------------------------------------------
diff --git a/app/Controllers/EmpDataServiceController.php b/app/Controllers/EmpDataServiceController.php
index 4a4e9faf..3ea1af3a 100755
--- a/app/Controllers/EmpDataServiceController.php
+++ b/app/Controllers/EmpDataServiceController.php
@@ -4360,13 +4360,15 @@ class EmpDataServiceController extends BaseController
{
$client_policy_id = $arrayData['client_policy_id'];
$cd_ac_pk = $this->clientPolicyModel->select('cd_ac_pk')->where('id',$client_policy_id)->first();
+ $sanitizedIds = array_map('intval', $arrayData['employeeIds']);
+ $placeholders = implode(',', array_fill(0, count($sanitizedIds), '?'));
$amount = $this->employeePolicyModel->query("
SELECT SUM(rata_premimum + gst) AS total_sum
FROM employee_polices
JOIN employees ON employees.id = employee_polices.employee_id
- WHERE employees.unit = '$unit'
- AND employee_polices.id IN (" . implode(',', $arrayData['employeeIds']) . ")
- ")->getRow();
+ WHERE employees.unit = ?
+ AND employee_polices.id IN ($placeholders)
+ ", array_merge([$unit], $sanitizedIds))->getRow();
if($amount){
@@ -4625,11 +4627,14 @@ class EmpDataServiceController extends BaseController
// AND employee_polices.id IN (" . implode(',', $arrayData['employeeIds']) . ")
// ")->getRow();
+ $sanitizedIds = array_map('intval', $arrayData['employeeIds']);
+ $placeholders = implode(',', array_fill(0, count($sanitizedIds), '?'));
+ $safeAddOneDay = (int)$add_one_day;
$amount = $this->employeePolicyModel->query("
SELECT
SUM(ROUND(
- ((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, emp_endorsement.new_value) + '$add_one_day')) / 365) +
- (((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, emp_endorsement.new_value) + '$add_one_day')) / 365) * 0.18),
+ ((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, emp_endorsement.new_value) + ?)) / 365) +
+ (((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, emp_endorsement.new_value) + ?)) / 365) * 0.18),
2
)) AS total_sum
FROM
@@ -4639,14 +4644,14 @@ class EmpDataServiceController extends BaseController
JOIN
emp_endorsement ON emp_endorsement.pk = employee_polices.id
WHERE
- employee_polices.id IN (" . implode(',', $arrayData['employeeIds']) . ")
- AND emp_endorsement.pk IN (" . implode(',', $arrayData['employeeIds']) . ")
+ employee_polices.id IN ($placeholders)
+ AND emp_endorsement.pk IN ($placeholders)
AND employee_polices.claim_status = 0
AND emp_endorsement.field_name = 'date_of_exit'
AND emp_endorsement.is_active = 1
AND emp_endorsement.actions = 'd'
- AND emp_endorsement.status != 'truncated';
- ")->getRow();
+ AND emp_endorsement.status != 'truncated'
+ ", array_merge([$safeAddOneDay, $safeAddOneDay], $sanitizedIds, $sanitizedIds))->getRow();
// dd(db_connect()->getLastQuery(), $amount);
diff --git a/app/Controllers/ExpenseController.php b/app/Controllers/ExpenseController.php
new file mode 100644
index 00000000..c734284d
--- /dev/null
+++ b/app/Controllers/ExpenseController.php
@@ -0,0 +1,412 @@
+myLogger = \Config\Services::mylogger();
+ $this->expenseModel = new ExpenseModel();
+ $this->clientModel = new ClientModel();
+ $this->clientPolicyModel = new ClientPolicyModel();
+ }
+
+ /**
+ * Web list + form view
+ */
+ public function index()
+ {
+ try {
+ $data['tab_name'] = 'Expense';
+ $data['page_name'] = 'Expense';
+ $descriptionPattern = '/^[a-zA-Z0-9\s\.\,\-\(\)\/\&\+]+$/u';
+
+ // Raw GET filters
+ $rawFilters = $this->request->getGet() ?? [];
+ $rawFilters = is_array($rawFilters) ? $rawFilters : [];
+
+ // Sanitize input array using existing helper
+ $sanitized = sanitizeInputArrayAdvanced($rawFilters);
+
+ $filters = [
+ 'client_id' => trim($sanitized['client_id'] ?? ''),
+ 'client_policy_id' => trim($sanitized['client_policy_id'] ?? ''),
+ 'approved_by' => trim($sanitized['approved_by'] ?? ''),
+ 'description' => trim($sanitized['description'] ?? ''),
+ 'amount' => trim($sanitized['amount'] ?? ''),
+ 'expense_date' => trim($sanitized['expense_date'] ?? ''),
+ ];
+
+ $validationErrors = [];
+
+ // Basic type / format validation for filters
+ if ($filters['client_id'] !== '' && ! ctype_digit($filters['client_id'])) {
+ $validationErrors[] = 'Invalid client selected for search.';
+ $filters['client_id'] = '';
+ }
+
+ if ($filters['client_policy_id'] !== '' && ! ctype_digit($filters['client_policy_id'])) {
+ $validationErrors[] = 'Invalid policy selected for search.';
+ $filters['client_policy_id'] = '';
+ }
+
+ if ($filters['approved_by'] !== '' && ! ctype_digit($filters['approved_by'])) {
+ $validationErrors[] = 'Invalid approver selected for search.';
+ $filters['approved_by'] = '';
+ }
+
+ if ($filters['description'] !== '' && ! preg_match($descriptionPattern, $filters['description'])) {
+ $validationErrors[] = 'Description filter contains invalid characters.';
+ $filters['description'] = '';
+ }
+
+ if ($filters['amount'] !== '') {
+ if (! is_numeric($filters['amount']) || (float) $filters['amount'] < 0) {
+ $validationErrors[] = 'Amount filter must be a non-negative number.';
+ $filters['amount'] = '';
+ }
+ }
+
+ if ($filters['expense_date'] !== '') {
+ $dt = \DateTime::createFromFormat('d-m-Y', $filters['expense_date']);
+ $errors = $dt ? \DateTime::getLastErrors() : ['warning_count' => 1, 'error_count' => 1];
+ if (! $dt || ! empty($errors['warning_count']) || ! empty($errors['error_count'])) {
+ $validationErrors[] = 'Expense Date filter must be in DD-MM-YYYY format.';
+ $filters['expense_date'] = '';
+ }
+ }
+
+ $data['filters'] = $filters;
+ $data['validation_errors'] = $validationErrors;
+
+ // Clients for dropdown
+ $data['clients'] = $this->clientModel
+ ->select('id, client_name, short_name')
+ ->where('is_active', 1)
+ ->orderBy('client_name', 'ASC')
+ ->findAll();
+
+ // Approved by (users) dropdown
+ $db = db_connect();
+ $data['approved_users'] = $db->table('user_profiles')
+ ->select('id, first_name')
+ ->where('is_active', 1)
+ ->whereIn('id', [7, 8])
+ ->orderBy('first_name', 'ASC')
+ ->get()
+ ->getResultArray();
+
+ // Policies for filter dropdown (when client filter is selected)
+ $data['policies_for_filter'] = [];
+ if ($filters['client_id'] !== '') {
+ $data['policies_for_filter'] = $this->clientPolicyModel
+ ->select('id, policy_no')
+ ->where('client_id', (int) $filters['client_id'])
+ ->where('is_active', 1)
+ ->orderBy('id', 'ASC')
+ ->findAll();
+ }
+
+ // Existing expenses with optional filters
+ $builder = $this->expenseModel
+ ->select('
+ expenses.*,
+ clients.client_name,
+ clients.short_name,
+ client_policy.policy_no,
+ user_profiles.first_name AS approved_by_name
+ ')
+ ->join('clients', 'clients.id = expenses.client_id')
+ ->join('client_policy', 'client_policy.id = expenses.client_policy_id', 'left')
+ ->join('user_profiles', 'user_profiles.id = expenses.approved_by', 'left')
+ ->where('expenses.is_active', 1);
+
+ if ($filters['client_id'] !== '') {
+ $builder->where('expenses.client_id', (int) $filters['client_id']);
+ }
+
+ if ($filters['client_policy_id'] !== '') {
+ $builder->where('expenses.client_policy_id', (int) $filters['client_policy_id']);
+ }
+
+ if ($filters['approved_by'] !== '') {
+ $builder->where('expenses.approved_by', (int) $filters['approved_by']);
+ }
+
+ if ($filters['description'] !== '') {
+ $builder->like('expenses.description', (string) $filters['description']);
+ }
+
+ if ($filters['amount'] !== '') {
+ $builder->where('expenses.amount', (float) $filters['amount']);
+ }
+
+ if ($filters['expense_date'] !== '') {
+ $dt = \DateTime::createFromFormat('d-m-Y', $filters['expense_date']);
+ if ($dt) {
+ $builder->where('expenses.expense_date', $dt->format('Y-m-d'));
+ }
+ }
+
+ $data['expenses'] = $builder
+ ->orderBy('expenses.id', 'DESC')
+ ->findAll();
+
+ return $this->loadLayout('expense_list', $data);
+ } catch (\Throwable $e) {
+ return handle_exception($e, $this->myLogger, $this->response);
+ }
+ }
+
+ /**
+ * Create / update expense (AJAX)
+ */
+ public function save()
+ {
+ try {
+ if ($this->request->getMethod() !== 'post') {
+ return $this->response
+ ->setStatusCode(405)
+ ->setJSON([
+ 'status' => false,
+ 'message' => 'Invalid request method',
+ ]);
+ }
+
+ $rawData = $this->request->getPost();
+ $data = sanitizeInputArrayAdvanced($rawData);
+
+ $id = isset($data['id']) && $data['id'] !== '' ? (int) $data['id'] : null;
+
+ $rules = [
+ 'client_id' => [
+ 'rules' => 'required|is_natural_no_zero',
+ 'errors' => [
+ 'required' => 'Client is required',
+ ],
+ ],
+ 'client_policy_id' => [
+ 'rules' => 'required|is_natural_no_zero',
+ 'errors' => [
+ 'required' => 'Policy is required',
+ ],
+ ],
+ 'description' => [
+ 'rules' => 'required|string|min_length[1]|max_length[2000]|regex_match[/^[a-zA-Z0-9\s\.\,\-\(\)\/\&\+]+$/]',
+ 'errors' => [
+ 'required' => 'Description is required',
+ 'min_length' => 'Description cannot be empty',
+ 'regex_match' => 'Description contains invalid characters.',
+ ],
+ ],
+ 'expense_date' => [
+ 'rules' => 'required|valid_date[d-m-Y]',
+ 'errors' => [
+ 'required' => 'Expense Date is required',
+ 'valid_date' => 'Expense Date must be in DD-MM-YYYY format',
+ ],
+ ],
+ 'approved_by' => [
+ 'rules' => 'required|is_natural_no_zero',
+ 'errors' => [
+ 'required' => 'Approved By is required',
+ ],
+ ],
+ 'amount' => [
+ 'rules' => 'required|numeric|greater_than_equal_to[0]',
+ 'errors' => [
+ 'required' => 'Amount is required',
+ 'numeric' => 'Amount must be numeric',
+ 'greater_than_equal_to' => 'Amount cannot be negative',
+ ],
+ ],
+ ];
+
+ if (! $this->validate($rules)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => false,
+ 'message' => 'Input validation failed',
+ 'errors' => $this->validator->getErrors(),
+ ]);
+ }
+
+ $payload = [
+ 'client_id' => (int) ($data['client_id'] ?? 0),
+ 'client_policy_id' => (int) ($data['client_policy_id'] ?? 0),
+ 'description' => $data['description'] ?? null,
+ 'approved_by' => (int) ($data['approved_by'] ?? 0),
+ 'amount' => $data['amount'] ?? null,
+ 'is_active' => 1,
+ ];
+
+ $expenseDate = $data['expense_date'] ?? null;
+ if (! empty($expenseDate)) {
+ $dt = \DateTime::createFromFormat('d-m-Y', $expenseDate);
+ $payload['expense_date'] = $dt ? $dt->format('Y-m-d') : null;
+ } else {
+ $payload['expense_date'] = null;
+ }
+
+ if ($id === null) {
+ $insertId = $this->expenseModel->insert($payload, true);
+ $success = ! empty($insertId);
+ $id = $insertId;
+ $message = $success
+ ? 'Expense created successfully'
+ : 'Unable to create expense. Please try again.';
+ } else {
+ $success = $this->expenseModel->update($id, $payload);
+ $message = $success
+ ? 'Expense updated successfully'
+ : 'Unable to update expense. Please try again.';
+ }
+
+ return $this->response
+ ->setStatusCode($success ? 200 : 400)
+ ->setJSON([
+ 'status' => (bool) $success,
+ 'message' => $message,
+ 'id' => $id,
+ ]);
+ } catch (\Throwable $e) {
+ return handle_exception($e, $this->myLogger, $this->response);
+ }
+ }
+
+ /**
+ * Get single expense (AJAX)
+ */
+ public function getExpense($id = null)
+ {
+ try {
+ $id = (int) $id;
+
+ if (empty($id)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => false,
+ 'message' => 'Invalid expense id',
+ ]);
+ }
+
+ $expense = $this->expenseModel
+ ->select('
+ expenses.*,
+ clients.client_name,
+ clients.short_name,
+ client_policy.policy_no,
+ user_profiles.first_name AS approved_by_name
+ ')
+ ->join('clients', 'clients.id = expenses.client_id', 'left')
+ ->join('client_policy', 'client_policy.id = expenses.client_policy_id', 'left')
+ ->join('user_profiles', 'user_profiles.id = expenses.approved_by', 'left')
+ ->where('expenses.id', $id)
+ ->where('expenses.is_active', 1)
+ ->first();
+
+ if (empty($expense)) {
+ return $this->response->setStatusCode(404)->setJSON([
+ 'status' => false,
+ 'message' => 'Expense not found',
+ ]);
+ }
+
+ return $this->response->setStatusCode(200)->setJSON([
+ 'status' => true,
+ 'data' => $expense,
+ ]);
+ } catch (\Throwable $e) {
+ return handle_exception($e, $this->myLogger, $this->response);
+ }
+ }
+
+ /**
+ * Soft delete expense (AJAX)
+ */
+ public function delete($id = null)
+ {
+ try {
+ if ($this->request->getMethod() !== 'post') {
+ return $this->response
+ ->setStatusCode(405)
+ ->setJSON([
+ 'status' => false,
+ 'message' => 'Invalid request method',
+ ]);
+ }
+
+ $id = (int) $id;
+
+ if (empty($id)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => false,
+ 'message' => 'Invalid expense id',
+ ]);
+ }
+
+ $payload = [
+ 'is_active' => 0,
+ ];
+
+ $success = $this->expenseModel->update($id, $payload);
+
+ return $this->response
+ ->setStatusCode($success ? 200 : 400)
+ ->setJSON([
+ 'status' => (bool) $success,
+ 'message' => $success
+ ? 'Expense deleted successfully'
+ : 'Unable to delete expense. Please try again.',
+ ]);
+ } catch (\Throwable $e) {
+ return handle_exception($e, $this->myLogger, $this->response);
+ }
+ }
+
+ /**
+ * Get policies by client for dropdown (AJAX)
+ */
+ public function clientPolicies()
+ {
+ try {
+ $clientId = (int) ($this->request->getGet('client_id') ?? 0);
+
+ if (empty($clientId)) {
+ return $this->response->setStatusCode(400)->setJSON([
+ 'status' => false,
+ 'message' => 'Client is required',
+ ]);
+ }
+
+ $policies = $this->clientPolicyModel
+ ->select('client_policy.id, client_policy.policy_no, policy_type.policy_type')
+ ->join('policy_type', 'policy_type.id = client_policy.policy_type_id AND policy_type.is_active = 1')
+ ->where('client_policy.client_id', $clientId)
+ ->where('client_policy.is_active', 1)
+ ->orderBy('client_policy.id', 'ASC')
+ ->findAll();
+
+ return $this->response->setStatusCode(200)->setJSON([
+ 'status' => true,
+ 'data' => $policies,
+ ]);
+ } catch (\Throwable $e) {
+ return handle_exception($e, $this->myLogger, $this->response);
+ }
+ }
+}
+
diff --git a/app/Controllers/MediAssistApiController.php b/app/Controllers/MediAssistApiController.php
index 26b82ce1..a59c2637 100644
--- a/app/Controllers/MediAssistApiController.php
+++ b/app/Controllers/MediAssistApiController.php
@@ -844,6 +844,8 @@ class MediAssistApiController extends BaseController
->get()
->getResultArray();
+ log_message('error','MEDI_ASSIST - Claim Status started | for ticket count: ' . count($TicketData));
+
// dd($TicketData);
if (!$TicketData) {
@@ -890,7 +892,11 @@ class MediAssistApiController extends BaseController
if ($response['status'] != true || empty($response['data']['claimsData'][0])) {
log_message('error','MEDI_ASSIST - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
- $error_data[$claimId][['status' => false,'message' => 'API call failed.','data' => $response]];
+ $error_data[$claimId] = [
+ 'response' => $response,
+ 'body' => $body
+ ];
+ continue; // skip to next ticket
}
// Extract Claim Status
diff --git a/app/Controllers/SalesController.php b/app/Controllers/SalesController.php
index c3f870c5..164444e9 100644
--- a/app/Controllers/SalesController.php
+++ b/app/Controllers/SalesController.php
@@ -7,6 +7,7 @@ use App\Models\SalesActualLeadModel;
use App\Models\SalesContactPersonModel;
use App\Models\SalesActivityModel;
use App\Models\SalesLeadNoteModel;
+use App\Models\SalesTargetModel;
use App\Models\UserModel;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\API\ResponseTrait;
@@ -20,6 +21,8 @@ class SalesController extends BaseController
protected $activityModel;
protected $noteModel;
protected $userModel;
+ protected $targetModel;
+
public function __construct()
{
@@ -28,6 +31,7 @@ class SalesController extends BaseController
$this->activityModel = new SalesActivityModel();
$this->noteModel = new SalesLeadNoteModel();
$this->userModel = new UserModel();
+ $this->targetModel = new SalesTargetModel();
}
@@ -53,55 +57,73 @@ class SalesController extends BaseController
return $this->loadLayout('sales/activity_view', $data);
}
+ public function loadtargets(){
+ $data = $this->getSalesStaffData();
+
+ $data['tab_name'] = 'Sales Team Targets';
+ $data['page_name'] = 'Sales Team Targets';
+
+ return $this->loadLayout('sales/target_view', $data);
+ }
+
/**
* HELPER: Fetches Sales Managers based on the logged-in user's role and branch
*/
private function getSalesStaffData(): array
{
- $db = \Config\Database::connect();
+ $db = \Config\Database::connect();
$logged_user_id = get_session_userid();
- $role = get_role_id();
- $team_id = user_team();
+ $role = get_role_id();
+ $team_id = user_team();
$data = [
- 'users' => [],
- 'sales_manager_ids' => []
+ 'users' => [],
+ 'sales_manager_ids'=> [],
+ 'sales_role' => '',
+ 'nhance_branch_id' => null,
+ 'assigned_ids' => [],
];
- $row = $db->table('user_profiles')->select('*')
- ->where('is_active', 1)->where('id', $logged_user_id)
- ->get()->getRow();
-
- $nhance_branch_id = $row ? $row->nhance_branch_id : null;
-
- // Is the logged-in user a Sales Manager? (Role 4, Team 5)
- if ($role == 4 && in_array(5, $team_id)) {
+ $row = $db->table('user_profiles')->select('*')
+ ->where('is_active', 1)->where('id', $logged_user_id)
+ ->get()->getRow();
+
+ $nhance_branch_id = $row ? $row->nhance_branch_id : null;
+ $data['nhance_branch_id']= $nhance_branch_id;
+
+ // ── Sales Manager (Role 4, Team 5) ──────────────────────────
+ if ($role == 4 && in_array(5, $team_id)) {
+
+ $data['sales_role'] = 'Sales Manager';
$data['sales_manager_ids'] = [$logged_user_id];
-
- $data['users'] = [
+ $data['assigned_ids'] = [$logged_user_id];
+ $data['users'] = [
[
'id' => $row->id,
- 'first_name' => $row->first_name,
- 'nhance_branch_id' => $nhance_branch_id
+ 'first_name' => $row->first_name,
+ 'last_name' => $row->last_name ?? '',
+ 'nhance_branch_id' => $nhance_branch_id,
]
];
- }
- // Otherwise fetch ALL sales managers in this branch
- elseif (in_array($role,[1,5])) {
-
- $data['users'] = $db->table('user_profiles up')
- ->select('up.id, up.first_name, up.last_name, up.nhance_branch_id')
- ->join('user_teams ut', 'ut.user_id = up.id')
- ->where('up.is_active', 1)
- ->where('ut.is_active', 1)
- ->where('up.role', 4)
- ->where('ut.team_id', 5)
- ->where('up.nhance_branch_id', $nhance_branch_id)
- ->get()
- ->getResultArray();
+ // ── Sales Head (Role 1 or 5) ─────────────────────────────────
+ } elseif (in_array($role, [1, 5])) {
- $data['sales_manager_ids'] = array_column($data['users'], 'id');
+ $data['sales_role'] = 'Sales Head';
+ $data['users'] = $db->table('user_profiles up')
+ ->select('up.id, up.first_name, up.last_name, up.nhance_branch_id')
+ ->join('user_teams ut', 'ut.user_id = up.id')
+ ->where('up.is_active', 1)
+ ->where('ut.is_active', 1)
+ ->where('up.role', 4)
+ ->where('ut.team_id', 5)
+ ->where('up.nhance_branch_id', $nhance_branch_id)
+ ->get()
+ ->getResultArray();
+
+ $ids = array_column($data['users'], 'id');
+ $data['sales_manager_ids'] = $ids;
+ $data['assigned_ids'] = $ids; // same value, both available
}
return $data;
@@ -751,6 +773,138 @@ class SalesController extends BaseController
}
}
+ // ==================== SALES TARGET APIs ====================
+ /**
+ * Get all sales targets
+ * GET /api/sales/targets
+ */
+ public function getTargets()
+ {
+ try {
+ $targets = $this->targetModel->findAll();
+ return $this->respond([
+ 'status' => 'success',
+ 'data' => $targets
+ ]);
+ } catch (\Exception $e) {
+ return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * Get sales target by user
+ * GET /api/sales/targets/user/{userId}
+ */
+ public function getTargetByUser($userId)
+ {
+ try {
+ $targets = $this->targetModel->where('user_id', $userId)->findAll();
+ return $this->respond([
+ 'status' => 'success',
+ 'data' => $targets
+ ]);
+ } catch (\Exception $e) {
+ return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * Get sales target by FY year
+ * GET /api/sales/targets/fy/{fyYear}
+ */
+ public function getTargetByFY($fyYear)
+ {
+ try {
+ $targets = $this->targetModel->where('fy_year', $fyYear)->findAll();
+ return $this->respond([
+ 'status' => 'success',
+ 'data' => $targets
+ ]);
+ } catch (\Exception $e) {
+ return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * Create sales target
+ * POST /api/sales/targets
+ */
+ public function createTarget()
+ {
+ try {
+ $data = $this->request->getJSON(true);
+ $data['created_by'] = $this->getUserId();
+ $data['updated_by'] = $this->getUserId();
+
+ if (!$this->targetModel->insert($data)) {
+ return $this->fail($this->targetModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
+ }
+
+ $targetId = $this->targetModel->getInsertID();
+ $target = $this->targetModel->find((int)$targetId);
+
+ return $this->respondCreated([
+ 'status' => 'success',
+ 'message' => 'Sales target created successfully',
+ 'data' => $target
+ ]);
+ } catch (\Exception $e) {
+ return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * Update sales target
+ * PUT /api/sales/targets/{id}
+ */
+ public function updateTarget($id)
+ {
+ try {
+ $target = $this->targetModel->find((int)$id);
+ if (!$target) {
+ return $this->failNotFound('Sales target not found');
+ }
+
+ $data = $this->request->getJSON(true);
+ $data['updated_by'] = $this->getUserId();
+
+ if (!$this->targetModel->update($id, $data)) {
+ return $this->fail($this->targetModel->errors(), ResponseInterface::HTTP_BAD_REQUEST);
+ }
+
+ $updatedTarget = $this->targetModel->find((int)$id);
+ return $this->respond([
+ 'status' => 'success',
+ 'message' => 'Sales target updated successfully',
+ 'data' => $updatedTarget
+ ]);
+ } catch (\Exception $e) {
+ return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
+ }
+ }
+
+ /**
+ * Delete sales target
+ * DELETE /api/sales/targets/{id}
+ */
+ public function deleteTarget($id)
+ {
+ try {
+ $target = $this->targetModel->find((int)$id);
+ if (!$target) {
+ return $this->failNotFound('Sales target not found');
+ }
+
+ $this->targetModel->delete((int)$id);
+ return $this->respondDeleted([
+ 'status' => 'success',
+ 'message' => 'Sales target deleted successfully'
+ ]);
+ } catch (\Exception $e) {
+ return $this->fail($e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
+ }
+ }
+
// ==================== HELPER METHODS ====================
/**
@@ -773,52 +927,23 @@ class SalesController extends BaseController
// ==================== Dashboard ====================
- public function dashboard(){
-
- $logged_user_id = get_session_userid();
- $role = get_role_id();
- $team_id = user_team();
+ public function dashboard()
+ {
$payload = $this->request->getGet();
+ $base = $this->getSalesStaffData();
+ $salesRole = $base['sales_role'];
+ $salesManagerIds = $base['sales_manager_ids'];
+ $userId = get_session_userid();
- $db = \Config\Database::connect();
+ // Get branch id from users array
+ $nhanceBranchId = $base['users'][0]['nhance_branch_id'] ?? null;
- $row = $db->table('user_profiles')
- ->select('*')
- ->where('is_active', 1)
- ->where('id', $logged_user_id)
- ->get()
- ->getRowArray();
-
- $nhance_branch_id = $row ? $row['nhance_branch_id'] : null;
-
- // dd($logged_user_id, $nhance_branch_id, $role, $team_id );
-
- if (in_array($role,[1,5])) {
-
- $sales_manager_ids = array_column(
- $db->table('user_profiles up')
- ->select('up.id')
- ->join('user_teams ut', 'ut.user_id = up.id')
- ->where([
- 'up.is_active' => 1,
- 'ut.is_active' => 1,
- 'up.role' => 4,
- 'ut.team_id' => 5,
- 'up.nhance_branch_id' => $nhance_branch_id
- ])
- ->get()
- ->getResultArray(),
- 'id'
- );
- $this->branchLevelDashboard($nhance_branch_id,$sales_manager_ids);
-
- }
- elseif ($role == 4 && in_array(5, $team_id)) {
- $sales_manager_ids = [$logged_user_id];
- $this->salesManagerLevelDashboard($logged_user_id,$sales_manager_ids, $payload);
+ if ($salesRole === 'Sales Head') {
+ $this->branchLevelDashboard($nhanceBranchId, $salesManagerIds);
+ } elseif ($salesRole === 'Sales Manager') {
+ $this->salesManagerLevelDashboard($userId, $salesManagerIds,$payload);
}
-
- }
+ }
public function branchLevelDashboard($branchId,$sales_manager_ids)
{
@@ -1001,7 +1126,7 @@ class SalesController extends BaseController
->findAll();
$data = [
- 'target' => $targetAmount,
+ 'target_amt' => $targetAmount,
'achieved' => $achievedAmount,
'remaining' => $remainingAmount,
'percent' => $achievementPercent,
@@ -1093,9 +1218,23 @@ class SalesController extends BaseController
/* ---------------- SUMMARY ---------------- */
- $summary = ucfirst($input['activity_type']) .
- ' with ' .
- $lead_data['company_name'];
+ $activityType = ucfirst($input['activity_type']);
+
+ $prepositionMap = [
+ 'Email' => 'to',
+ 'Call' => 'with',
+ 'Meeting' => 'with',
+ 'Visit' => 'to',
+ 'Demo' => 'with',
+ 'Share Docs' => 'to',
+ 'To Do' => 'for'
+ ];
+
+ $preposition = $prepositionMap[$activityType] ?? 'with';
+
+ $summary = "Activity scheduled : {$activityType} {$preposition} {$lead_data['company_name']}";
+
+
/* ---------------- GOOGLE PAYLOAD ---------------- */
diff --git a/app/Controllers/TicketServiceController.php b/app/Controllers/TicketServiceController.php
index f95f547d..8e96a780 100644
--- a/app/Controllers/TicketServiceController.php
+++ b/app/Controllers/TicketServiceController.php
@@ -30,8 +30,9 @@ use App\Models\TicketMasterModel;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Style\Fill;
-class TicketServiceController extends BaseController
+class TicketServiceController extends AdminController
{
use ResponseTrait;
@@ -1840,39 +1841,86 @@ class TicketServiceController extends BaseController
{
}
-
-
+
+
// --------------------------------------------------------------------------------------------------------------------------------
-
- public function tpaClaimDumpImporter($params)
+ /**
+ * Resolve and validate Claim Dump file metadata and physical file for TPA imports.
+ *
+ * @param int|null $fileId
+ * @return array{status:bool,message?:string,fileData?:array,filePath?:string}
+ */
+ private function resolveTpaClaimDumpFile(?int $fileId): array
{
- $file_id = $params['file_id'] ?? null; // Move outside try to ensure catch can see it
+ if (empty($fileId)) {
+ return [
+ 'status' => false,
+ 'message' => 'File ID is missing',
+ ];
+ }
+
+ $fileData = $this->claimDumpFileModel->find((int) $fileId);
+ if (!$fileData) {
+ return [
+ 'status' => false,
+ 'message' => 'Invalid file ID. No file data found',
+ ];
+ }
+
+ $filePath = WRITEPATH . 'uploads' . DIRECTORY_SEPARATOR . 'claim_dump_excel' . DIRECTORY_SEPARATOR . $fileData['file_name'];
+
+ if (!is_file($filePath)) {
+ return [
+ 'status' => false,
+ 'message' => 'Claim dump file not found',
+ ];
+ }
+
+ return [
+ 'status' => true,
+ 'fileData' => $fileData,
+ 'filePath' => $filePath,
+ ];
+ }
+
+ /**
+ * First TPA-wise job – parse Excel and push data into TPA staging table.
+ *
+ * @param array $params
+ * @return array
+ */
+ public function tpaClaimDumpImporter(array $params)
+ {
+ $file_id = isset($params['file_id']) ? (int) $params['file_id'] : null;
try {
- $file_path = WRITEPATH . 'uploads' . DIRECTORY_SEPARATOR . 'claim_dump_excel' . DIRECTORY_SEPARATOR;
+ $resolved = $this->resolveTpaClaimDumpFile($file_id);
- if (!$file_id) {
- return ['status' => false, 'message' => 'File ID is missing'];
+ if ($resolved['status'] === false) {
+ return [
+ 'status' => false,
+ 'message' => $resolved['message'] ?? 'Unable to resolve claim dump file',
+ ];
}
- $fileData = $this->claimDumpFileModel->find((int)$file_id);
- if (!$fileData) {
- return ['status' => false, 'message' => 'Invalid file ID. No file data found'];
- }
-
- $file_full_path = $file_path . $fileData['file_name'];
- if (!is_file($file_full_path)) {
- return ['status' => false, 'message' => 'Claim dump file not found'];
- }
+ $fileData = $resolved['fileData'];
+ $filePath = $resolved['filePath'];
$handler = TpaClaimsImportFactory::make($fileData['tpa_id'] ?? 0);
- $result = $handler->runTpaClaimDumpInsert($file_full_path, $file_id);
+ $result = $handler->runTpaClaimDumpInsert($filePath, $file_id);
if (!empty($result['status']) && $result['status'] === true) {
- Jobs::addJob(['job_name' => 'tpaClaimDumpToTicketMasterImporters', 'payload' => ['file_id' => $file_id]]);
+ Jobs::addJob([
+ 'job_name' => 'tpaClaimDumpToTicketMasterImporters',
+ 'payload' => ['file_id' => $file_id],
+ ]);
} else {
// FORCE FAIL LOGIC
- $this->markAsFailed($file_id, $result['message'] ?? 'System error contact admin', $fileData['created_by'] ?? null);
+ $this->markAsFailed(
+ $file_id,
+ $result['message'] ?? 'System error contact admin',
+ $fileData['created_by'] ?? null
+ );
}
return $result;
@@ -1884,9 +1932,9 @@ class TicketServiceController extends BaseController
}
return [
- 'status' => false,
- 'message' => 'TPA Claim dump import failed',
- 'error_data' => $th->getMessage()
+ 'status' => false,
+ 'message' => 'TPA Claim dump import failed',
+ 'error_data' => $th->getMessage(),
];
}
}
@@ -1908,30 +1956,37 @@ class TicketServiceController extends BaseController
return $this->claimDumpFileModel->update($file_id, $data);
}
- public function tpaClaimDumpToTicketMasterImporters($params)
+ /**
+ * Second TPA-wise job – move data from TPA staging into ticket_master.
+ *
+ * @param array $params
+ * @return array
+ */
+ public function tpaClaimDumpToTicketMasterImporters(array $params)
{
- $file_id = $params['file_id'] ?? null;
+ $file_id = isset($params['file_id']) ? (int) $params['file_id'] : null;
$fileData = null;
try {
- if (!$file_id) {
- return ['status' => false, 'message' => 'File ID is missing'];
+ $resolved = $this->resolveTpaClaimDumpFile($file_id);
+
+ if ($resolved['status'] === false) {
+ return [
+ 'status' => false,
+ 'message' => $resolved['message'] ?? 'Unable to resolve claim dump file',
+ ];
}
- $fileData = $this->claimDumpFileModel->where('id', $file_id)->first();
-
- if (!$fileData) {
- return ['status' => false, 'message' => 'Invalid file ID. No file data found to import'];
- }
+ $fileData = $resolved['fileData'];
$handler = TpaClaimsImportFactory::make($fileData['tpa_id'] ?? 0);
- $result = $handler->runTicketMasterInsert($params);
+ $result = $handler->runTicketMasterInsert($params);
if (!empty($result['status']) && $result['status'] === true) {
// Success: Update the status to success
$this->claimDumpFileModel->update($file_id, [
'status' => 'success',
- 'reason' => null
+ 'reason' => null,
]);
} else {
// Logic failure: The runTicketMasterInsert returned status false
@@ -1957,8 +2012,8 @@ class TicketServiceController extends BaseController
'message' => $th->getMessage(),
'error_data' => [
'line' => $th->getLine(),
- 'file' => $th->getFile()
- ]
+ 'file' => $th->getFile(),
+ ],
];
}
}
@@ -2011,5 +2066,176 @@ class TicketServiceController extends BaseController
return $data;
}
-
+ public function getTpaClaimDumpErrorData($file_id)
+ {
+ $file_id = (int) $file_id;
+
+ // Ensure we always have a Response object, even if controller was instantiated manually
+ $response = $this->response ?? service('response');
+
+ if ($file_id <= 0) {
+ return $response
+ ->setStatusCode(ResponseInterface::HTTP_BAD_REQUEST)
+ ->setJSON(['status' => false, 'message' => 'Invalid file id']);
+ }
+
+ $fileData = $this->claimDumpFileModel->find($file_id);
+
+ if (!$fileData) {
+ return $response
+ ->setStatusCode(ResponseInterface::HTTP_NOT_FOUND)
+ ->setJSON(['status' => false, 'message' => 'File record not found']);
+ }
+
+ $tpaId = (int) ($fileData['tpa_id'] ?? 0);
+
+ if ($tpaId <= 0) {
+ return $response
+ ->setStatusCode(ResponseInterface::HTTP_BAD_REQUEST)
+ ->setJSON(['status' => false, 'message' => 'TPA not linked with this file']);
+ }
+
+ // Resolve TPA staging table based on configured TPA IDs
+ $tableName = match ($tpaId) {
+ (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',
+ default => null,
+ };
+
+ if ($tableName === null) {
+ return $response
+ ->setStatusCode(ResponseInterface::HTTP_BAD_REQUEST)
+ ->setJSON(['status' => false, 'message' => 'Unsupported TPA for error dump export']);
+ }
+
+ $db = \Config\Database::connect();
+ $builder = $db->table($tableName);
+
+ // Fetch only records belonging to this file and having a rejection reason
+ $rows = $builder
+ ->where('file_id', $file_id)
+ ->where('is_active', 1)
+ ->where('master_reject_reason IS NOT NULL', null, false)
+ ->get()
+ ->getResultArray();
+
+ if (empty($rows)) {
+ // No error records – return a small Excel file with just a message
+ $spreadsheet = new Spreadsheet();
+ $sheet = $spreadsheet->getActiveSheet();
+ $sheet->setTitle('Errors');
+ $sheet->setCellValue('A1', 'Message');
+ $sheet->setCellValue('A2', 'No rejected records found for this file.');
+
+ $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
+ ob_start();
+ $writer->save('php://output');
+ $excelOutput = ob_get_clean();
+
+ $filename = 'tpa_claim_dump_errors_' . $file_id . '.xlsx';
+
+ return $response
+ ->setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+ ->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
+ ->setHeader('Cache-Control', 'max-age=0')
+ ->setBody($excelOutput);
+ }
+
+ // Columns that must NOT be included in the Excel export
+ $excludedColumns = [
+ 'id',
+ 'client_id',
+ 'client_policy_id',
+ 'ticket_id',
+ 'file_id',
+ 'created_at',
+ 'updated_at',
+ 'created_by',
+ 'updated_by',
+ 'is_active',
+ ];
+
+ $firstRow = $rows[0];
+
+ // Build header mapping and track the "Rejected Reason" column index
+ $dbColumnOrder = [];
+ $displayHeaderLabels = [];
+ $rejectedReasonColIdx = null; // 1-based index for Excel column
+
+ foreach ($firstRow as $columnName => $_) {
+ if (in_array($columnName, $excludedColumns, true)) {
+ continue;
+ }
+
+ $dbColumnOrder[] = $columnName;
+
+ if ($columnName === 'master_reject_reason' || $columnName === 'master_rejection_reason_key') {
+ $displayHeaderLabels[] = 'Rejected Reason';
+ $rejectedReasonColIdx = count($displayHeaderLabels); // current column index (1-based)
+ } else {
+ $displayHeaderLabels[] = $columnName;
+ }
+ }
+
+ $spreadsheet = new Spreadsheet();
+ $sheet = $spreadsheet->getActiveSheet();
+ $sheet->setTitle('Errors');
+
+ // Header row
+ $rowIndex = 1;
+ foreach ($displayHeaderLabels as $colIndex => $headerLabel) {
+ $columnLetter = Coordinate::stringFromColumnIndex($colIndex + 1);
+ $cellAddress = $columnLetter . $rowIndex;
+ $sheet->setCellValue($cellAddress, $headerLabel);
+ }
+
+ // Data rows
+ $rowIndex = 2;
+ foreach ($rows as $row) {
+ foreach ($dbColumnOrder as $i => $columnName) {
+ $colIndex = $i + 1;
+ $columnLetter = Coordinate::stringFromColumnIndex($colIndex);
+ $cellAddress = $columnLetter . $rowIndex;
+ $value = $row[$columnName] ?? null;
+
+ $sheet->setCellValue($cellAddress, $value);
+
+ // Highlight the "Rejected Reason" values
+ if ($rejectedReasonColIdx !== null && $colIndex === $rejectedReasonColIdx) {
+ $sheet->getStyle($cellAddress)
+ ->getFill()
+ ->setFillType(Fill::FILL_SOLID)
+ ->getStartColor()
+ ->setARGB('FFFFF4B2'); // light yellow
+ }
+ }
+
+ $rowIndex++;
+ }
+
+ // Autosize columns for better readability
+ $highestColumnIndex = count($displayHeaderLabels);
+ for ($col = 1; $col <= $highestColumnIndex; $col++) {
+ $columnLetter = Coordinate::stringFromColumnIndex($col);
+ $sheet->getColumnDimension($columnLetter)->setAutoSize(true);
+ }
+
+ $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
+ ob_start();
+ $writer->save('php://output');
+ $excelOutput = ob_get_clean();
+
+ $filename = 'tpa_claim_dump_errors_' . $file_id . '.xlsx';
+
+ return $response
+ ->setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
+ ->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
+ ->setHeader('Cache-Control', 'max-age=0')
+ ->setBody($excelOutput);
+ }
+
}
diff --git a/app/Controllers/VidalApiController.php b/app/Controllers/VidalApiController.php
index 04be9976..3836cb4b 100644
--- a/app/Controllers/VidalApiController.php
+++ b/app/Controllers/VidalApiController.php
@@ -567,6 +567,8 @@ class VidalApiController extends BaseController
// dd($TicketData);
+ log_message('error', "VIDAL - Claim Status | Total tickets fetched for status update: " . count($TicketData));
+
if (!$TicketData) {
log_message('error', "VIDAL - Claim Status | Claims not found to update status");
return $this->response->setJSON(['status' => false,'message' => 'Claims not found' ]);
@@ -599,7 +601,12 @@ class VidalApiController extends BaseController
if ($response['status'] != true || empty($response['data']['data']['claims'][0])) {
log_message('error', 'VIDAL - Claim Status FAILED | for ticket ID: ' . $claimId.' | response: '.json_encode($response));
- $error_data[$claimId][['status' => false,'message' => 'API call failed.','data' => $response]];
+ $error_data[$claimId] = [
+ 'status' => false,
+ 'message' => 'API call failed.',
+ 'data' => $response
+ ];
+ continue;
}
// Extract claim status
diff --git a/app/Helpers/excel_import_export_helper.php b/app/Helpers/excel_import_export_helper.php
index c7ba2982..dcffd660 100755
--- a/app/Helpers/excel_import_export_helper.php
+++ b/app/Helpers/excel_import_export_helper.php
@@ -766,18 +766,18 @@ if(!function_exists('query_construct_for_emp_policy_id')){
$gst_alise = '';
}
$subQuery .= "SELECT " . intval($index) . $row_id_alise;
- $subQuery .= "'" . $employee[$col_index['emp_name']] . "'" . $emp_name_alise;
- $subQuery .= "'" . $employee[$col_index['emp_code']] . "'" . $emp_code_alise;
- $subQuery .= "'" . $employee[$col_index['emp_dob']] . "'" . $emp_dob_alise;
- $subQuery .= "'" . $employee[$col_index['emp_gender']] . "'" . $emp_gender_alise;
- $subQuery .= "'" . $employee[$col_index['pre_existing_alignments']] . "'" . $pre_existing_alignments_alise;
- $subQuery .= "'" . $employee[$col_index['basic_cover_si']] . "'" . $basic_cover_si_alise;
- $subQuery .= "'" . $employee[$col_index['emp_relationship']] . "'" . $emp_relationship_alise;
- $subQuery .= "'" . $employee[$col_index['policy_end_date']] . "'" . $policy_end_date_alise;
- $subQuery .= "'" . $employee[$col_index['days']] . "'" . $days_alise;
- $subQuery .= "'" . $employee[$col_index['premium']] . "'" . $premium_alise;
- $subQuery .= "'" . $employee[$col_index['rata_premimum']] . "'" . $rata_premimum_alise;
- $subQuery .= "'" . $employee[$col_index['gst']] . "'" . $gst_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_name']]) . $emp_name_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_code']]) . $emp_code_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_dob']]) . $emp_dob_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_gender']]) . $emp_gender_alise;
+ $subQuery .= $db->escape($employee[$col_index['pre_existing_alignments']]) . $pre_existing_alignments_alise;
+ $subQuery .= $db->escape($employee[$col_index['basic_cover_si']]) . $basic_cover_si_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_relationship']]) . $emp_relationship_alise;
+ $subQuery .= $db->escape($employee[$col_index['policy_end_date']]) . $policy_end_date_alise;
+ $subQuery .= $db->escape($employee[$col_index['days']]) . $days_alise;
+ $subQuery .= $db->escape($employee[$col_index['premium']]) . $premium_alise;
+ $subQuery .= $db->escape($employee[$col_index['rata_premimum']]) . $rata_premimum_alise;
+ $subQuery .= $db->escape($employee[$col_index['gst']]) . $gst_alise;
}
// Complete the query
@@ -893,18 +893,18 @@ if(!function_exists('query_construct_second_stage')){
$gst_alise = '';
}
$subQuery .= "SELECT " . intval($index) . $row_id_alise;
- $subQuery .= "'" . $employee[$col_index['emp_name']] . "'" . $emp_name_alise;
- $subQuery .= "'" . $employee[$col_index['emp_code']] . "'" . $emp_code_alise;
- $subQuery .= "'" . $employee[$col_index['emp_dob']] . "'" . $emp_dob_alise;
- $subQuery .= "'" . $employee[$col_index['emp_gender']] . "'" . $emp_gender_alise;
- $subQuery .= "'" . $employee[$col_index['pre_existing_alignments']] . "'" . $pre_existing_alignments_alise;
- $subQuery .= "'" . $employee[$col_index['basic_cover_si']] . "'" . $basic_cover_si_alise;
- $subQuery .= "'" . $employee[$col_index['emp_relationship']] . "'" . $emp_relationship_alise;
- $subQuery .= "'" . $employee[$col_index['policy_end_date']] . "'" . $policy_end_date_alise;
- $subQuery .= "'" . $employee[$col_index['days']] . "'" . $days_alise;
- $subQuery .= "'" . $employee[$col_index['premium']] . "'" . $premium_alise;
- $subQuery .= "'" . $employee[$col_index['rata_premimum']] . "'" . $rata_premimum_alise;
- $subQuery .= "'" . $employee[$col_index['gst']] . "'" . $gst_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_name']]) . $emp_name_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_code']]) . $emp_code_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_dob']]) . $emp_dob_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_gender']]) . $emp_gender_alise;
+ $subQuery .= $db->escape($employee[$col_index['pre_existing_alignments']]) . $pre_existing_alignments_alise;
+ $subQuery .= $db->escape($employee[$col_index['basic_cover_si']]) . $basic_cover_si_alise;
+ $subQuery .= $db->escape($employee[$col_index['emp_relationship']]) . $emp_relationship_alise;
+ $subQuery .= $db->escape($employee[$col_index['policy_end_date']]) . $policy_end_date_alise;
+ $subQuery .= $db->escape($employee[$col_index['days']]) . $days_alise;
+ $subQuery .= $db->escape($employee[$col_index['premium']]) . $premium_alise;
+ $subQuery .= $db->escape($employee[$col_index['rata_premimum']]) . $rata_premimum_alise;
+ $subQuery .= $db->escape($employee[$col_index['gst']]) . $gst_alise;
}
// Complete the query
diff --git a/app/Libraries/DataServiceSqlite.php b/app/Libraries/DataServiceSqlite.php
index 226cba32..442efc63 100755
--- a/app/Libraries/DataServiceSqlite.php
+++ b/app/Libraries/DataServiceSqlite.php
@@ -65,12 +65,23 @@ class DataServiceSqlite
$this->sqliteDb->exec($sql);
}
+ private const ALLOWED_TABLES = ['http', 'log'];
+
public function insertData(array $data, string $tableName): bool
{
log_message('error', 'SQLite insert called: ');
+
+ if (!in_array($tableName, self::ALLOWED_TABLES, true)) {
+ log_message('error', 'SQLite insert rejected: invalid table name: ' . $tableName);
+ return false;
+ }
+
unset($data['context']);
- $columns = implode(', ', array_keys($data));
- // print_r($columns);
+
+ $safeColumns = array_map(function ($col) {
+ return preg_replace('/[^a-zA-Z0-9_]/', '', $col);
+ }, array_keys($data));
+ $columns = implode(', ', $safeColumns);
$placeholders = implode(', ', array_fill(0, count($data), '?'));
$sql = "INSERT INTO $tableName ($columns) VALUES ($placeholders)";
diff --git a/app/Libraries/TPAClaimsImportServices/AbhiClaimImportService.php b/app/Libraries/TPAClaimsImportServices/AbhiClaimImportService.php
index ffb4b970..103989bf 100644
--- a/app/Libraries/TPAClaimsImportServices/AbhiClaimImportService.php
+++ b/app/Libraries/TPAClaimsImportServices/AbhiClaimImportService.php
@@ -119,6 +119,19 @@ class AbhiClaimImportService extends BaseTpaClaimImportService
'Settled' => 11,
'Rejected' => 8,
'Cancelled' => 13,
+ 'Approved' => 9,
+ 'Closed' => 12,
+ 'Query' => 4,
+ 'Required Information' => 4,
+ 'In-Progress' => 5,
+ 'Paid' => 11,
+ 'Denied' => 8,
+ 'Cancelled' => 13,
+ 'Processed' => 61,
+ 'Information Awaited' => 4,
+ 'Denied Letter Sent' => 66,
+ 'Cashless Document Awaited' => 3,
+ 'RI Cancelled' => 13,
];
protected $dateColumns = [
@@ -164,14 +177,30 @@ class AbhiClaimImportService extends BaseTpaClaimImportService
}
- public function updateTicketIdInTPATable(): bool
+ public function updateTicketIdInTPATable(int $fileId): bool
{
- if (empty($data)) {
- return false;
+ $rows = $this->db->table('claims_dump_abhi cd')
+ ->select('cd.id, tm.id AS ticket_id')
+ ->join('ticket_master tm', 'tm.claim_dump_ref_id = cd.id AND tm.file_id = cd.file_id', 'inner')
+ ->where('cd.is_active', 1)
+ ->where('cd.file_id', $fileId)
+ ->where('cd.ticket_id IS NULL')
+ ->get()
+ ->getResultArray();
+
+ if (empty($rows)) {
+ return true;
}
- $builder = $this->db->table('claims_dump_abhi');
- return $builder->updateBatch($data, 'id');
+ $updateData = [];
+ foreach ($rows as $row) {
+ $updateData[] = [
+ 'id' => $row['id'],
+ 'ticket_id' => $row['ticket_id'],
+ ];
+ }
+
+ return $this->db->table('claims_dump_abhi')->updateBatch($updateData, 'id') !== false;
}
@@ -329,7 +358,7 @@ class AbhiClaimImportService extends BaseTpaClaimImportService
}
// Meta fields
- $item['claim_status_id'] = $statusMapping[$row['claim_status']] ?? 61;
+ $item['claim_status_id'] = $this->checkStatusMapping($this->statusMapping, $row['claim_status']);
$item['file_id'] = $file_id;
$item['claim_dump_ref_id'] = $row['id'];
$item['created_by'] = $file_data['created_by'] ?? null;
diff --git a/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php b/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php
index 3a6a5777..137caf25 100644
--- a/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php
+++ b/app/Libraries/TPAClaimsImportServices/BaseTpaClaimImportService.php
@@ -81,7 +81,7 @@ abstract class BaseTpaClaimImportService
$this->db->transBegin();
try {
- $file_id = $params['file_id'];
+ $file_id = $params['file_id'];
$ticketMasterData = $this->mapClaimMasterData($file_id);
// Check if mapping failed
@@ -101,6 +101,12 @@ abstract class BaseTpaClaimImportService
$this->db->transRollback();
return ['status' => false, 'message' => 'Ticket Master Claim bulk insert failed'];
}
+ // Map newly created ticket IDs back to the TPA staging table
+ if (!$this->updateTicketIdInTPATable($file_id)) {
+ $this->db->transRollback();
+ return ['status' => false, 'message' => 'Updating ticket_id in TPA table failed'];
+ }
+
$message .= 'Ticket Master Claim bulk insert success. ';
$hasExecutedTask = true;
}else{
@@ -328,6 +334,16 @@ abstract class BaseTpaClaimImportService
return $employeeData ?? [];
}
+ public function checkStatusMapping($statusArray, $statusString)
+ {
+ foreach ($statusArray as $key => $value) {
+ if (strtolower($statusString) == strtolower($key) || strtolower($statusString) == strtolower(trim($key))) {
+ return $value;
+ }
+ }
+ return null;
+ }
+
/**
* Map Excel rows to TPA table structure
*/
@@ -349,9 +365,9 @@ abstract class BaseTpaClaimImportService
abstract protected function importClaimMaster(array $data): bool;
/**
- * Update TPA table with ticket_master primary key
+ * Update TPA table with ticket_master primary key for a given file.
*/
- abstract protected function updateTicketIdInTPATable(): bool;
+ abstract protected function updateTicketIdInTPATable(int $fileId): bool;
/**
* Update TPA table with ticket_master insert rejected reason
diff --git a/app/Libraries/TPAClaimsImportServices/FhplClaimImportService.php b/app/Libraries/TPAClaimsImportServices/FhplClaimImportService.php
index 324fd3a7..7123230c 100644
--- a/app/Libraries/TPAClaimsImportServices/FhplClaimImportService.php
+++ b/app/Libraries/TPAClaimsImportServices/FhplClaimImportService.php
@@ -181,6 +181,13 @@ class FhplClaimImportService extends BaseTpaClaimImportService
protected $statusMapping = [
'Settled' => 11,
'Rejected' => 8,
+ 'Paid' => 11,
+ 'Approved' => 9,
+ 'Closed' => 12,
+ 'Under Process' => 5,
+ 'Query' => 4,
+ 'Required Information' => 4,
+ 'In-Progress' => 5,
];
protected $dateColumns = [
@@ -235,14 +242,31 @@ class FhplClaimImportService extends BaseTpaClaimImportService
}
- public function updateTicketIdInTPATable(): bool
+ public function updateTicketIdInTPATable(int $fileId): bool
{
- if (empty($data)) {
- return false;
+ // Join ticket_master with FHPL staging on file_id + claim_dump_ref_id -> id
+ $rows = $this->db->table('claims_dump_fhpl cd')
+ ->select('cd.id, tm.id AS ticket_id')
+ ->join('ticket_master tm', 'tm.claim_dump_ref_id = cd.id AND tm.file_id = cd.file_id', 'inner')
+ ->where('cd.is_active', 1)
+ ->where('cd.file_id', $fileId)
+ ->where('cd.ticket_id IS NULL')
+ ->get()
+ ->getResultArray();
+
+ if (empty($rows)) {
+ return true;
}
-
- $builder = $this->db->table('claims_dump_fhpl');
- return $builder->updateBatch($data, 'id');
+
+ $updateData = [];
+ foreach ($rows as $row) {
+ $updateData[] = [
+ 'id' => $row['id'],
+ 'ticket_id' => $row['ticket_id'],
+ ];
+ }
+
+ return $this->db->table('claims_dump_fhpl')->updateBatch($updateData, 'id') !== false;
}
@@ -400,7 +424,7 @@ class FhplClaimImportService extends BaseTpaClaimImportService
}
// Meta fields
- $item['claim_status_id'] = $statusMapping[$row['current_claim_status']] ?? 61;
+ $item['claim_status_id'] = $this->checkStatusMapping($this->statusMapping, $row['current_claim_status']) ?? 61;
$item['file_id'] = $file_id;
$item['claim_dump_ref_id'] = $row['id'];
$item['created_by'] = $file_data['created_by'] ?? null;
diff --git a/app/Libraries/TPAClaimsImportServices/IciciClaimImportService.php b/app/Libraries/TPAClaimsImportServices/IciciClaimImportService.php
index 132986a2..6e055139 100644
--- a/app/Libraries/TPAClaimsImportServices/IciciClaimImportService.php
+++ b/app/Libraries/TPAClaimsImportServices/IciciClaimImportService.php
@@ -106,7 +106,13 @@ class IciciClaimImportService extends BaseTpaClaimImportService
protected $statusMapping = [
'PAID' => 11,
+ 'SETTLED' => 11,
'REJECTED' => 8,
+ 'APPROVED' => 9,
+ 'CLOSED' => 12,
+ 'QUERY' => 4,
+ 'REQUIRED INFORMATION' => 4,
+ 'IN-PROGRESS' => 5,
];
protected $dateColumns = [
@@ -152,14 +158,30 @@ class IciciClaimImportService extends BaseTpaClaimImportService
}
- public function updateTicketIdInTPATable(): bool
+ public function updateTicketIdInTPATable(int $fileId): bool
{
- if (empty($data)) {
- return false;
+ $rows = $this->db->table('claims_dump_icici cd')
+ ->select('cd.id, tm.id AS ticket_id')
+ ->join('ticket_master tm', 'tm.claim_dump_ref_id = cd.id AND tm.file_id = cd.file_id', 'inner')
+ ->where('cd.is_active', 1)
+ ->where('cd.file_id', $fileId)
+ ->where('cd.ticket_id IS NULL')
+ ->get()
+ ->getResultArray();
+
+ if (empty($rows)) {
+ return true;
}
-
- $builder = $this->db->table('claims_dump_icici');
- return $builder->upsertBatch($data, 'id');
+
+ $updateData = [];
+ foreach ($rows as $row) {
+ $updateData[] = [
+ 'id' => $row['id'],
+ 'ticket_id' => $row['ticket_id'],
+ ];
+ }
+
+ return $this->db->table('claims_dump_icici')->updateBatch($updateData, 'id') !== false;
}
@@ -287,7 +309,7 @@ class IciciClaimImportService extends BaseTpaClaimImportService
$item['tpa_id'] = $client_policy_data['tpa_id'] ?? null;
$item['acm_id'] = $client_policy_data['acm_id'] ?? null;
$item['policy_no'] = $client_policy_data['policy_no'] ?? null;
- $item['relationship'] = $this->convertRelation($row['relation_group'] ?? '');
+ $item['relationship'] = $this->convertRelation($row['relation'] ?? '');
$employee_data = $this->getEmployeeDetails($file_data['client_id'], $file_data['client_policy_id'], $row['employee_member_id'], $item['relationship']);
@@ -317,7 +339,7 @@ class IciciClaimImportService extends BaseTpaClaimImportService
}
// Meta fields
- $item['claim_status_id'] = $statusMapping[$row['updated_status']] ?? 61;
+ $item['claim_status_id'] = $this->checkStatusMapping($this->statusMapping, $row['updated_status']) ?? 61;
$item['claim_dump_ref_id'] = $row['id'];
$item['file_id'] = $file_id;
$item['created_by'] = $file_data['created_by'] ?? null;
diff --git a/app/Libraries/TPAClaimsImportServices/MediAssistClaimImportService.php b/app/Libraries/TPAClaimsImportServices/MediAssistClaimImportService.php
index d052c9f5..4a2952fb 100644
--- a/app/Libraries/TPAClaimsImportServices/MediAssistClaimImportService.php
+++ b/app/Libraries/TPAClaimsImportServices/MediAssistClaimImportService.php
@@ -158,12 +158,15 @@ class MediAssistClaimImportService extends BaseTpaClaimImportService
protected $statusMapping = [
'Settled' => 11,
'Rejected' => 8,
+ 'Paid' => 11,
'Denied' => 8,
'Cancelled' => 13,
'Processed' => 61,
'Information Awaited' => 4,
'Denied Letter Sent' => 66,
'Cashless Document Awaited' => 3,
+ 'Approved' => 9,
+ 'Closed' => 12,
];
/**
@@ -192,16 +195,30 @@ class MediAssistClaimImportService extends BaseTpaClaimImportService
}
- public function updateTicketIdInTPATable(): bool
+ public function updateTicketIdInTPATable(int $fileId): bool
{
- if (empty($data)) {
- return false;
- }
-
- $builder = $this->db->table('claims_dump_medi_assist');
- $builder->insertBatch($data);
+ $rows = $this->db->table('claims_dump_medi_assist cd')
+ ->select('cd.id, tm.id AS ticket_id')
+ ->join('ticket_master tm', 'tm.claim_dump_ref_id = cd.id AND tm.file_id = cd.file_id', 'inner')
+ ->where('cd.is_active', 1)
+ ->where('cd.file_id', $fileId)
+ ->where('cd.ticket_id IS NULL')
+ ->get()
+ ->getResultArray();
- return true;
+ if (empty($rows)) {
+ return true;
+ }
+
+ $updateData = [];
+ foreach ($rows as $row) {
+ $updateData[] = [
+ 'id' => $row['id'],
+ 'ticket_id' => $row['ticket_id'],
+ ];
+ }
+
+ return $this->db->table('claims_dump_medi_assist')->updateBatch($updateData, 'id') !== false;
}
@@ -356,8 +373,8 @@ class MediAssistClaimImportService extends BaseTpaClaimImportService
// Meta fields
$item['claim_dump_ref_id'] = $row['id'];
- $item['file_id'] = $file_id;
- $item['claim_status_id'] = $statusMapping[$row['claim_status']] ?? 61;
+ $item['file_id'] = $file_id;
+ $item['claim_status_id'] = $this->checkStatusMapping($this->statusMapping, $row['claim_status']) ?? 61;
$item['created_by'] = $file_data['created_by'] ?? null;
$item['claim_type'] = 1;
$item['priority'] = 1;
diff --git a/app/Libraries/TPAClaimsImportServices/RcareClaimImportService.php b/app/Libraries/TPAClaimsImportServices/RcareClaimImportService.php
index 770caadd..afe95c4f 100644
--- a/app/Libraries/TPAClaimsImportServices/RcareClaimImportService.php
+++ b/app/Libraries/TPAClaimsImportServices/RcareClaimImportService.php
@@ -96,14 +96,15 @@ class RcareClaimImportService extends BaseTpaClaimImportService
];
protected $statusMapping = [
+ 'CL Paid with Settlement Letter' => 11,
'Settled' => 11,
+ 'Paid' => 11,
'Rejected' => 8,
- 'Denied' => 8,
- 'Cancelled' => 13,
- 'Processed' => 61,
- 'Information Awaited' => 4,
- 'Denied Letter Sent' => 66,
- 'Cashless Document Awaited' => 3,
+ 'Approved' => 9,
+ 'Closed' => 12,
+ 'CL Rejected' => 8,
+ 'CL Approved' => 9,
+ 'AL Closed' => 12,
];
protected $dateColumns = [
@@ -143,14 +144,30 @@ class RcareClaimImportService extends BaseTpaClaimImportService
}
- public function updateTicketIdInTPATable(): bool
+ public function updateTicketIdInTPATable(int $fileId): bool
{
- if (empty($data)) {
- return false;
+ $rows = $this->db->table('claims_dump_reliance cd')
+ ->select('cd.id, tm.id AS ticket_id')
+ ->join('ticket_master tm', 'tm.claim_dump_ref_id = cd.id AND tm.file_id = cd.file_id', 'inner')
+ ->where('cd.is_active', 1)
+ ->where('cd.file_id', $fileId)
+ ->where('cd.ticket_id IS NULL')
+ ->get()
+ ->getResultArray();
+
+ if (empty($rows)) {
+ return true;
}
-
- $builder = $this->db->table('claims_dump_reliance');
- return $builder->updateBatch($data, 'id');
+
+ $updateData = [];
+ foreach ($rows as $row) {
+ $updateData[] = [
+ 'id' => $row['id'],
+ 'ticket_id' => $row['ticket_id'],
+ ];
+ }
+
+ return $this->db->table('claims_dump_reliance')->updateBatch($updateData, 'id') !== false;
}
@@ -307,7 +324,7 @@ class RcareClaimImportService extends BaseTpaClaimImportService
}
// Meta fields
- $item['claim_status_id'] = $statusMapping[$row['final_status']] ?? 61;
+ $item['claim_status_id'] = $this->checkStatusMapping($this->statusMapping, $row['final_status']) ?? 61;
$item['file_id'] = $file_id;
$item['created_by'] = $file_data['created_by'] ?? null;
$item['claim_dump_ref_id'] = $row['id'];
diff --git a/app/Libraries/TPAClaimsImportServices/VidalClaimImportService.php b/app/Libraries/TPAClaimsImportServices/VidalClaimImportService.php
index c90d580b..70a1340c 100644
--- a/app/Libraries/TPAClaimsImportServices/VidalClaimImportService.php
+++ b/app/Libraries/TPAClaimsImportServices/VidalClaimImportService.php
@@ -349,10 +349,17 @@ class VidalClaimImportService extends BaseTpaClaimImportService
];
protected $statusMapping = [
- 'CL Paid with Settlement Letter' => 11,
- 'CL Rejected' => 8,
- 'CL Approved' => 9,
- 'AL Closed' => 12,
+ 'Settled' => 11,
+ 'Rejected' => 8,
+ 'Paid' => 11,
+ 'Denied' => 8,
+ 'Cancelled' => 13,
+ 'Processed' => 61,
+ 'Information Awaited' => 4,
+ 'Denied Letter Sent' => 66,
+ 'Cashless Document Awaited' => 3,
+ 'Approved' => 9,
+ 'Closed' => 12,
];
@@ -382,14 +389,30 @@ class VidalClaimImportService extends BaseTpaClaimImportService
}
- public function updateTicketIdInTPATable(): bool
+ public function updateTicketIdInTPATable(int $fileId): bool
{
- if (empty($data)) {
- return false;
+ $rows = $this->db->table('claims_dump_vidal cd')
+ ->select('cd.id, tm.id AS ticket_id')
+ ->join('ticket_master tm', 'tm.claim_dump_ref_id = cd.id AND tm.file_id = cd.file_id', 'inner')
+ ->where('cd.is_active', 1)
+ ->where('cd.file_id', $fileId)
+ ->where('cd.ticket_id IS NULL')
+ ->get()
+ ->getResultArray();
+
+ if (empty($rows)) {
+ return true;
}
-
- $builder = $this->db->table('claims_dump_vidal');
- return $builder->updateBatch($data, 'id');
+
+ $updateData = [];
+ foreach ($rows as $row) {
+ $updateData[] = [
+ 'id' => $row['id'],
+ 'ticket_id' => $row['ticket_id'],
+ ];
+ }
+
+ return $this->db->table('claims_dump_vidal')->updateBatch($updateData, 'id') !== false;
}
@@ -542,7 +565,7 @@ class VidalClaimImportService extends BaseTpaClaimImportService
}
// Meta fields
- $item['claim_status_id'] = $statusMapping[$row['claim_status']] ?? 61;
+ $item['claim_status_id'] = $this->checkStatusMapping($this->statusMapping, $row['claim_status']) ?? 61;
$item['file_id'] = $file_id;
$item['claim_dump_ref_id'] = $row['id'];
$item['created_by'] = $file_data['created_by'] ?? null;
diff --git a/app/Models/ClientModel.php b/app/Models/ClientModel.php
index c99a50f4..0a291e7c 100755
--- a/app/Models/ClientModel.php
+++ b/app/Models/ClientModel.php
@@ -228,8 +228,14 @@ class ClientModel extends Model
return $result;
}
+ private const ALLOWED_CONTACT_FIELDS = ['email', 'mobile', 'phone', 'name', 'contact_name', 'contact_email', 'contact_mobile'];
+
public function isDuplicateByClientBranch($value, $field, $clientId, $branchId)
{
+ if (!in_array($field, self::ALLOWED_CONTACT_FIELDS, true)) {
+ throw new \InvalidArgumentException("Invalid field name: {$field}");
+ }
+
$builder = $this->db->table('level_contacts lc')
->select('lc.id')
->join('client_branch cb', 'lc.ref_id = cb.id', 'left')
diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php
index 8171df0c..92efedf8 100755
--- a/app/Models/EmployeePolicyModel.php
+++ b/app/Models/EmployeePolicyModel.php
@@ -1146,6 +1146,8 @@ class EmployeePolicyModel extends Model
$endorsement_condition = "{$insurer_or_tpa}" === 'tpa' ? "AND (a.endorsement_id IS NULL OR a.endorsement_id = '')" : "AND (a.endorsement_id IS NULL OR a.endorsement_id = '')";
+ $add_one_day = (int)$add_one_day;
+
$query = $this->db->query("
SELECT DISTINCT
a.id as endorsement_primarykey,
@@ -1688,30 +1690,29 @@ class EmployeePolicyModel extends Model
public function bulkUpdate($emp_details)
{
// Extract IDs, tpa_ids, and uhids
- $ids = array_column($emp_details, 'id');
+ $ids = array_map('intval', array_column($emp_details, 'id'));
$tpa_ids = array_column($emp_details, 'tpa_id');
$uhids = array_column($emp_details, 'uhid');
- // Escape values for SQL
- $escapedIds = array_map([$this->db, 'escape'], $ids);
+ // Escape string values for SQL
$escapedTpaIds = array_map([$this->db, 'escape'], $tpa_ids);
$escapedUhids = array_map([$this->db, 'escape'], $uhids);
- // Construct the CASE statements
+ // Construct the CASE statements with int-cast IDs
$caseTpaId = array_map(function($id, $tpa_id) {
- return "WHEN id = $id THEN $tpa_id";
- }, $escapedIds, $escapedTpaIds);
+ return "WHEN id = {$id} THEN {$tpa_id}";
+ }, $ids, $escapedTpaIds);
$caseUhid = array_map(function($id, $uhid) {
- return "WHEN id = $id THEN $uhid";
- }, $escapedIds, $escapedUhids);
+ return "WHEN id = {$id} THEN {$uhid}";
+ }, $ids, $escapedUhids);
// Convert cases to a string
$caseTpaIdString = implode(' ', $caseTpaId);
$caseUhidString = implode(' ', $caseUhid);
// Convert ids to a string
- $idsString = implode(', ', $escapedIds);
+ $idsString = implode(', ', $ids);
// Construct the SQL query
$sql = "
@@ -1837,18 +1838,19 @@ class EmployeePolicyModel extends Model
$groupKeys = [];
foreach ($endorsement_details as $row) {
- $groupKey = $this->db->escape($row['group_key']);
+ $groupKey = (int)$row['group_key'];
$endorsementId = $this->db->escape($row['endorsement_id']);
$caseParts[] = "WHEN group_key = {$groupKey} THEN {$endorsementId}";
$groupKeys[] = $groupKey;
}
+ $groupKeysStr = implode(', ', $groupKeys);
$sql = "
UPDATE emp_endorsement
SET
endorsement_id = CASE " . implode(' ', $caseParts) . " END,
status = 'complete'
- WHERE group_key IN (" . implode(', ', $groupKeys) . ")
+ WHERE group_key IN ({$groupKeysStr})
";
$this->db->query($sql);
@@ -1866,26 +1868,37 @@ class EmployeePolicyModel extends Model
public function bulkUpdateForCorrection($emp_details){
+ $ids = [];
+ $caseStatements = [];
+
+ $employeeTableFields = $this->db->getFieldNames('employees');
+
foreach ($emp_details as $employee) {
- $id = $this->db->escape($employee['id']);
+ $id = (int)$employee['id'];
$ids[] = $id;
foreach ($employee as $field => $value) {
if ($field === 'id') continue;
+
+ $safeField = preg_replace('/[^a-zA-Z0-9_]/', '', $field);
+ if (!in_array($safeField, $employeeTableFields, true)) {
+ continue;
+ }
+
$escapedValue = $this->db->escape($value);
- if (!isset($caseStatements[$field])) {
- $caseStatements[$field] = [];
+ if (!isset($caseStatements[$safeField])) {
+ $caseStatements[$safeField] = [];
}
- $caseStatements[$field][] = "WHEN id = $id THEN $escapedValue";
+ $caseStatements[$safeField][] = "WHEN id = {$id} THEN {$escapedValue}";
}
}
// Construct the CASE strings
$caseStrings = [];
foreach ($caseStatements as $field => $cases) {
- $caseStrings[] = "$field = CASE " . implode(' ', $cases) . " END";
+ $caseStrings[] = "{$field} = CASE " . implode(' ', $cases) . " END";
}
// Convert ids to a string
@@ -1941,7 +1954,7 @@ class EmployeePolicyModel extends Model
->getRowArray();
// Determine if one day should be added for deletion
- $add_one_day = (!empty($result) && $result['deletion_add_day'] == 1) ? 1 : 0;
+ $add_one_day = (int)((!empty($result) && $result['deletion_add_day'] == 1) ? 1 : 0);
$query = $this->db->query("
@@ -2130,14 +2143,17 @@ class EmployeePolicyModel extends Model
$caseEndorsementId = "CASE ";
$ids = [];
foreach ($array as $item) {
- $caseStatus .= "WHEN id = {$item['id']} THEN '{$item['status']}' ";
- $caseEndorsementId .= "WHEN id = {$item['id']} THEN '{$item['endorsement_id']}' ";
- $ids[] = $item['id'];
+ $safeId = (int)$item['id'];
+ $safeStatus = $this->db->escape($item['status']);
+ $safeEndorsementId = $this->db->escape($item['endorsement_id']);
+ $caseStatus .= "WHEN id = {$safeId} THEN {$safeStatus} ";
+ $caseEndorsementId .= "WHEN id = {$safeId} THEN {$safeEndorsementId} ";
+ $ids[] = $safeId;
}
$caseStatus .= "END";
$caseEndorsementId .= "END";
$ids = implode(',', $ids);
- $query = "UPDATE emp_endorsement SET status = $caseStatus, endorsement_id = $caseEndorsementId WHERE id IN ($ids);"; // Execute the query
+ $query = "UPDATE emp_endorsement SET status = $caseStatus, endorsement_id = $caseEndorsementId WHERE id IN ($ids);";
$this->db->query($query);
}
diff --git a/app/Models/ExpenseModel.php b/app/Models/ExpenseModel.php
new file mode 100644
index 00000000..7d4a37c1
--- /dev/null
+++ b/app/Models/ExpenseModel.php
@@ -0,0 +1,73 @@
+validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
- $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- ->where('policy_transaction.' . $date_type . '<=', $endDate);
+ $builder->where('policy_transaction.' . $date_type . ' >=', $startDate)
+ ->where('policy_transaction.' . $date_type . ' <=', $endDate);
} else {
// $fromDate = date('Y-m-d', strtotime('-30 days'));
@@ -835,18 +852,16 @@
// Check if the start date and end date are provided
if ($start_date != 0 && $end_date != 0 && $date_type != 0 && $date_type != 'statement_month') {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
- // $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- // ->where('policy_transaction.' . $date_type . '<=', $endDate);
-
if($date_type == "policy_issue_date"){
$builder->where("pt_co_share_details.pt_policy_issue_date >=", $startDate)
->where("pt_co_share_details.pt_policy_issue_date <=", $endDate);
}else{
- $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- ->where('policy_transaction.' . $date_type . '<=', $endDate);
+ $builder->where('policy_transaction.' . $date_type . ' >=', $startDate)
+ ->where('policy_transaction.' . $date_type . ' <=', $endDate);
}
}
@@ -1064,6 +1079,7 @@
// Optimize Date Filtering
if (!empty($start_date) && !empty($end_date) && !empty($date_type)) {
+ $this->validateDateType($date_type);
$startDate = change_date_format($start_date, 'd/m/Y', 'Y-m-d 00:00:00');
$endDate = change_date_format($end_date, 'd/m/Y', 'Y-m-d 23:59:59');
@@ -1165,6 +1181,7 @@
if ($start_date != 0 && $end_date != 0 && $date_type != 0) {
+ $this->validateDateType($date_type);
$startDate = change_date_format($start_date, 'd/m/Y', 'Y-m-d 00:00:00');
$endDate = change_date_format($end_date, 'd/m/Y', 'Y-m-d 23:59:59');
@@ -1172,8 +1189,8 @@
$builder->where("pt_co_share_details.pt_policy_issue_date >=", $startDate)
->where("pt_co_share_details.pt_policy_issue_date <=", $endDate);
}else{
- $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- ->where('policy_transaction.' . $date_type . '<=', $endDate);
+ $builder->where('policy_transaction.' . $date_type . ' >=', $startDate)
+ ->where('policy_transaction.' . $date_type . ' <=', $endDate);
}
} else {
@@ -1349,18 +1366,16 @@
if ($start_date != 0 && $end_date != 0 && $date_type != 0) {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
- // $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- // ->where('policy_transaction.' . $date_type . '<=', $endDate);
-
if($date_type == "policy_issue_date"){
$builder->where("pt_co_share_details.pt_policy_issue_date >=", $startDate)
->where("pt_co_share_details.pt_policy_issue_date <=", $endDate);
}else{
- $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- ->where('policy_transaction.' . $date_type . '<=', $endDate);
+ $builder->where('policy_transaction.' . $date_type . ' >=', $startDate)
+ ->where('policy_transaction.' . $date_type . ' <=', $endDate);
}
} else {
@@ -1463,18 +1478,16 @@
if ($start_date != 0 && $end_date != 0 && $date_type != 0) {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
- // $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- // ->where('policy_transaction.' . $date_type . '<=', $endDate);
-
if($date_type == "policy_issue_date"){
$builder->where("pt_co_share_details.pt_policy_issue_date >=", $startDate)
->where("pt_co_share_details.pt_policy_issue_date <=", $endDate);
}else{
- $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- ->where('policy_transaction.' . $date_type . '<=', $endDate);
+ $builder->where('policy_transaction.' . $date_type . ' >=', $startDate)
+ ->where('policy_transaction.' . $date_type . ' <=', $endDate);
}
} else {
@@ -1574,18 +1587,16 @@
if ($start_date != 0 && $end_date != 0 && $date_type != 0) {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
- // $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- // ->where('policy_transaction.' . $date_type . '<=', $endDate);
-
if($date_type == "policy_issue_date"){
$builder->where("pt_co_share_details.pt_policy_issue_date >=", $startDate)
->where("pt_co_share_details.pt_policy_issue_date <=", $endDate);
}else{
- $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- ->where('policy_transaction.' . $date_type . '<=', $endDate);
+ $builder->where('policy_transaction.' . $date_type . ' >=', $startDate)
+ ->where('policy_transaction.' . $date_type . ' <=', $endDate);
}
} else {
@@ -1689,18 +1700,16 @@
// Date range filtering
if ($start_date != 0 && $end_date != 0 && $date_type != 0) {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
- // $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- // ->where('policy_transaction.' . $date_type . '<=', $endDate);
-
if($date_type == "policy_issue_date"){
$builder->where("pt_co_share_details.pt_policy_issue_date >=", $startDate)
->where("pt_co_share_details.pt_policy_issue_date <=", $endDate);
}else{
- $builder->where('policy_transaction.' . $date_type . '>=', $startDate)
- ->where('policy_transaction.' . $date_type . '<=', $endDate);
+ $builder->where('policy_transaction.' . $date_type . ' >=', $startDate)
+ ->where('policy_transaction.' . $date_type . ' <=', $endDate);
}
} else {
$fromDate = date('Y-m-d', strtotime('-90 days'));
@@ -2364,6 +2373,7 @@
}
if ($start_date != 0 && $end_date != 0 && $date_type != 0 && $date_type != 'statement_month') {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
@@ -2489,6 +2499,7 @@
// 3. Date condition (except statement_month)
if ($start_date != 0 && $end_date != 0 && $date_type != 0 && $date_type != 'statement_month') {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
@@ -3080,6 +3091,7 @@
// 3. Date condition (except statement_month)
if ($start_date != 0 && $end_date != 0 && $date_type != 0 && $date_type != 'statement_month') {
+ $this->validateDateType($date_type);
$startDate = date('Y-m-d 00:00:00', strtotime($start_date));
$endDate = date('Y-m-d 23:59:59', strtotime($end_date));
diff --git a/app/Models/SalesActivityModel.php b/app/Models/SalesActivityModel.php
index 8d82097f..e9a3801d 100644
--- a/app/Models/SalesActivityModel.php
+++ b/app/Models/SalesActivityModel.php
@@ -38,7 +38,7 @@ class SalesActivityModel extends Model
// Validation
protected $validationRules = [
'lead_id' => 'required|integer',
- 'activity_type' => 'required|in_list[Call,Email,Meeting,Demo,Share,Todo,Visit]',
+ 'activity_type' => 'required|in_list[Call,Email,Meeting,Visit,Demo,Share Docs,To Do]',
'notes' => 'required',
'scheduled_date' => 'required',
'assigned_to' => 'required|integer',
@@ -102,7 +102,7 @@ class SalesActivityModel extends Model
$assignedToIds = is_array($assigned_to) ? $assigned_to : explode(',', $assigned_to);
// Now it is guaranteed to be an array, making whereIn perfectly safe
- $this->whereIn('sales_actual_leads.assigned_to', $assignedToIds);
+ $this->whereIn('sales_activities.assigned_to', $assignedToIds);
}
diff --git a/app/Models/SalesTargetModel.php b/app/Models/SalesTargetModel.php
new file mode 100644
index 00000000..f23193f6
--- /dev/null
+++ b/app/Models/SalesTargetModel.php
@@ -0,0 +1,38 @@
+ 'required|integer',
+ 'fy_year' => 'required|max_length[9]',
+ 'target_amount' => 'required|decimal',
+ ];
+
+ protected $validationMessages = [
+ 'user_id' => ['required' => 'User is required'],
+ 'fy_year' => ['required' => 'Financial year is required'],
+ 'target_amount' => ['required' => 'Target amount is required', 'decimal' => 'Target amount must be a valid number'],
+ ];
+}
\ No newline at end of file
diff --git a/app/Models/TicketMasterModel.php b/app/Models/TicketMasterModel.php
index 324a18db..14101188 100644
--- a/app/Models/TicketMasterModel.php
+++ b/app/Models/TicketMasterModel.php
@@ -1,5 +1,4 @@
select("ticket_mail_template.*, CASE
- WHEN employees.email_corporate IS NULL OR employees.email_corporate = ''
- THEN ticket_master.emp_mail
- ELSE employees.email_corporate
+ ->select("ticket_mail_template.*, CASE
+ WHEN employees.email_corporate IS NULL OR employees.email_corporate = ''
+ THEN ticket_master.emp_mail
+ ELSE employees.email_corporate
END as emp_mail, ,ticket_master.claim_status_id")
->join('ticket_claim_status', 'ticket_master.claim_status_id = ticket_claim_status.id and ticket_claim_status.is_active = 1')
->join('ticket_mail_template', '
- ticket_claim_status.trigger_type = ticket_mail_template.trigger_type
- and ticket_claim_status.ticket_type = ticket_mail_template.ticket_type
+ ticket_claim_status.trigger_type = ticket_mail_template.trigger_type
+ and ticket_claim_status.ticket_type = ticket_mail_template.ticket_type
and ticket_mail_template.is_active = 1')
->join('employees', 'employees.id = ticket_master.emp_id', 'left')
->where('ticket_master.id', $ticket_id)
@@ -173,11 +171,11 @@ class TicketMasterModel extends Model
{
$ticket_data = $this->select("
ticket_master.*,
- CASE
- WHEN employees.email_corporate IS NULL OR employees.email_corporate = ''
- THEN ticket_master.emp_mail
- ELSE employees.email_corporate
- END as emp_mail,
+ CASE
+ WHEN employees.email_corporate IS NULL OR employees.email_corporate = ''
+ THEN ticket_master.emp_mail
+ ELSE employees.email_corporate
+ END as emp_mail,
user_profiles.first_name as acm,
user_profiles.mobile as acm_mobile,
@@ -205,7 +203,7 @@ class TicketMasterModel extends Model
//get TAT report BAND wise Data
// public function getTATReport($ticket_type = null, $start_date = null, $end_date = null)
- // {
+ // {
// //set default last 3 months data date
// $fromDate = date('Y-m-d', strtotime('-90 days'));
// $toDate = date('Y-m-d 23:59:59');
@@ -222,9 +220,9 @@ class TicketMasterModel extends Model
// }
// // Fetch claim statuses from the `ticket_claim_status` table
- // $statusQuery = " SELECT
+ // $statusQuery = " SELECT
// id, claim_status, ticket_type
- // FROM ticket_claim_status
+ // FROM ticket_claim_status
// Where is_active = 1
// $ticket_type_data_1
// ";
@@ -273,7 +271,6 @@ class TicketMasterModel extends Model
// $dynamicSelect = rtrim($dynamicSelect, ', ');
// // dd($dynamicSelect);
-
// // Construct the full SQL query
// $sql = "
// SELECT
@@ -326,7 +323,7 @@ class TicketMasterModel extends Model
// WHERE
// tm.ticket_type_id = tcs.id
// $ticket_type_data_2
- // AND tm.created_at >= '$fromDate'
+ // AND tm.created_at >= '$fromDate'
// AND tm.created_at <= '$toDate'
// AND tm.is_active = 1
// AND th.is_active = 1
@@ -371,9 +368,9 @@ class TicketMasterModel extends Model
// }
// // Fetch claim statuses from the `ticket_claim_status` table
- // $statusQuery = " SELECT
+ // $statusQuery = " SELECT
// id, claim_status, ticket_type
- // FROM ticket_claim_status
+ // FROM ticket_claim_status
// Where is_active = 1
// $ticket_type_data_1
// ";
@@ -422,7 +419,6 @@ class TicketMasterModel extends Model
// $dynamicSelect = rtrim($dynamicSelect, ', ');
// // dd($dynamicSelect);
-
// // Construct the full SQL query
// $sql = "
// SELECT
@@ -451,20 +447,20 @@ class TicketMasterModel extends Model
// FROM
// ticket_master tm
// LEFT JOIN (
- // SELECT
- // th.ticket_id,
+ // SELECT
+ // th.ticket_id,
// th.new_value AS claim_status_id,
// MAX(th.created_at) AS change_date
- // FROM
- // ticket_history th
- // WHERE
+ // FROM
+ // ticket_history th
+ // WHERE
// th.field_name = 'claim_status_id'
// AND th.is_active = 1
- // GROUP BY
+ // GROUP BY
// th.ticket_id, th.new_value
// ) AS latest_status ON latest_status.ticket_id = tm.id
// WHERE tm.is_active = 1
- // AND tm.created_at >= '$fromDate'
+ // AND tm.created_at >= '$fromDate'
// AND tm.created_at <= '$toDate'
// " . (!empty($ticket_type) ? " AND tm.ticket_type_id = $ticket_type" : "") . "
// GROUP BY tm.id, latest_status.claim_status_id, latest_status.change_date, tm.created_at
@@ -493,33 +489,33 @@ class TicketMasterModel extends Model
{
// Set default date range (last 90 days)
$fromDate = date('Y-m-d', strtotime('-90 days'));
- $toDate = date('Y-m-d 23:59:59');
-
- if (!empty($start_date) && !empty($end_date)) {
+ $toDate = date('Y-m-d 23:59:59');
+
+ if (! empty($start_date) && ! empty($end_date)) {
$fromDate = change_date_format($start_date);
- $toDate = change_date_format($end_date);
+ $toDate = change_date_format($end_date);
}
-
+
// Get all active claim statuses
$statusQuery = $this->db->table('ticket_claim_status')
->select('id, claim_status')
->where('is_active', 1)
->orderBy('id', 'ASC');
-
- if (!empty($ticket_type)) {
+
+ if (! empty($ticket_type)) {
$statusQuery->where('ticket_type', $ticket_type);
}
-
+
$statusResult = $statusQuery->get()->getResultArray();
-
+
// Create a list of all TAT categories we want in the output
$tatCategories = [
'Above 20 Days',
- '13-20 Days',
+ '13-20 Days',
'7-12 Days',
- '0-6 Days'
+ '0-6 Days',
];
-
+
// Initialize the result array with all TAT categories
$result = [];
foreach ($tatCategories as $category) {
@@ -529,39 +525,39 @@ class TicketMasterModel extends Model
}
$result[] = $row;
}
-
+
// Get the base query for ticket counts by status and TAT category
$query = $this->db->table('ticket_master tm')
->select([
'tcs.claim_status',
'CASE
WHEN DATEDIFF(CURDATE(), COALESCE(
- (SELECT MAX(th.created_at)
- FROM ticket_history th
- WHERE th.ticket_id = tm.id
+ (SELECT MAX(th.created_at)
+ FROM ticket_history th
+ WHERE th.ticket_id = tm.id
AND th.field_name = "claim_status_id"
AND th.is_active = 1),
tm.created_at
)) BETWEEN 0 AND 6 THEN "0-6 Days"
WHEN DATEDIFF(CURDATE(), COALESCE(
- (SELECT MAX(th.created_at)
- FROM ticket_history th
- WHERE th.ticket_id = tm.id
+ (SELECT MAX(th.created_at)
+ FROM ticket_history th
+ WHERE th.ticket_id = tm.id
AND th.field_name = "claim_status_id"
AND th.is_active = 1),
tm.created_at
)) BETWEEN 7 AND 12 THEN "7-12 Days"
WHEN DATEDIFF(CURDATE(), COALESCE(
- (SELECT MAX(th.created_at)
- FROM ticket_history th
- WHERE th.ticket_id = tm.id
+ (SELECT MAX(th.created_at)
+ FROM ticket_history th
+ WHERE th.ticket_id = tm.id
AND th.field_name = "claim_status_id"
AND th.is_active = 1),
tm.created_at
)) BETWEEN 13 AND 20 THEN "13-20 Days"
ELSE "Above 20 Days"
END AS tat_category',
- 'COUNT(*) AS count'
+ 'COUNT(*) AS count',
])
->join('ticket_claim_status tcs', 'tcs.id = tm.claim_status_id AND tcs.is_active = 1')
->where('tm.is_active', 1)
@@ -569,23 +565,23 @@ class TicketMasterModel extends Model
->where('tm.created_at <=', $toDate)
->groupBy('tcs.claim_status, tat_category')
->orderBy('FIELD(tat_category, "Above 20 Days", "13-20 Days", "7-12 Days", "0-6 Days")');
-
- if (!empty($ticket_type)) {
+
+ if (! empty($ticket_type)) {
$query->where('tm.ticket_type_id', $ticket_type);
}
-
+
$countResults = $query->get()->getResultArray();
-
+
// Populate the result array with actual counts
foreach ($countResults as $row) {
foreach ($result as &$categoryRow) {
if ($categoryRow['TAT_Category'] === $row['tat_category']) {
- $categoryRow[$row['claim_status']] = (int)$row['count'];
+ $categoryRow[$row['claim_status']] = (int) $row['count'];
break;
}
}
}
-
+
return $result;
}
@@ -593,21 +589,21 @@ class TicketMasterModel extends Model
{
$ticket_type_data_1 = "";
$ticket_type_data_2 = "";
- $statusBinds = [];
+ $statusBinds = [];
- if (!empty($policy_type)) {
- $ticket_type_data_1 = "AND ticket_type = :policy_type:";
- $ticket_type_data_2 = "AND master.ticket_type_id = :policy_type:";
+ if (! empty($policy_type)) {
+ $ticket_type_data_1 = "AND ticket_type = :policy_type:";
+ $ticket_type_data_2 = "AND master.ticket_type_id = :policy_type:";
$statusBinds['policy_type'] = $policy_type;
}
// Fetch claim statuses dynamically
- $statusQuery = "SELECT id, claim_status FROM ticket_claim_status WHERE is_active = 1 $ticket_type_data_1";
+ $statusQuery = "SELECT id, claim_status FROM ticket_claim_status WHERE is_active = 1 $ticket_type_data_1";
$statusResult = $this->db->query($statusQuery, $statusBinds)->getResultArray();
// Initialize dynamic query parts
- $dynamicSelect = '';
- $dynamicTotal = '';
+ $dynamicSelect = '';
+ $dynamicTotal = '';
$dynamicClosedTotal = '';
// Loop through each claim status and generate the CASE statements
@@ -624,7 +620,7 @@ class TicketMasterModel extends Model
'UNDER PROCESS - INVESTIGATION STATUS',
'UNDER PROCESS - QUERY DOCUMENT RECEIVED',
'APPROVED',
- 'PAYMENT INITIATED'
+ 'PAYMENT INITIATED',
])) {
$dynamicTotal .= "COUNT(CASE WHEN master.claim_status_id = {$status['id']} THEN master.id END) + ";
}
@@ -638,34 +634,34 @@ class TicketMasterModel extends Model
}
// Remove the trailing commas and `+` signs
- $dynamicSelect = rtrim($dynamicSelect, ', ');
- $dynamicTotal = rtrim($dynamicTotal, ' +');
+ $dynamicSelect = rtrim($dynamicSelect, ', ');
+ $dynamicTotal = rtrim($dynamicTotal, ' +');
$dynamicClosedTotal = rtrim($dynamicClosedTotal, ' +');
// print_rr($dynamicSelect);
// Construct the final SQL query
$sql = "
- SELECT
+ SELECT
tpa.id as TPA_ID,
tpa.name AS TPA_NAME,
$dynamicSelect,
($dynamicTotal) AS TOTAL,
($dynamicClosedTotal) AS CLEARED_TOTAL
- FROM
+ FROM
ticket_master master
- JOIN
+ JOIN
tpa ON master.tpa_id = tpa.id AND tpa.is_active = 1
- WHERE
+ WHERE
master.created_at BETWEEN :start_date: AND :end_date:
AND master.is_active = 1
$ticket_type_data_2
- GROUP BY
+ GROUP BY
tpa.id;
";
// Execute the query
- $binds = ["start_date"=>$start_date,"end_date"=>$end_date];
+ $binds = ["start_date" => $start_date, "end_date" => $end_date];
// Merge policy_type binds if present
- if (!empty($statusBinds)) {
+ if (! empty($statusBinds)) {
$binds = array_merge($binds, $statusBinds);
}
$result = $this->db->query($sql, $binds)->getResultArray();
@@ -680,28 +676,27 @@ class TicketMasterModel extends Model
if ($policy_type == 1) {
$ticket_type_data_1 = "";
$ticket_type_data_2 = "";
- $statusBinds = [];
+ $statusBinds = [];
- if (!empty($policy_type)) {
- $ticket_type_data_1 = "AND ticket_type = :policy_type:";
- $ticket_type_data_2 = "AND master.ticket_type_id = :policy_type:";
+ if (! empty($policy_type)) {
+ $ticket_type_data_1 = "AND ticket_type = :policy_type:";
+ $ticket_type_data_2 = "AND master.ticket_type_id = :policy_type:";
$statusBinds['policy_type'] = $policy_type;
}
// Fetch claim statuses dynamically
- $statusQuery = "SELECT id, claim_status FROM ticket_claim_status WHERE is_active = 1 $ticket_type_data_1";
- $statusResult = $this->db->query($statusQuery,$statusBinds)->getResultArray();
+ $statusQuery = "SELECT id, claim_status FROM ticket_claim_status WHERE is_active = 1 $ticket_type_data_1";
+ $statusResult = $this->db->query($statusQuery, $statusBinds)->getResultArray();
// Initialize dynamic query parts
$dynamicSelect = '';
- $dynamicTotal = '';
+ $dynamicTotal = '';
// Loop through each claim status and generate the CASE statements
foreach ($statusResult as $status) {
$dynamicSelect .= "
COUNT(CASE WHEN master.claim_status_id = {$status['id']} THEN master.id END) AS `{$status['claim_status']}`, ";
-
// Include in total count
$dynamicTotal .= "COUNT(CASE WHEN master.claim_status_id = {$status['id']} THEN master.id END) + ";
@@ -711,54 +706,54 @@ class TicketMasterModel extends Model
// Remove the trailing commas and `+` signs
$dynamicSelect = rtrim($dynamicSelect, ', ');
- $dynamicTotal = rtrim($dynamicTotal, ' +');
+ $dynamicTotal = rtrim($dynamicTotal, ' +');
// print_rr($dynamicSelect);
// Construct the final SQL query
$sql = "
- SELECT
+ SELECT
user_profiles.id as ACM_ID,
user_profiles.first_name AS ACM_NAME,
$dynamicSelect,
($dynamicTotal) AS TOTAL
- FROM
+ FROM
ticket_master master
- JOIN
+ JOIN
user_profiles ON master.acm_id = user_profiles.id AND user_profiles.is_active = 1
- WHERE
+ WHERE
master.created_at BETWEEN :start_date: AND :end_date:
AND master.is_active = 1
$ticket_type_data_2
- GROUP BY
+ GROUP BY
user_profiles.id;
";
- $binds = ["start_date"=>$start_date,"end_date"=>$end_date];
- // Merge policy_type binds if present
- if (!empty($statusBinds)) {
+ $binds = ["start_date" => $start_date, "end_date" => $end_date];
+ // Merge policy_type binds if present
+ if (! empty($statusBinds)) {
$binds = array_merge($binds, $statusBinds);
}
- $result = $this->db->query($sql,$binds)->getResultArray();
+ $result = $this->db->query($sql, $binds)->getResultArray();
// print_rr(count(($result)));
// print_rr($this->db->lastQuery);die();
return $result;
} else {
$ticket_type_data_1 = "";
$ticket_type_data_2 = "";
- $statusBinds = [];
+ $statusBinds = [];
- if (!empty($policy_type)) {
- $ticket_type_data_1 = "AND ticket_type = :policy_type:";
- $ticket_type_data_2 = "AND master.ticket_type_id = :policy_type:";
+ if (! empty($policy_type)) {
+ $ticket_type_data_1 = "AND ticket_type = :policy_type:";
+ $ticket_type_data_2 = "AND master.ticket_type_id = :policy_type:";
$statusBinds['policy_type'] = $policy_type;
}
// Fetch claim statuses dynamically
- $statusQuery = "SELECT id, claim_status FROM ticket_claim_status WHERE is_active = 1 $ticket_type_data_1";
- $statusResult = $this->db->query($statusQuery,$statusBinds)->getResultArray();
+ $statusQuery = "SELECT id, claim_status FROM ticket_claim_status WHERE is_active = 1 $ticket_type_data_1";
+ $statusResult = $this->db->query($statusQuery, $statusBinds)->getResultArray();
// Initialize dynamic query parts
- $dynamicSelect = '';
- $dynamicTotal = '';
+ $dynamicSelect = '';
+ $dynamicTotal = '';
$dynamicClosedTotal = '';
// Loop through each claim status and generate the CASE statements
@@ -773,7 +768,7 @@ class TicketMasterModel extends Model
'INSURER PENDING',
'INVESTIGATION',
'APPROVED',
- 'ON HOLD'
+ 'ON HOLD',
])) {
$dynamicTotal .= "COUNT(CASE WHEN master.claim_status_id = {$status['id']} THEN master.id END) + ";
}
@@ -787,52 +782,51 @@ class TicketMasterModel extends Model
}
// Remove the trailing commas and `+` signs
- $dynamicSelect = rtrim($dynamicSelect, ', ');
- $dynamicTotal = rtrim($dynamicTotal, ' +');
+ $dynamicSelect = rtrim($dynamicSelect, ', ');
+ $dynamicTotal = rtrim($dynamicTotal, ' +');
$dynamicClosedTotal = rtrim($dynamicClosedTotal, ' +');
// print_rr($dynamicSelect);
// Construct the final SQL query
$sql = "
- SELECT
+ SELECT
user_profiles.id as ACM_ID,
user_profiles.first_name AS ACM_NAME,
$dynamicSelect,
($dynamicTotal) AS TOTAL,
($dynamicClosedTotal) AS CLEARED_TOTAL
- FROM
+ FROM
ticket_master master
- JOIN
+ JOIN
user_profiles ON master.acm_id = user_profiles.id AND user_profiles.is_active = 1
- WHERE
+ WHERE
master.created_at BETWEEN :start_date: AND :end_date:
AND master.is_active = 1
$ticket_type_data_2
- GROUP BY
+ GROUP BY
user_profiles.id;
";
- $binds = ["start_date"=>$start_date,"end_date"=>$end_date];
+ $binds = ["start_date" => $start_date, "end_date" => $end_date];
// Execute the query
- // Merge policy_type binds if present
- if (!empty($statusBinds)) {
+ // Merge policy_type binds if present
+ if (! empty($statusBinds)) {
$binds = array_merge($binds, $statusBinds);
}
- $result = $this->db->query($sql,$binds)->getResultArray();
+ $result = $this->db->query($sql, $binds)->getResultArray();
// print_rr($this->db->lastQuery);die();
return $result;
-
}
}
//api
- public function get_ticket_data($emp_id, $returnType,$ticket_type = null, $ticket_id = null)
+ public function get_ticket_data($emp_id, $returnType, $ticket_type = null, $ticket_id = null)
{
$query = $this->select("
- ticket_master.*,
- tms.mail_subject as subject,
+ ticket_master.*,
+ tms.mail_subject as subject,
tms.id as ticket_message_id,
(
SELECT th1.old_value
@@ -854,11 +848,11 @@ class TicketMasterModel extends Model
$query->whereIn('sender', ['staff', 'user']);
$query->where('ticket_master.emp_id', $emp_id);
- if (!empty($ticket_id)) {
+ if (! empty($ticket_id)) {
$query->where('ticket_master.id', $ticket_id);
}
- if (!empty($ticket_type)) {
+ if (! empty($ticket_type)) {
$query->where('ticket_master.ticket_type_id', $ticket_type);
}
@@ -879,9 +873,9 @@ class TicketMasterModel extends Model
->select('tm.id, tm.ticket_type_id, tcs.claim_status, th.last_claim_status_change')
->join('ticket_claim_status tcs', 'tm.claim_status_id = tcs.id', 'left')
->join(
- '(SELECT ticket_id, MAX(created_at) AS last_claim_status_change
- FROM ticket_history
- WHERE field_name = \'claim_status_id\'
+ '(SELECT ticket_id, MAX(created_at) AS last_claim_status_change
+ FROM ticket_history
+ WHERE field_name = \'claim_status_id\'
GROUP BY ticket_id) th',
'tm.id = th.ticket_id',
'left'
@@ -898,8 +892,8 @@ class TicketMasterModel extends Model
$total = 0;
foreach ($statuses as $status) {
- $alias = strtolower(str_replace(' ', '_', $status));
- $summary[$alias] = 0;
+ $alias = strtolower(str_replace(' ', '_', $status));
+ $summary[$alias] = 0;
$summary[$alias . '_ids'] = '';
$dateLimit = $limit[$typeId][$status] ?? 3;
@@ -911,19 +905,18 @@ class TicketMasterModel extends Model
if (
$row['claim_status'] === $status &&
(
- !$row['last_claim_status_change'] ||
+ ! $row['last_claim_status_change'] ||
$row['last_claim_status_change'] <= $threshold
)
) {
$summary[$alias]++;
$ticketIds[] = $row['id'];
- if ($status == "APPROVED"|| $status == "SETTLED"|| $status == "CLOSED" ){
+ if ($status == "APPROVED" || $status == "SETTLED" || $status == "CLOSED") {
continue;
}
-
+
$total++;
-
}
}
@@ -934,8 +927,8 @@ class TicketMasterModel extends Model
$summary['total'] = $total;
// Add approved but not settled IDs and count
- $approvedNotSettled = $this->getNotSettledbutApprovedCount($typeId);
- $summary['approved_not_settled'] = $approvedNotSettled['count'];
+ $approvedNotSettled = $this->getNotSettledbutApprovedCount($typeId);
+ $summary['approved_not_settled'] = $approvedNotSettled['count'];
$summary['approved_not_settled_ids'] = $approvedNotSettled['ticket_ids'];
$finalResults[$typeId] = $summary;
@@ -960,13 +953,13 @@ class TicketMasterModel extends Model
$ids = $builder->get()->getRowArray();
// If no matching status IDs are found, return empty
- if (!$ids) {
+ if (! $ids) {
return ['count' => 0, 'ticket_ids' => ''];
}
// Extract approved and settled status IDs
$approved_id = $ids['approved_id'];
- $settled_id = $ids['settled_id'];
+ $settled_id = $ids['settled_id'];
// Subquery to get the latest approval time for each ticket
$subquery = $this->db->table('ticket_history')
@@ -983,12 +976,12 @@ class TicketMasterModel extends Model
// Left join to find if there is a settled status for each ticket after approval
$builder->join(
'ticket_history th_settled',
- "th_settled.ticket_id = tm.id
- AND th_settled.field_name = 'claim_status_id'
- AND th_settled.new_value = {$settled_id}
+ "th_settled.ticket_id = tm.id
+ AND th_settled.field_name = 'claim_status_id'
+ AND th_settled.new_value = {$settled_id}
AND th_settled.created_at > latest_approval.approved_time",
'left',
- false // Important for raw ON condition
+ false// Important for raw ON condition
);
// Filtering conditions: not settled and approved time older than 12 days
@@ -1001,7 +994,7 @@ class TicketMasterModel extends Model
$builder->select('tm.id');
// Execute the query
- $query = $builder->get();
+ $query = $builder->get();
$ticketIds = array_column($query->getResultArray(), 'id'); // Extract the IDs
// Convert ticket IDs array to a comma-separated string
@@ -1009,8 +1002,8 @@ class TicketMasterModel extends Model
// Return the count and comma-separated ticket IDs
return [
- 'count' => count($ticketIds),
- 'ticket_ids' => $ticketIdsString
+ 'count' => count($ticketIds),
+ 'ticket_ids' => $ticketIdsString,
];
}
@@ -1024,8 +1017,8 @@ class TicketMasterModel extends Model
AND cp.is_active = 1
";
- $binds = ["ticket_id"=>$ticket_id];
- $query = $this->db->query($sql,$binds);
+ $binds = ["ticket_id" => $ticket_id];
+ $query = $this->db->query($sql, $binds);
if ($query && $query->getNumRows() > 0) {
$row = $query->getRowArray();
@@ -1039,11 +1032,10 @@ class TicketMasterModel extends Model
public function getPolicyData($params)
{
- $client_name = $params['client_name'] ?? null;
+ $client_name = $params['client_name'] ?? null;
$insurer_short_name = $params['insurer_short_name'] ?? null;
- $tpa_short_name = $params['tpa_short_name'] ?? null;
- $policy_no = $params['policy_no'] ?? null;
-
+ $tpa_short_name = $params['tpa_short_name'] ?? null;
+ $policy_no = $params['policy_no'] ?? null;
$builder = $this->db->table('client_policy');
$builder->select('client_policy.*');
@@ -1055,19 +1047,19 @@ class TicketMasterModel extends Model
$builder->where('i.is_active', 1);
$builder->where('c.client_name', trim($client_name));
$builder->where('i.short_name', trim($insurer_short_name));
- if(!empty($tpa_short_name)){
- $builder->where('tpa.short_name', trim($tpa_short_name));
+ if (! empty($tpa_short_name)) {
+ $builder->where('tpa.short_name', trim($tpa_short_name));
}
$builder->where('client_policy.policy_no', trim($policy_no));
- $query = $builder->get();
+ $query = $builder->get();
$result = $query->getResultArray();
// dd($this->db->getLastQuery());
return $result;
}
public function getTheClaimDetails($params)
- {
+ {
$client_name = $params['client_name'] ?? null;
$policy_no = $params['policy_no'] ?? null;
$insurer_short_name = $params['insurer_short_name'] ?? null;
@@ -1099,19 +1091,19 @@ class TicketMasterModel extends Model
$builder->where('ticket_master.claim_number', trim($claim_no));
$builder->where('ticket_master.relationship', trim($relationship));
- if(!empty($tpa_short_name)){
- $builder->where('tpa.short_name', trim($tpa_short_name));
+ if (! empty($tpa_short_name)) {
+ $builder->where('tpa.short_name', trim($tpa_short_name));
}
- $query = $builder->get();
+ $query = $builder->get();
$result = $query->getResultArray();
return $result;
- }
+ }
public function getEmployeeAndEmployeePolicyDetails($params)
- {
+ {
$client_name = $params['client_name'] ?? null;
$emp_code = $params['emp_code'] ?? null;
$emp_name = $params['emp_name'] ?? null;
@@ -1124,7 +1116,6 @@ class TicketMasterModel extends Model
// $emp_name = "Lokesh";
// $policy_no = "GMC-1999/2000/2021/2022";
-
$builder = $this->db->table('employees e');
$builder->select("
e.id as emp_id,
@@ -1143,7 +1134,7 @@ class TicketMasterModel extends Model
cp.insurer_id,
cp.tpa_id,
cp.policy_no,
- CASE
+ CASE
WHEN cp.policy_type_id = 2 THEN 1
WHEN cp.policy_type_id = 1 THEN 2
WHEN cp.policy_type_id = 6 THEN 3
@@ -1165,7 +1156,7 @@ class TicketMasterModel extends Model
$builder->where('cp.policy_no', trim($policy_no));
$builder->where('LOWER(e.relationship)', strtolower('self'));
- $query = $builder->get();
+ $query = $builder->get();
$result = $query->getRowArray();
return $result;
@@ -1181,8 +1172,8 @@ class TicketMasterModel extends Model
$builder = $this->db->table('user_profiles');
$builder->select("user_profiles.*");
$builder->where('user_profiles.is_active', 1);
- $builder->where('user_profiles.mobile', trim($acm_mobile));
- $query = $builder->get();
+ $builder->where('user_profiles.mobile', trim($acm_mobile));
+ $query = $builder->get();
$result = $query->getRowArray();
return $result;
@@ -1193,9 +1184,9 @@ class TicketMasterModel extends Model
public function getInsuredDetails($params)
{
- $client_id = $params['client_id'] ?? null;
+ $client_id = $params['client_id'] ?? null;
$emp_code = $params['emp_code'] ?? null;
- $policy_id = $params['client_policy_id'] ?? null;
+ $policy_id = $params['client_policy_id'] ?? null;
$insured_name = $params['insured_name'] ?? null;
$builder = $this->db->table('employees e');
@@ -1220,7 +1211,7 @@ class TicketMasterModel extends Model
$builder->where('e.client_id', trim($client_id));
$builder->where('ep.client_policy_id', trim($policy_id));
- $query = $builder->get();
+ $query = $builder->get();
$result = $query->getRowArray();
// dd($this->db->getLastQuery());
return $result;
diff --git a/app/Views/DashBoard.php b/app/Views/DashBoard.php
index e71d67ff..0eff67a2 100755
--- a/app/Views/DashBoard.php
+++ b/app/Views/DashBoard.php
@@ -245,7 +245,7 @@
/assets/images/active_leads_and_bds_renewal.png" alt="Logo" height="14"
class="active_leads " style="display:none;">
- Leads and BDS Renewals
+ Opportunities and BDS Renewals
diff --git a/app/Views/claim_dump_file_list.php b/app/Views/claim_dump_file_list.php
index 1330cded..9ba0451b 100644
--- a/app/Views/claim_dump_file_list.php
+++ b/app/Views/claim_dump_file_list.php
@@ -24,6 +24,66 @@
.dataTables_length label {height: 21px !important;}
.readonly-select { background-color: #f3f3f3 !important; cursor: not-allowed; pointer-events: none; }
+
+.custom-tooltip {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+}
+
+.info-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 18px;
+ height: 18px;
+ background-color: #007bff;
+ color: #fff;
+ border-radius: 50%;
+ font-size: 14px;
+ font-style: italic;
+ font-weight: bold;
+ font-family: Georgia, serif;
+ line-height: 1;
+ vertical-align: middle;
+}
+
+.tooltiptext {
+ visibility: hidden;
+ opacity: 0;
+ position: fixed; /* fixed instead of absolute to escape modal overflow */
+ background: #333;
+ color: #fff;
+ padding: 10px 14px;
+ border-radius: 6px;
+ white-space: normal; /* allow text wrapping */
+ width: 320px; /* fixed width for multiline */
+ font-size: 12px;
+ font-weight: normal;
+ font-style: normal;
+ line-height: 1.6;
+ z-index: 99999;
+ transition: opacity 0.2s ease;
+ pointer-events: none;
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
+ top: 20px !important;
+ left: 155px !important;
+}
+
+.tooltiptext::after {
+ content: "";
+ position: absolute;
+ top: 100%;
+ left: 20px;
+ border: 6px solid transparent;
+ border-top-color: #333;
+}
+
+.custom-tooltip:hover .tooltiptext {
+ visibility: visible;
+ opacity: 1;
+}
+
@@ -151,7 +221,16 @@