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..6b6a8e33 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -44,7 +44,7 @@ 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]], 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/Controllers/ClientController.php b/app/Controllers/ClientController.php index 8879cda2..de22eacf 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -7822,20 +7822,18 @@ class ClientController extends AdminController ->join('employees', 'clients.id = employees.client_id', 'left') ->join('employee_polices', 'employees.id = employee_polices.employee_id', 'left') ->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) + ->where('employee_polices.client_policy_id', $param) ->groupBy('employees.emp_code') ->get() ->getResultArray(); - // print_r(db_connect()->getLastQuery()); die; + // print_r(db_connect()->getLastQuery()->getQuery()); die; $dataForClientAndInsurer = $this->clientPolicyModel ->select(" @@ -7938,8 +7936,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 +7962,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/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index 02852b26..a7592ca0 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 @@ -5349,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 = []; @@ -5418,14 +5429,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/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 c0267eb8..84b349a1 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 { @@ -132,6 +133,13 @@ class BdsPlacementModel extends Model public function getLeadInstallmentDetails() { + /** @var BdsConfig $config */ + $config = config(BdsConfig::class); + + if (!$config->shouldFetchInstallmentRemindersToday()) { + return []; + } + $heads = $this->db->table('user_profiles') ->select('email')->where(['role' => 5, 'is_active' => 1]) ->get()->getResultArray(); @@ -147,14 +155,24 @@ 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", $this->addBusinessDays(5)); + ->where("lipd.utr_no IS NULL"); + + $targetPaymentDate = $this->addBusinessDays($config->installmentReminderBusinessDays); + + 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(); diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php index 7be33e5e..101ab426 100755 --- a/app/Views/client_policy.php +++ b/app/Views/client_policy.php @@ -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) { diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php index 7a0e9ff2..098229d9 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