diff --git a/.env.sample b/.env.sample index b288c04c..65018cd5 100755 --- a/.env.sample +++ b/.env.sample @@ -153,6 +153,18 @@ LEAD_CLIENT_FROM_MAIL_ID = # BDS Daily Report Emails Configuration bds.dailyReportEmails = +# BDS Installment Reminder (pending UTR / overdue) — used by getLeadInstallmentDetails / sendInstallmentRemainderMail cron +# Master switch: when false, no installment reminder records are fetched +bds.installmentReminder.enabled = true +# Business days ahead of today to match upcoming payment_date (was hardcoded 5) +bds.installmentReminder.businessDays = 5 +# When true, also fetch records with null UTR whose payment_date is already past (overdue) +bds.installmentReminder.fetchOverduePendingUtr = false +# When true, fetch every day; when false, only on days listed in bds.installmentReminder.days +bds.installmentReminder.daily = true +# Comma-separated weekdays (mon,tue,wed,thu,fri,sat,sun) — used only when daily = false +bds.installmentReminder.days = mon,tue,wed,thu,fri + #-------------------------------------------------------------------- # MEDI ASSIST WELLNESS SSO Configuration diff --git a/app/Config/Acl.php b/app/Config/Acl.php index 8b0476ea..f273ba13 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -44,7 +44,8 @@ class Acl '#^/sendDataToTPA#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID, MANAGER_ROLE_ID]], '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID, MANAGER_ROLE_ID]], '#^/viewClaimFile#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID]], - '#^/employee/tpaReportsDashboard#' => ['roles' => [ACCOUNT_MANAGER_ROLE_ID]], + '#^/employee/tpaReportsDashboard#' => ['roles' => [ACCOUNT_MANAGER_ROLE_ID, ADMIN_ROLE_ID, HEAD_ROLE_ID]], + '#^/policy_tranction/sendInstallmentRemainderMail#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], diff --git a/app/Config/BdsConfig.php b/app/Config/BdsConfig.php new file mode 100644 index 00000000..100c746c --- /dev/null +++ b/app/Config/BdsConfig.php @@ -0,0 +1,64 @@ +installmentReminderEnabled = $this->envToBool( + env('bds.installmentReminder.enabled', 'true') + ); + $this->installmentReminderBusinessDays = max( + 0, + (int) env('bds.installmentReminder.businessDays', 5) + ); + $this->installmentReminderFetchOverduePendingUtr = $this->envToBool( + env('bds.installmentReminder.fetchOverduePendingUtr', 'false') + ); + $this->installmentReminderDaily = $this->envToBool( + env('bds.installmentReminder.daily', 'true') + ); + + $days = env('bds.installmentReminder.days', 'mon,tue,wed,thu,fri'); + $this->installmentReminderDays = array_values(array_filter(array_map( + static fn (string $day): string => strtolower(substr(trim($day), 0, 3)), + explode(',', (string) $days) + ))); + } + + public function shouldFetchInstallmentRemindersToday(): bool + { + if (!$this->installmentReminderEnabled) { + return false; + } + + if ($this->installmentReminderDaily) { + return true; + } + + $today = strtolower(date('D')); + + return in_array($today, $this->installmentReminderDays, true); + } + + private function envToBool(mixed $value): bool + { + return in_array(strtolower((string) $value), ['1', 'true', 'yes', 'on'], true); + } +} diff --git a/app/Config/Exceptions.php b/app/Config/Exceptions.php index 4173dcdd..0ec3c4ba 100755 --- a/app/Config/Exceptions.php +++ b/app/Config/Exceptions.php @@ -3,7 +3,7 @@ namespace Config; use CodeIgniter\Config\BaseConfig; -use CodeIgniter\Debug\ExceptionHandler; +use App\Debug\CorsExceptionHandler; use CodeIgniter\Debug\ExceptionHandlerInterface; use Psr\Log\LogLevel; use Throwable; @@ -99,6 +99,6 @@ class Exceptions extends BaseConfig */ public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface { - return new ExceptionHandler($this); + return new CorsExceptionHandler($this); } } diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 656b22a9..e9d2aea9 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -447,6 +447,7 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) { $routes->get('downloadFullMemberDataExcelErrorFile/(:any)', 'LeadsController::downloadFullMemberDataExcelErrorFile/$1'); $routes->get('getMemberDataExcelFileErrors', 'LeadsController::getMemberDataExcelFileErrors'); $routes->post('savePlacementDataAndValidateMemberDataFile', 'LeadsController::savePlacementDataAndValidateMemberDataFile'); + $routes->post('savePlacementDataWithoutMail', 'LeadsController::savePlacementDataWithoutMail'); $routes->get('checkMemberDataFileValidationStatus', 'LeadsController::checkMemberDataFileValidationStatus'); $routes->match(['get', 'post', 'delete'], 'nhanceBranchMaster', 'MasterController::nhanceBranchMaster'); $routes->match(['get', 'post', 'delete'], 'vehicleTypeMaster', 'MasterController::vehicleTypeMaster'); @@ -482,7 +483,7 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) { }); }); -$routes->post("policy_tranction/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail"); +$routes->get("policy_tranction/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail"); $routes->cli("cli/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail"); $routes->cli("cli/cronDailyBDSReport", "PolicyTransactionController::cronDailyBDSReport"); $routes->cli('cli/croneDailyActivityReport', 'DashboardController::croneDailyActivityReport'); @@ -725,6 +726,7 @@ $routes->group("employeeRest", ["filter" => ['GlobalPostFileUploadGuard', 'ratel $routes->get("deleteDependence", "EmployeeRestController::deleteDependence"); $routes->get("getEmployeeAndDependenceByClientId", "EmployeeRestController::getEmployeeAndDependenceByClientId"); $routes->get("getClientPolicy", "EmployeeRestController::getClientPolicy"); + $routes->get("getClientRM", "EmployeeRestController::getClientRM"); $routes->get("getAddOnPolicy", "EmployeeRestController::getAddOnPolicy"); $routes->post("iAgreeForAddOn", "EmployeeRestController::iAgreeForAddOn"); $routes->get("exportDataByClientPolicyId", "EmployeeRestController::exportDataByClientPolicyId"); diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index 4c9edd8d..0af6898a 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -2474,11 +2474,11 @@ class ClientController extends AdminController ] ], 'name.*' => [ - 'rules' => 'required|min_length[3]|regex_match[/^[a-zA-Z0-9\s\-_]+$/]', + 'rules' => 'required|min_length[3]|regex_match[/^[a-zA-Z0-9\s.\-_]+$/]', 'errors' => [ 'required' => 'Contact name is required', 'min_length' => 'Contact name must be at least 3 characters long', - 'regex_match' => 'Contact name can only contain letters, numbers, spaces, hyphens and underscores.' + 'regex_match' => 'Contact name can only contain letters, numbers, spaces, periods, hyphens and underscores.' ] ], 'designation.*' => [ @@ -2658,11 +2658,11 @@ class ClientController extends AdminController ] ], 'name.*' => [ - 'rules' => 'required|min_length[3]|regex_match[/^[a-zA-Z0-9\s\-_]+$/]', + 'rules' => 'required|min_length[3]|regex_match[/^[a-zA-Z0-9\s.\-_]+$/]', 'errors' => [ 'required' => 'Contact name is required', 'min_length' => 'Contact name must be at least 3 characters long', - 'regex_match' => 'Contact name can only contain letters, numbers, spaces, hyphens and underscores.' + 'regex_match' => 'Contact name can only contain letters, numbers, spaces, periods, hyphens and underscores.' ] ], 'designation.*' => [ @@ -7798,7 +7798,6 @@ class ClientController extends AdminController public function getTheEmpDataForClaim($param, $type = null) { - // Construct the base query $data = $this->clientPolicyModel ->select(" clients.id AS client_id, @@ -7816,36 +7815,34 @@ class ClientController extends AdminController employee_polices.uhid AS policy_no, employee_polices.client_policy_id ") - ->join('clients', 'client_policy.client_id = clients.id', 'left') - ->join('insurers', 'client_policy.insurer_id = insurers.id', 'left') + ->join('clients', 'client_policy.client_id = clients.id') + ->join('insurers', 'client_policy.insurer_id = insurers.id') ->join('tpa', 'client_policy.tpa_id = tpa.id', 'left') - ->join('employees', 'clients.id = employees.client_id', 'left') - ->join('employee_polices', 'employees.id = employee_polices.employee_id', 'left') + ->join('employees', 'clients.id = employees.client_id') + ->join('employee_polices', 'employees.id = employee_polices.employee_id AND client_policy.id = employee_polices.client_policy_id') ->where('client_policy.is_active', 1) - ->where('insurers.is_active', 1) - ->where('tpa.is_active', 1) - ->where('employees.is_active', 1) - ->where('employees.relationship', "Self") - ->where('employee_polices.is_active', 1) - ->whereIn('employees.emp_status', ['active', 'expired']) - ->whereIn('employee_polices.status', ['active', 'expired']) - ->where('employees.is_active', 1) ->where('client_policy.id', $param) - ->groupBy('employees.emp_code') + ->where('employees.is_active', 1) + ->where('employees.relationship', 'Self') + ->whereIn('employees.emp_status', ['active', 'expired']) + ->where('employee_polices.is_active', 1) + ->whereIn('employee_polices.status', ['active', 'expired']) + ->groupBy('employees.id') + ->orderBy('employees.name', 'ASC') ->get() ->getResultArray(); - // print_r(db_connect()->getLastQuery()); die; + // print_r(db_connect()->getLastQuery()->getQuery()); die; $dataForClientAndInsurer = $this->clientPolicyModel ->select(" - clients.id AS client_id, - clients.client_name, - insurers.id AS insurer_id, - insurers.name AS insurer_name, - tpa.id AS tpa_id, - tpa.name AS tpa_name, - ") + clients.id AS client_id, + clients.client_name, + insurers.id AS insurer_id, + insurers.name AS insurer_name, + tpa.id AS tpa_id, + tpa.name AS tpa_name + ") ->join('clients', 'client_policy.client_id = clients.id', 'left') ->join('insurers', 'client_policy.insurer_id = insurers.id', 'left') ->join('tpa', 'client_policy.tpa_id = tpa.id', 'left') @@ -7938,8 +7935,8 @@ class ClientController extends AdminController ->join('employees', 'clients.id = employees.client_id') ->join('employee_polices', 'employees.id = employee_polices.employee_id AND client_policy.id = employee_polices.client_policy_id') ->where('client_policy.is_active', 1) - ->where('insurers.is_active', 1) - ->where('tpa.is_active', 1) + // ->where('insurers.is_active', 1) + // ->where('tpa.is_active', 1) ->where('employees.is_active', 1) ->whereIn('employees.emp_status', ['active', 'expired']) ->where('employees.relationship', "Self") @@ -7964,7 +7961,7 @@ class ClientController extends AdminController $data = $query->get()->getRowArray(); - // print_r(db_connect()->getLastQuery()); die; + // print_r(db_connect()->getLastQuery()->getQuery()); die; $memberData = []; $dataForClientAndInsurer = []; diff --git a/app/Controllers/EmpDataServiceController.php b/app/Controllers/EmpDataServiceController.php index 07a7ce3b..62f10af2 100755 --- a/app/Controllers/EmpDataServiceController.php +++ b/app/Controllers/EmpDataServiceController.php @@ -2217,18 +2217,18 @@ class EmpDataServiceController extends BaseController 'file_id' => $file_id, ]]); - $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ - 'client_policy_id' => $client_policy_id ?? null, - 'endorsement_no' => $endorsement_id ?? null, - 'emp_count' => $emp_count ?? null, - 'action_type' => $file['event_type'] ?? null, - 'no_of_insured' => count($no_of_insured ?? []) ?? null, - 'no_of_dependent' => count($no_of_dependent ?? []) ?? null, - 'base_premium' => $base_bremium_and_gst['base_premium'] ?? null, - 'gst' => $base_bremium_and_gst['gst'] ?? null, - 'policy_issue_date' => $policy_issue_date ?? null, - 'created_by' => $file['created_by'] ?? null, - ]]); + // $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ + // 'client_policy_id' => $client_policy_id ?? null, + // 'endorsement_no' => $endorsement_id ?? null, + // 'emp_count' => $emp_count ?? null, + // 'action_type' => $file['event_type'] ?? null, + // 'no_of_insured' => count($no_of_insured ?? []) ?? null, + // 'no_of_dependent' => count($no_of_dependent ?? []) ?? null, + // 'base_premium' => $base_bremium_and_gst['base_premium'] ?? null, + // 'gst' => $base_bremium_and_gst['gst'] ?? null, + // 'policy_issue_date' => $policy_issue_date ?? null, + // 'created_by' => $file['created_by'] ?? null, + // ]]); // $this->cashDepositCalculationForInception($depositeData); // $this->sendMailForDownloadingECard($emp_policy_ids); @@ -2666,14 +2666,14 @@ class EmpDataServiceController extends BaseController $file_data = $this->getDataByFileId($file_id, 'success'); $this->setPullNotification($file_data); - $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ - 'client_policy_id' => $client_policy_id ?? null, - 'endorsement_no' => $endorsement_id[0] ?? null, - 'emp_count' => $emp_count ?? null, - 'action_type' => $file['event_type'] ?? null, - 'policy_issue_date' => $policy_issue_date ?? null, - 'created_by' => $file['created_by'] ?? null, - ]]); + // $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ + // 'client_policy_id' => $client_policy_id ?? null, + // 'endorsement_no' => $endorsement_id[0] ?? null, + // 'emp_count' => $emp_count ?? null, + // 'action_type' => $file['event_type'] ?? null, + // 'policy_issue_date' => $policy_issue_date ?? null, + // 'created_by' => $file['created_by'] ?? null, + // ]]); //import file to upload Google Drive @@ -3401,18 +3401,18 @@ class EmpDataServiceController extends BaseController 'file_id' => $file_id, ]]); - $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ - 'client_policy_id' => $client_policy_id ?? null, - 'endorsement_no' => $endorsement_id ?? null, - 'emp_count' => $emp_count ?? null, - 'action_type' => $file['event_type'] ?? null, - 'no_of_insured' => count($no_of_insured ?? []) ?? null, - 'no_of_dependent' => count($no_of_dependent ?? []) ?? null, - 'base_premium' => $base_bremium_and_gst['base_premium'] ?? null, - 'gst' => $base_bremium_and_gst['gst'] ?? null, - 'policy_issue_date' => $policy_issue_date ?? null, - 'created_by' => $file['created_by'] ?? null, - ]]); + // $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ + // 'client_policy_id' => $client_policy_id ?? null, + // 'endorsement_no' => $endorsement_id ?? null, + // 'emp_count' => $emp_count ?? null, + // 'action_type' => $file['event_type'] ?? null, + // 'no_of_insured' => count($no_of_insured ?? []) ?? null, + // 'no_of_dependent' => count($no_of_dependent ?? []) ?? null, + // 'base_premium' => $base_bremium_and_gst['base_premium'] ?? null, + // 'gst' => $base_bremium_and_gst['gst'] ?? null, + // 'policy_issue_date' => $policy_issue_date ?? null, + // 'created_by' => $file['created_by'] ?? null, + // ]]); } @@ -3920,18 +3920,18 @@ class EmpDataServiceController extends BaseController 'file_id' => $file_id, ]]); - $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ - 'client_policy_id' => $client_policy_id ?? null, - 'endorsement_no' => $endorsement_id ?? null, - 'emp_count' => $emp_count ?? null, - 'action_type' => $file['event_type'] ?? null, - 'no_of_insured' => count($no_of_insured ?? []) ?? null, - 'no_of_dependent' => count($no_of_dependent ?? []) ?? null, - 'base_premium' => $base_bremium_and_gst['base_premium'] ?? null, - 'gst' => $base_bremium_and_gst['gst'] ?? null, - 'policy_issue_date' => $policy_issue_date ?? null, - 'created_by' => $file['created_by'] ?? null, - ]]); + // $r = Jobs::addJob(['job_name' => 'makeEntryForBDSPolicyTransaction', 'payload' => [ + // 'client_policy_id' => $client_policy_id ?? null, + // 'endorsement_no' => $endorsement_id ?? null, + // 'emp_count' => $emp_count ?? null, + // 'action_type' => $file['event_type'] ?? null, + // 'no_of_insured' => count($no_of_insured ?? []) ?? null, + // 'no_of_dependent' => count($no_of_dependent ?? []) ?? null, + // 'base_premium' => $base_bremium_and_gst['base_premium'] ?? null, + // 'gst' => $base_bremium_and_gst['gst'] ?? null, + // 'policy_issue_date' => $policy_issue_date ?? null, + // 'created_by' => $file['created_by'] ?? null, + // ]]); } $file_data = $this->getDataByFileId($file_id, 'success'); diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index fcf7c9f6..176fba86 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -1643,6 +1643,53 @@ class EmployeeRestController extends AdminController } } + public function getClientRM() + { + try { + $client_id = $this->request->getGet('client_id'); + + if (empty($client_id)) { + return $this->respond(['status' => 'failed', 'code' => 400, 'message' => 'client_id is required'], 200); + } + + $clientRmRecords = $this->clientRMModel + ->select('client_rm.level, user_profiles.first_name, user_profiles.email, user_profiles.mobile') + ->join('user_profiles', 'user_profiles.id = client_rm.user_id') + ->where('md5(client_rm.client_id)', $client_id) + ->where('client_rm.is_active', 1) + ->whereIn('client_rm.level', [1, 3]) + ->findAll(); + + $level_1 = []; + $level_2 = []; + + foreach ($clientRmRecords as $record) { + $user = [ + 'first_name' => $record['first_name'], + 'email' => $record['email'], + 'mobile' => $record['mobile'], + ]; + + if ((int) $record['level'] === 3) { + $level_1[] = $user; + } else { + $level_2[] = $user; + } + } + + return $this->respond([ + 'status' => 'success', + 'code' => 200, + 'data' => [ + 'level_1' => $level_1, + 'level_2' => $level_2, + ], + ], 200); + } catch (\Exception $e) { + return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500); + } + } + public function getAddOnPolicy() { try { @@ -2264,6 +2311,11 @@ class EmployeeRestController extends AdminController client_policy.inception_type as inception_type, client_policy.policy_no as policy_no, client_policy.insurer_id as insurer_id, + client_policy.policy_terms, + insurers.name as insurer_name, + tpa.name as tpa_name, + tpa.short_name as tpa_short_name, + insurers.short_name as insurer_short_name, DATE_FORMAT(client_policy.policy_start_date, '%d-%m-%Y') AS policy_start_date, DATE_FORMAT(client_policy.policy_end_date, '%d-%m-%Y') AS policy_expiry_date, clients.client_logo as client_logo, @@ -2278,6 +2330,8 @@ class EmployeeRestController extends AdminController ", false) ->join('clients', 'clients.id = client_policy.client_id', 'left') ->join('policy_type', 'policy_type.id = client_policy.policy_type_id', 'left') + ->join('insurers', 'insurers.id = client_policy.insurer_id', 'left') + ->join('tpa', 'tpa.id = client_policy.tpa_id', 'left') ->where('md5(client_policy.client_id)', $this->request->getGet('client_id')) ->where('client_policy.client_branch_id', $this->request->getGet('client_branch_id')) ->where('client_policy.is_active', 1) @@ -2316,6 +2370,26 @@ class EmployeeRestController extends AdminController $value['is_ecard_bulk_download'] = 0; $value['is_ecard_bulk_download_for_employee'] = 0; + $terms = json_decode($value['policy_terms'], true) ?? []; + if ($value['policy_type_id'] == 1) { + $policyGroup = 'gpa'; + } elseif (in_array($value['policy_type_id'], [6, 7, 72])) { + $policyGroup = 'other'; + } else { + $policyGroup = 'gmc'; + } + $value['policy_terms'] = isset($terms['enrollment_display_key']) && ! empty($terms['enrollment_display_key']) + ? $terms['enrollment_display_key'] + : $this->policyTermsFiter($terms, $policyGroup); + + $sumInsuredLabel = in_array($value['policy_type_id'], [1, 6, 7]) ? 'Sum Assured' : 'Sum Insured'; + $sumInsuredValue = $terms['sum_insured'] ?? ($terms['sumInsured2'] ?? null); + if ($sumInsuredValue !== null && $sumInsuredValue !== '') { + if (! array_key_exists($sumInsuredLabel, $value['policy_terms'])) { + $value['policy_terms'] = array_merge([$sumInsuredLabel => $sumInsuredValue], $value['policy_terms']); + } + } + array_push($result, $value); } diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php index 49412b34..d6cd0df5 100644 --- a/app/Controllers/LeadsController.php +++ b/app/Controllers/LeadsController.php @@ -3764,7 +3764,7 @@ class LeadsController extends BaseController if(isset($propsal_and_insurer)) { if (! empty($propsal_and_insurer[0])) { - $parts = explode('-', $propsal_and_insurer[0], 2); + $parts = explode('-', $propsal_and_insurer, 2); $proposal_key = $parts[0] ?? null; $insurer_key = $parts[1] ?? null; } else { @@ -3811,8 +3811,8 @@ class LeadsController extends BaseController if (! empty($installment_data)) { foreach ($installment_data as $key => $value) { // print_r($value);die - $value['payment_date'] = ! empty($value['payment_date']) && strtotime($value['payment_date']) - ? date('Y/m/d', strtotime($value['payment_date'])) + $value['payment_date'] = ! empty($value['payment_date']) + ? change_date_format($value['payment_date']) : null; if (isset($value['id']) && ! empty($value['id'])) { $this->leadInstallmentPaymentDetails->where('id', $value['id'])->set($value)->update(); @@ -8272,8 +8272,8 @@ class LeadsController extends BaseController if (is_array($installments) && ! empty($installments)) { foreach ($installments as $installment) { - $installment['payment_date'] = ! empty($installment['payment_date']) && strtotime($installment['payment_date']) - ? date('Y-m-d', strtotime($installment['payment_date'])) + $installment['payment_date'] = ! empty($installment['payment_date']) + ? change_date_format($installment['payment_date']) : null; $installment['lead_id'] = $lead_id; @@ -8326,6 +8326,105 @@ class LeadsController extends BaseController } } + public function savePlacementDataWithoutMail() + { + try { + $params = $this->request->getPost(); + + if (empty($params['lead_id'])) { + return $this->respond([ + 'status' => false, + 'code' => 400, + 'message' => 'Opportunity ID is required', + ], 400); + } + + $lead_id = $params['lead_id']; + $lead_data = $this->leadsModel->where('id', $lead_id)->first(); + + if (! $lead_data) { + return $this->respond([ + 'status' => false, + 'code' => 404, + 'message' => 'Lead not found', + ], 404); + } + + $data = [ + 'placement_date' => ! empty($params['placement_date']) ? change_date_format($params['placement_date']) : null, + 'payment_date' => ! empty($params['payment_date']) ? change_date_format($params['payment_date']) : null, + 'utr_no' => $params['utr_no'] ?? null, + 'is_cd' => $params['is_cd'] ?? null, + 'premium_amount' => $params['premium_amount'] ?? null, + 'total_amount' => $params['total_amount'] ?? null, + 'cd_amount' => $params['cd_amount'] ?? null, + 'no_of_installment' => $params['no_of_installment'] ?? null, + 'is_installment' => $params['is_installment'] ?? null, + 'agreed_percentage' => $params['agreed_percentage'] ?? null, + ]; + + if (! empty($params['acm_pk'])) { + $data['acm_id'] = $params['acm_pk']; + } + + if (! empty($params['policy_start_date'])) { + $converted_start = change_date_format($params['policy_start_date']); + if ($converted_start !== $lead_data['policy_start_date']) { + $data['policy_start_date'] = $converted_start; + } + } + + if (! empty($params['policy_end_date'])) { + $converted_end = change_date_format($params['policy_end_date']); + if ($converted_end !== $lead_data['policy_end_date']) { + $data['policy_end_date'] = $converted_end; + } + } + + if (! empty($params['tpa_id']) && strpos($params['tpa_id'], '-') !== false) { + list($tpaBranchId, $tpaId) = explode('-', $params['tpa_id']); + $data['tpa_branch_id'] = $tpaBranchId; + $data['tpa_id'] = $tpaId; + } + + $this->leadsModel->update($lead_id, $data); + + if (! empty($params['installments'])) { + $installments = json_decode($params['installments'], true); + + if (is_array($installments) && ! empty($installments)) { + foreach ($installments as $installment) { + $installment['payment_date'] = ! empty($installment['payment_date']) + ? change_date_format($installment['payment_date']) + : null; + + $installment['lead_id'] = $lead_id; + + if (! empty($installment['id'])) { + $this->leadInstallmentPaymentDetails->update($installment['id'], $installment); + } else { + $this->leadInstallmentPaymentDetails->insert($installment); + } + } + } + } + + return $this->respond([ + 'status' => true, + 'code' => 200, + 'message' => 'Placement data saved successfully', + 'lead_id' => $lead_id, + ], 200); + } catch (\Exception $e) { + return $this->respond([ + 'status' => false, + 'code' => 500, + 'message' => 'Error while saving placement data', + 'error' => $e->getMessage(), + ], 500); + } + } + public function checkMemberDataFileValidationStatus() { $lead_id = $this->request->getVar('lead_id'); diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index a8d1ab90..a381b23f 100644 --- a/app/Controllers/PolicyTransactionController.php +++ b/app/Controllers/PolicyTransactionController.php @@ -40,6 +40,7 @@ use App\Models\NhanceBranchModel; use App\Models\BDSDumpModel; use App\Models\VehicleModel; use CodeIgniter\CLI\CLI; +use Config\BdsConfig; use Exception; class PolicyTransactionController extends BaseController @@ -1023,7 +1024,6 @@ class PolicyTransactionController extends BaseController 'follower_policy_no.*' => ['label' => 'Follower Policy No', 'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9\/_-]+$/]', 'errors' => [ 'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.' ]], - 'calc_policy_issue_date.*' => ['label' => 'Policy Issue Date', 'rules' => 'required', 'errors' => ['required' => 'Policy Issue Date is required']], 'co_share_per.*' => ['label' => 'Co-Share %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Co-Share % must be a valid decimal.']], 'non_comm_per_amt.*' => ['label' => 'Non-Comm Premium', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Amount must be numeric.']], 'base_premium.*' => ['label' => 'Base Premium','rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Base Premium must be numeric.']], @@ -1054,6 +1054,26 @@ class PolicyTransactionController extends BaseController 'exp_amt.*' => ['label' => 'Expected Amount', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'The Expected Amount field must contain a valid number.']] ]; + $isCoShare = !empty($post_data['co_share']); + $calcPolicyIssueDateRule = [ + 'label' => 'Policy Issue Date', + 'rules' => 'required', + 'errors' => ['required' => 'Policy Issue Date is required'], + ]; + + if ($isCoShare) { + $coShareTypes = $post_data['co_share_type'] ?? []; + if (is_array($coShareTypes)) { + foreach ($coShareTypes as $index => $type) { + if ((int) $type === 1) { + $rules["calc_policy_issue_date.$index"] = $calcPolicyIssueDateRule; + } + } + } + } else { + $rules['calc_policy_issue_date.*'] = $calcPolicyIssueDateRule; + } + if(isset($post_data['client_type']) && $post_data['client_type'] == 1){ $rules['client_branch_id'] = ['label' => 'Client Branch', 'rules' => 'required', 'errors' => ['required' => 'Client branch is required']]; } @@ -1181,6 +1201,15 @@ class PolicyTransactionController extends BaseController $data['co_share'] = 1; } + if ($data['co_share'] == 1 && !empty($data['follow_insurer_id']) && is_array($data['follow_insurer_id'])) { + foreach ($data['follow_insurer_id'] as $index => $followInsurer) { + if (($data['co_share_type'][$index] ?? 2) == 1 && !empty($followInsurer)) { + list($data['insurer_branch_id'], $data['insurer_id']) = explode('-', $followInsurer); + break; + } + } + } + // if (!isset($data['bro_payable_by'])) { // $data['bro_payable_by'] = 0; // } elseif ($data['bro_payable_by']) { @@ -5321,6 +5350,16 @@ class PolicyTransactionController extends BaseController $this->myLogger->logme("error", "Cron Job For Send Installment Remainder Mail Started"); try { + /** @var BdsConfig $bdsConfig */ + $bdsConfig = config(BdsConfig::class); + if (!$bdsConfig->shouldFetchInstallmentRemindersToday()) { + $this->myLogger->logme( + 'error', + 'Installment reminder fetch skipped (bds.installmentReminder.enabled / daily / days config)' + ); + CLI::write('Installment reminder fetch skipped per .env configuration'); + return ['status' => false, 'message' => 'Fetch skipped per configuration', 'response' => []]; + } $bdsInstallmentData = []; @@ -5331,11 +5370,11 @@ class PolicyTransactionController extends BaseController } $this->myLogger->logme("error", "Data for BDS Installment " . json_encode($bdsInstallmentData)); - // print_r($bdsInstallmentData);die(); + // print_rr($bdsInstallmentData);die(); if (empty($bdsInstallmentData)) { - $this->myLogger->logme("error", "No Client Installment is Due in the 15th Day"); - CLI::write("No Client Installment is Due in the 15th Day"); + $this->myLogger->logme("error", "No Client Installment is Due in the 5th Day"); + CLI::write("No Client Installment is Due in the 5th Day"); return ['status' => false, 'message' => 'No data found', 'response' => []]; } @@ -5356,8 +5395,10 @@ class PolicyTransactionController extends BaseController $this->myLogger->logme('error', 'res: ' . json_encode($res)); if ($res->status == 'success') { + CLI::write("Mail sent successfully to " . count($to_mail) . " recipients"); return ['status' => true, 'message' => 'Mail sent successfully', 'response' => $res]; } else { + CLI::write("Mail sent failed to " . count($to_mail) . " recipients"); return ['status' => false, 'message' => 'Mail sent failed', 'response' => $res]; } } @@ -5390,14 +5431,17 @@ class PolicyTransactionController extends BaseController Policy No : {$policy_no}"; + $contactPersonEmail = trim((string) ($data['contact_person_email'] ?? '')); + $to_mail = array_merge( array_column($heads, 'email'), array_column($admins, 'email'), array_column($buisness_team, 'email'), - [$sales_person_mail] + [$sales_person_mail], + $contactPersonEmail !== '' ? [$contactPersonEmail] : [] ); - $to_mail = array_unique($to_mail); + $to_mail = array_values(array_unique(array_filter($to_mail))); $this->myLogger->logme("error", "Selected To Address : " . json_encode($to_mail)); diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index a3e0e01c..8da4c33d 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -3321,78 +3321,71 @@ class TicketController extends BaseController } } - public function getPoliciesbyEmpID() + public function getPoliciesbyEmpID() { - $received_data = $this->request->getPost(); - $ticket_type_id = $this->request->getPost('ticket_type_id') ?? null; - $client_id = $this->request->getPost('client_id') ?? null; - $emp_id = $received_data['emp_id']; + $emp_id = (int) ($this->request->getPost('emp_id') ?? 0); + $ticket_type_id = (int) ($this->request->getPost('ticket_type_id') ?? 0); + $client_id = (int) ($this->request->getPost('client_id') ?? 0); - // Get all client policy IDs for the given employee - if ($ticket_type_id == 1) { - - //get the self data for get the all policy list aginst the emp_code - $self_data = $this->employeeModel->where('is_active', 1)->where('id', $emp_id)->first(); - - $db = db_connect(); - $builder = $db->table('employees e'); - $builder->select('ep.*'); - $builder->join('employee_polices ep', 'e.id = ep.employee_id'); - $builder->join('client_policy cp', 'cp.id = ep.client_policy_id AND cp.policy_type_id IN (2,3,4,5)'); - $builder->where('e.is_active', 1); - $builder->where('ep.is_active', 1); - $builder->where('e.emp_code', $self_data['emp_code']); - if(!empty($client_id)){ - $builder->where('e.client_id', $client_id); - } - $builder->groupBy('client_policy_id'); - - $query = $builder->get(); - $policies = $query->getResultArray(); - } else { - - $policies = $this->employeePolicyModel - ->select('client_policy_id') - ->where('employee_id', $emp_id) - ->where('is_active', 1) - ->where('status', 'active') - ->findAll(); + if ($emp_id <= 0) { + return $this->respond(['status' => false, 'message' => 'Invalid Employee']); } - // Return empty if no policies found - if (empty($policies)) { - return []; + $policyTypeMap = [ + 1 => [2, 3, 4, 5], // GMC + 2 => [1], // GPA + 3 => [6], // EDLI + 4 => [7], // GTLI + 72 => [72], // OPD + ]; + + $db = db_connect(); + $builder = $db->table('employee_polices ep'); + $builder->select('ep.client_policy_id'); + $builder->join('employees e', 'e.id = ep.employee_id'); + $builder->join('client_policy cp', 'cp.id = ep.client_policy_id'); + $builder->where('ep.employee_id', $emp_id); + $builder->where('ep.is_active', 1); + $builder->whereIn('ep.status', ['active', 'expired']); + $builder->where('e.is_active', 1); + + if ($client_id > 0) { + $builder->where('e.client_id', $client_id); } - - // Extract client policy IDs into an array - $policy_ids = array_column($policies, 'client_policy_id'); - - // Fetch all policy names and IDs in one query + + if (isset($policyTypeMap[$ticket_type_id])) { + $builder->whereIn('cp.policy_type_id', $policyTypeMap[$ticket_type_id]); + } + + $policyRows = $builder->groupBy('ep.client_policy_id')->get()->getResultArray(); + $policy_ids = array_values(array_unique(array_column($policyRows, 'client_policy_id'))); + + if (empty($policy_ids)) { + return $this->respond(['status' => false, 'message' => 'Policy Not Found']); + } + $policyNameandID = $this->clientPolicyModel ->select(' - CONCAT(policy_type.policy_type, "-", client_policy.policy_no) as client_policy_name, - client_policy.id as client_policy_value, - client_policy.policy_type_id, - client_policy.policy_no, - insurers.id as insurer_id, - insurers.name as insurer_name, - tpa.name as tpa_name, - tpa.id as tpa_id, - ') + CONCAT(policy_type.policy_type, "-", client_policy.policy_no) as client_policy_name, + client_policy.id as client_policy_value, + client_policy.policy_type_id, + client_policy.policy_no, + insurers.id as insurer_id, + insurers.name as insurer_name, + tpa.name as tpa_name, + tpa.id as tpa_id + ') ->join('policy_type', 'policy_type.id = client_policy.policy_type_id AND policy_type.is_active = 1') ->join('insurers', 'insurers.id = client_policy.insurer_id AND insurers.is_active = 1', 'left') ->join('tpa', 'tpa.id = client_policy.tpa_id AND tpa.is_active = 1', 'left') - // ->where('client_policy.policy_status', 1) ->whereIn('client_policy.id', $policy_ids) - ->findAll(); - - // dd($policyNameandID); - if ($policyNameandID){ + ->findAll(); - return $this->respond(['status'=>true,'policy_data'=> $policyNameandID]); - }else{ - return $this->respond(['status'=>false,'message'=> "Policy Not Found"]); + if (!empty($policyNameandID)) { + return $this->respond(['status' => true, 'policy_data' => $policyNameandID]); } + + return $this->respond(['status' => false, 'message' => 'Policy Not Found']); } public function getCheckListAndConvertArrayToString($ticket_data) diff --git a/app/Debug/CorsExceptionHandler.php b/app/Debug/CorsExceptionHandler.php new file mode 100644 index 00000000..977d1257 --- /dev/null +++ b/app/Debug/CorsExceptionHandler.php @@ -0,0 +1,39 @@ +handler = new ExceptionHandler($config); + } + + public function handle( + Throwable $exception, + RequestInterface $request, + ResponseInterface $response, + int $statusCode, + int $exitCode + ): void { + (new Cors())->after($request, $response); + + $this->handler->handle($exception, $request, $response, $statusCode, $exitCode); + } +} diff --git a/app/Filters/Cors.php b/app/Filters/Cors.php index 60a97a89..6d2d3f02 100644 --- a/app/Filters/Cors.php +++ b/app/Filters/Cors.php @@ -355,9 +355,13 @@ class Cors implements FilterInterface return $response; } - // For non-OPTIONS requests, don't return a response - // Let the request proceed to the controller - // CORS headers will be added in after() method + // Apply CORS headers on the shared response before other before-filters run. + // When a before-filter returns early (4xx/5xx), CodeIgniter skips after-filters, + // so relying only on after() leaves error responses without CORS headers. + if (! empty($origin) && $this->isOriginAllowed($origin)) { + $this->addCorsHeaders(Services::response(), $request, $origin, false); + } + return null; } diff --git a/app/Models/BdsPlacementModel.php b/app/Models/BdsPlacementModel.php index e27ecd9c..341e16a2 100644 --- a/app/Models/BdsPlacementModel.php +++ b/app/Models/BdsPlacementModel.php @@ -3,6 +3,7 @@ namespace App\Models; use CodeIgniter\Model; +use Config\BdsConfig; class BdsPlacementModel extends Model { @@ -115,8 +116,31 @@ class BdsPlacementModel extends Model return $data; } + private function addBusinessDays(int $days, ?string $fromDate = null): string + { + $date = new \DateTime($fromDate ?? 'today'); + $added = 0; + + while ($added < $days) { + $date->modify('+1 day'); + if ((int) $date->format('N') < 6) { + $added++; + } + } + + return $date->format('Y-m-d'); + } + public function getLeadInstallmentDetails() { + /** @var BdsConfig $config */ + $config = config(BdsConfig::class); + // print_r($config);die(); + + if (!$config->shouldFetchInstallmentRemindersToday()) { + return []; + } + $heads = $this->db->table('user_profiles') ->select('email')->where(['role' => 5, 'is_active' => 1]) ->get()->getResultArray(); @@ -132,17 +156,30 @@ class BdsPlacementModel extends Model ->get()->getResultArray(); $builder = $this->db->table("lead_installment_payment_details lipd") - ->select("lipd.*, COALESCE(ct.client_name, leads.client_name) as client_name, COALESCE(ct.short_name, leads.client_short_name) as short_name, COALESCE(cb.branch_name, leads.branch_name) as branch_name, leads.salse_person_id, cp.policy_no") + ->select("lipd.*, COALESCE(ct.client_name, leads.client_name) as client_name, COALESCE(ct.short_name, leads.client_short_name) as short_name, COALESCE(cb.branch_name, leads.branch_name) as branch_name, leads.salse_person_id, leads.contact_person_email, cp.policy_no") ->join("leads", "leads.id = lipd.lead_id") ->join("clients ct", "ct.id = leads.client_id", "left") ->join("client_branch cb", "cb.id = leads.client_branch_id", "left") ->join("client_policy cp", "cp.id = leads.source_policy_id", "left") ->where("lipd.is_active", 1) - ->where("lipd.utr_no IS NULL") - ->where("lipd.payment_date", date('Y-m-d', strtotime('+15 days'))); + ->where("lipd.utr_no IS NULL OR lipd.utr_no = ''"); + + $targetPaymentDate = $this->addBusinessDays($config->installmentReminderBusinessDays); + // print_r($targetPaymentDate);die(); + + if ($config->installmentReminderFetchOverduePendingUtr) { + $builder->groupStart() + ->where('lipd.payment_date', $targetPaymentDate) + ->orWhere('lipd.payment_date <', date('Y-m-d')) + ->groupEnd(); + } else { + $builder->where('lipd.payment_date', $targetPaymentDate); + } $data = $builder->get()->getResultArray(); + // print_r($this->db->getLastQuery()->getQuery());die(); + foreach ($data as &$row) { $sales_person_ids = json_decode($row['salse_person_id'], true); $sales_person_id = $sales_person_ids[0] ?? null; diff --git a/app/Models/LeadsModel.php b/app/Models/LeadsModel.php index d194375a..ef88ba21 100644 --- a/app/Models/LeadsModel.php +++ b/app/Models/LeadsModel.php @@ -176,6 +176,10 @@ class LeadsModel extends Model ->join('lead_files', 'leads.id = lead_files.lead_id AND lead_files.type = 2 AND lead_files.is_active = 1', 'left') ->where('leads.is_active', 1); + if (get_role_id() == STAFF_ROLE_ID) { + $data->where('leads.created_by', get_session_userid()); + } + if (! empty($where)) { $data->where($where); } diff --git a/app/Views/client_branch.php b/app/Views/client_branch.php index 61f5ec37..f3ada156 100755 --- a/app/Views/client_branch.php +++ b/app/Views/client_branch.php @@ -202,7 +202,7 @@ input:checked + .slider-branch-contact:before { @@ -265,8 +265,8 @@ input:checked + .slider-branch-contact:before { + data-parsley-pattern="^[A-Za-z\s.]+$" + data-parsley-pattern-message="Contact name may contain only letters, spaces, and periods.">
@@ -773,8 +773,8 @@ function appendContactHtml(contact = false, reset = false) {
+ data-parsley-pattern="^[A-Za-z\\s.]+$" + data-parsley-pattern-message="Contact name may contain only letters, spaces, and periods.">
diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php index 26bcab2c..101ab426 100755 --- a/app/Views/client_policy.php +++ b/app/Views/client_policy.php @@ -37,9 +37,12 @@ font-weight: 500; color: #333; justify-content: flex-end; - margin-right: 40px; } +.expired-policies-toggle-wrap { + padding-bottom: 10px; +} + .switch-label input { opacity: 0; width: 0; @@ -48,7 +51,8 @@ .switch-label .slider, .switch-label .slider_blue { - pointer-events: none; + cursor: pointer; + flex-shrink: 0; } .slider, @@ -142,19 +146,15 @@ input:checked + .slider_blue::before {
- -
- -
- -
+
+ +
@@ -177,8 +177,8 @@ input:checked + .slider_blue::before {
-
- +
+

@@ -1546,14 +1546,8 @@ input:checked + .slider_blue::before { return isNaN(parsed.getTime()) ? null : parsed; } - var policyMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; - function formatPolicyDisplayDate(inputDate) { - var d = parsePolicyDate(inputDate); - if (!d) { - return (inputDate && String(inputDate).trim() !== '') ? String(inputDate) : ''; - } - return d.getDate() + '/' + policyMonthNames[d.getMonth()] + '/' + d.getFullYear(); + return formatPolicyFormDate(inputDate); } function formatPolicyFormDate(inputDate) { @@ -2903,7 +2897,7 @@ $(document).ready(function () { $('#table-client-policy').DataTable().clear().destroy(); } - $('#table-client-policy tbody').html(policyTable); // replace tbody content + $('#policy_table').html(policyTable); const policyTableInstance = $('#table-client-policy').DataTable({ paging: true, diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php index 7a0e9ff2..25c51f36 100755 --- a/app/Views/layout/header.php +++ b/app/Views/layout/header.php @@ -2017,7 +2017,7 @@ body[data-sidebar-size="condensed"] .footer {
  • Retail Endorsement
  • - +
  • TPA Reports
  • @@ -2218,7 +2218,7 @@ body[data-sidebar-size="condensed"] .footer {
    " required> + " required>
    - " required> + " required>
    - "> + ">
    @@ -945,7 +945,7 @@
    - "> + ">
    @@ -962,8 +962,14 @@
    + +

    +
    + +
    +
    @@ -1018,6 +1024,7 @@
    +
    @@ -1026,8 +1033,6 @@
    -
    -

    Attachments Files


    @@ -1037,6 +1042,7 @@
    +
    @@ -1327,22 +1333,22 @@ const editor2 = Jodit.make("#internal_mail_content", editorConfig); var placement_date_datePicker = flatpickr("#placement_date", { - dateFormat: "d-m-Y", + dateFormat: "d/m/Y", allowInput: false, }); var payment_date_datePicker = flatpickr("#payment_date", { - dateFormat: "d-m-Y", + dateFormat: "d/m/Y", allowInput: false, }); var policy_start_date_datePicker = flatpickr("#policy_start_date", { - dateFormat: "d-m-Y", + dateFormat: "d/m/Y", allowInput: false, }); var policy_end_date_datePicker = flatpickr("#policy_end_date", { - dateFormat: "d-m-Y", + dateFormat: "d/m/Y", allowInput: false, }); @@ -4664,7 +4670,7 @@ function appendInsurerContact(data) { $.each(data, function(index, item) { $('#placement_to').append($('