From 191fddc3983374d5c172d92248de5814df35c99f Mon Sep 17 00:00:00 2001 From: velz Date: Fri, 6 Mar 2026 12:58:52 +0530 Subject: [PATCH 01/54] FIX_DUP_IMPORTS --- app/Controllers/LeadsController.php | 40 +++-------------------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php index 41739b6a..6a8f9d5e 100644 --- a/app/Controllers/LeadsController.php +++ b/app/Controllers/LeadsController.php @@ -1,21 +1,18 @@ Date: Fri, 6 Mar 2026 22:24:42 +0530 Subject: [PATCH 02/54] FIX_UI Issues --- app/Controllers/EmployeeController.php | 22 +- app/Controllers/LeadsController.php | 2 + app/Controllers/TicketController.php | 3 +- app/Views/DashBoard.php | 3 +- app/Views/UserList.php | 2 +- app/Views/cd_master_list.php | 2 +- app/Views/client_deposit_list.php | 95 +-- app/Views/client_onboarding.php | 8 +- app/Views/dms_search.php | 251 ++++---- app/Views/endorsement_list.php | 181 +++--- app/Views/faq_list.php | 2 +- app/Views/frontend_content_list.php | 2 +- app/Views/import_export.php | 2 +- app/Views/insurer_list.php | 2 +- app/Views/insurer_onboarding.php | 2 +- app/Views/insurer_statement_list.php | 73 +-- app/Views/kyc_list.php | 2 +- app/Views/layout/footer.php | 85 ++- app/Views/layout/header.php | 251 ++++++-- app/Views/lead_filter.php | 291 +++++---- app/Views/leads_form.php | 10 +- app/Views/leads_list.php | 101 ++- app/Views/leads_non_eb.php | 9 +- app/Views/nhance_branch_list.php | 2 +- app/Views/outstanding_report_list.php | 179 ++++-- app/Views/payout_list.php | 7 + app/Views/payout_list_handler.php | 165 +++-- .../policy_transaction_endorsement_form.php | 2 +- .../policy_transaction_endorsement_list.php | 318 +++++----- .../policy_transaction_inception_list.php | 272 ++++---- app/Views/policy_type_list.php | 2 +- app/Views/pos_list.php | 2 +- .../pt_endorsement_form_file_upload_tab.php | 2 +- app/Views/pt_form_file_upload_tab.php | 2 +- app/Views/report_bds.php | 7 + app/Views/report_bds_filter.php | 308 +++++---- app/Views/retail_endorsement_list.php | 210 ++++--- app/Views/rto_master_list.php | 2 +- .../branch_level_dashboard_view_2mar.php | 526 ++++++++++++++++ .../branch_level_dashboard_view_3mar.php | 592 ++++++++++++++++++ .../sales/branch_level_dashboard_view_mar.php | 294 +++++++++ app/Views/thz_notes.php | 9 +- app/Views/ticket_edit_onbording.php | 9 +- app/Views/ticket_list.php | 20 +- app/Views/ticket_search.php | 320 +++++----- app/Views/tpa_list.php | 2 +- app/Views/variance_report_list.php | 381 +++++++---- app/Views/vehicle_master_list.php | 2 +- app/Views/vehicle_type_list.php | 2 +- app/Views/vehicle_type_master_list.php | 2 +- 50 files changed, 3567 insertions(+), 1473 deletions(-) create mode 100644 app/Views/sales/branch_level_dashboard_view_2mar.php create mode 100644 app/Views/sales/branch_level_dashboard_view_3mar.php create mode 100644 app/Views/sales/branch_level_dashboard_view_mar.php diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 01664e76..df182e0a 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -163,17 +163,21 @@ class EmployeeController extends AdminController public function getClientWithPolicies() { - //echo $this->request->isAJAX();die(); - $result = $this->clientModel->clientsWithPolicies(); + try { + //echo $this->request->isAJAX();die(); + $result = $this->clientModel->clientsWithPolicies(); - // dd($result); + // dd($result); - // print_r($result);die(); - if (!count($result)) { - return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'no data found'], 200); - } else { - - return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $result], 200); + // print_r($result);die(); + if (!count($result)) { + return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'no data found'], 200); + } else { + + return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $result], 200); + } + } catch (\Throwable $th) { + return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => $th->getMessage()], 500); } } diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php index 2d3988ac..53f8ecd6 100644 --- a/app/Controllers/LeadsController.php +++ b/app/Controllers/LeadsController.php @@ -4379,6 +4379,8 @@ class LeadsController extends BaseController 'selected_lead_type' => $type, 'actual_lead_id' => $actual_lead_id, ]; + $data['tab_name'] = 'Opportunities'; + $data['page_name'] = 'Opportunities'; if ($actual_lead_id > 0) { diff --git a/app/Controllers/TicketController.php b/app/Controllers/TicketController.php index 7c70ec06..f3e930a1 100644 --- a/app/Controllers/TicketController.php +++ b/app/Controllers/TicketController.php @@ -1025,7 +1025,8 @@ class TicketController extends BaseController $data['claim_status'] = $this->transFormClaimStatus($claim_status_id, $ticket_type); $data['client_for_motor'] = $this->clientModel->select('id,client_name,phone')->where('client_type', 2)->where('is_active', 1)->findAll(); } - + $data['tab_name'] = "Claims"; + $data['page_name'] = "Claims"; return $this->loadLayout('ticket_edit_onbording', $data); } diff --git a/app/Views/DashBoard.php b/app/Views/DashBoard.php index 0eff67a2..d09b90c7 100755 --- a/app/Views/DashBoard.php +++ b/app/Views/DashBoard.php @@ -185,7 +185,8 @@ -
+ +
diff --git a/app/Views/UserList.php b/app/Views/UserList.php index 919e7de1..9659eaf4 100755 --- a/app/Views/UserList.php +++ b/app/Views/UserList.php @@ -355,7 +355,7 @@ table.dataTable tbody td {
-
+
-
- - - - - - - - - - + -> + --> +
+
Insurer Name Insurer Branch Name CD Account Number Current Balance Action
+ + + + + + + + + - - - + + + + + - - - - - - - - - -
Insurer Name Insurer Branch Name CD Account Number Current Balance Action
insurer_name;?>insurer_branch_name;?>cd_master_account_no;?>insurer_name;?>insurer_branch_name;?>cd_master_account_no;?>₹ - insurer_id; - $cd_ac_pk = $value->cd_ac_pk; - // Check if the balance information exists for the insurer - if (isset($balances[$insurerId . '-'. $cd_ac_pk])) { - $balance = $balances[$insurerId . '-'. $cd_ac_pk]->balance; - echo $balance; - } else { - echo "N/A"; // Display "Not Available" if balance information is not present - } - ?> - - insurer_id}?client_id={$value->client_id}&cd_ac_pk={$value->cd_ac_pk}"); ?>"> - View Deposit - -
+ ₹ + insurer_id; + $cd_ac_pk = $value->cd_ac_pk; + // Check if the balance information exists for the insurer + if (isset($balances[$insurerId . '-'. $cd_ac_pk])) { + $balance = $balances[$insurerId . '-'. $cd_ac_pk]->balance; + echo $balance; + } else { + echo "N/A"; // Display "Not Available" if balance information is not present + } + ?> + + + insurer_id}?client_id={$value->client_id}&cd_ac_pk={$value->cd_ac_pk}"); ?>"> + View Deposit + + + + + + +
@@ -70,7 +75,7 @@ $(document).ready(function() { $('#tickets-table').DataTable({ // dom: "<'row'<'col-sm-0'f><'col-sm-9 text-right'B>>", - dom: "<'row'<'col-12 d-flex justify-content-between align-items-center'<'datatable-search dataTables_filter'f><'datatable-buttons dt-buttons'B>>>", + dom: "<'row'<'col-12 d-flex justify-content-between align-items-center'<'datatable-search dataTables_filter'f><'datatable-buttons dt-buttons'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>>", lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]], diff --git a/app/Views/client_onboarding.php b/app/Views/client_onboarding.php index 928836a0..e7af7f88 100755 --- a/app/Views/client_onboarding.php +++ b/app/Views/client_onboarding.php @@ -271,14 +271,18 @@
-
+ +
diff --git a/app/Views/dms_search.php b/app/Views/dms_search.php index f3e1bad0..ea953fff 100644 --- a/app/Views/dms_search.php +++ b/app/Views/dms_search.php @@ -25,83 +25,102 @@ .dataTables_length label {height: 21px !important;} + .filter-sidebar { + height: 100%; + width: 0; + position: fixed; + z-index: 1001; + top: 0; + right: 0; + background-color: #f8f9fa; + overflow-x: hidden; + transition: 0.5s; + box-shadow: -2px 0 5px rgba(0,0,0,0.1); + display: flex; + flex-direction: column; + } + + .filter-sidebar-header { + padding: 15px 20px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; + } + + .filter-sidebar-header .closebtn { + font-size: 28px; + text-decoration: none; + color: #6c757d; + } + + .filter-sidebar .closebtn:hover { + color: #000; + } + + .filter-sidebar-content { + padding: 20px; + flex-grow: 1; + overflow-y: auto; + } + + .filter-sidebar-footer { + padding: 15px 20px; + display: flex; + justify-content: flex-end; + border-top: 1px solid #dee2e6; + flex-shrink: 0; + gap: 10px; + } + -
-
-
-
-
-

- Filter - - - -

-
-
-
-
" id='dms_search_form'> -
+
+
+

Filter

+ × +
+
+ " id='dms_search_form'> +
-
- - - - - - -
- -
- - - - -
-
- -
- OR -
-
- -
- - - - - - -
- -
- - - - -
- -
- - - -
- -
- -
-
-
+
+ + + +
-
-
+
+ + +
+
+ OR +
+
+ + + + +
+ +
+ + +
+
+ +
+
+
@@ -109,9 +128,7 @@

Files

-
-
@@ -131,18 +148,15 @@ - - - - + @@ -157,10 +171,15 @@ \ No newline at end of file diff --git a/app/Views/endorsement_list.php b/app/Views/endorsement_list.php index 76642e9a..66ef74c5 100755 --- a/app/Views/endorsement_list.php +++ b/app/Views/endorsement_list.php @@ -13,50 +13,88 @@ left: 79px; } .dataTables_length label {height: 21px !important;} + .filter-sidebar { + height: 100%; + width: 0; + position: fixed; + z-index: 1001; + top: 0; + right: 0; + background-color: #f8f9fa; + overflow-x: hidden; + transition: 0.5s; + box-shadow: -2px 0 5px rgba(0,0,0,0.1); + display: flex; + flex-direction: column; + } + .filter-sidebar-header { + padding: 15px 20px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; + } + + .filter-sidebar-header .closebtn { + font-size: 28px; + text-decoration: none; + color: #6c757d; + } + + .filter-sidebar .closebtn:hover { + color: #000; + } + + .filter-sidebar-content { + padding: 20px; + flex-grow: 1; + overflow-y: auto; + } + + .filter-sidebar-footer { + padding: 15px 20px; + display: flex; + justify-content: flex-end; + border-top: 1px solid #dee2e6; + flex-shrink: 0; + gap: 10px; + }
-
-
-
-
-
-

- Filter - - - -

-
-
- -
-
-
- -
+
+
+

Filter

+ × +
+
+
+
+
+ + +
+
+ + +
-
-
- -
+
+ + +
-
-
- -
- -
-
+
+
-
- -
- - -
-
+ +
- +
+
@@ -87,12 +118,12 @@
-
+
- + href="">
@@ -212,11 +243,9 @@ function fetchClientPolicies() { - $('#loader').show(); var apiURL = '' + 'util/clients-with-policies'; console.log('fetchClientPolicies'); - // console.log(apiURL); $.ajax({ url: apiURL, method: 'GET', @@ -225,9 +254,7 @@ "X-Requested-With": "XMLHttpRequest" }, success: function(response) { - // console.log(response.code); - // console.log(response.dataStatus); - // console.log(response.data); + $('#loader').hide(); // ✅ hide AFTER data received if (response.code === 200 && response.dataStatus === true && response.data !== "") { try { clientPolicies = (response.data); @@ -280,13 +307,20 @@ } }, error: function(xhr, status, error) { + $('#loader').hide(); // ✅ hide on error too console.error('Error fetching data from API:', error); } }); - - $('#loader').hide(); + } + /* Modified by Gemini Code Assist */ + function openEndorsementListFilterNav() { + document.getElementById("filter-sidebar").style.width = "350px"; } + /* Modified by Gemini Code Assist */ + function closeFilterNav() { + document.getElementById("filter-sidebar").style.width = "0"; + } function appendClients(data) { @@ -432,11 +466,7 @@ } - document.getElementById('toggleIcon').addEventListener('click', function() { - var icon = document.getElementById('icon'); - icon.classList.toggle('mdi-chevron-down'); - icon.classList.toggle('mdi-chevron-up'); - }); + $('.emp_data_model').click(function() { @@ -611,6 +641,13 @@ // openTicket(); // } // }, + { + text: ' Filter ', + className: 'btn app-btn-primary mr-2', + action: function(e, dt, node, config) { + openEndorsementListFilterNav(); + } + }, { extend: 'collection', text: ' Export ', @@ -632,24 +669,6 @@ ] } ], - // buttons: [{ - // extend: 'csv', - // text: 'CSV', - // title: 'Endorsement-List', - // className: 'my_class', - // exportOptions: { - // columns: ':not(:last-child)', - // format: { - // body: function (data, row, column, node) { - // // Convert data to string to avoid scientific notation in CSV - // if (!isNaN(data) && parseFloat(data) > 1e20) { - // return `'${data}`; - // } - // return data.toString();// Ensures all data is treated as strings - // } - // } - // } - // }], initComplete: function(settings, json) { $('.my_class').css({ "position": "relative", diff --git a/app/Views/faq_list.php b/app/Views/faq_list.php index bc49cd41..3df7a4ae 100644 --- a/app/Views/faq_list.php +++ b/app/Views/faq_list.php @@ -36,7 +36,7 @@
-
+
diff --git a/app/Views/frontend_content_list.php b/app/Views/frontend_content_list.php index 71f8e0ed..2a2b5ee7 100644 --- a/app/Views/frontend_content_list.php +++ b/app/Views/frontend_content_list.php @@ -35,7 +35,7 @@
-
+
diff --git a/app/Views/import_export.php b/app/Views/import_export.php index 276b51fd..a21bb3ff 100755 --- a/app/Views/import_export.php +++ b/app/Views/import_export.php @@ -51,7 +51,7 @@ } -
+
diff --git a/app/Views/insurer_list.php b/app/Views/insurer_list.php index 05e0dc7e..57e04cbb 100755 --- a/app/Views/insurer_list.php +++ b/app/Views/insurer_list.php @@ -46,7 +46,7 @@
-
+
-
- - -
-
-
-
-
- - -
-
-
-
- -
-
-
-
-
-
@@ -1815,15 +1772,23 @@ }); // Initialize DataTable + // Change Comment: Added dom and buttons properties to arrange search, switch, and upload button on a single line, similar to client_list.php. const table = $('#tickets-table').DataTable({ + dom: "<'row'<'col-12 d-flex justify-content-between align-items-center'<'datatable-search dataTables_filter'f><'datatable-buttons dt-buttons'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>>", + buttons: [ + { + text: 'Upload ', + className: 'btn btn-primary waves-effect waves-light', + action: function(e, dt, node, config) { + showFileUploadModal(); + } + } + ], // Your existing DataTable options here "order": [], // Disable initial sorting if needed "pageLength": 10, - // "dom": '<"top"lf>rt<"bottom"ip><"clear">', // This places length and filter controls at top - // "language": { - // "lengthMenu": "Show _MENU_ entries", - // "search": "Search:" - // } language: { lengthMenu: "Show _MENU_ entries", search: ` @@ -1840,6 +1805,16 @@ emptyTable: '
No Data found
' } }); + + // Change Comment: Prepending the 'Failed Status' switch to the DataTable's button container to group it with other controls. + $(".datatable-buttons").prepend(` + + + + + + + `); // Add event listener for switch changes $('#statusSwitch').on('change', function() { diff --git a/app/Views/kyc_list.php b/app/Views/kyc_list.php index 342e24d3..7754f2a8 100755 --- a/app/Views/kyc_list.php +++ b/app/Views/kyc_list.php @@ -43,7 +43,7 @@
-
+
-
+
-
+
© NHANCE @@ -155,23 +155,68 @@ "closeButton": true, }; + + diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php index 0086c4f5..2bc18794 100755 --- a/app/Views/layout/header.php +++ b/app/Views/layout/header.php @@ -118,7 +118,9 @@ * { font-family: 'Poppins' !important; } - + body { + background-color: #ffffff !important; /* ← ADD THIS */ + } .content { min-height: 70vh; } @@ -142,8 +144,17 @@ min-height: 100vh !important; } + /* REPLACE WITH THIS */ + body, + html, + #wrapper, + .content-page, body .content-page { - margin-top: 90px !important; + background-color: #ffffff !important; + } + + body .content-page { + margin-top: 50px !important; } @@ -154,7 +165,8 @@ z-index: 4; width: 90%; margin-left: 120px !important; - background: #fff; + background: #ffffff !important; + box-shadow: 0 2px 0 #ffffff !important; /* seals bottom edge */ } .top-navbar-div { @@ -164,6 +176,8 @@ justify-content: space-between; margin-top: 20px; margin-left: 15px; + /* height: 100%; + width: 100%; */ } @@ -1657,10 +1671,12 @@ .left-btn { left: 0; + border-radius : 10px !important; } .right-btn { right: 0; + border-radius : 10px !important; } input[type="search"]::-webkit-search-cancel-button { @@ -1669,9 +1685,166 @@ } + @@ -1686,7 +1859,7 @@ -
+
@@ -2117,7 +2290,7 @@ -->
  • - Sales Team Targets + Sales Team Targets
  • @@ -2180,44 +2353,52 @@
    Welcome first_name) ? get_session_userdata()->first_name : 'NOT SET') ?>
    diff --git a/app/Views/lead_filter.php b/app/Views/lead_filter.php index 620d4a08..58753443 100644 --- a/app/Views/lead_filter.php +++ b/app/Views/lead_filter.php @@ -2,140 +2,177 @@ .col-12 { max-width: 98% !important; } + .filter-sidebar { + height: 100%; + width: 0; + position: fixed; + z-index: 1001; + top: 0; + right: 0; + background-color: #f8f9fa; + overflow-x: hidden; + transition: 0.5s; + box-shadow: -2px 0 5px rgba(0,0,0,0.1); + display: flex; + flex-direction: column; + } + + .filter-sidebar-header { + padding: 15px 20px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; + } + + .filter-sidebar-header .closebtn { + font-size: 28px; + text-decoration: none; + color: #6c757d; + } + + .filter-sidebar .closebtn:hover { + color: #000; + } + + .filter-sidebar-content { + padding: 20px; + flex-grow: 1; + overflow-y: auto; + } + + .filter-sidebar-footer { + padding: 15px 20px; + display: flex; + justify-content: flex-end; + border-top: 1px solid #dee2e6; + flex-shrink: 0; + gap: 10px; + }
    -
    -
    -
    -
    -
    -

    - Filter - - - -

    - -
    -
    -
    -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    -
    - - -
    - -
    - - -
    - -
    - - -
    - - - -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    - +
    +
    +
    +

    Filter

    + × +
    +
    +
    +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    +
    + + +
    + +
    + + +
    + +
    + + +
    +
    +
    +
    + +
    + + @@ -167,7 +204,7 @@ //----- AJAX FUNCTIONS -------------------------------------------------------------------------------- function fetchTicketListData() { - + closeOpportunitiesListFilterNav(); var issuer_type = $('#filter_issuer_type').val(); var lead_type = $('#filter_lead_type').val(); var policy_type = $('#filter_policy_type').val(); diff --git a/app/Views/leads_form.php b/app/Views/leads_form.php index 089bff40..c45fc7bd 100644 --- a/app/Views/leads_form.php +++ b/app/Views/leads_form.php @@ -102,6 +102,10 @@ border-width: 1px !important; } +
    @@ -120,12 +124,12 @@ Back
    --> -

    +

    @@ -773,6 +777,8 @@ hide_list_show_add(); var page_title = 'Edit Opportunity'; + var pageSubTitle = 'Edit Opportunity'; + var pageBackButton = ''; $('#page_title').text(page_title); $('#leads_primarykey').val(res.data.id); diff --git a/app/Views/leads_list.php b/app/Views/leads_list.php index 7ad9f74a..a03b90fc 100644 --- a/app/Views/leads_list.php +++ b/app/Views/leads_list.php @@ -9,7 +9,7 @@ table.dataTable tbody td { } .col-12 { - max-width: 98% !important; + max-width: 100% !important; } .dataTables_filter { @@ -141,7 +141,9 @@ table.dataTable tbody td { } .dataTables_length label {height: 21px !important;} /* Modeal class */ - +.table-responsive { + overflow-x: auto !important; +} @@ -149,10 +151,10 @@ table.dataTable tbody td {
    -
    -
    -

    Opportunities List

    -
    +
    +
    @@ -333,19 +335,28 @@ table.dataTable tbody td { document.body.appendChild(customDropdown); - row.addEventListener("click", function(event) { - - // 1. CRITICAL CHECK: Stop propagation if the click came from the dropdown toggle itself. - if (event.target.closest('.dropdown-toggle')) { - event.stopPropagation(); - - // **IMPORTANT:** Since you're using a custom script, you need to - // manually trigger the logic for your custom detached dropdown here. - // The code below should run when the dropdown toggle is clicked: - const originalDropdown = event.target.closest('.btn-group').querySelector('.dropdown-menu'); - if (originalDropdown) { + row.addEventListener("click", function(event) { + if (event.target.closest('.dropdown-toggle')) { + event.stopPropagation(); + const originalDropdown = event.target.closest('.btn-group').querySelector('.dropdown-menu'); + if (originalDropdown) { + 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; + } + return; + } + + if (event.target.closest('td:last-child')) { + return; + } - // This is the code that opens your custom dropdown if (activeDropdown) { activeDropdown.style.display = 'none'; } @@ -358,34 +369,9 @@ table.dataTable tbody td { customDropdown.style.top = `${rect.bottom + 5}px`; activeDropdown = customDropdown; - } + event.stopPropagation(); + }); - return; // Exit the row listener early - } - - // 2. Ignore clicks on the entire action column (your existing, good check) - if (event.target.closest('td:last-child')) { - return; - } - - // ... rest of your row logic for general row clicks ... - - 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(); // Only needed if there is a parent handler - }); - - // Handle clicks on dropdown items customDropdown.querySelectorAll('.dropdown-item').forEach(item => { item.addEventListener('click', function(e) { console.log("##############"); @@ -467,11 +453,18 @@ table.dataTable tbody td { lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]], buttons: [ { - text: ' Add ', - className: 'btn app-btn-primary mr-2', - action: function(e, dt, node, config) { - openLeadTypeAskModal(); - } + text: ' Filter ', + className: 'btn app-btn-primary mr-2', + action: function(e, dt, node, config) { + openOpportunitiesListFilterNav(); + } + }, + { + text: ' Add ', + className: 'btn app-btn-primary mr-2', + action: function(e, dt, node, config) { + openLeadTypeAskModal(); + } }, { extend: 'collection', @@ -707,5 +700,11 @@ table.dataTable tbody td { this.closest('.radio-option').classList.add('selected'); }); }); - + + \ No newline at end of file diff --git a/app/Views/leads_non_eb.php b/app/Views/leads_non_eb.php index c4caca5f..5cc76583 100644 --- a/app/Views/leads_non_eb.php +++ b/app/Views/leads_non_eb.php @@ -47,7 +47,10 @@ border-width: 1px !important; } - +
    @@ -62,12 +65,12 @@ Back
    --> -

    +

    diff --git a/app/Views/nhance_branch_list.php b/app/Views/nhance_branch_list.php index 7dc6f819..7c304596 100644 --- a/app/Views/nhance_branch_list.php +++ b/app/Views/nhance_branch_list.php @@ -9,7 +9,7 @@
    -
    +
    diff --git a/app/Views/outstanding_report_list.php b/app/Views/outstanding_report_list.php index db7d0bb1..81fb5d32 100644 --- a/app/Views/outstanding_report_list.php +++ b/app/Views/outstanding_report_list.php @@ -34,79 +34,107 @@ padding-left: 15px !important; } .dataTables_length label {height: 21px !important;} + .filter-sidebar { + height: 100%; + width: 0; + position: fixed; + z-index: 1001; + top: 0; + right: 0; + background-color: #f8f9fa; + overflow-x: hidden; + transition: 0.5s; + box-shadow: -2px 0 5px rgba(0,0,0,0.1); + display: flex; + flex-direction: column; + } + + .filter-sidebar-header { + padding: 15px 20px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; + } + + .filter-sidebar-header .closebtn { + font-size: 28px; + text-decoration: none; + color: #6c757d; + } + + .filter-sidebar .closebtn:hover { + color: #000; + } + + .filter-sidebar-content { + padding: 20px; + flex-grow: 1; + overflow-y: auto; + } + + .filter-sidebar-footer { + padding: 15px 20px; + display: flex; + justify-content: flex-end; + border-top: 1px solid #dee2e6; + flex-shrink: 0; + gap: 10px; + }
    -
    -
    -
    -
    -

    - Filter - - - -

    -
    -
    -
    -
    +
    +
    +

    Filter

    + × +
    +
    +
    +
    -
    - - -
    - -
    - - -
    - -
    - -
    - - -
    - - - -
    - -
    - - -
    -
    +
    + +
    + +
    + + +
    + +
    + +
    + + +
    + + +
    +
    +
    @@ -172,6 +200,14 @@ \ No newline at end of file diff --git a/app/Views/sales/branch_level_dashboard_view_mar.php b/app/Views/sales/branch_level_dashboard_view_mar.php new file mode 100644 index 00000000..efc8d3cb --- /dev/null +++ b/app/Views/sales/branch_level_dashboard_view_mar.php @@ -0,0 +1,294 @@ + + +
    + + +
    +
    +
    +
    Total Leads
    + +
    +
    +
    +
    Total Activities
    + +
    +
    +
    +
    Pending Activities
    + +
    +
    +
    +
    Completed Activities
    + +
    + +
    + +
    +
    +
    +

    Pending Activities - All Team

    + +
    +
    + + + + + + + + + + + + '📞', + 'Email' => '✉️', + 'Meeting' => '📅', + 'Visit' => '🚗', + 'Demo' => '🖥️', + 'Share Docs' => '📄', + 'To Do' => '✓' + ]; + $icon = $activityIcons[$a['activity_type']] ?? '📌'; + $statusClass = strtolower(str_replace(' ', '-', $a['status'])); + $formattedscheduledDate = date('M d, Y, h:i A', strtotime($a['scheduled_date'])); + ?> + + + + + + + + + + + + + +
    CompanyActivity & AssignedDateStatus
    +
    + +
    +
    + +
    + +
    +
    +
    No activities found +
    +
    +
    + +
    +
    + +

    Sales Team Performance

    + +
    {$firstLetter}
    +
    +
    {$fullName}
    +
    {$role}
    +
    +
    +
    {$totalActs} acts
    +
    {$doneActs} done
    +
    +
    "; + } ?> + + +
    +

    Activity Breakdown

    + + ['color' => '#ff6b35', 'icon' => '📞'], + 'Email' => ['color' => '#48bb78', 'icon' => '✉️'], + 'Meeting' => ['color' => '#4299e1', 'icon' => '📅'], + 'Visit' => ['color' => '#ecc94b', 'icon' => '🚗'], + 'Demo' => ['color' => '#9f7aea', 'icon' => '🖥️'], + 'Share Docs' => ['color' => '#ed8936', 'icon' => '📄'], + 'To Do' => ['color' => '#718096', 'icon' => '✓'], + ]; + ?> + + + + +
    + + + + + % +
    + + +
    +
    No activities found +
    + +
    +
    +
    + +
    +
    +

    All Leads Overview

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CompanyStatusAssigned ToActivitiesOpportunities
    +
    +
    👤
    No leads found +
    +
    +
    +
    \ No newline at end of file diff --git a/app/Views/thz_notes.php b/app/Views/thz_notes.php index 194ed82d..f6931370 100644 --- a/app/Views/thz_notes.php +++ b/app/Views/thz_notes.php @@ -133,15 +133,18 @@ hr{ background-color: #00999E !important; } - +
    -

    +
    diff --git a/app/Views/ticket_edit_onbording.php b/app/Views/ticket_edit_onbording.php index 45eabbc3..f2483182 100644 --- a/app/Views/ticket_edit_onbording.php +++ b/app/Views/ticket_edit_onbording.php @@ -38,8 +38,13 @@
    + + -
    +
    diff --git a/app/Views/ticket_list.php b/app/Views/ticket_list.php index da6b20be..fbd40b94 100644 --- a/app/Views/ticket_list.php +++ b/app/Views/ticket_list.php @@ -52,13 +52,13 @@ table.dataTable tbody td {
    -
    -
    +
    +
    @@ -310,6 +310,13 @@ $(document).ready(function() { "<'row align-items-center'<'col-5 text-start'i><'col-7 d-flex justify-content-end align-items-center'<'me-2'l>p>>", lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]], buttons: [ + { + text: ' Filter ', + className: 'btn app-btn-primary mr-2', + action: function(e, dt, node, config) { + openTicketFilterNav(); + } + }, { text: ' Add ', className: 'btn app-btn-primary mr-2', @@ -410,4 +417,11 @@ $(document).on('click', 'tbody tr', function (e) { }); + + \ No newline at end of file diff --git a/app/Views/ticket_search.php b/app/Views/ticket_search.php index ea470c39..9abd8e4e 100644 --- a/app/Views/ticket_search.php +++ b/app/Views/ticket_search.php @@ -3,174 +3,196 @@ max-width: 98% !important; } + .filter-sidebar { + height: 100%; + width: 0; + position: fixed; + z-index: 1001; + top: 0; + right: 0; + background-color: #f8f9fa; + overflow-x: hidden; + transition: 0.5s; + box-shadow: -2px 0 5px rgba(0,0,0,0.1); + display: flex; + flex-direction: column; +} + +.filter-sidebar-header { + padding: 15px 20px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; +} + +.filter-sidebar-header .closebtn { + font-size: 28px; + text-decoration: none; + color: #6c757d; +} + +.filter-sidebar .closebtn:hover { + color: #000; +} + +.filter-sidebar-content { + padding: 20px; + flex-grow: 1; + overflow-y: auto; +} + +.filter-sidebar-footer { + padding: 15px 20px; + display: flex; + justify-content: flex-end; + border-top: 1px solid #dee2e6; + flex-shrink: 0; + gap: 10px; +} -
    -
    -
    -
    -
    -
    -

    - Filter - - - -

    -
    -
    -
    -
    +
    +
    +

    Filter

    + × +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    -
    - - -
    +
    + + +
    - +
    + + +
    +
    + + +
    +
    + + +
    -
    - - -
    +
    + + +
    -
    - - -
    +
    + + +
    -
    - - -
    - -
    - - -
    - -
    - - -
    - - - -
    - - -
    - -
    - - -
    - -
    - - -
    - - - -
    - Clear - Submit -
    - -
    - -
    -
    -
    +
    -
    -
    - +
    +
    + +
    + +
    -
    -
    +
    + -
    +
    - + + +
    No targets added yet.
    +
    +
    🎯
    +

    No targets added yet.

    +
    +
    @@ -445,7 +452,7 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans- ────────────────────────────────────────── */ async function renderDetailTable(userId) { const tbody = document.getElementById('detailTableBody'); - tbody.innerHTML = 'Loading...'; + tbody.innerHTML = `⏳ Loading targets...`; try { const res = await fetch(`${API}/targets/user/${userId}`); @@ -453,7 +460,7 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans- const records = json.data || []; if (records.length === 0) { - tbody.innerHTML = 'No targets added yet.'; + tbody.innerHTML = '
    🎯

    No targets added yet.

    '; return; } // records.sort((a, b) => b.id - a.id); From 3c3a068042ad67556319a4a04b6847e0caec96a6 Mon Sep 17 00:00:00 2001 From: velz Date: Mon, 9 Mar 2026 09:53:13 +0530 Subject: [PATCH 06/54] FEAT_VISIT_OFFBOARD --- app/Config/Acl.php | 137 ++++++++++++++++++++++++- app/Controllers/EmployeeController.php | 82 +++++++++++++-- app/Controllers/JobWorker.php | 4 + 3 files changed, 214 insertions(+), 9 deletions(-) diff --git a/app/Config/Acl.php b/app/Config/Acl.php index b4d85eac..45ca160a 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -15,6 +15,13 @@ class Acl '#^/loginPos#' => ['public' => true], '#^/getVerifyPosMobileNo#' => ['public' => true], '#^/getVerifiedPosUserData#' => ['public' => true], + '#^/chat#' => ['public' => true], + '#^/widget#' => ['public' => true], + '#^/chatbottest#' => ['public' => true], + '#^/chatbot#' => ['public' => true], + '#^/getSSORedirectUrl#' => ['public' => true], + '#^/getEmployeePolicy#' => ['public' => true], + '#^/downloadFileTableFile#' => ['public' => true], '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]], '#^/getEmployeeActiveOrInactivePolicy#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/bulkEcardDownloadAsZip#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], @@ -54,6 +61,34 @@ class Acl 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [] ], + '#^/hrFileDownload#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/sendPushNotification#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/sendEmail#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/getPolicyLevelEmployeeSummaryData#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/cdTransactionData#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/claimsSearch#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/getBackToEnrolledDetails#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], // ===================== USER MANAGEMENT ===================== '#^/user#' => [ @@ -88,6 +123,18 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] ], + '#^/dmsSearch#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], + '#^/downloadGdriveFile#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], + '#^/driveListFiles#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], '#^/bds_upload#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] @@ -108,12 +155,60 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] ], + '#^/importRules#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], // ===================== CLAIMS / TICKETS ===================== '#^/ticket#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [CLAIMS_TEAM_ID] ], + '#^/ticketSave#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketList#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketConversationSave#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketConversationList#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketType#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketHistoryList#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketAutoFetchDetails#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/initiateClaim#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/departments#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/get_ticket_data#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/claimView#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], '#^/claim_mis#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [CLAIMS_TEAM_ID] @@ -138,6 +233,22 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], 'teams' => [] ], + '#^/add_advertise_image#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], + '#^/remove_advertise_image#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], + '#^/getAdvertiseImage#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], + '#^/showAdvertiseImage#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], '#^/frontend_content#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], 'teams' => [] @@ -146,6 +257,10 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], 'teams' => [] ], + '#^/getFEContent#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], // ===================== LOGS ===================== '#^/logs#' => [ @@ -167,9 +282,25 @@ class Acl // ===================== WEBHOOKS / 3RD PARTY ===================== '#^/dispatchWebhookData#' => ['public' => true], '#^/retrieveWebhookData#' => ['public' => true], - // '#^/ICICI#' => ['public' => true], - // '#^/Vidal#' => ['public' => true], - // '#^/MediAssist#' => ['public' => true], + '#^/ecardRequest#' => ['public' => true], + '#^/getTPAID#' => ['public' => true], + '#^/fileDownload#' => ['public' => true], + '#^/generateAuthToken#' => ['public' => true], + '#^/createEnrollmentBatch#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [ENROLLMENT_TEAM_ID]], + '#^/getEnrollmentBatchStatus#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [ENROLLMENT_TEAM_ID]], + '#^/fetchUHIDDetails#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [ENROLLMENT_TEAM_ID]], + '#^/FhplGetBenefDetails#' => ['roles' => [ADMIN_ROLE_ID]], + '#^/EcardRequest#' => ['public' => true], + '#^/HospitalNetwork#' => ['public' => true], + '#^/VidalGetBenefDetails#' => ['public' => true], + '#^/ClaimDetail#' => ['public' => true], + '#^/SubmitClaim#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/IntimateClaim#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/IRSubmission#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/ClaimStatusUpdate#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/syncTpaClaimToNhance#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/HealthIndiaGetBenefDetails#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/testTracelog#' => ['roles' => [ADMIN_ROLE_ID]], // ===================== CLI ===================== '#^/cli/#' => ['public' => true], diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 01664e76..2f22bbe4 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -3564,7 +3564,7 @@ class EmployeeController extends AdminController public function initiateWellnessOnboard($client_policy_id) { $r = Jobs::addJob(['job_name' => 'initiateWellnessOnboardJob','payload' => ['client_policy_id' => $client_policy_id]]); - //$this->initiateWellnessOnboardJob(['client_policy_id' => $client_policy_id]); + // $this->initiateWellnessOnboardJob(['client_policy_id' => $client_policy_id]); return $this->respond(['status' => true, 'code' => 200, 'message' => 'Process started'], 200); } @@ -4577,14 +4577,17 @@ class EmployeeController extends AdminController $statusCode = $response->getStatusCode(); $rawBody = $response->getBody(); $result = json_decode($rawBody, true); + // print_rr($result); - // 4. Handle based on HTTP Status Code - if ($statusCode >= 200 && $statusCode < 300) { + // 4. Handle based on HTTP Status Code - BUG FIX: Changed = to == for proper comparison + if ($statusCode == 200) { $this->myLogger->logme('error', "VISIT_OFFBOARD API Success (Code $statusCode): Policy deleted."); - return [ - 'status' => true, - 'data' => $result + $return_data = [ + 'memberIds' => $params['memberIds'] ?? [], + 'api_result' => $result ]; + $this->updateVisitoffboardStatus($return_data); + return $return_data; } // Log API-level errors (4xx or 5xx) @@ -4607,6 +4610,73 @@ class EmployeeController extends AdminController } } + + /** + * Updates the wellness onboard status in the database for deleted members. + * + * Marks employee policy records as deleted in the wellness system after + * a successful API response from the wellness onboard service. + * + * @param array $data Contains 'memberIds' array and 'api_result' from API response + * @return bool Returns true if update was successful or no action needed, false on error + */ + public function updateVisitoffboardStatus(array $data): bool + { + try { + // Validate input data structure + if (empty($data) || !is_array($data)) { + $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Invalid data parameter'); + return false; + } + + // Check if API result exists + if (empty($data['api_result'])) { + $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: No API result found in data'); + return false; + } + + $apiResult = $data['api_result']; + + // Verify API success status - BUG FIX: Proper key access and validation + if (($apiResult['message'] ?? null) !== 'success') { + $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: API response not successful - ' . json_encode($apiResult)); + return false; + } + + // Extract member IDs safely - BUG FIX: Corrected key from memberids to memberIds + $memberIds = $data['memberIds'] ?? []; + + if (empty($memberIds) || !is_array($memberIds)) { + $this->myLogger->logme('warn', 'VISIT_OFFBOARD_STATUS_UPDATE: No valid memberIds provided for update'); + return true; // Not an error if no members to update + } + + if(!empty($apiResult['missingMemberIds']) && is_array($apiResult['missingMemberIds'])) + { + $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: missing member IDs found - ' . json_encode($apiResult['missingMemberIds'])); + } + // Update wellness_onboard status for deleted members - Append '_DEL' to existing value + $updateResult = $this->employeePolicyModel + ->whereIn('id', $memberIds) + ->set('wellness_onboard', "CONCAT(wellness_onboard, '_DEL')", false) + ->update(); + + if ($updateResult !== false) { + $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Updated ' . $updateResult . ' employee policy records with wellness_onboard_DEL status'); + return true; + } else { + $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Database update operation failed'); + return false; + } + + + + } catch (\Exception $e) { + $this->myLogger->logme('error', 'VISIT_OFFBOARD_STATUS_UPDATE: Exception occurred - ' . $e->getMessage() . ' - File: ' . $e->getFile() . ' - Line: ' . $e->getLine()); + return false; + } + } + public function insufficientCdBalanceHrMailSend() { $post_data = $this->request->getJson(true); diff --git a/app/Controllers/JobWorker.php b/app/Controllers/JobWorker.php index 9aba4443..5840ac3f 100755 --- a/app/Controllers/JobWorker.php +++ b/app/Controllers/JobWorker.php @@ -238,6 +238,10 @@ class JobWorker extends AdminController 'getEmployeeEcardFromTmpFolderAndZipToS3' => [ 'type' => 'CC', // Handler Category 'handler' => 'App\Controllers\EmployeeController', + ], + 'visitOffBoard' => [ + 'type' => 'CC', // Handler Category + 'handler' => 'App\Controllers\EmployeeController', ] ]; From 9194787e14157710912bea817481088e18cbd7da Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Mon, 9 Mar 2026 09:58:49 +0530 Subject: [PATCH 07/54] CHANGE_TPA_RECON --- app/Config/Routes.php | 2 + app/Controllers/EmployeeController.php | 122 +++++++++++++++++++++---- 2 files changed, 108 insertions(+), 16 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 2c4d629c..17126e97 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -227,6 +227,8 @@ $routes->group("/employee", ["filter" => "authMVC"], function ($routes) { $routes->get("retail-endorsement-list", "EmployeeController::retailendorsementlist"); $routes->post("retail-endorsement-save", "EmployeeController::retailendorsementsave"); $routes->get("getTPADataVariationReport/(:num)", "EmployeeController::getTPADataVariationReport/$1"); + $routes->get("getTPADataVariationReportView/(:num)", "EmployeeController::getTPADataVariationReport/$1/view"); + $routes->get("proceedTPADataVariationNextStep/(:num)", "EmployeeController::proceedTPADataVariationNextStep/$1"); $routes->get("bulkGenerateEcardAndStoreinS3", "EmployeeController::bulkGenerateEcardAndStoreinS3"); $routes->get('clearCdSession', 'EmployeeController::clearCdSession'); $routes->get('checkSessionStatus', 'EmployeeController::checkSessionStatus'); diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 01664e76..76e2b811 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -3938,14 +3938,14 @@ class EmployeeController extends AdminController } } - public function getTPADataVariationReport($file_id) + public function getTPADataVariationReport($file_id, $type = 'download') { $file_info = $this->batchFileModel->where('id', $file_id)->find(); $client_id = $file_info[0]['client_id']; $client_policy_id = $file_info[0]['client_policy_id']; $TpaApiDataModel = new TpaApiDataModel(); $emp_data_wo_tpa_id = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id); - + //loop emp data with TPA data for matches foreach ($emp_data_wo_tpa_id as $db_key => $db_row) @@ -3965,10 +3965,10 @@ class EmployeeController extends AdminController // die(); //not_in_tpa $tpa_emp_codes = $TpaApiDataModel->select('emp_code') - ->where('file_id', $file_id) - ->where('is_active', 1) - ->groupBy('emp_code') - ->findAll(); + ->where('file_id', $file_id) + ->where('is_active', 1) + ->groupBy('emp_code') + ->findAll(); $tpa_emp_codes = array_column($tpa_emp_codes, 'emp_code'); $not_in_tpa = $this->employeePolicyModel->getTPADataVariationReport($client_id, $client_policy_id, $file_id,$tpa_emp_codes); @@ -3982,20 +3982,110 @@ class EmployeeController extends AdminController ->where('is_active',1) ->where('file_id',$file_id) ->whereNotIn('emp_code',$master_emp_codes) - ->findAll(); + ->findAll(); // d($not_in_nhance);die(); - if( !empty($not_in_tpa) || !empty($not_in_nhance) || !empty($emp_data_wo_tpa_id) ) - { - $this->exportVariationReportExcel($not_in_tpa,$not_in_nhance,$emp_data_wo_tpa_id); - } - else - { - return false; - } - // $this->exportVariationReportExcel([],[],[]); + if (!empty($not_in_tpa) || !empty($not_in_nhance) || !empty($emp_data_wo_tpa_id)) { + if ($type === 'download') { + $this->exportVariationReportExcel($not_in_tpa, $not_in_nhance, $emp_data_wo_tpa_id); + } else { + $response = [ + 'not_in_tpa' => $not_in_tpa, + 'not_in_nhance' => $not_in_nhance, + 'mismatch_data' => $emp_data_wo_tpa_id, + ]; + return $this->respond( + [ + 'status' => true, + 'code' => 200, + 'message' => '', + 'data' => $response, + ], + 200 + ); + } + } else { + if ($type === 'download') { + return false; + } + return $this->respond( + [ + 'status' => false, + 'code' => 202, + 'message' => 'No data found', + 'data' => [], + ], + 200 + ); + } + } + + public function proceedTPADataVariationNextStep($file_id) + { + try { + if (empty($file_id)) { + return $this->respond( + [ + 'status' => false, + 'code' => 400, + 'message' => 'Invalid file reference', + 'data' => [], + ], + 200 + ); + } + + $file = $this->batchFileModel->find($file_id); + + if (!$file) { + return $this->respond( + [ + 'status' => false, + 'code' => 404, + 'message' => 'File not found', + 'data' => [], + ], + 200 + ); + } + + $this->myLogger->logme( + 'error', + 'TPA variation review completed and proceed to next clicked', + [ + 'file_id' => $file_id, + 'user_id' => get_session_userid(), + ] + ); + + return $this->respond( + [ + 'status' => true, + 'code' => 200, + 'message' => 'Proceed to next step recorded successfully.', + 'data' => [], + ], + 200 + ); + } catch (\Throwable $e) { + $this->myLogger->logme( + 'error', + 'Error while processing TPA variation proceed to next: ' . $e->getMessage(), + ['file_id' => $file_id] + ); + + return $this->respond( + [ + 'status' => false, + 'code' => 500, + 'message' => 'Unable to proceed to the next step at the moment.', + 'data' => [], + ], + 200 + ); + } } From 157fa892adda201a2598b773996abd0ff4c4b631 Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Mon, 9 Mar 2026 10:17:39 +0530 Subject: [PATCH 08/54] CHANGE_ADD_JOB_FOR_VISIT_DELETION --- app/Controllers/EmpDataServiceController.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/Controllers/EmpDataServiceController.php b/app/Controllers/EmpDataServiceController.php index 3ea1af3a..45e7097c 100755 --- a/app/Controllers/EmpDataServiceController.php +++ b/app/Controllers/EmpDataServiceController.php @@ -3891,6 +3891,13 @@ class EmpDataServiceController extends BaseController $policy_name = $this->getPolicyNameUsingClientPolicyId($client_policy_id); $job_details = new Jobs(); + + $r = Jobs::addJob(['job_name' => 'visitOffBoard', 'payload' => [ + 'memberIds' => $employee_policy_table_primaryKey ?? [], + 'policyNumber' => $policy_name['policy_no'] ?? null , + 'source' => 'NHANCE' + ]]); + $r = Jobs::addJob(['job_name' => 'cashDepositCalculationForDeletion', 'payload' => [ 'employeeIds' => $employee_policy_table_primaryKey, 'client_id' => $client_id, @@ -4703,7 +4710,7 @@ class EmpDataServiceController extends BaseController public function getPolicyNameUsingClientPolicyId($client_policy_id) { - return $this->clientPolicyModel->select('policy_type.policy_type as policy_name') + return $this->clientPolicyModel->select('policy_type.policy_type as policy_name, client_policy.policy_no') ->join('policy_type', 'policy_type.id = client_policy.policy_type_id') ->where('client_policy.id', $client_policy_id) ->first(); From 6b99b9961b6e4e3b270a4c996ae2995697711dfd Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Tue, 10 Mar 2026 10:22:07 +0530 Subject: [PATCH 09/54] CHANGE_HR_ACCESS_CONTROLL_INSIGHT_ADD --- app/Views/hr_access_controll.php | 75 +++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/app/Views/hr_access_controll.php b/app/Views/hr_access_controll.php index f2d69989..6e1dd2ac 100644 --- a/app/Views/hr_access_controll.php +++ b/app/Views/hr_access_controll.php @@ -1,4 +1,58 @@
    @@ -72,6 +132,7 @@ by + @@ -157,36 +218,39 @@ - +
    + +
    - @@ -228,10 +292,252 @@
    + + \ No newline at end of file From fc7941ed26515ea66456dcc8a56c9642bbae3764 Mon Sep 17 00:00:00 2001 From: "sanjeev.p" Date: Thu, 12 Mar 2026 15:25:56 +0530 Subject: [PATCH 16/54] FIX_FAQ_and_FE_Content --- .../AppContentManagementController.php | 242 ++++++++++++++++-- app/Views/client_onboarding.php | 2 +- app/Views/faq_list.php | 14 +- app/Views/frontend_content_list.php | 27 +- .../policy_transaction_inception_form.php | 20 +- .../policy_transaction_inception_list.php | 6 +- .../assets/images/sales_tracker_light_sb.png | Bin 0 -> 1815 bytes 7 files changed, 265 insertions(+), 46 deletions(-) create mode 100644 public/assets/images/sales_tracker_light_sb.png diff --git a/app/Controllers/AppContentManagementController.php b/app/Controllers/AppContentManagementController.php index c3bcde67..e13732b2 100755 --- a/app/Controllers/AppContentManagementController.php +++ b/app/Controllers/AppContentManagementController.php @@ -226,6 +226,14 @@ class AppContentManagementController extends AdminController if ($this->request->getMethod() === 'post') { + /** + * -------------------------------------------------------------------------- + * STEP 1: INITIAL VALIDATION + * -------------------------------------------------------------------------- + * These are the basic validation rules. For 'content' and 'notes', we only + * check if they are provided and within the allowed length. + * The more advanced security check for script tags happens next. + */ $rules = [ 'fe_id' => [ 'rules' => 'permit_empty|integer|is_natural', @@ -258,22 +266,20 @@ class AppContentManagementController extends AdminController 'regex_match' => 'Heading contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' ] ], - 'content' => [ - 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'content' => [ + 'rules' => 'required|max_length[5000]', 'errors' => [ - 'required' => 'Content is required', - 'max_length' => 'Content cannot exceed 5000 characters', - 'regex_match' => 'Content contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'required' => 'Content is required', + 'max_length' => 'Content cannot exceed 5000 characters', ] ], 'notes' => [ - 'rules' => 'required|max_length[1500]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[1500]', 'errors' => [ - 'required' => 'Notes are required', - 'max_length' => 'Notes cannot exceed 1500 characters', - 'regex_match' => 'Notes contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'required' => 'Notes are required', + 'max_length' => 'Notes cannot exceed 1500 characters', ] - ] + ], ]; if (!$this->validate($rules)) { @@ -284,9 +290,60 @@ class AppContentManagementController extends AdminController 'errors' => $this->validator->getErrors() ]); } - $request_post_data = $this->request->getPost(); - $data = sanitizeInputArrayAdvanced($request_post_data); - $id = $data['fe_id'] ?? null; + + /************************************************************************** + * REFACTORED SANITIZATION LOGIC (XSS Protection) + ************************************************************************** + * + * Per the user's request, we are avoiding the generic `sanitizeInputArrayAdvanced` + * on the `content` and `notes` fields, as they require special HTML + * handling. + * + * The new process is: + * 1. Get the raw `content` and `notes` directly from the POST request. + * 2. Perform the critical XSS validation on this raw content using `hasXssTags()`. + * If it fails, the request is rejected immediately. This satisfies all + * the failure test cases (Tests 4-9). + * 3. Take all *other* POST data and sanitize it using the generic + * `sanitizeInputArrayAdvanced` function. + * 4. Sanitize the now-validated `content` and `notes` using our specific + * `sanitizeHtml()` function, which allows safe HTML. + * 5. Combine the sanitized data into a final array for database insertion. + * + *************************************************************************/ + + // Step 1: Get raw `content` and `notes`. + $rawContent = $this->request->getPost('content'); + $rawNotes = $this->request->getPost('notes'); + + // Step 2: Perform critical XSS validation on raw input. + $xssErrors = []; + if ($this->hasXssTags($rawContent)) { + $xssErrors['content'] = 'Content contains restricted tags. Script, iframe and event handlers are not allowed'; + } + if ($this->hasXssTags($rawNotes)) { + $xssErrors['notes'] = 'Notes contains restricted tags. Script, iframe and event handlers are not allowed'; + } + + if (!empty($xssErrors)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => $xssErrors + ]); + } + + // Step 3: Sanitize all *other* POST data. + $otherPostData = $this->request->getPost(); + unset($otherPostData['content'], $otherPostData['notes']); + $data = sanitizeInputArrayAdvanced($otherPostData); + + // Step 4 & 5: Sanitize and re-combine `content` and `notes`. + $data['content'] = $this->sanitizeHtml($rawContent); + $data['notes'] = $this->sanitizeHtml($rawNotes); + + $id = $data['fe_id'] ?? null; if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) { return $this->response->setStatusCode(400)->setJSON([ @@ -416,19 +473,17 @@ class AppContentManagementController extends AdminController ] ], 'question' => [ - 'rules' => 'required|max_length[1000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[1000]', 'errors' => [ 'required' => 'Question is required', 'max_length' => 'Question cannot exceed 1000 characters', - 'regex_match' => 'Question contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' ] ], 'answer' => [ - 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[5000]', 'errors' => [ 'required' => 'Answer is required', 'max_length' => 'Answer cannot exceed 5000 characters', - 'regex_match' => 'Answer contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' ] ] ]; @@ -443,9 +498,50 @@ class AppContentManagementController extends AdminController ]); } - $request_post_data = $this->request->getPost(); - $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data); - $data = array_filter($sanitized_post_data, fn($v) => $v !== '' && $v !== null); + /************************************************************************** + * XSS PROTECTION FOR 'question' and 'answer' + ************************************************************************** + * + * Applying the same security model as `frontend_content`. + * + * 1. Validate raw `question` and `answer` for malicious tags using `hasXssTags()`. + * If found, reject the request immediately. + * 2. Sanitize all *other* fields using the generic `sanitizeInputArrayAdvanced`. + * 3. Sanitize the `question` and `answer` using the HTML-aware `sanitizeHtml()` + * function to allow safe tags before saving. + * + *************************************************************************/ + + // Step 1: Validate raw input for XSS threats. + $rawQuestion = $this->request->getPost('question'); + $rawAnswer = $this->request->getPost('answer'); + $xssErrors = []; + + if ($this->hasXssTags($rawQuestion)) { + $xssErrors['question'] = 'Question contains restricted tags. Script, iframe and event handlers are not allowed'; + } + if ($this->hasXssTags($rawAnswer)) { + $xssErrors['answer'] = 'Answer contains restricted tags. Script, iframe and event handlers are not allowed'; + } + + if (!empty($xssErrors)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => 'error', + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => $xssErrors, + 'ref' => $ref + ]); + } + + // Step 2 & 3: Sanitize and combine data. + $otherPostData = $this->request->getPost(); + unset($otherPostData['question'], $otherPostData['answer']); + $data = sanitizeInputArrayAdvanced($otherPostData); + + $data['question'] = $this->sanitizeHtml($rawQuestion); + $data['answer'] = $this->sanitizeHtml($rawAnswer); + $id = $data['faq_id'] ?? null; if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) { @@ -470,12 +566,6 @@ class AppContentManagementController extends AdminController $msg = "Updated"; } - // if ($returnType === 'web') { - // return redirect()->back()->with($status ? 'success' : 'error', "FAQ $msg " . ($status ? 'successfully' : 'failed')); - // } - - // return $this->response->setJSON([ - // ])->setStatusCode($result ? 200 : 400); return $this->response->setJSON([ 'status' => $status ? 'success' : 'error', 'message' => "FAQ $msg " . ($status ? 'successfully' : 'failed'), @@ -611,4 +701,104 @@ class AppContentManagementController extends AdminController // } + + // Add these two private methods inside AppContentManagementController + + + /** + * ================================================================================= + * HTML SANITIZATION & VALIDATION HELPER METHODS + * ================================================================================= + * The following two methods are the core of the XSS protection logic. + */ + + + /** + * sanitizeHtml() + * + * This function cleans a string of HTML, ensuring it is safe to display in a browser. + * It allows a specific set of safe HTML tags and removes any dangerous attributes + * from those tags. + * + * @param string $input The raw HTML string from user input. + * @return string The cleaned, safe HTML string. + */ + private function sanitizeHtml(string $input): string + { + /** + * Define a whitelist of allowed HTML tags. Any tag not in this list will be + * completely removed. We are allowing basic formatting, lists, tables, etc. + */ + // ✅ Added , ,

    -

    ,
    ,
    , , 
    for Jodit support + $allowed_tags = '