MERGE_TEST_BUG_FIXES

This commit is contained in:
Ubuntu 2026-08-04 14:49:17 +05:30
commit efe78a258c
7 changed files with 569 additions and 211 deletions

View File

@ -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);

View File

@ -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,133 @@ 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 = '
<p>Dear ' . esc($employeeName ?: 'Team') . ',</p>
<p>A new dependent has been added and is pending for approval.</p>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse;">
<tr><td><strong>Client</strong></td><td>' . esc($clientName) . '</td></tr>
<tr><td><strong>Branch</strong></td><td>' . esc($branchName) . '</td></tr>
<tr><td><strong>Policy</strong></td><td>' . esc($policyNo) . '</td></tr>
<tr><td><strong>Employee</strong></td><td>' . esc($employeeName) . '</td></tr>
<tr><td><strong>Employee Code</strong></td><td>' . esc($employeeCode) . '</td></tr>
<tr><td><strong>Dependent Name</strong></td><td>' . esc($dependentName) . '</td></tr>
<tr><td><strong>Relationship</strong></td><td>' . esc($relationship) . '</td></tr>
<tr><td><strong>Date of Birth</strong></td><td>' . esc($dependentDob) . '</td></tr>
<tr><td><strong>Effective Date</strong></td><td>' . esc($effectiveDate) . '</td></tr>
<tr><td><strong>Added By</strong></td><td>' . esc($createdByType) . '</td></tr>
</table>
<p>Please review this request in Approvals.</p>
<p>Best regards,<br>Nhance Team</p>
<p><small>This is an auto-generated email. Please do not reply.</small></p>
';
$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 +6853,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 +6915,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 +6986,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 +6995,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 +7002,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);

View File

@ -337,6 +337,8 @@ class MailHelper
$cc = (isset($params['cc']) && !empty($params['cc'])) ? $params['cc'] : '';
$from_address = isset($params['from_mail']) && !empty($params['from_mail']) ? $params['from_mail'] : getenv('email.fromEmail');
$params['from_mail'] = $from_address;
// $from_address = "claims@nhanceindia.in";
if(isset($params['common'])){ $params['common']['from_mail'] = $from_address; }
try {

View File

@ -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');

View File

@ -1,111 +1,242 @@
<?php
$getData = $getData ?? [];
$pro_rata_total = 0;
$gst_total = 0;
if (! function_exists('format_pending_approval_date')) {
function format_pending_approval_date($date)
{
if (empty($date)) {
return '-';
}
$timestamp = strtotime((string) $date);
return $timestamp ? date('d/m/Y', $timestamp) : '-';
}
}
?>
<style>
.badge2 { display: inline-block; padding: .25em .4em; font-size: 75%; font-weight: 700; line-height: 1; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: .25rem; }
.badge2-secondary2 { color: #fff; background-color: #187607; }
.table-responsive { overflow-x: auto; }
#client_list .card-body {
padding: 12px 16px 8px;
}
#pending-approvals-table .approval-action-btn {
width: 28px;
height: 28px;
padding: 0;
line-height: 28px;
border-radius: 50%;
}
#pending-approvals-table .employee-meta {
line-height: 1.2;
}
#pending-approvals-table .employee-meta small {
display: block;
color: #6c757d;
font-size: 11px;
margin-top: 1px;
}
#pending-approvals-table .approval-status-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 72px;
width: 72px;
height: 22px;
padding: 0;
font-size: 11px;
font-weight: 600;
border-radius: 12px;
line-height: 1;
}
#pending-approvals-table .approval-reject-info {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
margin-left: 6px;
color: #dc3545;
cursor: pointer;
vertical-align: middle;
font-size: 18px;
line-height: 1;
}
#pending-approvals-table .approval-reject-info:hover,
#pending-approvals-table .approval-reject-info:focus {
color: #00999E;
outline: none;
}
#pending-approvals-table .approval-reject-tooltip-text {
visibility: hidden;
opacity: 0;
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
min-width: 160px;
max-width: 280px;
padding: 6px 10px;
background: #343a40;
color: #fff;
font-size: 12px;
font-weight: 400;
line-height: 1.4;
border-radius: 6px;
white-space: normal;
word-wrap: break-word;
z-index: 9999;
pointer-events: none;
text-align: left;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: opacity 0.15s ease;
}
#pending-approvals-table .approval-reject-tooltip-text::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: #343a40;
}
#pending-approvals-table .approval-reject-info:hover .approval-reject-tooltip-text,
#pending-approvals-table .approval-reject-info:focus .approval-reject-tooltip-text {
visibility: visible;
opacity: 1;
}
#pending-approvals-table .badge {
font-size: 11px;
padding: 3px 8px;
}
#pending-approvals-table tbody td:last-child {
overflow: visible !important;
text-overflow: clip;
position: relative;
}
#pending-approvals-table_wrapper .dataTables_scrollBody,
#pending-approvals-table_wrapper table.dataTable tbody td:last-child {
overflow: visible !important;
}
#pending-approvals-table_wrapper .row {
margin-left: 0;
margin-right: 0;
margin-bottom: 6px;
}
#pending-approvals-table_wrapper .row:last-child {
margin-bottom: 0;
}
#pending-approvals-table_wrapper .dataTables_filter,
#pending-approvals-table_wrapper .dt-buttons {
margin-bottom: 0;
}
#pending-approvals-table_wrapper .dataTables_filter label {
margin-bottom: 0;
}
#pending-approvals-table_wrapper .dataTables_info,
#pending-approvals-table_wrapper .dataTables_length label,
#pending-approvals-table_wrapper .dataTables_paginate {
margin-bottom: 0;
padding-top: 0;
font-size: 13px;
}
#pending-approvals-table_wrapper .dataTables_length select {
margin: 0 6px;
padding: 2px 6px;
height: auto;
}
</style>
<div class="row" id="client_list">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row" style="padding-bottom: 10px;">
<div class="col-6" style="align-self: center;">
<h4 style="position: relative;">Pending Approvals</h4>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover m-0 table-centered nowrap w-100" cellspacing="0" id="employee-data-list-table">
<table data-custom-table-css="table" class="table table-hover mb-0 nowrap w-100 table-centered m-0" cellspacing="0" id="pending-approvals-table">
<thead class="bg-light">
<tr>
<th>S.No</th>
<?php if (($getData['client_id'] ?? '0') != '0' && ($getData['branch_id'] ?? '0') == '0') { ?>
<th>Branch</th>
<?php } ?>
<th>Name</th>
<th>EMP Code</th>
<th>Relationship</th>
<th>Gender</th>
<th>Email</th>
<th>Mobile</th>
<th>Date of Birth</th>
<th>Policy name</th>
<th>Insurer name</th>
<th>TPA ID</th>
<th>Risk ID</th>
<th>Policy status</th>
<th>Processed By</th>
<th>Reject Reason</th>
<th>()Sum Insured</th>
<th>()Premium</th>
<th>()Pro Rata Premium</th>
<th>()GST</th>
<th>Action</th>
<th class="font-weight-medium">Employee&nbsp;</th>
<th class="font-weight-medium">Dependent&nbsp;</th>
<th class="font-weight-medium">Relationship&nbsp;</th>
<th class="font-weight-medium">Date Of Birth&nbsp;</th>
<th class="font-weight-medium">Dependent Effective Date&nbsp;</th>
<th class="font-weight-medium">Policy&nbsp;</th>
<th class="font-weight-medium">Status&nbsp;</th>
<th class="font-weight-medium text-center">Action&nbsp;</th>
</tr>
</thead>
<tbody class="font-12">
<?php if (! empty($employees)) {
foreach ($employees as $key => $employee) {
$pro_rata_total += (float) ($employee['rata_premimum'] ?? 0);
$gst_total += (float) ($employee['gst'] ?? 0);
foreach ($employees as $employee) {
$rowStatus = strtolower((string) ($employee['status'] ?? ''));
?>
<tr>
<td><b><?= $key + 1 ?></b></td>
<?php if (($getData['client_id'] ?? '0') != '0' && ($getData['branch_id'] ?? '0') == '0') { ?>
<td><?= esc($employee['client_branch_name'] ?? '') ?></td>
<?php } ?>
<td class="employee-meta">
<?= esc($employee['self_name'] ?? '-') ?>
<small><?= esc($employee['emp_code'] ?? '') ?></small>
</td>
<td><?= esc($employee['name'] ?? '') ?></td>
<td><?= esc($employee['emp_code'] ?? '') ?></td>
<td><?= esc($employee['relationship'] ?? '') ?></td>
<td><?= esc($employee['gender'] ?? '') ?></td>
<td><?= esc($employee['email_corporate'] ?? '') ?></td>
<td><?= esc($employee['mobile'] ?? '') ?></td>
<td><?= ! empty($employee['dob']) ? date('d/m/Y', strtotime($employee['dob'])) : '-' ?></td>
<td><?= esc(($employee['policy_type'] ?? '') . ' - ' . ($employee['policy_no'] ?? '')) ?></td>
<td><?= esc($employee['insurer_short_name'] ?? '') ?></td>
<td><?= esc($employee['tpa_id'] ?? '') ?></td>
<td><?= esc($employee['uhid'] ?? '') ?></td>
<td><?= format_pending_approval_date($employee['dob'] ?? null) ?></td>
<td><?= format_pending_approval_date($employee['date_coverage'] ?? null) ?></td>
<td><?= esc($employee['policy_no'] ?? '') ?></td>
<td>
<?php
$rowStatus = strtolower((string) ($employee['status'] ?? ''));
if ($rowStatus === 'pending_approval') {
echo '<span class="badge badge-info">Pending Approval</span>';
echo '<span class="badge badge-warning approval-status-badge">Pending</span>';
} elseif ($rowStatus === 'active') {
echo '<span class="badge badge-success">Approved</span>';
echo '<span class="badge badge-success approval-status-badge">Approved</span>';
} elseif ($rowStatus === 'rejected') {
echo '<span class="badge badge-danger">Rejected</span>';
echo '<span class="badge badge-danger approval-status-badge">Rejected</span>';
} else {
echo esc($employee['status'] ?? '');
echo esc($employee['status'] ?? '-');
}
?>
</td>
<td><?= esc($employee['processed_by'] ?? $employee['emp_processed_by'] ?? '-') ?></td>
<td><?= esc($employee['reject_reason'] ?? $employee['emp_reject_reason'] ?? '-') ?></td>
<td><?= format_indian_number($employee['basic_cover_si'] ?? 0) ?></td>
<td><?= format_indian_number($employee['premium'] ?? 0) ?></td>
<td><?= format_indian_number($employee['rata_premimum'] ?? 0) ?></td>
<td><?= format_indian_number($employee['gst'] ?? 0) ?></td>
<td>
<td class="text-nowrap text-center">
<?php
$rejectReason = trim((string) (
$employee['reject_reason']
?? $employee['emp_reject_reason']
?? $employee['policy_reject_reason']
?? ''
));
?>
<?php if ($rowStatus === 'pending_approval') { ?>
<div class="btn-group dropdown">
<a href="javascript:void(0);" class="dropdown-toggle arrow-none btn btn-light btn-sm" data-toggle="dropdown" aria-expanded="false">
<i class="mdi mdi-dots-horizontal"></i>
</a>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="javascript:void(0);"
onclick="processPendingDependent('<?= $employee['employee_id'] ?>', '<?= $employee['client_policy_id'] ?>', 'approved')">
<i class="mdi mdi-check-circle mr-2 text-success font-18 vertical-middle"></i>Approve
</a>
<a class="dropdown-item" href="javascript:void(0);"
onclick="processPendingDependent('<?= $employee['employee_id'] ?>', '<?= $employee['client_policy_id'] ?>', 'rejected')">
<i class="mdi mdi-close-circle mr-2 text-danger font-18 vertical-middle"></i>Reject
</a>
</div>
</div>
<button type="button" class="btn btn-success approval-action-btn mr-1" title="Approve"
onclick="processPendingDependent('<?= $employee['employee_id'] ?>', '<?= $employee['client_policy_id'] ?>', 'approved')">
<i class="mdi mdi-check"></i>
</button>
<button type="button" class="btn btn-danger approval-action-btn" title="Reject"
onclick="processPendingDependent('<?= $employee['employee_id'] ?>', '<?= $employee['client_policy_id'] ?>', 'rejected')">
<i class="mdi mdi-close"></i>
</button>
<?php } elseif ($rowStatus === 'rejected') { ?>
<button type="button" class="btn btn-success approval-action-btn" title="Approve"
onclick="processPendingDependent('<?= $employee['employee_id'] ?>', '<?= $employee['client_policy_id'] ?>', 'approved')">
<i class="mdi mdi-check"></i>
</button>
<span class="approval-reject-info" tabindex="0" role="button" aria-label="Reject reason">
<i class="mdi mdi-information-outline"></i>
<span class="approval-reject-tooltip-text"><?= esc($rejectReason !== '' ? $rejectReason : 'No reject reason provided') ?></span>
</span>
<?php } else { ?>
-
<?php } ?>
@ -114,15 +245,6 @@ $gst_total = 0;
<?php }
} ?>
</tbody>
<tfoot>
<tr>
<th colspan="<?= (($getData['client_id'] ?? '0') != '0' && ($getData['branch_id'] ?? '0') == '0') ? 18 : 17 ?>"></th>
<th>Total</th>
<th><?= format_indian_number($pro_rata_total) ?></th>
<th><?= format_indian_number($gst_total) ?></th>
<th></th>
</tr>
</tfoot>
</table>
</div>
</div>
@ -131,11 +253,78 @@ $gst_total = 0;
</div>
<script>
if ($.fn.DataTable && !$.fn.DataTable.isDataTable('#employee-data-list-table')) {
$('#employee-data-list-table').DataTable({
scrollX: true,
function initPendingApprovalsDataTable() {
if (!$.fn.DataTable) {
return;
}
var $table = $('#pending-approvals-table');
if (!$table.length) {
return;
}
if ($.fn.DataTable.isDataTable('#pending-approvals-table')) {
$table.DataTable().destroy();
}
if (typeof nhanceListDataTableBeforeInit === 'function') {
nhanceListDataTableBeforeInit();
}
var dtOptions = {
dom: "<'row'<'col-sm-7'f><'col-sm-5 text-right'B>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row align-items-center'<'col-5 text-start'i><'col-7 d-flex justify-content-end align-items-center'<'me-2'l>p>>",
order: [],
pageLength: 25
});
pageLength: 10,
lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]],
buttons: [
{
extend: 'excel',
text: '<i class="mdi mdi-file-excel"></i><span class="btn-custom"> EXCEL </span>',
className: 'btn app-btn-secondary',
title: 'Approvals',
sheetName: 'Approvals',
exportOptions: {
columns: [0, 1, 2, 3, 4, 5, 6],
format: {
body: function (data, row, column, node) {
var $node = $(node);
if (column === 0) {
var name = $node.clone().children().remove().end().text().trim();
var code = $node.find('small').text().trim();
return code ? (name + ' (' + code + ')') : name;
}
return $node.text().replace(/\s+/g, ' ').trim();
}
}
}
}
],
language: {
search: `
<div class="datatable-search-wrapper" style="position:relative; display:inline-block;">
_INPUT_
<i class="mdi mdi-magnify datatable-search-icon"
style="position:absolute; right:10px; top:50%; transform:translateY(-50%); color:#666;"></i>
</div>`,
searchPlaceholder: "Search",
emptyTable: '<div class="text-center text-muted">No approval records found</div>'
}
};
var pendingApprovalsTable = typeof nhanceMergeListDataTableOptions === 'function'
? $table.DataTable(nhanceMergeListDataTableOptions(dtOptions))
: $table.DataTable(dtOptions);
if (typeof nhanceListDataTableAfterInit === 'function') {
nhanceListDataTableAfterInit();
}
if (typeof nhanceListDataTableBindAdjust === 'function') {
nhanceListDataTableBindAdjust(pendingApprovalsTable);
}
}
initPendingApprovalsDataTable();
</script>

View File

@ -110,92 +110,26 @@
var client_branch_id = '<?= isset($getData) ? $getData['branch_id'] : '0' ?>';
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($('<option>', { value: '0', text: 'Select'}));
$('#policies').empty();
$('#policies').append($('<option>', { value: '0', text: 'Select' }));
$('#branch_id').trigger('change.select2');
$('#policies').trigger('change.select2');
var selectedClient = $(this).val();
var filteredBranch = branch_list[selectedClient];
@ -294,10 +244,10 @@
var selectedClient = $('#clients').val();
var filteredPoliciesByClient = policy_list_by_client[selectedClient] || [];
var filteredPoliciesByBranch = filteredPoliciesByClient.filter(function(item) {
return item.client_branch_id === selectedBranch;
return String(item.client_branch_id) === String(selectedBranch);
});
appendPolicies(filteredPoliciesByBranch);
if (Array.isArray(filteredPoliciesByBranch) && filteredPoliciesByBranch.length === 0) {
if (Array.isArray(filteredPoliciesByBranch) && filteredPoliciesByBranch.length === 0 && selectedBranch && selectedBranch !== '0') {
toastr.warning('No policies found for the selected client branch.');
}
});
@ -363,7 +313,7 @@
if (status === 'rejected') {
Swal.fire({
title: 'Reject Dependent',
html: '<p class="mb-2">Please enter the reject reason.</p>',
html: '<p class="mb-2">Please enter the reject reason. <span class="text-danger">*</span></p>',
input: 'textarea',
inputPlaceholder: 'Reject reason...',
inputAttributes: {
@ -374,6 +324,14 @@
showCancelButton: true,
confirmButtonText: 'Reject',
cancelButtonText: 'Cancel',
preConfirm: (value) => {
var reason = String(value || '').trim();
if (!reason) {
Swal.showValidationMessage('Reject reason is required');
return false;
}
return reason;
},
inputValidator: (value) => {
if (!value || !String(value).trim()) {
return 'Reject reason is required';
@ -383,7 +341,7 @@
if (!result.isConfirmed) {
return;
}
submitPendingDependent(employeeId, clientPolicyId, status, String(result.value).trim());
submitPendingDependent(employeeId, clientPolicyId, status, String(result.value || '').trim());
});
return;
}

View File

@ -2006,7 +2006,7 @@ body[data-sidebar-size="condensed"] .footer {
<a href="<?= base_url('/employee/list') ?>">View Members</a>
</li>
<li>
<a href="<?= base_url('/employee/pending-approvals') ?>">View Pending Approvals</a>
<a href="<?= base_url('/employee/pending-approvals') ?>">Approvals</a>
</li>
<li>
<a href="<?= base_url('/employee/endorsement-list') ?>">View Endorsement</a>