diff --git a/app/Config/Acl.php b/app/Config/Acl.php index 0f90a7a6..b66743fb 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -313,7 +313,7 @@ class Acl // ===================== DEFAULT DENY (ZERO TRUST) ===================== '#^/#' => [ - 'roles' => [ADMIN_ROLE_ID], + 'roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [] ], ]; diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index 5f61287b..d1bc5d9b 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -1233,16 +1233,106 @@ class ClientController extends AdminController public function createClientKYCInfo() { $this->myLogger->logme('error', 'Create Client KYC function called'); - - $rules = [ - 'other_docs_name' => [ - 'label' => 'Documents Name', - 'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9_\- ]+$/]', - 'errors' => [ - 'regex_match' => 'Document Name can only contain letters, numbers, hyphens, and underscores' - ] - ], + $data = $this->request->getPost(); + $sanitized_data = sanitizeInputArrayAdvanced($data); + $form_type = $sanitized_data['form_type'] ?? null; + $client_id = $sanitized_data['client_id'] ?? null; + $uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents'; + $allowedExtensions = ['pdf', 'jpg', 'jpeg', 'png']; + $maxFileSize = 5 * 1024 * 1024; // 5MB + if (empty($client_id)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => ['client_id' => 'Client is required'] + ]); + } + + // Multi-row handler for Additional Documents form + if ($form_type === 'others') { + $docNames = $this->request->getPost('other_docs_name'); + if (!is_array($docNames)) { + $docNames = [$docNames]; + } + + $uploadedFiles = $this->request->getFileMultiple('file_name'); + if (!is_array($uploadedFiles)) { + $uploadedFiles = []; + } + + $rows = max(count($docNames), count($uploadedFiles)); + $validationErrors = []; + + if ($rows === 0) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => ['file_name' => 'At least one file is required'] + ]); + } + + for ($i = 0; $i < $rows; $i++) { + $docName = trim((string)($docNames[$i] ?? '')); + $fileObj = $uploadedFiles[$i] ?? null; + + if ($docName === '') { + $validationErrors["other_docs_name.$i"] = 'Documents Name is required'; + } elseif (!preg_match('/^[a-zA-Z0-9_\- ]+$/', $docName)) { + $validationErrors["other_docs_name.$i"] = 'Document Name can only contain letters, numbers, hyphens, and underscores'; + } + + if (!$fileObj || !$fileObj->isValid()) { + $validationErrors["file_name.$i"] = 'KYC document file is required'; + } else { + $extension = strtolower((string)$fileObj->getExtension()); + if (!in_array($extension, $allowedExtensions, true)) { + $validationErrors["file_name.$i"] = 'Allowed file types: pdf, jpg, jpeg, png'; + } + + if ((int)$fileObj->getSize() > $maxFileSize) { + $validationErrors["file_name.$i"] = 'File size should not exceed 5MB'; + } + } + } + + if (!empty($validationErrors)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => $validationErrors + ]); + } + + foreach ($uploadedFiles as $index => $singleFile) { + $fileName = file_Upload_for_lead($singleFile, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); + if (empty($fileName)) { + return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to upload KYC document'], 200); + } + + $insertData = [ + 'client_id' => $client_id, + 'kyc_doc_type_id' => $sanitized_data['kyc_doc_type_id'] ?? 0, + 'other_docs_name' => trim((string)($docNames[$index] ?? '')), + 'file_name' => $fileName, + 'created_by' => get_session_userid() + ]; + + $insertID = $this->clientKYCDocsModel->insert($insertData); + if (!$insertID) { + return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to upload KYC document'], 200); + } + } + + $kycDocs = $this->generateKycOthersTable($client_id); + return $this->respond(['status' => true, 'code' => 200, 'data' => $kycDocs], 200); + } + + // Backward compatible handler for primary KYC upload + $rules = [ 'file_name' => [ 'rules' => 'uploaded[file_name]|max_size[file_name,5120]|ext_in[file_name,pdf,jpg,jpeg,png]', 'errors' => [ @@ -1262,35 +1352,22 @@ class ClientController extends AdminController ]); } - $data = $this->request->getPost(); - $sanitized_data = sanitizeInputArrayAdvanced($data); - $form_type = $sanitized_data['form_type'] ?? null; - $uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents'; - - unset($data['file_name']); - $file = $this->request->getFile('file_name'); - - $fileName = file_Upload($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); + $fileName = file_Upload_for_lead($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); if (!empty($fileName)) { $sanitized_data['file_name'] = $fileName; } $sanitized_data['created_by'] = get_session_userid(); - $insertID = $this->clientKYCDocsModel->insert($sanitized_data); + if ($insertID) { - if ($form_type === 'others') { - $kycDocs = $this->generateKycOthersTable($sanitized_data['client_id']); - } else { - $kycDocs = $this->generateKycPrimaryTable($sanitized_data['client_id']); - } - return $this->respond(['status' => true, 'code' => 200, 'data' => $kycDocs, 'file_name' => $file - ], 200); - } else { - return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to upload KYC document'], 200); + $kycDocs = $this->generateKycPrimaryTable($client_id); + return $this->respond(['status' => true, 'code' => 200, 'data' => $kycDocs, 'file_name' => $file], 200); } + + return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to upload KYC document'], 200); } /** Edit Client KYC Documents V1 */ @@ -1327,7 +1404,7 @@ class ClientController extends AdminController $file = $this->request->getFile('file_name'); - $fileName = file_Upload($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); + $fileName = file_Upload_for_lead($file, $uploadFilePath, UPLOAD_EXT_KYC_DOCS); if (!empty($fileName)) { $sanitized_data['file_name'] = $fileName; @@ -1352,24 +1429,40 @@ class ClientController extends AdminController public function deleteClientKycDocs($id = null) { + $client_id = $this->request->getGet('client_id'); + $updateData = [ + 'is_active' => 0, + 'updated_by' => get_session_userid() + ]; - $delete = $this->clientKYCDocsModel->where('kyc_doc_type_id', $id)->delete(); + $delete = $this->clientKYCDocsModel->update($id, $updateData); if ($delete) { - return $this->respond(['status' => true, 'code' => 200, 'id' => $id], 200); - } else { - return $this->respond(['status' => false, 'code' => 404, 'message' => 'no data found'], 200); + $response = ['status' => true, 'code' => 200, 'id' => $id]; + if (!empty($client_id)) { + $response['data'] = $this->generateKycPrimaryTable($client_id); + } + return $this->respond($response, 200); } + return $this->respond(['status' => false, 'code' => 404, 'message' => 'no data found'], 200); } public function deleteClientKycOtherDocs($id = null) { + $client_id = $this->request->getGet('client_id'); + $updateData = [ + 'is_active' => 0, + 'updated_by' => get_session_userid() + ]; - $delete = $this->clientKYCDocsModel->where('id', $id)->delete(); + $delete = $this->clientKYCDocsModel->update($id, $updateData); if ($delete) { - return $this->respond(['status' => true, 'code' => 200, 'id' => $id], 200); - } else { - return $this->respond(['status' => false, 'code' => 404, 'message' => 'no data found'], 200); + $response = ['status' => true, 'code' => 200, 'id' => $id]; + if (!empty($client_id)) { + $response['data'] = $this->generateKycOthersTable($client_id); + } + return $this->respond($response, 200); } + return $this->respond(['status' => false, 'code' => 404, 'message' => 'no data found'], 200); } @@ -3660,7 +3753,7 @@ class ClientController extends AdminController $db = db_connect(); $builder = $db->table('kyc_docs kd'); - $builder->select('kd.*, ck.file_name AS upload_doc_name'); + $builder->select('kd.*, ck.file_name AS upload_doc_name, ck.id AS client_kyc_id'); $builder->join('clients c', 'kd.kyc_type_id = c.entity_type_id'); $builder->join( 'client_kyc_documents ck', @@ -4712,7 +4805,8 @@ class ClientController extends AdminController if (file_exists($file)) { return $this->response->download($file, null)->setFileName($file_name); } else { - return "File not found."; + $data['message'] = 'The Physical File Not Found'; + echo view('errors/404', $data); } } @@ -9675,7 +9769,8 @@ class ClientController extends AdminController // download() takes the path as first param and null (or data) as second return $this->response->download($file, null); } else { - return "File not found at: " . $file; + $data['message'] = 'The Physical File Not Found'; + echo view('errors/404', $data); } } diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index 18acb569..50e1dd16 100644 --- a/app/Controllers/PolicyTransactionController.php +++ b/app/Controllers/PolicyTransactionController.php @@ -701,11 +701,11 @@ class PolicyTransactionController extends BaseController nhance_branch.branch_name as nhance_branch_name, rm.first_name AS rm_name ') - ->join('user_teams', 'user_profiles.id = user_teams.user_id') + // ->join('user_teams', 'user_profiles.id = user_teams.user_id') ->join('nhance_branch', 'user_profiles.nhance_branch_id = nhance_branch.id','left') ->join('user_profiles AS rm', 'user_profiles.rm_id = rm.id', 'left') - ->where('user_teams.team_id', 5) - ->where('user_teams.is_active', 1) + // ->where('user_teams.team_id', 5) + // ->where('user_teams.is_active', 1) ->where('user_profiles.is_active', 1) ->groupBy('user_profiles.id', 'asc') ->findAll(); @@ -727,7 +727,7 @@ class PolicyTransactionController extends BaseController ->join('user_teams', 'user_profiles.id = user_teams.user_id') ->join('nhance_branch', 'user_profiles.nhance_branch_id = nhance_branch.id', 'left') ->join('user_profiles AS rm', 'user_profiles.rm_id = rm.id', 'left') - ->where('user_profiles.role', 3) + // ->where('user_profiles.role', 3) ->where('user_profiles.is_active', 1) ->groupBy('user_profiles.id', 'asc') ->findAll(); @@ -970,8 +970,8 @@ class PolicyTransactionController extends BaseController 'valid_date' => 'Please provide a valid D.O.E date.', 'regex_match' => 'The D.O.E date format is incorrect. ' ]], - 'emp_count' => ['label' => 'No of Insured', 'rules' => 'permit_empty|numeric', 'errors' => [ - 'numeric' => 'No of Insured must contain only numbers.' + 'emp_count' => ['label' => 'No of Employees', 'rules' => 'permit_empty|numeric', 'errors' => [ + 'numeric' => 'No of Employees must contain only numbers.' ]], 'dependent_count' => ['label' => 'No of Dependents', 'rules' => 'permit_empty|numeric', 'errors' => [ 'numeric' => 'No of Dependents must contain only numbers.' @@ -2491,9 +2491,9 @@ class PolicyTransactionController extends BaseController 'errors' => ['valid_date' => 'Please provide a valid Endorsement Effective Date.'] ], 'emp_count' => [ - 'label' => 'No of Insured', + 'label' => 'No of Employees', 'rules' => 'permit_empty|numeric', - 'errors' => ['numeric' => 'No of Insured must be a number.'] + 'errors' => ['numeric' => 'No of Employees must be a number.'] ], 'dependent_count' => [ 'label' => 'No of Dependents', @@ -5792,7 +5792,7 @@ class PolicyTransactionController extends BaseController 'pt_policy_issue_date' => change_date_format($policy_issue_date, 'd/M/Y', 'Y-m-d'), 'file_id' => $params['file_id'], - 'created_by' => $file['created_by'] ?? null, + 'created_by' => $file['created_by'] ?? null, ]; if(!empty($vehicle_id) && !empty($client_id)){ diff --git a/app/Models/PolicyTransactionModel.php b/app/Models/PolicyTransactionModel.php index 940aeb41..2e520918 100644 --- a/app/Models/PolicyTransactionModel.php +++ b/app/Models/PolicyTransactionModel.php @@ -1063,15 +1063,21 @@ ->where('policy_transaction.is_active', 1) ->where('policy_transaction.action_type', 'inception'); - if ( - (!in_array(get_role_id(), [1, 5])) && - !( - in_array(MANAGEMENT_TEAM_ID, user_team()) || - in_array(FINANCE_TEAM_ID, user_team()) || - in_array(BUSINESS_TEAM_ID, user_team()) - ) - ) { - if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) { + // if ( + // (!in_array(get_role_id(), [1, 5])) && + // !( + // in_array(MANAGEMENT_TEAM_ID, user_team()) || + // in_array(FINANCE_TEAM_ID, user_team()) || + // in_array(BUSINESS_TEAM_ID, user_team()) + // ) + // ) { + // if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) { + // $builder->where('policy_transaction.created_by', get_session_userid()); + // } + // } + + if ((!in_array(get_role_id(), [1, 5]))) { + if (in_array(POS_TEAM_ID, user_team())) { $builder->where('policy_transaction.created_by', get_session_userid()); } } @@ -1165,20 +1171,27 @@ ->where('policy_transaction.is_active', 1) ->where('policy_transaction.action_type !=', 'inception'); - if ( - (!in_array(get_role_id(), [1, 5])) && - !( - in_array(MANAGEMENT_TEAM_ID, user_team()) || - in_array(FINANCE_TEAM_ID, user_team()) || - in_array(BUSINESS_TEAM_ID, user_team()) - ) - ) { - if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) { + // if ( + // (!in_array(get_role_id(), [1, 5])) && + // !( + // in_array(MANAGEMENT_TEAM_ID, user_team()) || + // in_array(FINANCE_TEAM_ID, user_team()) || + // in_array(BUSINESS_TEAM_ID, user_team()) + // ) + // ) { + // if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) { + // $builder->where('policy_transaction.created_by', get_session_userid()); + // } + // } + + if ((!in_array(get_role_id(), [1, 5]))) { + if (in_array(POS_TEAM_ID, user_team())) { $builder->where('policy_transaction.created_by', get_session_userid()); } } + if ($start_date != 0 && $end_date != 0 && $date_type != 0) { $this->validateDateType($date_type); @@ -3067,15 +3080,21 @@ $conditions = ""; // start safely // 1. Role-based restrictions - if ( - (!in_array(get_role_id(), [1, 5])) && - !( - in_array(MANAGEMENT_TEAM_ID, user_team()) || - in_array(FINANCE_TEAM_ID, user_team()) || - in_array(BUSINESS_TEAM_ID, user_team()) - ) - ) { - if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) { + // if ( + // (!in_array(get_role_id(), [1, 5])) && + // !( + // in_array(MANAGEMENT_TEAM_ID, user_team()) || + // in_array(FINANCE_TEAM_ID, user_team()) || + // in_array(BUSINESS_TEAM_ID, user_team()) + // ) + // ) { + // if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) { + // $conditions .= " AND pt.created_by = " . get_session_userid(); + // } + // } + + if ((!in_array(get_role_id(), [1, 5]))) { + if (in_array(POS_TEAM_ID, user_team())) { $conditions .= " AND pt.created_by = " . get_session_userid(); } } diff --git a/app/Views/client_kyc.php b/app/Views/client_kyc.php index c8a43c29..636b07a7 100755 --- a/app/Views/client_kyc.php +++ b/app/Views/client_kyc.php @@ -39,26 +39,28 @@
- -
-
- - -
-
- - -
- -
- +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ + +
+
@@ -94,6 +96,24 @@ var kycPrimaryKey = $('#client_id_kyc').val(); + function getAdditionalDocRowTemplate(index) { + return ` +
+
+ + +
+
+ + +
+
+ +
+
+ `; + } + $(document).ready(function(){ kycPrimaryKey = $('#kyc_PrimaryKey').val(); @@ -195,6 +215,20 @@ }); }); + $(document).on('click', '#add_more_other_docs', function () { + var nextIndex = $('#additional_docs_rows .additional-doc-row').length; + $('#additional_docs_rows').append(getAdditionalDocRowTemplate(nextIndex)); + $('#additional_docs_rows .remove-additional-doc-row').show(); + }); + + $(document).on('click', '.remove-additional-doc-row', function () { + $(this).closest('.additional-doc-row').remove(); + + if ($('#additional_docs_rows .additional-doc-row').length <= 1) { + $('#additional_docs_rows .remove-additional-doc-row').hide(); + } + }); + }) /*** for Others documents form submit ***/ @@ -202,8 +236,35 @@ event.preventDefault(); var isValid = $('#kyc_form').parsley().validate(); - var rowHtml = ''; var form_action = ''; + var allowedExtensions = ['pdf', 'png', 'jpeg', 'jpg']; + + $('#kyc_form .other-doc-name-field, #kyc_form .other-doc-file-field').removeClass('is-invalid'); + + $('#additional_docs_rows .additional-doc-row').each(function() { + var docNameField = $(this).find('.other-doc-name-field'); + var fileField = $(this).find('.other-doc-file-field'); + var docNameValue = (docNameField.val() || '').trim(); + var selectedFile = fileField[0].files[0]; + + if (docNameValue === '' || !selectedFile) { + isValid = false; + if (docNameValue === '') { + docNameField.addClass('is-invalid'); + } + if (!selectedFile) { + fileField.addClass('is-invalid'); + } + return; + } + + var fileExtension = selectedFile.name.split('.').pop().toLowerCase(); + if (allowedExtensions.indexOf(fileExtension) === -1) { + isValid = false; + fileField.addClass('is-invalid'); + } + }); + if (isValid) { if(kycPrimaryKey === ''){ @@ -240,6 +301,8 @@ } $('#kyc_form').trigger('reset'); + $('#additional_docs_rows .additional-doc-row').not(':first').remove(); + $('#additional_docs_rows .remove-additional-doc-row').hide(); }, error: function(xhr, status, error) { console.error(xhr.responseText); @@ -274,6 +337,8 @@ } }); + } else { + toastr.warning('Please fill all Additional Document rows and upload valid files.', 'Warning'); } }); @@ -291,12 +356,14 @@ if (result.isConfirmed) { var kyc_id = $(this).attr('data-id'); - $.get(''+kyc_id, function (data) { - // console.log('kyc-'+ kyc_id) - // console.log(data) - if(data){ - $('#form_'+kyc_id).show(); - $('#name_'+kyc_id).hide(); + var client_id = $(this).attr('data-client-id') || $('#client_id_kyc').val(); + $.get(''+kyc_id, { client_id: client_id }, function (data) { + if(data && data.status){ + if (data.data) { + $('#tbody').empty(); + $('#tbody').append(data.data); + } + toastr.success('Document deleted successfully', 'Success'); } }) } @@ -317,10 +384,16 @@ if (result.isConfirmed) { var kyc_id = $(this).attr('data-id'); - $.get(''+kyc_id, function (data) { - // console.log('kyc-'+ kyc_id) - if(data){ - $('#kyc-'+ kyc_id).remove(); + var client_id = $(this).attr('data-client-id') || $('#client_id_kyc').val(); + $.get(''+kyc_id, { client_id: client_id }, function (data) { + if(data && data.status){ + if (data.data) { + $('#other_docs').empty(); + $('#other_docs').append(data.data); + } else { + $('#kyc-'+ kyc_id).remove(); + } + toastr.success('Document deleted successfully', 'Success'); } }) } diff --git a/app/Views/client_kyc_other_table.php b/app/Views/client_kyc_other_table.php index 119c7831..c6629722 100644 --- a/app/Views/client_kyc_other_table.php +++ b/app/Views/client_kyc_other_table.php @@ -2,9 +2,17 @@ $item): ?> - - + + + + + diff --git a/app/Views/client_kyc_primary_table.php b/app/Views/client_kyc_primary_table.php index 20317d97..86c2674f 100644 --- a/app/Views/client_kyc_primary_table.php +++ b/app/Views/client_kyc_primary_table.php @@ -17,7 +17,17 @@ - + + + + + + diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php index 7fe0372d..42012b60 100755 --- a/app/Views/layout/header.php +++ b/app/Views/layout/header.php @@ -2108,9 +2108,10 @@ body[data-sidebar-size="condensed"] .footer {
- + + + -
  • @@ -2141,27 +2142,29 @@ body[data-sidebar-size="condensed"] .footer {
  • - -
  • - - - Policy TAT Reports - -
    - -
    -
  • +
  • + + + Policy TAT Reports + +
    + +
    +
  • + +
    - +
    diff --git a/app/Views/policy_transaction_inception_list.php b/app/Views/policy_transaction_inception_list.php index aeecd703..39b49b27 100644 --- a/app/Views/policy_transaction_inception_list.php +++ b/app/Views/policy_transaction_inception_list.php @@ -661,6 +661,11 @@ function getAddPage(){ if(view == 1){ runInceptionAddFlowFromList(); + setTimeout(() => { + var backUrl = ''; + var backButton = ``; + updateNavTitle('Add Policy', backButton); + }, 500); } }