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..68a7209a 100755 --- a/app/Config/Constants.php +++ b/app/Config/Constants.php @@ -133,3 +133,4 @@ 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']); diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 234b82a9..630da754 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,7 @@ $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->group('claims-collection-v2', static function ($routes) { $routes->get('preview', 'ClaimsCollectionV2DashboardController::preview'); 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/MasterController.php b/app/Controllers/MasterController.php index 022c3a31..694d011b 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,27 @@ class MasterController extends AdminController } } + public function downloadInsurerClaimForm($id = null) + { + $insurer = $this->insurerModel->where(['id' => (int) $id, 'is_active' => 1])->first(); + + if (empty($insurer) || empty($insurer['insurer_claim_form'])) { + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Claim form file not found'); + } + + $storedFileName = basename($insurer['insurer_claim_form']); + $downloadFileName = !empty($insurer['insurer_claim_form_original_name']) + ? basename($insurer['insurer_claim_form_original_name']) + : $storedFileName; + $filePath = WRITEPATH . 'insurer_claim_form/' . $storedFileName; + + if (!is_file($filePath)) { + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Claim form file not found'); + } + + return $this->response->download($filePath, null)->setFileName($downloadFileName); + } + public function editInsurerGet($id = null) { $this->myLogger->logme('error','Edit TPA Onboarding function called'); @@ -3084,6 +3155,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..7b708c07 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -3405,18 +3405,31 @@ 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; } - + + if (!empty($insurer_data['insurer_claim_form'])) { + $storedFileName = basename($insurer_data['insurer_claim_form']); + $downloadFileName = !empty($insurer_data['insurer_claim_form_original_name']) + ? basename($insurer_data['insurer_claim_form_original_name']) + : $storedFileName; + $filePath = WRITEPATH . 'insurer_claim_form/' . $storedFileName; + + if (is_file($filePath)) { + return $this->response->download($filePath, null)->setFileName($downloadFileName); + } + } + $fileName = $insurer_data['short_name'] . '.pdf'; $filePath = ROOTPATH . 'public/claim_sample_forms/' . $fileName; - + try { if (file_exists($filePath)) { return $this->response->download($filePath, null); 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..b8343762 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -99,6 +99,30 @@ 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('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..47dadb1a 100755 --- a/app/Views/insurer_basic_info.php +++ b/app/Views/insurer_basic_info.php @@ -187,6 +187,33 @@ input:checked + .slider:before { + +