From 0ffb0b4e324ad422d6a0da32f3661e01ae121616 Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Sat, 4 Jan 2025 18:38:36 +0530 Subject: [PATCH] CHANGE_TRUNCATED_ADD_DEP_ADD_ENDO_NO_AND_OTHER : RV --- app/Controllers/ClientController.php | 31 ++- app/Controllers/EmpDataServiceController.php | 207 ++++++++------- app/Controllers/EmployeeController.php | 127 +++++++-- app/Controllers/LeadsController.php | 3 +- app/Controllers/MasterController.php | 23 +- app/Helpers/excel_util_helper.php | 2 +- app/Models/CDMasterModel.php | 37 ++- app/Models/EmployeePolicyModel.php | 240 +++++++++++++++++- app/Views/cd_master_list.php | 134 +++++----- .../sample_import_Addition.xlsx | Bin 6370 -> 6482 bytes .../sample_import_Dependent_Addition.xlsx | Bin 6370 -> 6485 bytes 11 files changed, 595 insertions(+), 209 deletions(-) diff --git a/app/Controllers/ClientController.php b/app/Controllers/ClientController.php index eba1c8de..4b8c38a0 100755 --- a/app/Controllers/ClientController.php +++ b/app/Controllers/ClientController.php @@ -1091,7 +1091,7 @@ class ClientController extends AdminController $data['reminder_date'] = null; } - $data['created_by'] = get_session_userid(); + $data['created_by'] = get_session_userid(); $policy_tranction_data = [ @@ -3842,7 +3842,7 @@ class ClientController extends AdminController // dd($this->request); // $employeeRestController = new EmployeeServiceController(); - // $employeeRestController->employeesEnrollmentInsert(['file_id' => 721]); + // $employeeRestController->employeesOnboardPreprocess(['file_id' => 721]); // $r = Jobs::addJob(['job_name' => 'employeesEnrollmentInsert','payload' => ['file_id' => 721]]); @@ -3871,6 +3871,33 @@ class ClientController extends AdminController // $empServiceController = new EmployeeServiceController(); // $res = $empServiceController->excelFileDataValidation(['file_id' => '319']); // dd($res); + + // $EmpDataServiceController = new EmpDataServiceController(); + // $EmpDataServiceController->importInceptionFileValidation(['file_id' => 160]); + + $EmpDataServiceController = new EmpDataServiceController(); + // $EmpDataServiceController->importInceptionUpdateTPAandUHID(['file_id' => 162]); + // $EmpDataServiceController->importInceptionFileValidation(['file_id' => 162]); + // $EmpDataServiceController->importDeletionValidation(['file_id' => 171]); + // $EmpDataServiceController->importDeletionUpdateEndorsementID(['file_id' => 171]); + $array = [ + "employeeIds" => ["12800", "12798", "12797", "12799"], + "client_id" => "159", + "client_policy_id" => "336", + "client_branch_id" => "126", + "cd_ac_no" => "Apple_123", + "endorsement_no" => "ENDORSEMENT_ID", + "count" => 4, + "event_name" => "deletion", + "policy_name" => "GMC", + "user_id" => "1" + ]; + + $EmpDataServiceController->cashDepositCalculationForDeletion($array); + + // $employeeRestController = new EmployeeServiceController(); + // $employeeRestController->employeesOnboardPreprocess(['file_id' => 757]); + } // ------------------------------------------------------------------------------------------------------- diff --git a/app/Controllers/EmpDataServiceController.php b/app/Controllers/EmpDataServiceController.php index 0e618c6f..8926ffa5 100755 --- a/app/Controllers/EmpDataServiceController.php +++ b/app/Controllers/EmpDataServiceController.php @@ -169,13 +169,13 @@ class EmpDataServiceController extends BaseController $cash_balance['balance'] = $balance['opening_bal']; } - // Calculate the total amount from the objects - $totals = 0; - foreach ($objects as $item) { - $totals = $totals + $item->total; - } - - $totals = round($totals, 2); + // Calculate the total amount from the objects + $totals = 0; + foreach ($objects as $item) { + $totals = $totals + $item->total; + } + + $totals = round($totals, 2); if($export_data['insurer_or_tpa'] == 'insurer') //check CD amt related issue for only insurer, not tpa { @@ -423,7 +423,18 @@ class EmpDataServiceController extends BaseController 'db_column_name' => 'total' ] ]; + + //for addition and dependent addition adding a ENDORSEMENT NO column + if(in_array($export_data['event_type'], ['addition', 'dependent_addition'])){ + $excel_header_columns[] = [ + 'column_index' => 18, + 'column_name' => 'ENDORSEMENT NO', + 'db_column_name' => '' + ]; + } + }else{ + // get excel export format structure array // $template_json = $this->clientPolicyModel // ->select('insurer_excel_export_template.jsoncolumns') @@ -1278,6 +1289,7 @@ class EmpDataServiceController extends BaseController $this->myLogger->logme('info', 'Inception File Validation -- Function called'); $file_id = $params['file_id']; + // dd($file_id); $this->myLogger->logme('error', 'Inception File Validation -- Batch File Table Primary ID : {data}', ['data' => $file_id]); @@ -1310,30 +1322,36 @@ class EmpDataServiceController extends BaseController // array_pop($excel_data); $inceptionHeader = [ - 'S.No', - 'NAME OF EMP/DEP', - 'EMP ID', - // 'EMP/DEP TYPE', - // 'RELATIONSHIP CODE', - 'DOB', - 'GENDER', - 'PRE EXISTING AILMENTS', - 'BASIC COVER SI', - 'DATE OF COVERAGE', - 'AGE', - 'RELATIONSHIP', - 'REMARKS', - 'POLICY END DATE', - 'NO OF DAYS', - 'TPA ID', - 'UHID', - // 'PREMIUM', - 'PRO RATA PREMIUM', - 'GST', - 'TOTAL AMOUNT' - ]; + 'S.No', + 'NAME OF EMP/DEP', + 'EMP ID', + // 'EMP/DEP TYPE', + // 'RELATIONSHIP CODE', + 'DOB', + 'GENDER', + 'PRE EXISTING AILMENTS', + 'BASIC COVER SI', + 'DATE OF COVERAGE', + 'AGE', + 'RELATIONSHIP', + 'REMARKS', + 'POLICY END DATE', + 'NO OF DAYS', + 'TPA ID', + 'UHID', + // 'PREMIUM', + 'PRO RATA PREMIUM', + 'GST', + 'TOTAL AMOUNT', + ]; + if(in_array($file['event_type'], ['addition', 'dependent_addition'])){ + $inceptionHeader[] = 'ENDORSEMENT NO'; + } + + // dd($inceptionHeader); foreach ($inceptionHeader as $key => $value) { + if($excel_header[$key] != $value){ $data = [ 'status' => 'failed-5', @@ -1352,47 +1370,9 @@ class EmpDataServiceController extends BaseController $emp_count = count($excel_data); + //get the employee data for excel file validation $employee_data = $this->employeePolicyModel->getInceptionEmployeeDataForExportExcel($ref_data, 1); - // dd($employee_data, $excel_data); - // ->select(' - - // employee_polices.id as emp_policy_id, - // employees.name AS emp_name, - // employees.emp_code AS emp_code, - // "Has Define" as emp_type, - // employees.relationship_code AS emp_relationship_code, - // employees.dob AS emp_dob, - // employees.gender AS emp_gender, - // employee_polices.pre_existing_alignments, - // employee_polices.basic_cover_si, - // employee_polices.date_of_coverage, - // TIMESTAMPDIFF(YEAR, employees.dob, CURDATE()) AS emp_age, - // employees.relationship AS emp_relationship, - // employees.change_event AS change_event, - // employee_polices.policy_end_date, - // employee_polices.days, - // employee_polices.tpa_id, - // employee_polices.uhid, - // employee_polices.premium, - // employee_polices.rata_premimum, - // employee_polices.gst, - // (employee_polices.rata_premimum + employee_polices.gst) AS total - // ') - - // ->join('employees', 'employees.id = employee_polices.employee_id') - // ->where('employee_polices.client_policy_id', $client_policy_id) - // ->where('employees.client_id', $client_id) - // ->where('employees.client_branch_id', $client_branch_id) - // ->where("employee_polices.{$id} IS NULL OR employee_polices.{$id} = ''") - // ->where('employee_polices.is_active', 1) - // ->where('employee_polices.status', 'active') - // ->where('employees.is_active', 1) - // ->where('employees.emp_status', 'active') - // ->findAll(); - - - if ($employee_data == null || empty($employee_data)) { if ($insurer_or_tpa == 'tpa') { @@ -1425,7 +1405,6 @@ class EmpDataServiceController extends BaseController } $this->myLogger->logme('error', 'Inception File Validation -- UHID or TPAID already updated or the uploadedfile is not correct'); - } $excel_data_count = count($excel_data); @@ -1446,7 +1425,6 @@ class EmpDataServiceController extends BaseController $this->myLogger->logme('error', 'Inception File Validation -- excel file count partially : {data}', ['data' => $partially_updated_data]); } - if ($emp_data_count < $excel_data_count) { $data = [ @@ -1724,6 +1702,7 @@ class EmpDataServiceController extends BaseController $file_id = $params['file_id']; $file = $this->batchFileModel->find($file_id); + // dd($file); if (!$file) { @@ -1756,22 +1735,20 @@ class EmpDataServiceController extends BaseController ->first(); $get_policy_type = $this->clientPolicyModel - ->select('policy_type.policy_type, policies.policy_type_id as policy_type_id') - ->join('policies', 'policies.id = client_policy.policy_id') - ->join('policy_type', 'policy_type.id = policies.policy_type_id') + ->select('client_policy.*, policy_type.policy_type') + ->join('policy_type', 'policy_type.id = client_policy.policy_type_id', 'left') ->where('client_policy.id', $client_policy_id) ->first(); + // dd($get_policy_type); $status_val = 'success'; if ($status == 'in-progress-partially') { - $status_val = 'partially success'; } $this->myLogger->logme('error', 'Inception Update TPA and UHID -- file name : {data}', ['data' => $file['file_name']]); - $file_name_with_path = WRITEPATH . "/uploads/import_excel/" . $file['file_name']; $excel_data = $this->readExcelFileToArray($file_name_with_path); unset($excel_data[0]); // Remove header row @@ -1782,10 +1759,15 @@ class EmpDataServiceController extends BaseController $emp_details = []; $tpa_id = []; $uhid = []; + $emp_endorsement_table_data = []; + $enrollment_file_id = null; + $endorsement_id = null; $emp_count = count($excel_data); $db = \Config\Database::connect(); + // print_rr($excel_data); die; + foreach ($excel_data as $key => $value) { $name = $value[1]; @@ -1825,11 +1807,54 @@ class EmpDataServiceController extends BaseController $emp_details[] = array('id' => $result['id'], 'tpa_id' => $value[13], 'uhid' => $value[14]); } + //for addition and dependent_addition endorsement , endorsement_id update functionality + if(in_array($file['event_type'], ['addition', 'dependent_addition']) && isset($value[18])){ + + $action = 'a'; + if($file['event_type'] == "dependent_addition"){ + $action = 'da'; + } + + $endorsement_id = $value[18]; + + $result_for_endorsement = $this->empEndorsementModel + ->select('emp_endorsement.*, employees.id as emp_id, employee_polices.id as emp_policy_id') + ->join('employee_polices', 'employee_polices.id = emp_endorsement.pk') + ->join('employees', 'employees.emp_code = emp_endorsement.emp_code') + ->where('employees.emp_code', $emp_code) + ->where('employees.name', $name) + ->where('employees.client_id', $client_id) + ->where('employees.client_branch_id', $client_branch_id) + ->where('emp_endorsement.actions', $action) + ->where('employee_polices.client_policy_id', $client_policy_id) + ->where('employee_polices.is_active', 1) + ->where('employee_polices.status', 'active') + ->where('employees.is_active', 1) + ->where('employees.emp_status', 'active') + ->where('(emp_endorsement.endorsement_id IS NULL OR emp_endorsement.endorsement_id = "")') + ->groupBy('emp_endorsement.group_key') + ->first(); + + if (!empty($result_for_endorsement) && count($result_for_endorsement)) { + $enrollment_file_id = $result_for_endorsement['file_id']; //files table primary key + $emp_endorsement_table_data[] = array('id' => $result_for_endorsement['id'], 'group_key' => $result_for_endorsement['group_key'], 'endorsement_id' => $value[18], 'status' => 'complete'); + } + } + } + } + // dd($emp_endorsement_table_data, $enrollment_file_id); + + //update the employee policy data (TPAID or UHID) $return = $this->employeePolicyModel->bulkUpdate($emp_details); + if(in_array($file['event_type'], ['addition', 'dependent_addition']) && !empty($emp_endorsement_table_data)){ + $this->employeePolicyModel->updateEmpEndorsementAddition($emp_endorsement_table_data); + $this->storeEndorsementNumber($file_id, $endorsement_id, $enrollment_file_id); + } + // Update batch file status and amount $this->batchFileModel->update($file_id, [ 'count' => $emp_count, @@ -1865,7 +1890,7 @@ class EmpDataServiceController extends BaseController 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'cd_ac_no' => $CD_Account_Number['cd_ac_no'] ?? null, - 'endorsement_no' => null, + 'endorsement_no' => $endorsement_id, 'client_branch_id' => $client_branch_id, 'count' => $emp_count, 'event_name' => $file['event_type'], @@ -2256,6 +2281,7 @@ class EmpDataServiceController extends BaseController $emp_details = []; $endorsement_id = []; $endorsement_details = []; + $enrollment_file_id = null; $emp_count = count($excel_data); $db = \Config\Database::connect(); @@ -2268,7 +2294,6 @@ class EmpDataServiceController extends BaseController $endorsement_id[] = $value[10]; $uhid = $value[1]; - $result = $this->empEndorsementModel ->select('emp_endorsement.*, employees.id as emp_id') ->join('employees', 'employees.id = emp_endorsement.pk') @@ -2289,8 +2314,8 @@ class EmpDataServiceController extends BaseController ->first(); if (isset($result['id']) && $result['id'] !== null) { - // return $result; + $enrollment_file_id = $result['file_id']; $emp_details[] = array('id' => $result['emp_id'], $result['field_name'] => $value[8]); $endorsement_details[] = array('group_key' => $result['group_key'], 'id' => $result['id'], 'endorsement_id' => $value[10], 'status' => 'complete'); } @@ -2301,7 +2326,7 @@ class EmpDataServiceController extends BaseController $this->empEndorsementModel->updateBatch($endorsement_details, 'group_key'); $this->employeePolicyModel->bulkUpdateForCorrection($emp_details); - $this->storeEndorsementNumber($file_id, $endorsement_id[0]); + $this->storeEndorsementNumber($file_id, $endorsement_id[0], $enrollment_file_id); // Update batch file status and amount @@ -2815,6 +2840,7 @@ class EmpDataServiceController extends BaseController $employeeIds = []; $emp_details = []; $endorsement_id = ''; + $enrollment_file_id = ''; $endorsement_details = []; $totals = 0; @@ -2846,6 +2872,8 @@ class EmpDataServiceController extends BaseController ->first(); if (isset($result['id']) && $result['id'] !== null) { + + $enrollment_file_id = $result['file_id']; $emp_policy_ids[] = array('id' => $result['emp_policy_id'], 'is_active' => 0); $employeeIds[] = $result['emp_policy_id']; $endorsement_details[] = array('id' => $result['id'], 'group_key' => $result['group_key'], 'endorsement_id' => $value[19], 'status' => 'complete'); @@ -2905,7 +2933,7 @@ class EmpDataServiceController extends BaseController // } $this->employeePolicyModel->bulkUpdateForEndorsement($endorsement_details); - $this->storeEndorsementNumber($file_id, $endorsement_id); + $this->storeEndorsementNumber($file_id, $endorsement_id, $enrollment_file_id); // Update batch file status and amount @@ -2990,7 +3018,7 @@ class EmpDataServiceController extends BaseController // array_pop($excel_data); $headers = ['S.No','EMP ID','EMP NAME','DOB','GENDER','RELATIONSHIP','SUM INSURED','Date of Leaving','Policy End Date','No Of Days','Premium','Pro Rata Premium','GST','Total','Claim Status','ENDORSEMENT_ID']; - + // dd($headers, $excel_header); foreach ($headers as $key => $value) { if($excel_header[$key] != $value){ @@ -3322,6 +3350,7 @@ class EmpDataServiceController extends BaseController $employee_policy_table_data = []; $employee_policy_table_primaryKey = []; $endorsement_id = ''; + $enrollment_file_id = null; //files table primary key $totals = 0; @@ -3342,12 +3371,15 @@ class EmpDataServiceController extends BaseController 'emp_name' => $emp_name, 'emp_code' => $emp_code ]; + $result = $this->employeePolicyModel->fetchEmpEndorsementData($fetch_data); + // dd($result, db_connect()->getLastQuery()); if (isset($result['emp_endorsement_primarykey']) && $result['emp_endorsement_primarykey'] !== null) { + $enrollment_file_id = $result['file_id']; //files table primary key $employee_policy_table_primaryKey[] = $result['emp_policy_primarykey']; //for cash deposite - $employee_policy_table_data[] = array('id' => $result['emp_policy_primarykey'], 'date_of_exit' => $result['date_of_exit'], 'reason_for_exit' => $result['reason_for_exit'], 'status' => $result['status']); + $employee_policy_table_data[] = array('id' => $result['emp_policy_primarykey'], 'date_of_exit' => $result['date_of_exit'], 'reason_for_exit' => $result['reason_for_exit'], 'claim_status' => $result['claim_status'], 'status' => $result['status']); // $employees_table_data[] = array('id' => $result['employees_id'], 'emp_status' => $result['status']); $emp_endorsement_table_data[] = array('id' => $result['emp_endorsement_primarykey'], 'group_key' => $result['group_key'], 'endorsement_id' => $value[15], 'status' => 'complete'); } @@ -3360,7 +3392,6 @@ class EmpDataServiceController extends BaseController // dd($employees_table_data, $emp_endorsement_table_data, $employee_policy_table_data, $employee_policy_table_primaryKey, $totals, $emp_count); - // Check if $employees_table_data is null or empty // if (empty($employees_table_data)) { // return ['status' => 'error', 'message' => 'Employees table data is empty or null.']; @@ -3379,7 +3410,7 @@ class EmpDataServiceController extends BaseController // $this->employeeModel->updateBatch($employees_table_data, 'id'); $this->employeePolicyModel->updateBatch($employee_policy_table_data, 'id'); $this->employeePolicyModel->bulkUpdateForEndorsement($emp_endorsement_table_data); - $this->storeEndorsementNumber($file_id, $endorsement_id); + $this->storeEndorsementNumber($file_id, $endorsement_id, $enrollment_file_id); // Update batch file status and amount $this->batchFileModel->update($file_id, [ @@ -3388,12 +3419,12 @@ class EmpDataServiceController extends BaseController 'amount' => $rounded_totals, ]); - $this->myLogger->logme('error', 'Deletion Update Endorsement ID -- Employee count : {data}', ['data' => $emp_count]); $this->myLogger->logme('error', 'Deletion Update Endorsement ID -- Batch File status : {data}', ['data' => $status_val]); //call the cash deposite function if ($file['insurer_or_tpa'] == 'insurer') { + $policy_name = $this->getPolicyNameUsingClientPolicyId($client_policy_id); $job_details = new Jobs(); $r = Jobs::addJob(['job_name' => 'cashDepositCalculationForDeletion', 'payload' => [ @@ -4021,10 +4052,11 @@ class EmpDataServiceController extends BaseController WHERE employee_polices.id IN (" . implode(',', $arrayData['employeeIds']) . ") AND emp_endorsement.pk IN (" . implode(',', $arrayData['employeeIds']) . ") + AND employee_polices.claim_status = 0 AND emp_endorsement.field_name = 'date_of_exit' ")->getRow(); - // dd(db_connect()->getLastQuery(), $amount); + dd(db_connect()->getLastQuery(), $amount); if($amount){ @@ -4518,7 +4550,7 @@ class EmpDataServiceController extends BaseController $this->messageModel->insert($msg_data); } - public function storeEndorsementNumber($file_id, $endorsement_no) + public function storeEndorsementNumber($file_id, $endorsement_no, $enrollment_file_id) { // Log the function entry with input parameters $this->myLogger->logme('error', "storeEndorsementNumber --- Starting function with file_id: $file_id and endorsement_no: $endorsement_no"); @@ -4554,6 +4586,7 @@ class EmpDataServiceController extends BaseController 'insurer_id' => $filedata['insurer_id'], 'tpa_id' => $filedata['tpa_id'], 'endorsement_no' => $endorsement_no, + 'file_id' => $enrollment_file_id, 'endorsement_type' => $filedata['event_type'], 'created_by' => $filedata['created_by'], ]); diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 2495ed2b..2f05a1d4 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -1236,17 +1236,19 @@ class EmployeeController extends AdminController $loggedInUserID = get_session_userid(); $policy_data = $this->clientPolicyModel->where('id', $client_policy_id)->first(); + $cd_tranction = $this->cashDepositModel - ->where('client_id', $client_id) - ->where('insurer_id', $policy_data['insurer_id']) - ->where('event_name',$file['action']) - ->where('client_policy_id', $client_policy_id) + ->where('client_id', $client_id) //client + ->where('insurer_id', $policy_data['insurer_id']) //insurer + ->where('event_name',$file['action']) //event + ->where('client_policy_id', $client_policy_id)//policy ->orderBy('id', 'desc') ->first(); + // $file['action'] = 'si_enhancement'; // $result = []; - // !dd($file); + // dd($file); if ($file['action'] == 'inception' || $file['action'] == 'dependent_addition' || $file['action'] == 'addition' || $file['action'] == 'enrollment' || $file['action'] == 'missed_inception') { @@ -1256,6 +1258,7 @@ class EmployeeController extends AdminController $result = $this->employeeModel->getEmpListByFileId(file_id: $file_id, emp_status: ['active'], policy_status: ['active']); } + $result = []; // ~dd($result); if (count($result) && $role_id == null) { if(get_role_id() == 1 || get_role_id() == 5){ @@ -1265,18 +1268,57 @@ class EmployeeController extends AdminController } } else { + $this->myLogger->logme('error', 'TRUNCATED STARTED WITH ADMIN OR HEAD PERMISSION'); + $this->myLogger->logme('error', 'Event Type : -- {data} --', ['data' => $file['action']]); + + + // GET THE CD AMOUND + //get cd amount for the particular file id to reverse entry to the cash deposite + $cd_amount = $cd_tranction['amount']; + if(in_array($file['action'], ['addition', 'dependent_addition'])){ + $cd_amount_total = $this->employeePolicyModel->getAdditionDataForTruncated($file_id, $file['action']); + // dd($cd_amount_total); + $cd_amount = $cd_amount_total['total']; + + $this->myLogger->logme('error', 'Addition or Dependent Addition CD Amount : {data}', ['data' => $cd_amount]); + } + + $this->myLogger->logme('error', 'CD Amount : {data}', ['data' => $cd_amount]); + + if($file['action'] != 'enrollment') - { + { + //STEP: 1 - Update employee policy table //update emp and emp plocies $db = db_connect(); - $query = "UPDATE employees JOIN employee_polices ON employees.id = employee_polices.employee_id and employees.file_id = $file_id SET employees.emp_status = 'truncated', employee_polices.status = 'truncated', employees.is_active = 0,employee_polices.is_active = 0 WHERE employees.file_id = $file_id"; + $query = " + UPDATE employee_polices + JOIN employees ON employees.id = employee_polices.employee_id + SET employee_polices.status = 'truncated', employee_polices.is_active = 0 + WHERE employees.file_id = $file_id + "; + $db->query($query); $affectedRows = $db->affectedRows(); + $this->myLogger->logme('error', 'employee_polices table update query : {data}', ['data' => $query]); + $this->myLogger->logme('error', 'employee_polices table updated - Affected Rows : {data}', ['data' => $affectedRows]); // print_r($db->getLastQuery()); die; // $affectedRows = 10; + //STEP:2 - Update emp_endorsement Table + //update truncated status and is_active 0 to the Emp_endorsement table + if(in_array($file['action'], ['addition', 'dependent_addition'])){ + $this->empEndorsementModel->where('file_id', $file_id) + ->set(['status' => 'truncated','is_active' => 0]) + ->update(); + + $this->myLogger->logme('error', 'emp_endorsement table updated'); + } + + //STEP:3 - Update files table //update file status $this->fileModel->where('id', $file_id)->set(['status' => 'truncated'])->update(); + $this->myLogger->logme('error', 'files table updated'); } else { @@ -1316,7 +1358,12 @@ class EmployeeController extends AdminController $db = db_connect(); $emp_codes = '(' . implode(',', array_map(fn($code) => "'$code'", $emp_codes)) . ')'; $dependent_policies = '(' . implode(',', $dependent_policies) . ')'; - $query = "UPDATE employee_polices JOIN employees ON employees.id = employee_polices.employee_id and employees.emp_code in $emp_codes SET employee_polices.status = 'truncated', employee_polices.is_active = 0 WHERE employee_polices.client_policy_id in $dependent_policies"; + $query = " + UPDATE employee_polices + JOIN employees ON employees.id = employee_polices.employee_id and employees.emp_code in $emp_codes + SET employee_polices.status = 'truncated', employee_polices.is_active = 0 + WHERE employee_polices.client_policy_id in $dependent_policies + "; $db->query($query); $affectedRows = $db->affectedRows(); @@ -1326,10 +1373,11 @@ class EmployeeController extends AdminController } + //FINAL STEP - Update reverse entry in cash_deposite table if($cd_tranction){ $cd_data = [ - 'amount' => $cd_tranction['amount'], + 'amount' => $cd_amount, 'sub_type_id' => 8, 'endorsement_no' => null, 'insurer_id' =>$policy_data['insurer_id'], @@ -1339,12 +1387,17 @@ class EmployeeController extends AdminController 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'cd_ac_no' => $policy_data['cd_ac_no'] ?? null, + 'cd_ac_pk' => $policy_data['cd_ac_pk'] ?? null, 'event_name' => $file['action'], ]; $response = DepositHelper::saveDeposit($cd_data, $loggedInUserID); + $this->myLogger->logme('error', 'cash_deposite table updated -- cd transaction'); + } + $this->myLogger->logme('error', 'SUCCESSFULLY TRUNCATED'); + return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => round($affectedRows / 2)], 200); } @@ -1361,23 +1414,57 @@ class EmployeeController extends AdminController // print_r($this->empEndorsementModel->getLastQuery()); // echo $res[0]->count;die(); + if ($res[0]->count == 0 || $role_id == 5 || $role_id == 1) { - //update truncated status to db + + $this->myLogger->logme('error', 'TRUNCATED STARTED WITH ADMIN OR HEAD PERMISSION'); + $this->myLogger->logme('error', 'Event Type : -- {data} --', ['data' => $file['action']]); + + $transaction_type = 'Credit'; + $cd_amount = $cd_tranction['amount']; + + if($file['action'] == 'deletion'){ + $transaction_type = 'Debit'; + //get cd amount for the particular file id to reverse entry to the cash deposite for only deletion + $cd_amount_total = $this->employeePolicyModel->getDeletionDataForTruncated($file['id']); + $totalSum = array_sum(array_column($cd_amount_total, 'total')); + $cd_amount = $totalSum; + + $this->myLogger->logme('error', 'Deletion CD Amount : {data}', ['data' => $cd_amount]); + } + + $this->myLogger->logme('error', 'Endorsemnt CD Amount : {data}', ['data' => $cd_amount]); + + + //STEP 1: + //update truncated status to the Emp_endorsement table $this->empEndorsementModel->where('file_id', $file_id) ->set(['status' => 'truncated','is_active' => 0]) ->update(); - //update file status + + $this->myLogger->logme('error', 'emp_endorsement table updated'); + + //STEP 2: + if($file['action'] == 'deletion') { + //update the employee policy table reverse the data + $this->employeePolicyModel->updateEmployeePolicyTruncateReverse($file_id); + $this->myLogger->logme('error', 'employee_polices table updated for deletion'); + } + + if($file['action'] == 'correction'){ + + } + + // STEP 3: + //update files table status to "truncated" $this->fileModel->where('id', $file_id)->set(['status' => 'truncated'])->update(); + $this->myLogger->logme('error', 'files table updated'); + if($cd_tranction && $file['action'] != 'correction'){ - $transaction_type = 'Credit'; - if($file['action'] == 'deletion'){ - $transaction_type = 'Debit'; - } - $cd_data = [ - 'amount' => $cd_tranction['amount'], + 'amount' => $cd_amount, 'sub_type_id' => 8, 'endorsement_no' => null, 'insurer_id' =>$policy_data['insurer_id'], @@ -1387,13 +1474,19 @@ class EmployeeController extends AdminController 'client_id' => $client_id, 'client_policy_id' => $client_policy_id, 'cd_ac_no' => $policy_data['cd_ac_no'] ?? null, + 'cd_ac_pk' => $policy_data['cd_ac_pk'] ?? null, 'event_name' => $file['action'], ]; $response = DepositHelper::saveDeposit($cd_data, $loggedInUserID); + $this->myLogger->logme('error', 'cash_deposite table updated -- cd transaction'); + } + $this->myLogger->logme('error', 'SUCCESSFULLY TRUNCATED'); + return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'success'], 200); + } else { if(get_role_id() == 1 || get_role_id() == 5){ return $this->respond(['role' => get_role_id(), 'dataStatus' => false, 'code' => 404, 'message' => 'File data already processed. Do you want to truncate data from uploaded file?'], 200); diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php index 5b44f63a..edf882ba 100644 --- a/app/Controllers/LeadsController.php +++ b/app/Controllers/LeadsController.php @@ -864,11 +864,12 @@ class LeadsController extends BaseController { $lead_id = $params['lead_id']; $lead_data = $this->leadsModel->find($lead_id); + $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; + if (!$lead_data) { return ['status' => 'failed', 'message' => 'Lead data not found']; } if ($lead_data['file_name']) { - $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; // $file_name_with_path = WRITEPATH . "/uploads/lead_files/NonPrintableCharacters.xlsx"; //check physical file diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php index 6a81ebf5..d08f930a 100755 --- a/app/Controllers/MasterController.php +++ b/app/Controllers/MasterController.php @@ -1313,12 +1313,31 @@ class MasterController extends AdminController ->where('id', $id) ->where('is_active', 1) ->first(); + + $db = db_connect(); + $builder = $db->table('cd_master'); + $builder->select('cd_master.cd_ac_no, cd_master.id, COUNT(cash_deposit.cd_ac_no) AS cd_ac_no_count_cd_tranction'); + $builder->join('cash_deposit', 'cash_deposit.cd_ac_pk = cd_master.id'); + $builder->where('cash_deposit.is_active', 1); + $builder->where('cd_master.is_active', 1); + $builder->where('cd_master.id', $id); + $builder->groupBy('cd_master.id'); - // convert the date formate 2000-01-01 to 01-01-2000 + $query = $builder->get(); + $result = $query->getResultArray(); + + // print_r($result); die; + + $count = 0; + if(isset($result[0])){ + $count = $result[0]['cd_ac_no_count_cd_tranction']; + } + + // convert the date formate 2000-01-01 to 01-01-2000 $cd_data['opening_date'] = date('d-m-Y', strtotime($cd_data['opening_date'])); if ($cd_data) { - return $this->respond(['status' => true, 'code' => 200, 'data' => $cd_data], 200); + return $this->respond(['status' => true, 'code' => 200, 'data' => $cd_data, 'cd_transaction_count' => $count], 200); } else { return $this->respond(['status' => false, 'code' => 404], 200); } diff --git a/app/Helpers/excel_util_helper.php b/app/Helpers/excel_util_helper.php index 77c6c552..3c254374 100755 --- a/app/Helpers/excel_util_helper.php +++ b/app/Helpers/excel_util_helper.php @@ -1160,7 +1160,7 @@ if (!function_exists('premium_calculation_manager')) { if($temp_slab_rates[0]['si_or_bp'] == 2) { - $temp_si = $emp_data['basic_pay'] * $temp_slab_rates[0]['si_or_bp']; + $temp_si = $emp_data['basic_pay'] * $temp_slab_rates[0]['basic_multiplier']; $temp_premium = ($temp_si * $temp_slab_rates[0]['multiplier']) / 1000; $emp_data['policy_details']['basic_cover_si'] = $temp_si; diff --git a/app/Models/CDMasterModel.php b/app/Models/CDMasterModel.php index 8c7581a3..663ea3bc 100755 --- a/app/Models/CDMasterModel.php +++ b/app/Models/CDMasterModel.php @@ -65,28 +65,37 @@ class CDMasterModel extends Model { $query = $this->db->table('cd_master') + ->select('cd_master.*, clients.client_name, clients.short_name, insurers.name AS insurer_name, user_profiles.first_name AS user_name, IFNULL(cd_ac_counts.cd_ac_no_count, 0) AS cd_ac_no_count, IFNULL(cd_ac_counts_for_cdt.cd_ac_no_count_cd_tranction, 0) AS cd_ac_no_count_cd_tranction') ->join('clients', 'clients.id = cd_master.client_id') ->join('insurers', 'insurers.id = cd_master.insurer_id') ->join('user_profiles', 'user_profiles.id = cd_master.created_by') ->join( - '(SELECT cd_master.cd_ac_no, COUNT(client_policy.cd_ac_no) AS cd_ac_no_count - FROM cd_master - JOIN client_policy ON client_policy.cd_ac_no = cd_master.cd_ac_no - WHERE client_policy.is_active = 1 - AND cd_master.is_active = 1 - GROUP BY cd_master.cd_ac_no) AS cd_ac_counts', - 'cd_ac_counts.cd_ac_no = cd_master.cd_ac_no', + '(SELECT cd_master.cd_ac_no, cd_master.id, COUNT(client_policy.cd_ac_no) AS cd_ac_no_count + + FROM cd_master + JOIN client_policy ON client_policy.cd_ac_pk = cd_master.id + WHERE client_policy.is_active = 1 + AND cd_master.is_active = 1 + GROUP BY cd_master.id + + ) AS cd_ac_counts', + + 'cd_ac_counts.id = cd_master.id', 'left' ) ->join( - '(SELECT cd_master.cd_ac_no, COUNT(cash_deposit.cd_ac_no) AS cd_ac_no_count_cd_tranction - FROM cd_master - JOIN cash_deposit ON cash_deposit.cd_ac_no = cd_master.cd_ac_no - WHERE cash_deposit.is_active = 1 - AND cd_master.is_active = 1 - GROUP BY cd_master.cd_ac_no) AS cd_ac_counts_for_cdt', - 'cd_ac_counts_for_cdt.cd_ac_no = cd_master.cd_ac_no', + '(SELECT cd_master.cd_ac_no, cd_master.id, COUNT(cash_deposit.cd_ac_no) AS cd_ac_no_count_cd_tranction + + FROM cd_master + JOIN cash_deposit ON cash_deposit.cd_ac_pk = cd_master.id + WHERE cash_deposit.is_active = 1 + AND cd_master.is_active = 1 + GROUP BY cd_master.id + + ) AS cd_ac_counts_for_cdt', + + 'cd_ac_counts_for_cdt.id = cd_master.id', 'left' ) ->where('cd_master.is_active', 1) diff --git a/app/Models/EmployeePolicyModel.php b/app/Models/EmployeePolicyModel.php index 9908c094..8c98dc21 100755 --- a/app/Models/EmployeePolicyModel.php +++ b/app/Models/EmployeePolicyModel.php @@ -806,26 +806,26 @@ class EmployeePolicyModel extends Model deletiondata.dateofexit, deletiondata.reasonforexit, deletiondata.status, + deletiondata.claimstatus, DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + '$add_one_day' AS no_of_days, - CASE - WHEN employee_polices.claim_status = 0 THEN + WHEN deletiondata.claimstatus = 0 THEN ROUND((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365, 2) ELSE 0 END AS pro_rata_premium, CASE - WHEN employee_polices.claim_status = 0 THEN + WHEN deletiondata.claimstatus = 0 THEN ROUND(((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365) * 0.18, 2) ELSE 0 END AS gst, CASE - WHEN employee_polices.claim_status = 0 THEN + WHEN deletiondata.claimstatus = 0 THEN ROUND(((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365) + (((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365) * 0.18), 2) ELSE @@ -833,7 +833,7 @@ class EmployeePolicyModel extends Model END AS total, CASE - WHEN employee_polices.claim_status = 0 THEN + WHEN deletiondata.claimstatus = 0 THEN 'No claim' ELSE 'Claim' @@ -854,7 +854,8 @@ class EmployeePolicyModel extends Model MAX(CASE WHEN field_name = 'change_event' THEN new_value END) AS changeevent, MAX(CASE WHEN field_name = 'date_of_exit' THEN new_value END) AS dateofexit, MAX(CASE WHEN field_name = 'reason_for_exit' THEN new_value END) AS reasonforexit, - MAX(CASE WHEN field_name = 'status' THEN new_value END) AS status + MAX(CASE WHEN field_name = 'status' THEN new_value END) AS status, + MAX(CASE WHEN field_name = 'claim_status' THEN new_value END) AS claimstatus FROM emp_endorsement WHERE @@ -922,6 +923,7 @@ class EmployeePolicyModel extends Model ee.id as emp_endorsement_primarykey, ep.id as emp_policy_primarykey, e.id as employees_primarykey, + ee.file_id, ee.group_key, ( SELECT employees.id @@ -949,7 +951,12 @@ class EmployeePolicyModel extends Model CASE WHEN ee.field_name = 'status' THEN ee.new_value END - ) AS status + ) AS status, + MAX( + CASE + WHEN ee.field_name = 'claim_status' THEN ee.new_value + END + ) AS claim_status FROM emp_endorsement AS ee JOIN employee_polices AS ep ON ep.id = ee.pk @@ -959,7 +966,7 @@ class EmployeePolicyModel extends Model AND ep.client_policy_id = '$client_policy_id' AND e.client_branch_id = '$client_branch_id' AND ee.name = '$emp_name' - AND ee.field_name IN ('date_of_exit', 'reason_for_exit', 'status') + AND ee.field_name IN ('date_of_exit', 'reason_for_exit', 'status', 'claim_status') AND ep.is_active = 1 AND ep.status = 'active' AND e.is_active = 1 @@ -1360,13 +1367,13 @@ class EmployeePolicyModel extends Model return "WHEN group_key = $id THEN $endorsement_id"; }, $escapedIds, $escapedEndorsementIds); - $caseStatus = array_map(function ($id, $status) { - return "WHEN status = $id THEN $status"; - }, $escapedIds, $escapedStatuses); + // $caseStatus = array_map(function ($id, $status) { + // return "WHEN status = $id THEN $status"; + // }, $escapedIds, $escapedStatuses); // Convert cases to a string $caseEndorsementIdString = implode(' ', $caseEndorsementId); - $caseStatusString = implode(' ', $caseStatus); + // $caseStatusString = implode(' ', $caseStatus); // Convert ids to a string $idsString = implode(', ', $escapedIds); @@ -1376,10 +1383,12 @@ class EmployeePolicyModel extends Model UPDATE emp_endorsement SET endorsement_id = CASE {$caseEndorsementIdString} END, - status = CASE {$caseStatusString} END + status = 'complete' WHERE group_key IN ({$idsString}) "; + + // dd($sql); // Begin a transaction $this->db->transBegin(); @@ -1396,6 +1405,7 @@ class EmployeePolicyModel extends Model // Otherwise, commit $this->db->transCommit(); } + // $this->storeEndorsementNumber($file_id, $endorsement_id, $enrollment_file_id); return $this->db->getLastQuery(); } catch (\Exception $e) { @@ -1467,5 +1477,209 @@ class EmployeePolicyModel extends Model } + //for truncate get deletion data + public function getDeletionDataForTruncated($file_id) + { + // Fetch the necessary details in a single query using JOINs + $result = $this->db->table('files f') + ->select('i.deletion_add_day') + ->join('client_policy cp', 'cp.id = f.policy_id', 'left') + ->join('insurers i', 'i.id = cp.insurer_id', 'left') + ->where('f.id', $file_id) + ->get() + ->getRowArray(); + + // Determine if one day should be added for deletion + $add_one_day = (!empty($result) && $result['deletion_add_day'] == 1) ? 1 : 0; + + + $query = $this->db->query(" + + SELECT DISTINCT + + a.id as endorsement_primarykey, + a.group_key, + employee_polices.id as primaryKey, + employees.name AS emp_name, + employees.emp_code AS emp_code, + employees.dob AS emp_dob, + employees.gender AS emp_gender, + employees.relationship AS emp_relationship, + employees.relationship_code AS emp_relationship_code, + employees.emp_type as emp_type, + 'D' as event_type_data, + TIMESTAMPDIFF(YEAR, employees.dob, CURDATE()) AS emp_age, + + employees.doj AS emp_doj, + employees.mobile AS emp_mobile, + employees.email_corporate AS emp_email_c, + employees.email_personal AS emp_email_p, + employees.band AS emp_grade, + employees.designation AS emp_designation, + employees.basic_pay AS emp_basic_pay, + + employee_polices.basic_cover_si, + employee_polices.uhid as uhid, + employee_polices.policy_end_date, + employee_polices.rata_premimum as premium, + employee_polices.claim_status, + + deletiondata.empstatus, + deletiondata.changeevent, + deletiondata.dateofexit, + deletiondata.reasonforexit, + deletiondata.status, + deletiondata.claimstatus, + + DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + '$add_one_day' AS no_of_days, + + CASE + WHEN deletiondata.claimstatus = 0 THEN + ROUND((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365, 2) + ELSE + 0 + END AS pro_rata_premium, + + CASE + WHEN deletiondata.claimstatus = 0 THEN + ROUND(((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365) * 0.18, 2) + ELSE + 0 + END AS gst, + + CASE + WHEN deletiondata.claimstatus = 0 THEN + ROUND(((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365) + + (((employee_polices.rata_premimum * (DATEDIFF(employee_polices.policy_end_date, deletiondata.dateofexit) + $add_one_day)) / 365) * 0.18), 2) + ELSE + 0 + END AS total, + + CASE + WHEN deletiondata.claimstatus = 0 THEN + 'No claim' + ELSE + 'Claim' + END AS claim_status + + FROM + emp_endorsement a + LEFT JOIN + employee_polices ON a.pk = employee_polices.id + LEFT JOIN + employees ON employee_polices.employee_id = employees.id + + LEFT JOIN ( + SELECT + emp_code, + group_key, + MAX(CASE WHEN field_name = 'emp_status' THEN new_value END) AS empstatus, + MAX(CASE WHEN field_name = 'change_event' THEN new_value END) AS changeevent, + MAX(CASE WHEN field_name = 'date_of_exit' THEN new_value END) AS dateofexit, + MAX(CASE WHEN field_name = 'reason_for_exit' THEN new_value END) AS reasonforexit, + MAX(CASE WHEN field_name = 'status' THEN new_value END) AS status, + MAX(CASE WHEN field_name = 'claim_status' THEN new_value END) AS claimstatus + FROM + emp_endorsement + WHERE + status != 'truncated' + GROUP BY + group_key + + ) AS deletiondata + + ON a.emp_code = deletiondata.emp_code AND a.status != 'truncated' + + WHERE a.file_id = {$file_id} + AND a.actions = 'd' + AND a.status != 'truncated' + AND employee_polices.is_active = 1 + AND employees.is_active = 1 + group by group_key + "); + + + $result = $query->getResultArray(); + // dd($this->db->getLastQuery(), $result); + // dd($result); + + return $result; + + } + + //for truncate get addition data + public function getAdditionDataForTruncated($file_id, $event_type) + { + $action = "a"; + if($event_type == "dependent_addition"){ + $action = "da"; + } + + $query = $this->db->query(" + + SELECT + ROUND(SUM(ep.rata_premimum + ep.gst), 2) AS total + FROM + emp_endorsement ee + JOIN + employee_polices ep ON ee.pk = ep.id + WHERE + ee.file_id = $file_id + AND ee.actions = '$action' + AND ep.status != 'truncated' + AND ee.status != 'truncated' + AND ee.is_active = 1 + AND ep.is_active = 1; + "); + + + $result = $query->getResultArray(); + // dd($this->db->getLastQuery(), $result); + // dd($result); + + return $result[0]; + + } + + // reverse the employee policy table data for the truncated the deletion file + public function updateEmployeePolicyTruncateReverse($file_id) + { + $this->db->query(" + UPDATE employee_polices + SET + is_active = 1, + status = 'active', + date_of_exit = NULL, + reason_for_exit = NULL, + claim_status = 0, + WHERE + id IN ( + SELECT pk + FROM emp_endorsement + WHERE file_id = $file_id + GROUP BY group_key + ) + AND status = 'inactive' + "); + + } + + //update employee policy table status truncated and is_active 0 for truncated to the addition file + public function updateEmpEndorsementAddition($array) + { + $caseStatus = "CASE "; + $caseEndorsementId = "CASE "; + $ids = []; + foreach ($array as $item) { + $caseStatus .= "WHEN id = {$item['id']} THEN '{$item['status']}' "; + $caseEndorsementId .= "WHEN id = {$item['id']} THEN '{$item['endorsement_id']}' "; + $ids[] = $item['id']; + } + $caseStatus .= "END"; + $caseEndorsementId .= "END"; + $ids = implode(',', $ids); + $query = "UPDATE emp_endorsement SET status = $caseStatus, endorsement_id = $caseEndorsementId WHERE id IN ($ids);"; // Execute the query + $this->db->query($query); + } } \ No newline at end of file diff --git a/app/Views/cd_master_list.php b/app/Views/cd_master_list.php index cf0f19e8..cdc6d4bc 100755 --- a/app/Views/cd_master_list.php +++ b/app/Views/cd_master_list.php @@ -57,28 +57,18 @@ table.dataTable thead th { by - 0 && $row['cd_ac_no_count_cd_tranction'] > 1) {?> - @@ -171,6 +161,7 @@ table.dataTable thead th { \ No newline at end of file diff --git a/public/sample_import_excel/sample_import_Addition.xlsx b/public/sample_import_excel/sample_import_Addition.xlsx index 19b1f86f6eb171a34e7fb815aa6ec834bcead456..9c6b4752bbb0e336dfa5f903ab398e72f455409b 100644 GIT binary patch literal 6482 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 NI64tkDS!fb_CFhf#Lxf$ literal 6370 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 d{?770Hm0FXvG==70p2_@p((}BwvYUu#u@_<0? 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 Mt%$1RM|yMhKhz`2;Q#;t literal 6370 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 d{?770H