From 1fd983ea7b256262427bd0a3e772f47272b6abe5 Mon Sep 17 00:00:00 2001 From: Venkatesh Date: Tue, 4 Aug 2026 14:29:04 +0530 Subject: [PATCH 1/2] CHANGE_MAIL_SEND --- app/Controllers/EmployeeController.php | 41 +- app/Controllers/EmployeeRestController.php | 222 ++++++++++- app/Models/EmployeePolicyModel.php | 7 + .../employee_pending_approvals_data_list.php | 371 +++++++++++++----- app/Views/employee_pending_approvals_list.php | 132 +++---- app/Views/layout/header.php | 2 +- 6 files changed, 564 insertions(+), 211 deletions(-) diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 34480720..4ed9f93b 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -169,18 +169,37 @@ class EmployeeController extends AdminController $data = []; $filterData = $this->request->getGet() ?: []; - $data['employees'] = $this->employeePolicyModel->getPendingApprovalDependents( - client_id: $filterData['client_id'] ?? null, - policy_id: $filterData['policy_id'] ?? null, - branch_id: $filterData['branch_id'] ?? null, + $client_id = $filterData['client_id'] ?? null; + $policy_id = $filterData['policy_id'] ?? null; + $branch_id = $filterData['branch_id'] ?? null; + + $employees = $this->employeePolicyModel->getPendingApprovalDependents( + client_id: $client_id, + policy_id: $policy_id, + branch_id: $branch_id, ); + + // Default: only pending_approval. When ACM filters client + branch + policy → show all statuses. + $hasFullFilter = ! empty($client_id) && $client_id != '0' + && ! empty($branch_id) && $branch_id != '0' + && ! empty($policy_id) && $policy_id != '0'; + + if (! $hasFullFilter && ! empty($employees)) { + $employees = array_values(array_filter($employees, static function ($row) { + return strtolower((string) ($row['status'] ?? '')) === 'pending_approval'; + })); + } + + $data['employees'] = $employees; $data['getData'] = [ - 'client_id' => $filterData['client_id'] ?? '0', - 'policy_id' => $filterData['policy_id'] ?? '0', - 'branch_id' => $filterData['branch_id'] ?? '0', + 'client_id' => $client_id ?? '0', + 'policy_id' => $policy_id ?? '0', + 'branch_id' => $branch_id ?? '0', 'emp_code' => '', 'emp_name' => '', - 'status' => ['pending_approval', 'active', 'rejected'], + 'status' => $hasFullFilter + ? ['pending_approval', 'active', 'rejected'] + : ['pending_approval'], ]; // AJAX filter submit → return table HTML only @@ -189,9 +208,9 @@ class EmployeeController extends AdminController return $this->respond(['status' => true, 'html' => $html], 200); } - // Default page load → list all pending dependents - $data['tab_name'] = 'Pending Approvals'; - $data['page_name'] = 'Pending Approvals'; + // Default page load → list pending dependents only + $data['tab_name'] = 'Approvals'; + $data['page_name'] = 'Approvals'; $data['default_table_html'] = view('employee_pending_approvals_data_list', $data); $this->loadLayout('employee_pending_approvals_list', $data); diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 874be0c1..3c16bc58 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -6365,6 +6365,7 @@ class EmployeeRestController extends AdminController if ($data) { $Count = 0; + $newDependentsForNotification = []; foreach ($data as $item) { $self_data = $this->employeeModel @@ -6402,6 +6403,18 @@ class EmployeeRestController extends AdminController if ($employee) { $Count++; + $newDependentsForNotification[] = [ + 'employee_id' => (int) $employee, + 'emp_code' => (string) ($item->emp_code ?? ''), + 'dependent_name' => (string) ($item->name ?? ''), + 'relationship' => (string) ($item->relationship ?? ''), + 'dob' => (string) ($item->dob ?? ''), + 'client_id' => (int) ($item->client_id ?? 0), + 'client_branch_id' => (int) ($item->client_branch_id ?? 0), + 'client_policy_id' => (int) ($item->client_policy_id ?? 0), + 'dependent_effective_date' => (string) ($item->dependent_effective_date ?? ''), + 'created_by_type' => isset($item->hr_id) ? 'HR' : 'USER', + ]; } } } @@ -6417,6 +6430,12 @@ class EmployeeRestController extends AdminController $this->updatePremiumAmount($data[0]->client_policy_id, $data[0]->emp_code, $data[0]->client_branch_id); + if (! empty($newDependentsForNotification)) { + foreach ($newDependentsForNotification as $dependentNotificationData) { + $this->sendDependentAddNotificationMail($dependentNotificationData); + } + } + $result = []; return $this->respond(['status' => 'success', 'code' => 200, 'data' => $result], 200); } else { @@ -6432,6 +6451,130 @@ class EmployeeRestController extends AdminController } } + /** + * Notify client/branch HRs and client account managers when a dependent is added. + */ + private function sendDependentAddNotificationMail(array $dependentData): void + { + try { + $clientId = (int) ($dependentData['client_id'] ?? 0); + $branchId = (int) ($dependentData['client_branch_id'] ?? 0); + $clientPolicyId = (int) ($dependentData['client_policy_id'] ?? 0); + + if ($clientId <= 0 || $branchId <= 0 || $clientPolicyId <= 0) { + return; + } + + $db = \Config\Database::connect(); + + $clientData = $this->clientModel + ->select('id, client_name, email') + ->where('id', $clientId) + ->first(); + + $branchData = $this->clientBranchModel + ->select('id, branch_name') + ->where('id', $branchId) + ->first(); + + $policyData = $this->clientPolicyModel + ->select('id, policy_no') + ->where('id', $clientPolicyId) + ->first(); + + $selfEmployee = $this->employeeModel + ->select('name') + ->where('client_id', $clientId) + ->where('emp_code', (string) ($dependentData['emp_code'] ?? '')) + ->where('relationship', 'Self') + ->where('is_active', 1) + ->first(); + + $branchHrEmails = $db->table('level_contacts') + ->select('email') + ->where('ref_id', $branchId) + ->where('contact_type', 'client') + ->where('is_active', 1) + ->where('email IS NOT NULL', null, false) + ->where("TRIM(email) != ''", null, false) + ->get() + ->getResultArray(); + + $accountManagerEmails = $this->clientRMModel->findAccountManagerEmail($clientId) ?? []; + + $recipientEmails = []; + + if (! empty($clientData['email'])) { + $recipientEmails[] = trim((string) $clientData['email']); + } + + foreach ($branchHrEmails as $branchHrEmailRow) { + $recipientEmails[] = trim((string) ($branchHrEmailRow['email'] ?? '')); + } + + if (is_array($accountManagerEmails)) { + foreach ($accountManagerEmails as $accountManagerEmail) { + $recipientEmails[] = trim((string) $accountManagerEmail); + } + } + + $recipientEmails = array_values(array_unique(array_filter($recipientEmails, static function ($email) { + return filter_var($email, FILTER_VALIDATE_EMAIL); + }))); + + if (empty($recipientEmails)) { + log_message('info', '[DependentAddMail] No recipient emails found for client_id=' . $clientId . ', branch_id=' . $branchId); + return; + } + + $clientName = (string) ($clientData['client_name'] ?? ''); + $branchName = (string) ($branchData['branch_name'] ?? ''); + $policyNo = (string) ($policyData['policy_no'] ?? ''); + $employeeName = (string) ($selfEmployee['name'] ?? ''); + + $dependentName = (string) ($dependentData['dependent_name'] ?? ''); + $relationship = (string) ($dependentData['relationship'] ?? ''); + $dependentDob = ! empty($dependentData['dob']) ? date('d/m/Y', strtotime((string) $dependentData['dob'])) : '-'; + $effectiveDate = ! empty($dependentData['dependent_effective_date']) ? date('d/m/Y', strtotime((string) $dependentData['dependent_effective_date'])) : '-'; + $createdByType = (string) ($dependentData['created_by_type'] ?? 'USER'); + $employeeCode = (string) ($dependentData['emp_code'] ?? ''); + + $subject = 'Dependent Added - Approval Required | ' . ($clientName ?: 'Client'); + + $message = ' +

Dear ' . esc($employeeName ?: 'Team') . ',

+

A new dependent has been added and is pending for approval.

+ + + + + + + + + + + +
Client' . esc($clientName) . '
Branch' . esc($branchName) . '
Policy' . esc($policyNo) . '
Employee' . esc($employeeName) . '
Employee Code' . esc($employeeCode) . '
Dependent Name' . esc($dependentName) . '
Relationship' . esc($relationship) . '
Date of Birth' . esc($dependentDob) . '
Effective Date' . esc($effectiveDate) . '
Added By' . esc($createdByType) . '
+

Please review this request in Approvals.

+ '; + + $mailPayload = [ + 'mail' => $recipientEmails, + 'subject' => $subject, + 'message' => $message, + 'attachments' => [], + 'reply_to' => '', + ]; + + $mailResult = MailHelper::send_email($mailPayload); + $this->myLogger->logme('info', '[DependentAddMail] mail_result=' . json_encode($mailResult)); + } catch (\Throwable $th) { + log_message('error', '[DependentAddMail] ' . $th->getMessage() . ' in ' . $th->getFile() . ':' . $th->getLine()); + $this->myLogger->logme('error', '[DependentAddMail] ' . $th->getMessage()); + } + } + public function deleteDependencev2() { try { @@ -6707,8 +6850,22 @@ class EmployeeRestController extends AdminController } return $this->employeePolicyModel - ->select('employees.*, employee_polices.employee_id, employee_polices.basic_cover_si, employee_polices.premium, employee_polices.gst, employee_polices.tpa_id, employee_polices.rand_string, employee_polices.uhid as uhid') + ->select(' + employees.*, + employee_polices.employee_id, + employee_polices.basic_cover_si, + employee_polices.premium, + employee_polices.gst, + employee_polices.tpa_id, + employee_polices.rand_string, + employee_polices.uhid as uhid, + employee_polices.processed_by, + employee_polices.reject_reason, + employee_polices.date_coverage + ') ->join('employees', 'employee_polices.employee_id = employees.id', 'left') + ->join('client_policy', 'client_policy.id = employee_polices.client_policy_id', 'left') + ->join('policy_type', 'policy_type.id = client_policy.policy_type_id', 'left') ->whereIn('employee_polices.employee_id', $employeeIds) ->where('employee_polices.client_policy_id', $client_policy_id) ->where('employee_polices.is_active', 1) @@ -6755,41 +6912,59 @@ class EmployeeRestController extends AdminController $employee = $this->employeeModel ->where('id', $employee_id) - ->where('is_active', 1) ->first(); if (!$employee) { - return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Employee not found or inactive'], 200); + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Employee not found'], 200); } - if (($employee['emp_status'] ?? null) === 'active') { + $emp_status = strtolower((string) ($employee['emp_status'] ?? '')); + + if ($emp_status === 'active') { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Dependent is already approved'], 200); } - if (($employee['emp_status'] ?? null) !== 'pending_approval') { - return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Dependent is not pending approval'], 200); + if ($status === 'approved') { + if (! in_array($emp_status, ['pending_approval', 'rejected'], true)) { + return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Dependent cannot be approved'], 200); + } + } elseif ($emp_status !== 'pending_approval') { + return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Only pending dependents can be rejected'], 200); } $employee_policy = $this->employeePolicyModel ->where('employee_id', $employee_id) ->where('client_policy_id', $client_policy_id) - ->where('is_active', 1) ->first(); if (!$employee_policy) { - return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Employee policy not found or inactive'], 200); + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Employee policy not found'], 200); + } + + $policy_status = strtolower((string) ($employee_policy['status'] ?? '')); + + if ($status === 'approved') { + if (! in_array($policy_status, ['pending_approval', 'rejected'], true)) { + return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Employee policy cannot be approved'], 200); + } + } elseif ($policy_status !== 'pending_approval') { + return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'Only pending employee policy can be rejected'], 200); } if ($status === 'approved') { $employee_update_data = [ - 'updated_by' => $updated_by, - 'processed_by' => $processed_by_role, - 'emp_status' => 'active', + 'updated_by' => $updated_by, + 'processed_by' => $processed_by_role, + 'emp_status' => 'active', + 'is_active' => 1, + 'reject_reason' => null, ]; $policy_update_data = [ - 'updated_by' => $updated_by, - 'processed_by' => $processed_by_role, - 'status' => 'active', + 'updated_by' => $updated_by, + 'processed_by' => $processed_by_role, + 'status' => 'active', + 'is_active' => 1, + 'reject_reason' => null, ]; } else { $employee_update_data = [ @@ -6808,11 +6983,7 @@ class EmployeeRestController extends AdminController ]; } - $employee_updated = $this->employeeModel - ->where('id', $employee_id) - ->where('is_active', 1) - ->set($employee_update_data) - ->update(); + $employee_updated = $this->employeeModel->update($employee_id, $employee_update_data); if (!$employee_updated) { return $this->respond(['status' => 'failed', 'code' => 500, 'data' => 'Failed to update employee status'], 200); @@ -6821,7 +6992,6 @@ class EmployeeRestController extends AdminController $policy_updated = $this->employeePolicyModel ->where('employee_id', $employee_id) ->where('client_policy_id', $client_policy_id) - ->where('is_active', 1) ->set($policy_update_data) ->update(); @@ -6829,7 +6999,17 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'failed', 'code' => 500, 'data' => 'Failed to update employee policy status'], 200); } - return $this->respond(['status' => 'success', 'code' => 200, 'data' => []], 200); + return $this->respond([ + 'status' => 'success', + 'code' => 200, + 'message' => $status === 'approved' ? 'Dependent approved successfully' : 'Dependent rejected successfully', + 'data' => [ + 'employee_id' => $employee_id, + 'client_policy_id' => $client_policy_id, + 'status' => $status, + 'reject_reason' => $status === 'rejected' ? $reject_reason : null, + ], + ], 200); } catch (\Exception $e) { log_message('error', 'Error in processDependentAdd: ' . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine()); return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500); diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php index c500495f..54905353 100755 --- a/app/Models/EmployeePolicyModel.php +++ b/app/Models/EmployeePolicyModel.php @@ -420,6 +420,7 @@ class EmployeePolicyModel extends Model 'emp.emp_status', 'emp.is_active as emp_is_active', 'emp.reject_reason as emp_reject_reason', + 'employee_polices.reject_reason as policy_reject_reason', 'emp.processed_by as emp_processed_by', 'emp.mobile as mobile', 'emp.doj', @@ -483,6 +484,12 @@ class EmployeePolicyModel extends Model ->where('employee_polices.status', 'rejected') ->groupEnd() ->groupEnd() + ->orderBy("CASE + WHEN employee_polices.status = 'pending_approval' THEN 1 + WHEN employee_polices.status = 'rejected' THEN 2 + WHEN employee_polices.status = 'active' THEN 3 + ELSE 4 + END", 'ASC', false) ->orderBy('employee_polices.updated_at', 'DESC') ->orderBy('emp.emp_code', 'ASC') ->orderBy('employee_polices.employee_id', 'ASC'); diff --git a/app/Views/employee_pending_approvals_data_list.php b/app/Views/employee_pending_approvals_data_list.php index 0ea20681..792bc98f 100644 --- a/app/Views/employee_pending_approvals_data_list.php +++ b/app/Views/employee_pending_approvals_data_list.php @@ -1,111 +1,242 @@
-
-
-

Pending Approvals

-
-
- +
- - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + $employee) { - $pro_rata_total += (float) ($employee['rata_premimum'] ?? 0); - $gst_total += (float) ($employee['gst'] ?? 0); + foreach ($employees as $employee) { + $rowStatus = strtolower((string) ($employee['status'] ?? '')); ?> - - - - + - - - - - - - - - + + + - - - - - - - - - - - - - - - -
S.NoBranchNameEMP CodeRelationshipGenderEmailMobileDate of BirthPolicy nameInsurer nameTPA IDRisk IDPolicy statusProcessed ByReject Reason(₹)Sum Insured(₹)Premium(₹)Pro Rata Premium(₹)GSTActionEmployee Dependent Relationship Date Of Birth Dependent Effective Date Policy Status Action 
+ + + Pending Approval'; + echo 'Pending'; } elseif ($rowStatus === 'active') { - echo 'Approved'; + echo 'Approved'; } elseif ($rowStatus === 'rejected') { - echo 'Rejected'; + echo 'Rejected'; } else { - echo esc($employee['status'] ?? ''); + echo esc($employee['status'] ?? '-'); } ?> + + - + + + + + + + + - @@ -114,15 +245,6 @@ $gst_total = 0;
Total
@@ -131,11 +253,78 @@ $gst_total = 0;
diff --git a/app/Views/employee_pending_approvals_list.php b/app/Views/employee_pending_approvals_list.php index d89014ba..4e055d8d 100644 --- a/app/Views/employee_pending_approvals_list.php +++ b/app/Views/employee_pending_approvals_list.php @@ -110,92 +110,26 @@ var client_branch_id = ''; function init() { - const table = document.getElementById("tickets-table") || document.getElementById("employee-data-list-table"); - if (!table) return; - - let activeDropdown = null; - - table.querySelectorAll("tbody tr").forEach(row => { - const customDropdown = createCustomDropdown(row); - if (!customDropdown) return; - - document.body.appendChild(customDropdown); - - row.addEventListener("click", function(event) { - handleRowClick(event, customDropdown); - }); - - customDropdown.querySelectorAll('.dropdown-item').forEach(item => { - item.addEventListener('click', function(e) { - handleItemClick(e, item); - }); - }); - }); - - document.addEventListener("click", handleDocumentClick); - - function createCustomDropdown(row) { - const originalDropdown = row.querySelector('.dropdown-menu'); - if (!originalDropdown) return null; - - const customDropdown = document.createElement('div'); - customDropdown.className = 'custom-dropdown-menu'; - const originalItems = originalDropdown.querySelectorAll('.dropdown-item'); - customDropdown.innerHTML = originalDropdown.innerHTML; - - customDropdown.querySelectorAll('.dropdown-item').forEach((item, index) => { - const originalItem = originalItems[index]; - const originalOnclick = originalItem.getAttribute('onclick'); - if (originalOnclick) { - item.setAttribute('data-onclick', originalOnclick); - item.removeAttribute('onclick'); - } - }); - - return customDropdown; - } - - function handleRowClick(event, customDropdown) { - if (event.target.closest('td:last-child')) { - return; - } - if (activeDropdown) { - activeDropdown.style.display = 'none'; - } - const rect = event.target.getBoundingClientRect(); - customDropdown.style.display = 'block'; - customDropdown.style.position = 'fixed'; - customDropdown.style.left = `${rect.left}px`; - customDropdown.style.top = `${rect.bottom + 5}px`; - activeDropdown = customDropdown; - event.stopPropagation(); - } - - function handleItemClick(e, item) { - const onclickAttr = item.getAttribute('data-onclick'); - if (onclickAttr) { - eval(onclickAttr); - } - const href = item.getAttribute('href'); - if (href && href !== '#' && href !== 'javascript: void(0);') { - window.location.href = href; - } - if (activeDropdown) { - activeDropdown.style.display = 'none'; - activeDropdown = null; - } - e.stopPropagation(); - } - - function handleDocumentClick() { - if (activeDropdown) { - activeDropdown.style.display = 'none'; - activeDropdown = null; - } - } + initPendingApprovalsDataTable(); } $(document).ready(function() { + $("#clients").select2({ + width: '100%', + placeholder: 'Select' + }); + $("#branch_id").select2({ + width: '100%', + placeholder: 'Select' + }); + $("#policies").select2({ + width: '100%', + placeholder: 'Select' + }); + + $("textarea.select2-search__field").attr('rows', '1'); + $("textarea.select2-search__field").css('resize', 'none'); + getClientAndBranchAndPolicy(); setTimeout(function() { init(); @@ -214,6 +148,17 @@ policy_list = res.policy_data; policy_list_by_client = res.policyListByClient; appendClients(client_list); + + if (client_id && client_id !== '0' && branch_list[client_id]) { + appendBranch(branch_list[client_id]); + } + + if (client_id && client_id !== '0' && client_branch_id && client_branch_id !== '0') { + var initialPolicies = (policy_list_by_client[client_id] || []).filter(function(item) { + return String(item.client_branch_id) === String(client_branch_id); + }); + appendPolicies(initialPolicies); + } } }, error: function(xhr, status, error) { @@ -235,6 +180,7 @@ } $('#clients').append(option); }); + $('#clients').trigger('change.select2'); } function appendBranch(data) { @@ -253,6 +199,7 @@ } $('#branch_id').append(option); }); + $('#branch_id').trigger('change.select2'); } function appendPolicies(data) { @@ -273,6 +220,7 @@ } $('#policies').append(option); }); + $('#policies').trigger('change.select2'); } $(document).ready(function() { @@ -281,6 +229,8 @@ $('#branch_id').append($('