diff --git a/.gitignore b/.gitignore index adeb2bd5..91df762f 100755 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ writable/**/*.sqlite writable/tmp/* !writable/tmp/.gitkeep +writable/insurer_claim_form/* +!writable/insurer_claim_form/Claim_Form_IRDAI.pdf + vendor/ build/ composer.lock diff --git a/app/Config/Constants.php b/app/Config/Constants.php index c9ed0960..b9691662 100755 --- a/app/Config/Constants.php +++ b/app/Config/Constants.php @@ -133,3 +133,5 @@ define('UPLOAD_EXT_EXCEL', ['xls', 'xlsx', 'ods', 'csv']); define('UPLOAD_EXT_MAIL_ATTACHMENTS', ['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx', 'xls', 'xlsx']); define('UPLOAD_EXT_NON_EB_RACK_RATE', ['pdf', 'xls', 'xlsx']); define('UPLOAD_EXT_ASSET_FILES', ['pdf', 'xls', 'xlsx', 'csv']); +define('UPLOAD_EXT_INSURER_CLAIM_FORM', ['pdf', 'doc', 'docx']); +define('INSURER_DEFAULT_CLAIM_FORM_FILE', 'Claim_Form_IRDAI.pdf'); diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 234b82a9..e18e3df7 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -257,6 +257,7 @@ $routes->group("/master", ["filter" => "authMVC"], function ($routes) { $routes->get("create", "MasterController::insurerOnboarding"); $routes->post("createpost", "MasterController::createInsurerGeneralInfo"); $routes->post("edit", "MasterController::editInsurerGeneralInfo"); + $routes->get("download-claim-form/(:num)", "MasterController::downloadInsurerClaimForm/$1"); $routes->get("list/(:any)", "MasterController::editInsurerOnboarding/$1"); $routes->group("branch", ["filter" => "authMVC"], function ($routes) { @@ -464,6 +465,8 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) { $routes->get('insertSampleTpaApiData/(:any)', 'TestingController::insertSampleTpaApiData/$1'); $routes->get('listEmployeeCountByClientPolicy', 'TestingController::listEmployeeCountByClientPolicy'); $routes->get('testMediAssistWellness','TestingController::testMediAssistWellness'); + $routes->match(['get', 'post'], 'decryptVisitSso', 'ApiServiceController::decryptVisitSso'); // disabled for now do not remove this + $routes->get("getInsurerClaimFormDownloadUrl", "EmployeeRestController::getInsurerClaimFormDownloadUrl"); $routes->group('claims-collection-v2', static function ($routes) { $routes->get('preview', 'ClaimsCollectionV2DashboardController::preview'); @@ -750,6 +753,7 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel $routes->get("cdTransactionData", "EmployeeRestController::cdTransactionData"); $routes->match( ['get', 'post'], 'claimsSearch','EmployeeRestController::claimsSearch'); $routes->get("claimView", "EmployeeRestController::claimView"); + $routes->get("getInsurerClaimFormDownloadUrl", "EmployeeRestController::getInsurerClaimFormDownloadUrl"); $routes->get("exportCashDepositData", "EmployeeRestController::exportCashDepositData"); $routes->get("hrFileList", "EmployeeRestController::hrFileList"); $routes->get("hrFileUploadMasters", "EmployeeRestController::hrFileUploadMasters"); diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php index 735cbfb0..de934916 100644 --- a/app/Controllers/ApiServiceController.php +++ b/app/Controllers/ApiServiceController.php @@ -580,6 +580,86 @@ class ApiServiceController extends BaseController } } + /** + * Decrypt Visit SSO userParams (reverse of Visit encryption in getWellnessUrl). + * Accepts encrypted string or full SSO URL via POST/GET as userParams or encrypted_sso. + */ + public function decryptVisitSso() + { + $encrypted = $this->request->getGet('encrypted_sso'); + + if (empty($encrypted)) { + return $this->response->setJSON([ + 'status' => false, + 'message' => 'userParams or encrypted_sso is required', + ]); + } + + $result = $this->decryptVisitSsoParams($encrypted); + + if ($result === false) { + return $this->response->setJSON([ + 'status' => false, + 'message' => 'Decryption failed. Check encrypted value and VISIT_SECRET_KEY / VISIT_IV.', + ]); + } + + return $this->response->setJSON([ + 'status' => true, + 'data' => $result['params'], + 'plainText' => $result['plainText'], + ]); + } + + /** + * Decrypt Visit SSO payload using the same key/IV as getWellnessUrl Visit branch. + * + * @param string $encrypted Base64URL userParams value or full SSO URL containing userParams= + * @return array{plainText: string, params: array}|false + */ + private function decryptVisitSsoParams(string $encrypted) + { + if (strpos($encrypted, 'userParams=') !== false) { + $query = []; + parse_str(parse_url($encrypted, PHP_URL_QUERY) ?? '', $query); + $encrypted = $query['userParams'] ?? ''; + } + + $encrypted = trim($encrypted); + if ($encrypted === '') { + return false; + } + + $base64 = strtr($encrypted, '-_', '+/'); + $base64 .= str_repeat('=', (4 - strlen($base64) % 4) % 4); + + $cipherRaw = base64_decode($base64, true); + if ($cipherRaw === false) { + return false; + } + + $derivedKey = hash('sha256', env('VISIT_SECRET_KEY'), true); + $plainText = openssl_decrypt( + $cipherRaw, + 'aes-256-cbc', + $derivedKey, + OPENSSL_RAW_DATA, + env('VISIT_IV') + ); + + if ($plainText === false) { + return false; + } + + $params = []; + parse_str($plainText, $params); + + return [ + 'plainText' => $plainText, + 'params' => $params, + ]; + } + /** * Manual TPA Claim Push - accepts claim_id via POST and delegates to pushClaims(). * Returns the response from pushClaims() as the API response. diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index cc4767dc..dd4a261c 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -5941,4 +5941,196 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to sent mail.', 'result' => $result], 200); } + public function getInsurerClaimFormDownloadUrl() + { + $clientPolicyId = trim((string) ($this->request->getGet('client_policy_id') ?? '')); + + if ($clientPolicyId === '') { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => 'client_policy_id is required', + 'client_policy_id' => null, + 'request_uri' => (string) current_url(), + 'request_method' => $this->request->getMethod(), + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Missing required parameter | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Missing required parameter | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'client_policy_id is required', + 'data' => [], + ], 200); + } + + if (! ctype_digit($clientPolicyId) || (int) $clientPolicyId <= 0) { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => 'Invalid client_policy_id', + 'client_policy_id' => $clientPolicyId, + 'request_uri' => (string) current_url(), + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Invalid client_policy_id | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Invalid client_policy_id | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'client_policy_id must be a valid positive number', + 'data' => [], + ], 200); + } + + try { + $clientPolicy = $this->clientPolicyModel + ->select('client_policy.id, client_policy.insurer_id, client_policy.policy_no, client_policy.is_active, insurers.id as insurer_pk, insurers.name as insurer_name, insurers.short_name as insurer_short_name, insurers.is_active as insurer_is_active, insurers.insurer_claim_form, insurers.insurer_claim_form_original_name') + ->join('insurers', 'insurers.id = client_policy.insurer_id', 'left') + ->where('client_policy.id', (int) $clientPolicyId) + ->first(); + + if (empty($clientPolicy)) { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => 'Client policy not found', + 'client_policy_id' => (int) $clientPolicyId, + 'request_uri' => (string) current_url(), + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Client policy not found | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Client policy not found | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 404, + 'message' => 'Client policy not found for the given client_policy_id', + 'data' => [], + ], 200); + } + + if ((int) ($clientPolicy['is_active'] ?? 0) !== 1) { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => 'Client policy is inactive', + 'client_policy_id' => (int) $clientPolicyId, + 'policy_no' => $clientPolicy['policy_no'] ?? null, + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Inactive client policy | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Inactive client policy | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 404, + 'message' => 'Client policy is inactive', + 'data' => [], + ], 200); + } + + if (empty($clientPolicy['insurer_id'])) { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => 'Insurer is not mapped to client policy', + 'client_policy_id' => (int) $clientPolicyId, + 'policy_no' => $clientPolicy['policy_no'] ?? null, + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Insurer not mapped | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Insurer not mapped | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 404, + 'message' => 'Insurer is not mapped to this client policy', + 'data' => [], + ], 200); + } + + if ((int) ($clientPolicy['insurer_is_active'] ?? 0) !== 1) { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => 'Insurer is inactive', + 'client_policy_id' => (int) $clientPolicyId, + 'insurer_id' => (int) $clientPolicy['insurer_id'], + 'insurer_name' => $clientPolicy['insurer_name'] ?? null, + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Inactive insurer | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Inactive insurer | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 404, + 'message' => 'Insurer is inactive for this client policy', + 'data' => [], + ], 200); + } + + $insurerData = [ + 'id' => $clientPolicy['insurer_id'], + 'name' => $clientPolicy['insurer_name'] ?? '', + 'short_name' => $clientPolicy['insurer_short_name'] ?? '', + 'insurer_claim_form' => $clientPolicy['insurer_claim_form'] ?? null, + 'insurer_claim_form_original_name'=> $clientPolicy['insurer_claim_form_original_name'] ?? null, + ]; + + $claimFormAvailability = resolve_insurer_claim_form_file($insurerData); + + if (empty($claimFormAvailability['available'])) { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => 'Insurer claim form file not found', + 'client_policy_id' => (int) $clientPolicyId, + 'insurer_id' => (int) $clientPolicy['insurer_id'], + 'insurer_name' => $clientPolicy['insurer_name'] ?? null, + 'insurer_short_name' => $clientPolicy['insurer_short_name'] ?? null, + 'stored_claim_form' => $clientPolicy['insurer_claim_form'] ?? null, + 'checked_paths' => $claimFormAvailability['checked_paths'] ?? [], + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Claim form file not found | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Claim form file not found | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 404, + 'message' => 'Insurer claim form is not available for this client policy', + 'data' => [], + ], 200); + } + + $downloadUrl = base_url('claim-form-download/' . md5((string) $clientPolicy['insurer_id'])); + + log_message('info', '[getInsurerClaimFormDownloadUrl] Success | ' . json_encode([ + 'client_policy_id' => (int) $clientPolicyId, + 'insurer_id' => (int) $clientPolicy['insurer_id'], + 'file_source' => $claimFormAvailability['source'], + 'file_name' => $claimFormAvailability['file_name'], + 'download_url' => $downloadUrl, + ])); + + return $this->respond([ + 'status' => true, + 'code' => 200, + 'message' => 'Insurer claim form download URL fetched successfully', + 'data' => [ + 'download_url' => $downloadUrl, + ], + ], 200); + } catch (\Throwable $th) { + $errorContext = [ + 'api' => 'getInsurerClaimFormDownloadUrl', + 'error' => $th->getMessage(), + 'client_policy_id' => $clientPolicyId, + 'file' => $th->getFile(), + 'line' => $th->getLine(), + 'trace' => $th->getTraceAsString(), + ]; + log_message('error', '[getInsurerClaimFormDownloadUrl] Exception | ' . json_encode($errorContext)); + $this->myLogger->logme('error', '[getInsurerClaimFormDownloadUrl] Exception | ' . json_encode($errorContext)); + + return $this->respond([ + 'status' => false, + 'code' => 500, + 'message' => 'Unable to fetch insurer claim form download URL. Please try again later.', + 'data' => [], + ], 200); + } + } + } diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php index 022c3a31..32e868e3 100755 --- a/app/Controllers/MasterController.php +++ b/app/Controllers/MasterController.php @@ -331,6 +331,13 @@ class MasterController extends AdminController 'ext_in' => 'Allowed file types: jpg, jpeg, png', ] ], + 'insurer_claim_form' => [ + 'rules' => 'if_exist|max_size[insurer_claim_form,5120]|ext_in[insurer_claim_form,pdf,doc,docx]', + 'errors' => [ + 'max_size' => 'Claim form file size should not exceed 5 MB', + 'ext_in' => 'Allowed file types: pdf, doc, docx', + ] + ], ]; // $rules = [ // 'name' => [ @@ -368,6 +375,14 @@ class MasterController extends AdminController $uploadFilePath = ROOTPATH . 'public/uploads/logo/'; $file_name = file_Upload($this->request->getFile('insurer_logo'), $uploadFilePath, UPLOAD_EXT_IMAGES); + + $claimFormUploadPath = WRITEPATH . 'insurer_claim_form/'; + if (!is_dir($claimFormUploadPath)) { + mkdir($claimFormUploadPath, 0777, true); + } + $insurerShortName = trim((string) ($this->request->getPost('short_name') ?? '')); + $claimFormUpload = file_Upload_random_name($this->request->getFile('insurer_claim_form'), $claimFormUploadPath, UPLOAD_EXT_INSURER_CLAIM_FORM, $insurerShortName); + $data = $this->request->getPost(); $sanitized_post_data = sanitizeInputArrayAdvanced($data); @@ -376,6 +391,10 @@ class MasterController extends AdminController $sanitized_post_data['is_multi_event'] = (!empty($sanitized_post_data['is_multi_event'])) ? 1 : 0; $sanitized_post_data['created_by'] = get_session_userid(); $sanitized_post_data['insurer_logo'] = $file_name; + if (!empty($claimFormUpload['stored_name'])) { + $sanitized_post_data['insurer_claim_form'] = $claimFormUpload['stored_name']; + $sanitized_post_data['insurer_claim_form_original_name'] = $claimFormUpload['original_name']; + } $insert = $this->insurerModel->insert($sanitized_post_data); @@ -573,6 +592,13 @@ class MasterController extends AdminController 'ext_in' => 'Only JPG, JPEG, and PNG files are allowed.', ] ], + 'insurer_claim_form' => [ + 'rules' => 'permit_empty|max_size[insurer_claim_form,5120]|ext_in[insurer_claim_form,pdf,doc,docx]', + 'errors' => [ + 'max_size' => 'Claim form file size should not exceed 5 MB', + 'ext_in' => 'Allowed file types: pdf, doc, docx', + ] + ], ]; if (!$this->validateData($postData, $rules)) { @@ -594,6 +620,18 @@ class MasterController extends AdminController $uploadFilePath = ROOTPATH . 'public/uploads/logo/'; $file_name = file_Upload($this->request->getFile('insurer_logo'), $uploadFilePath, UPLOAD_EXT_IMAGES); + + $claimFormUploadPath = WRITEPATH . 'insurer_claim_form/'; + if (!is_dir($claimFormUploadPath)) { + mkdir($claimFormUploadPath, 0777, true); + } + $insurerShortName = trim((string) ($this->request->getPost('short_name') ?? '')); + if ($insurerShortName === '' && !empty($this->request->getPost('PrimaryKey'))) { + $existingInsurerForShortName = $this->insurerModel->find($this->request->getPost('PrimaryKey')); + $insurerShortName = trim((string) ($existingInsurerForShortName['short_name'] ?? '')); + } + $claimFormUpload = file_Upload_random_name($this->request->getFile('insurer_claim_form'), $claimFormUploadPath, UPLOAD_EXT_INSURER_CLAIM_FORM, $insurerShortName); + $data = $this->request->getPost(); $sanitized_post_data = sanitizeInputArrayAdvanced($data); $id = $sanitized_post_data['PrimaryKey']; @@ -607,6 +645,18 @@ class MasterController extends AdminController $sanitized_post_data['insurer_logo'] = $file_name; } + if (!empty($claimFormUpload['stored_name'])) { + $existingInsurer = $this->insurerModel->find($id); + if (!empty($existingInsurer['insurer_claim_form'])) { + $oldClaimFormPath = $claimFormUploadPath . $existingInsurer['insurer_claim_form']; + if (is_file($oldClaimFormPath)) { + unlink($oldClaimFormPath); + } + } + $sanitized_post_data['insurer_claim_form'] = $claimFormUpload['stored_name']; + $sanitized_post_data['insurer_claim_form_original_name'] = $claimFormUpload['original_name']; + } + $update = $this->insurerModel->update($id,$sanitized_post_data); if($update){ @@ -616,6 +666,24 @@ class MasterController extends AdminController } } + public function downloadInsurerClaimForm($id = null) + { + $insurer = $this->insurerModel->where(['id' => (int) $id, 'is_active' => 1])->first(); + + if (empty($insurer)) { + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Claim form file not found'); + } + + $claimFormFile = resolve_insurer_claim_form_file($insurer); + + if (empty($claimFormFile['available']) || empty($claimFormFile['file_path'])) { + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Claim form file not found'); + } + + return $this->response->download($claimFormFile['file_path'], null) + ->setFileName($claimFormFile['file_name']); + } + public function editInsurerGet($id = null) { $this->myLogger->logme('error','Edit TPA Onboarding function called'); @@ -3084,6 +3152,7 @@ class MasterController extends AdminController 'files' => WRITEPATH . 'uploads/commission/files', 'rules' => WRITEPATH . 'uploads/commission/rules', 'claim_sample_forms' => ROOTPATH . 'public/claim_sample_forms/', + 'insurer_claim_form' => WRITEPATH . 'insurer_claim_form/', 'tmp' => ROOTPATH . 'public/tmp/', 'bds_dump_excel' => WRITEPATH . 'uploads/bds_dump_excel/', 'claims_mis' => WRITEPATH . 'uploads/claims_mis/', diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index b4171cb9..0e1b76a2 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -3405,25 +3405,26 @@ class TicketController extends BaseController } public function downloadClaimForm($insurer_id) - { + { $insurerModel = new InsurerModel(); $insurer_data = $insurerModel->where('MD5(id)', $insurer_id)->where('is_active', 1)->first(); - + if (!$insurer_data) { $data['message'] = 'The Physical File Not Found'; echo view('errors/404', $data); + return; } - - $fileName = $insurer_data['short_name'] . '.pdf'; - $filePath = ROOTPATH . 'public/claim_sample_forms/' . $fileName; - + + $claimFormFile = resolve_insurer_claim_form_file($insurer_data); + try { - if (file_exists($filePath)) { - return $this->response->download($filePath, null); - } else { - $data['message'] = 'The Physical File Not Found'; - echo view('errors/404', $data); + if (!empty($claimFormFile['available']) && !empty($claimFormFile['file_path'])) { + return $this->response->download($claimFormFile['file_path'], null) + ->setFileName($claimFormFile['file_name']); } + + $data['message'] = 'The Physical File Not Found'; + echo view('errors/404', $data); } catch (\Exception $e) { $this->myLogger->logme('error', $e->getMessage()); return $this->response->setStatusCode(500)->setBody('An error occurred while downloading the file.'); diff --git a/app/Database/insurers_add_claim_form_column.sql b/app/Database/insurers_add_claim_form_column.sql new file mode 100644 index 00000000..7ed6d458 --- /dev/null +++ b/app/Database/insurers_add_claim_form_column.sql @@ -0,0 +1,5 @@ +ALTER TABLE insurers + ADD COLUMN insurer_claim_form VARCHAR(255) NULL DEFAULT NULL AFTER insurer_logo; + +ALTER TABLE insurers + ADD COLUMN insurer_claim_form_original_name VARCHAR(255) NULL DEFAULT NULL AFTER insurer_claim_form; diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index a79b8b49..00955f17 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -99,6 +99,92 @@ if (! function_exists('file_Upload')) { } } +if (! function_exists('file_Upload_random_name')) { + function file_Upload_random_name($fileToUpload, $filepath, array $allowedExtensions = UPLOAD_ALLOWED_EXTENSIONS, string $namePrefix = ''): array + { + $empty = ['stored_name' => '', 'original_name' => '']; + + if ($fileToUpload === null || ! $fileToUpload->isValid() || $fileToUpload->hasMoved()) { + return $empty; + } + + if (! validate_upload_extension($fileToUpload, $allowedExtensions)) { + return $empty; + } + + $originalName = sanitize_upload_filename($fileToUpload->getClientName() ?: $fileToUpload->getName()); + $ext = strtolower($fileToUpload->getClientExtension() ?: pathinfo($originalName, PATHINFO_EXTENSION)); + $namePrefix = preg_replace('/[^a-zA-Z0-9\-_]/', '', $namePrefix); + $prefix = $namePrefix !== '' ? $namePrefix . '_' : ''; + $storedName = $prefix . time() . '_' . bin2hex(random_bytes(8)) . ($ext !== '' ? '.' . $ext : ''); + $fileToUpload->move($filepath, $storedName); + + return ['stored_name' => $storedName, 'original_name' => $originalName]; + } +} + +if (! function_exists('resolve_insurer_claim_form_file')) { + function resolve_insurer_claim_form_file(array $insurer): array + { + $checkedPaths = []; + $claimFormDir = WRITEPATH . 'insurer_claim_form/'; + + if (!empty($insurer['insurer_claim_form'])) { + $storedFileName = basename($insurer['insurer_claim_form']); + $uploadedPath = $claimFormDir . $storedFileName; + $checkedPaths[] = $uploadedPath; + + if (is_file($uploadedPath)) { + return [ + 'available' => true, + 'file_path' => $uploadedPath, + 'file_name' => !empty($insurer['insurer_claim_form_original_name']) + ? basename($insurer['insurer_claim_form_original_name']) + : $storedFileName, + 'source' => 'uploaded', + 'checked_paths' => $checkedPaths, + ]; + } + } + + $defaultPath = $claimFormDir . INSURER_DEFAULT_CLAIM_FORM_FILE; + $checkedPaths[] = $defaultPath; + + if (is_file($defaultPath)) { + return [ + 'available' => true, + 'file_path' => $defaultPath, + 'file_name' => INSURER_DEFAULT_CLAIM_FORM_FILE, + 'source' => 'irdai_default', + 'checked_paths' => $checkedPaths, + ]; + } + + if (!empty($insurer['short_name'])) { + $legacyPath = ROOTPATH . 'public/claim_sample_forms/' . $insurer['short_name'] . '.pdf'; + $checkedPaths[] = $legacyPath; + + if (is_file($legacyPath)) { + return [ + 'available' => true, + 'file_path' => $legacyPath, + 'file_name' => $insurer['short_name'] . '.pdf', + 'source' => 'legacy', + 'checked_paths' => $checkedPaths, + ]; + } + } + + return [ + 'available' => false, + 'file_path' => null, + 'file_name' => null, + 'source' => null, + 'checked_paths' => $checkedPaths, + ]; + } +} + if (! function_exists('file_Upload_for_lead')) { function file_Upload_for_lead($fileToUpload, $filepath, array $allowedExtensions = UPLOAD_ALLOWED_EXTENSIONS) { diff --git a/app/Models/InsurerModel.php b/app/Models/InsurerModel.php index a08b3c9e..5b375e09 100755 --- a/app/Models/InsurerModel.php +++ b/app/Models/InsurerModel.php @@ -15,6 +15,8 @@ class InsurerModel extends Model "name", "short_name", "insurer_logo", + "insurer_claim_form", + "insurer_claim_form_original_name", "created_by", "updated_by", "is_active", diff --git a/app/Views/insurer_basic_info.php b/app/Views/insurer_basic_info.php index b3af15ed..5e010955 100755 --- a/app/Views/insurer_basic_info.php +++ b/app/Views/insurer_basic_info.php @@ -187,6 +187,39 @@ input:checked + .slider:before { + +
+ +
+
+ + +
+
+ Allowed: PDF, DOC, DOCX. Max size: 5MB. If no insurer form is uploaded, will be used. + + + +
+
+
@@ -240,10 +273,47 @@ input:checked + .slider:before { } }); + // Custom Parsley validator for insurer claim form file size + window.Parsley.addValidator('insurerClaimMaxFileSize', { + validateString: function(value, maxSize, parsleyInstance) { + if (!window.FileReader) { + return true; + } + var files = parsleyInstance.$element[0].files; + if (files.length == 0) { + return true; + } + return files[0].size <= maxSize * 1024; + }, + requirementType: 'integer', + messages: { + en: 'This file should not be larger than %s KB.' + } + }); + + // Custom Parsley validator for insurer claim form file extension + window.Parsley.addValidator('insurerClaimFileExtension', { + validateString: function(value, requirement, parsleyInstance) { + var file = parsleyInstance.$element[0].files[0]; + if (!file) { return true; } + var extensions = requirement.split(',').map(function(ext) { return ext.trim().toLowerCase(); }); + var fileExtension = file.name.split('.').pop().toLowerCase(); + return extensions.indexOf(fileExtension) !== -1; + }, + requirementType: 'string', + messages: { + en: 'Allowed extensions are: %s.' + } + }); + $('#insurer_logo').on('change', function() { PreviewImage(); }); + $('#insurer_claim_form').on('change', function() { + validateInsurerClaimFormFile(true); + }); + $("#insurer_general_form").submit(function(events) { events.preventDefault(); @@ -251,6 +321,10 @@ input:checked + .slider:before { if (!validateInsurerLogoFile(true)) { return; } + + if (!validateInsurerClaimFormFile(true)) { + return; + } // var isValid = $('#insurer_General_PrimaryKey').parsley().validate(); var isValid = $('#insurer_general_form').parsley().validate(); @@ -430,6 +504,45 @@ input:checked + .slider:before { $('#logo_error_container').empty(); return true; } + + function resetInsurerClaimFormInput() { + var fileInput = document.getElementById("insurer_claim_form"); + fileInput.value = ""; + $('#claim_form_error_container').empty(); + } + + function validateInsurerClaimFormFile(showToastr) { + var fileInput = document.getElementById("insurer_claim_form"); + if (!fileInput.files || !fileInput.files[0]) { + return true; + } + + var file = fileInput.files[0]; + var fileName = file.name.toLowerCase(); + var parts = fileName.split('.'); + var allowedExtensions = /(\.pdf|\.doc|\.docx)$/i; + + if (!allowedExtensions.exec(fileName) || parts.length > 2) { + $('#claim_form_error_container').html(''); + if (showToastr) { + toastr.warning("Only PDF, DOC, and DOCX files are allowed.", "Invalid file type"); + } + resetInsurerClaimFormInput(); + return false; + } + + if ((file.size / 1024) > 5120) { + $('#claim_form_error_container').html(''); + if (showToastr) { + toastr.warning("File size should not exceed 5MB.", "Invalid file size"); + } + resetInsurerClaimFormInput(); + return false; + } + + $('#claim_form_error_container').empty(); + return true; + } //----------------------------------------------------------------------------------------------------- diff --git a/tests/smoke_get_insurer_claim_form_download_url.php b/tests/smoke_get_insurer_claim_form_download_url.php new file mode 100644 index 00000000..ac7b5a5d --- /dev/null +++ b/tests/smoke_get_insurer_claim_form_download_url.php @@ -0,0 +1,185 @@ +systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php'; +require_once SYSTEMPATH . 'Config/DotEnv.php'; +(new CodeIgniter\Config\DotEnv(ROOTPATH))->load(); + +defined('ENVIRONMENT') || define('ENVIRONMENT', env('CI_ENVIRONMENT', 'development')); + +$boot = APPPATH . 'Config/Boot/' . ENVIRONMENT . '.php'; +if (is_file($boot)) { + require_once $boot; +} + +use App\Controllers\EmployeeRestController; +use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\URI; +use Config\Services; + +$pass = 0; +$fail = 0; +$results = []; + +function ok(string $label, bool $cond, string $detail = ''): void +{ + global $pass, $fail, $results; + if ($cond) { + $pass++; + $results[] = '[PASS] ' . $label . ($detail ? " — {$detail}" : ''); + } else { + $fail++; + $results[] = '[FAIL] ' . $label . ($detail ? " — {$detail}" : ''); + } +} + +function invokeApi(EmployeeRestController $controller, array $query): array +{ + $uri = new URI('http://localhost/nhance_v2/employeeRest/getInsurerClaimFormDownloadUrl'); + if ($query !== []) { + $uri->setQuery(http_build_query($query)); + } + + $request = new IncomingRequest( + config('App'), + $uri, + null, + new \CodeIgniter\HTTP\UserAgent() + ); + $request->setGlobal('get', $query); + + $response = Services::response(); + $logger = Services::logger(); + $controller->initController($request, $response, $logger); + + $response = $controller->getInsurerClaimFormDownloadUrl(); + $body = json_decode($response->getBody(), true); + + return is_array($body) ? $body : []; +} + +$db = db_connect('default'); +$controller = new EmployeeRestController(); + +$legacyPolicy = $db->query( + "SELECT cp.id AS client_policy_id, i.short_name + FROM client_policy cp + JOIN insurers i ON i.id = cp.insurer_id + WHERE cp.is_active = 1 + AND i.is_active = 1 + AND i.short_name = 'ICICIPRU' + LIMIT 1" +)->getRowArray(); + +$uploadedPolicy = $db->query( + "SELECT cp.id AS client_policy_id, i.short_name, i.insurer_claim_form + FROM client_policy cp + JOIN insurers i ON i.id = cp.insurer_id + WHERE cp.is_active = 1 + AND i.is_active = 1 + AND i.insurer_claim_form IS NOT NULL + AND i.insurer_claim_form <> '' + LIMIT 1" +)->getRowArray(); + +$inactivePolicy = $db->query( + 'SELECT id AS client_policy_id FROM client_policy WHERE is_active = 0 LIMIT 1' +)->getRowArray(); + +$missingParam = invokeApi($controller, []); +ok('Missing client_policy_id returns 400', ($missingParam['code'] ?? null) === 400, json_encode($missingParam)); + +$invalidParam = invokeApi($controller, ['client_policy_id' => 'abc']); +ok('Invalid client_policy_id returns 400', ($invalidParam['code'] ?? null) === 400, json_encode($invalidParam)); + +$notFound = invokeApi($controller, ['client_policy_id' => '999999999']); +ok('Unknown client_policy_id returns 404', ($notFound['code'] ?? null) === 404, json_encode($notFound)); + +if (!empty($inactivePolicy['client_policy_id'])) { + $inactive = invokeApi($controller, ['client_policy_id' => (string) $inactivePolicy['client_policy_id']]); + ok('Inactive client policy returns 404', ($inactive['code'] ?? null) === 404, json_encode($inactive)); +} + +if (!empty($legacyPolicy['client_policy_id'])) { + $legacyPath = ROOTPATH . 'public/claim_sample_forms/' . $legacyPolicy['short_name'] . '.pdf'; + $legacy = invokeApi($controller, ['client_policy_id' => (string) $legacyPolicy['client_policy_id']]); + $legacyResolved = resolve_insurer_claim_form_file(['short_name' => $legacyPolicy['short_name']]); + ok( + 'No uploaded form falls back to IRDAI default (ICICIPRU policy)', + ($legacy['status'] ?? false) === true + && ($legacy['code'] ?? null) === 200 + && !empty($legacy['data']['download_url']) + && count($legacy['data']) === 1 + && ($legacyResolved['source'] ?? '') === 'irdai_default', + 'legacy_file_exists=' . (is_file($legacyPath) ? 'yes' : 'no') . ' | ' . json_encode($legacy) + ); +} + +$irdaiDefaultPolicy = $db->query( + "SELECT cp.id AS client_policy_id, i.short_name + FROM client_policy cp + JOIN insurers i ON i.id = cp.insurer_id + WHERE cp.is_active = 1 + AND i.is_active = 1 + AND (i.insurer_claim_form IS NULL OR i.insurer_claim_form = '') + AND i.short_name NOT IN ('ICICIPRU', 'DIGITLIF', 'MAXLIFE', 'NIA', 'OIC', 'PIFL', 'RELIANCE') + LIMIT 1" +)->getRowArray(); + +if (!empty($irdaiDefaultPolicy['client_policy_id'])) { + $irdai = invokeApi($controller, ['client_policy_id' => (string) $irdaiDefaultPolicy['client_policy_id']]); + $irdaiResolved = resolve_insurer_claim_form_file(['short_name' => $irdaiDefaultPolicy['short_name']]); + ok( + 'IRDAI default claim form fallback', + ($irdai['status'] ?? false) === true + && ($irdai['code'] ?? null) === 200 + && !empty($irdai['data']['download_url']) + && count($irdai['data']) === 1 + && ($irdaiResolved['source'] ?? '') === 'irdai_default', + json_encode($irdai) + ); +} + +if (!empty($uploadedPolicy['client_policy_id'])) { + $uploadedPath = WRITEPATH . 'insurer_claim_form/' . basename((string) $uploadedPolicy['insurer_claim_form']); + $uploaded = invokeApi($controller, ['client_policy_id' => (string) $uploadedPolicy['client_policy_id']]); + $uploadedResolved = resolve_insurer_claim_form_file([ + 'insurer_claim_form' => $uploadedPolicy['insurer_claim_form'], + 'short_name' => $uploadedPolicy['short_name'] ?? '', + ]); + ok( + 'Uploaded claim form success', + ($uploaded['status'] ?? false) === true + && ($uploaded['code'] ?? null) === 200 + && !empty($uploaded['data']['download_url']) + && count($uploaded['data']) === 1 + && ($uploadedResolved['source'] ?? '') === 'uploaded', + 'file_exists=' . (is_file($uploadedPath) ? 'yes' : 'no') . ' | ' . json_encode($uploaded) + ); +} + +$cliPolicyId = $argv[1] ?? ($legacyPolicy['client_policy_id'] ?? null); +if ($cliPolicyId) { + $manual = invokeApi($controller, ['client_policy_id' => (string) $cliPolicyId]); + echo "\nManual test client_policy_id={$cliPolicyId}\n"; + echo json_encode($manual, JSON_PRETTY_PRINT) . "\n"; +} + +echo "\nSmoke test summary: {$pass} passed, {$fail} failed\n"; +foreach ($results as $line) { + echo $line . "\n"; +} + +exit($fail > 0 ? 1 : 0); diff --git a/writable/insurer_claim_form/Claim_Form_IRDAI.pdf b/writable/insurer_claim_form/Claim_Form_IRDAI.pdf new file mode 100644 index 00000000..95861048 Binary files /dev/null and b/writable/insurer_claim_form/Claim_Form_IRDAI.pdf differ