diff --git a/app/Config/Routes.php b/app/Config/Routes.php index eab9f909..6a7ac292 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -317,6 +317,13 @@ $routes->group("policy_tranction", ["filter" => "authMVC"], function ($routes) { $routes->get("list", "PolicyTransactionController::reportBDS"); }); + $routes->group("statement", ["filter" => "authMVC"], function ($routes) { + $routes->get("list", "PolicyTransactionController::statementList"); + $routes->post("upload", "PolicyTransactionController::uploadInsurerStatement"); + $routes->get("getPaymentDetails/(:any)", "PolicyTransactionController::getInvoicePaymentDetails/$1"); + $routes->post("saveInvoicePaymentDetails", "PolicyTransactionController::saveInvoicePaymentDetails"); + }); + }); $routes->cli('cli/processjob', 'JobWorker::processJob'); diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index 7c9c46e7..60daeb55 100644 --- a/app/Controllers/PolicyTransactionController.php +++ b/app/Controllers/PolicyTransactionController.php @@ -25,7 +25,9 @@ use App\Models\EmployeeModel; use App\Models\UserTeamsModel; use App\Models\UserModel; use App\Models\EmployeePolicyModel; - +use App\Models\InsurerStatements; +use App\Models\InvPaymentDetailsModel; +use Kint; class PolicyTransactionController extends BaseController { @@ -51,6 +53,9 @@ class PolicyTransactionController extends BaseController protected $userTeamsModel; protected $userModel; protected $employeePolicyModel; + protected $insurerStatements; + protected $invoiceStatus; + protected $invPaymentDetailsModel; public function __construct() { @@ -76,6 +81,15 @@ class PolicyTransactionController extends BaseController $this->userTeamsModel = new UserTeamsModel(); $this->userModel = new UserModel(); $this->employeePolicyModel = new EmployeePolicyModel(); + $this->insurerStatements = new InsurerStatements(); + $this->invPaymentDetailsModel = new InvPaymentDetailsModel(); + $this->invoiceStatus = [ + 'pending' => 'Pending', + 'generated' => 'Generated', + 'sent' => 'Sent', + 'payment_received' => 'Payment Received', + + ]; } // Policy Transaction Inception @@ -965,6 +979,438 @@ class PolicyTransactionController extends BaseController $this->loadLayout('report_bds_filter', $data); } + + //insurer statement list page + public function statementList() + { + // dd($this->updateInsurerStatement(['file_id' => 13])); + // $data['insurers'] = $this->insurerModel->where('is_active',1)->findAll(); + $data['invoice_status_array'] = $this->invoiceStatus; + $data['insurers'] = $this->insurerBranchModel ->getInsurerBranchesWithInsurerNames(); + + // dd( $data['insurers']); + $data['insurer_statement_list'] = $this->insurerStatements + ->select('insurer_statements.*, + insurers.name AS insurer_name,insurers.short_name,user_profiles.first_name,insurer_branch.branch_code + ') + ->join('insurers', 'insurer_statements.insurer_id = insurers.id') + ->join('insurer_branch', 'insurer_statements.branch_id = insurer_branch.id') + ->join('user_profiles', 'insurer_statements.created_by = user_profiles.id') + ->orderBy('insurer_statements.id', 'desc') + ->findAll(); + // dd( $data['insurer_statement_list']); + $this->loadLayout('insurer_statement_list', $data); + } + + public function uploadInsurerStatement() + { + + //validate uploaded file + $filename = ''; + $validated = $this->validate([ + 'statement' => [ + 'uploaded[statement]', + 'mime_in[statement,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]', + 'max_size[statement,16384]', + ], + ]); + $this->createStatementFolder(); + if ($validated) + { + $avatar = $this->request->getFile('statement'); + if (!$avatar) { + $this->myLogger->logme("error", 'Statement File not found'); + return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400); + } + + $is_moved = $avatar->move(WRITEPATH . 'uploads/statements/'); + if ($is_moved) { + $filename = $avatar->getName(); + // Handle successful upload, e.g., log success or further processing + $this->myLogger->logme("error", 'Statement File moved successful'); + + } else { + $this->myLogger->logme("error", 'Statement File move failed'); + return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => 'File move failed'], 500); + } + } else { + $this->myLogger->logme("error", 'Statement Upload failed Invalid file'); + return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404); + } + + //process post variable entry in file table + $loggedInUserID = get_session_userid(); + // dd($loggedInUserID); + // $loggedInUserID = 8; + + $insurer = $this->request->getPost('insurer'); + + $insurer_id = explode('-', $insurer)[0]; + $branch_id = explode('-', $insurer)[1]; + // print_r($insurer_id); + // print_r($branch_id); + // die(); + $month = $this->request->getPost('statement_month'); + $month = change_date_format($month,'Y-M-d','Y-m-d'); + // print_r($month);die; + + $file_id = $this->insurerStatements->insert(['insurer_id' => $insurer_id, 'branch_id' => $branch_id, 'file_name' => $filename,'month' => $month, 'created_by' => $loggedInUserID]); //here field policy_id have client_policy_id and not policy id from policy master + $this->myLogger->logme("error", '{file_id} statement uploaded success', ['file_id' => $file_id]); + + //validate file + $validation_result = $this->validateInsurerStatement(['file_id' => $file_id]); + //update file content to DB + if($validation_result['status'] ) + { + $this->updateInsurerStatement(['file_id' => $file_id]); + } + + if (!isset($file_id) || !$validation_result['status']) { + return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file not uploaded', 'error_data' => $validation_result['error_data'],'error_code' => $validation_result['error_code']], 200); + } + + return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200); + } + + public function createStatementFolder() + { + $folderPath = WRITEPATH . 'uploads/statements/'; + + // Check if the folder doesn't exist + if (!file_exists($folderPath)) + { + // Create the folder + if (mkdir($folderPath, 0777, true)) { + $this->myLogger->logme('error','statement upload folder created successfully'); + + // Set permissions to a+rwx (read, write, execute for all) + chmod($folderPath, 0777); + $this->myLogger->logme('error','Permissions set to a+rwx.'); + } else { + // echo "Failed to create folder."; + $this->myLogger->logme('error','Failed to create statement upload folder.'); + } + } + else + { + $this->myLogger->logme('error','upload folder exists.'); + } + } + + public function validateInsurerStatement($params) + { + //get file info + $file_id = $params['file_id']; + $file = $this->insurerStatements->find($file_id); + // dd($file); + $date = new \DateTime($file['month']); + + $month = $date->format('m'); + $year = $date->format('Y'); + + $error_data = ['error_code' => '','error_data' => []]; + $status = 'success'; + $ret_status = true; + // dd($month.'-'.$year); + $return = []; + if(!isset($file)) + { + //file not found in DB + return array('status' => false, 'msg' => 'statement file not found in DB'); + } + $file_name_with_path = WRITEPATH."/uploads/statements/".$file['file_name']; + + //check physical file + if(!file_exists($file_name_with_path)) + { + //file not found update status and reason + $message = "Physcial file not found"; + // echo $message; + $this->myLogger->logme('error',($message . ' for statement file id ' . $file_id)); + $this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed','reason' => json_encode(['error_code' => 0,'error_data' => $message])])->update(); + return array('status' => false, 'error_code' => 0); //0 - Physcial file not found + } + + //get excel data to php array + $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); + $sheet = $spreadsheet->getActiveSheet(); + + $highestRowAndColumn = $sheet->getHighestRowAndColumn(); + // dd($highestRowAndColumn); + $excel_data = $sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); + unset($excel_data[0]); + // dd($excel_data); + //get no of line items and update in DB + $line_items = count($excel_data); + // get uploaded month transactions data + $source_data = $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactions(month:$month,year:$year,insurer_id:$file['insurer_id'],insurer_branch_id:$file['branch_id']); + // Kint::dump($source_data); + // Kint::dump($excel_data); + + // check policy no,insurer and etc in DB for this month + // if all good return true, otherwise return false with messssage + foreach ($excel_data as $excel_key => $excel_row) + { + $is_source_found = 0; + $excel_row[4] = trim($excel_row[4]); + $excel_row[5] = trim($excel_row[5]); + // Kint::dump(change_date_format($excel_row[4],'d-m-Y','Y-m-d')); + // echo $excel_row[1].'#'.$excel_row[2] .'#'.$excel_row[3].'#'.change_date_format($excel_row[4],'d-m-Y','Y-m-d').'#'.change_date_format($excel_row[5],'d-m-Y','Y-m-d').'
'; + foreach ($source_data as $source_key => $source_row) + { + // Kint::dump(change_date_format($excel_row[3],'d-m-Y','Y-m-d')); + if( (trim($excel_row[1]) == $source_row['policy_no']) && trim($excel_row[2]) == $source_row['endorsement_no'] && trim($excel_row[3]) == $source_row['client_name'] && change_date_format($excel_row[4],'d-m-Y','Y-m-d') == $source_row['policy_start_date'] && change_date_format($excel_row[5],'d-m-Y','Y-m-d') == $source_row['policy_end_date']) + { + $is_source_found = 1; + unset($source_data[$source_key]); + continue 2; + } + } + + if($is_source_found == 0) + { + // echo $excel_key.'-'.$excel_row[1] . '- not found
'; + $error_data['error_code'] = 1;//match not found + // $error_data['error_data'] = ($error_data['error_data'] ?? []); + $error_data['error_data'] = array_merge($error_data['error_data'],[$excel_row[0]]);//match not found + } + } + + if($error_data['error_code']) + { + $status = 'failed'; + $ret_status = false; + } + //update in DB + $this->insurerStatements->where('id', $file_id)->set(['line_items' => $line_items,'file_status' => $status,'reason' => json_encode($error_data)])->update(); + return array('status' => $ret_status, 'error_code' => $error_data['error_code'],'error_data' => $error_data['error_data']); + } + + + public function updateInsurerStatement($params) + { + //get file info + $file_id = $params['file_id']; + $file = $this->insurerStatements->find($file_id); + // dd($file); + $date = new \DateTime($file['month']); + + $month = $date->format('m'); + $year = $date->format('Y'); + + $error_data = ['error_code' => '','error_data' => []]; + $status = 'success'; + $ret_status = true; + // dd($month.'-'.$year); + $return = []; + if(!isset($file)) + { + //file not found in DB + return array('status' => false, 'msg' => 'statement file not found in DB'); + } + $file_name_with_path = WRITEPATH."/uploads/statements/".$file['file_name']; + + //check physical file + if(!file_exists($file_name_with_path)) + { + //file not found update status and reason + $message = "Physcial file not found"; + // echo $message; + $this->myLogger->logme('error',($message . ' for statement file id ' . $file_id)); + $this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed','reason' => json_encode(['error_code' => 0,'error_data' => $message])])->update(); + return array('status' => false, 'error_code' => 0); //0 - Physcial file not found + } + + //get excel data to php array + $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); + $sheet = $spreadsheet->getActiveSheet(); + + $highestRowAndColumn = $sheet->getHighestRowAndColumn(); + // dd($highestRowAndColumn); + $excel_data = $sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); + unset($excel_data[0]); + // dd($excel_data); + //get no of line items and update in DB + $line_items = count($excel_data); + // get uploaded month transactions data + $source_data = $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactions(month:$month,year:$year,insurer_id:$file['insurer_id'],insurer_branch_id:$file['branch_id']); + // Kint::dump($source_data);die; + // Kint::dump($excel_data); + + // check policy no,insurer and etc in DB for this month + // if all good return true, otherwise return false with messssage + $data_to_update = []; + foreach ($excel_data as $excel_key => $excel_row) + { + $is_source_found = 0; + $excel_row[4] = trim($excel_row[4]); + $excel_row[5] = trim($excel_row[5]); + + foreach ($source_data as $source_key => $source_row) + { + // Kint::dump(change_date_format($excel_row[3],'d-m-Y','Y-m-d')); + if( (trim($excel_row[1]) == $source_row['policy_no']) && trim($excel_row[2]) == $source_row['endorsement_no'] && trim($excel_row[3]) == $source_row['client_name'] && change_date_format($excel_row[4],'d-m-Y','Y-m-d') == $source_row['policy_start_date'] && change_date_format($excel_row[5],'d-m-Y','Y-m-d') == $source_row['policy_end_date']) + { + $is_source_found = 1; + + //calculate percentage first + $total_amt = 0; + + $actual_bp_per = trim($excel_row[9]); + $actual_bp_brokerage = trim($excel_row[12]); + $actual_bp_amt = trim($excel_row[6]); + + if(($actual_bp_brokerage && $actual_bp_brokerage != 0 && $actual_bp_brokerage != "")) + { + $total_amt += $actual_bp_brokerage; + //percentage reverse calculation + if($actual_bp_per == 0 || $actual_bp_per == "") + { + $actual_bp_per = round(($actual_bp_brokerage / $actual_bp_amt) * 100,2); + } + + } + else + { + $actual_bp_brokerage = $actual_bp_amt * ($actual_bp_per / 100); + $total_amt += $actual_bp_brokerage; + } + + $actual_tp_per = trim($excel_row[10]); + $actual_tp_brokerage = trim($excel_row[13]); + $actual_tp_amt = trim($excel_row[7]); + + if($actual_tp_brokerage && $actual_tp_brokerage != 0 && $actual_tp_brokerage != "") + { + $total_amt += $actual_tp_brokerage; + //percentage reverse calculation + if($actual_tp_per == 0 || $actual_tp_per == "") + { + $actual_tp_per = ($actual_tp_brokerage / $actual_tp_amt) * 100; + } + } + else + { + $actual_tp_brokerage = $actual_tp_amt * ($actual_tp_per / 100); + $total_amt += $actual_tp_brokerage; + } + + $actual_tep_per = trim($excel_row[11]); + $actual_tep_brokerage = trim($excel_row[14]); + $actual_tep_amt = trim($excel_row[8]); + + if($actual_tep_brokerage && $actual_tep_brokerage != 0 && $actual_tep_brokerage != "") + { + $total_amt += $actual_tep_brokerage; + //percentage reverse calculation + if($actual_tep_per == 0 || $actual_tep_per == "") + { + $actual_tep_per = ($actual_tep_brokerage / $actual_tep_amt) * 100; + } + } + else + { + $actual_tep_brokerage = $actual_tep_amt * ($actual_tep_per / 100); + $total_amt += $actual_tep_brokerage; + } + + //find variance + $variance_amt = $source_row['exp_amt'] - $total_amt; + + $data_to_update[] = ['id' => $source_row['id'],'actual_bp_amt' => $actual_bp_amt,'actual_tp_amt' => $actual_tp_amt,'actual_tep_amt' => $actual_tep_amt,'actual_bp_per' => $actual_bp_per,'actual_tp_per' => $actual_tp_per,'actual_tep_per' => $actual_tep_per,'variance' => $variance_amt,'actual_tep_brokerage_amt' => $actual_tep_brokerage,'actual_tp_brokerage_amt' => $actual_tp_brokerage,'actual_bp_brokerage_amt' => $actual_bp_brokerage,'reward' => trim($excel_row[15]),'statement_id' => $file_id]; + + unset($source_data[$source_key]); + continue 2; + } + } + } + $this->PTCOShareDetailsModel->updateBatch($data_to_update, 'id'); + // dd($data_to_update); + // if($error_data['error_code']) + // { + // $status = 'failed'; + // $ret_status = false; + // } + //update in DB + //$this->insurerStatements->where('id', $file_id)->set(['file_status' => $status,'reason' => json_encode($error_data)])->update(); + return array('status' => $ret_status, 'error_code' => $error_data['error_code'],'error_data' => $error_data['error_data']); + } + + public function getInvoicePaymentDetails() + { + $statement_id = $this->request->getUri()->getSegment(4); + + $inv_details = $this->insurerStatements->find($statement_id); + $inv_payment_details = $this->invPaymentDetailsModel + ->where('statement_id',$statement_id) + ->where('is_active',1) + ->get() + ->getResultArray(); + // print_r($inv_details); + $data = [ 'invoice_status' => $inv_details['invoice_status'], + 'invoice_no' => $inv_details['invoice_no'], + 'invoice_date' => $inv_details['invoice_date'] ]; + $data['payments'] = $inv_payment_details; + return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $data], 200); + + + } + + public function saveInvoicePaymentDetails() + { + $jsonData = $this->request->getJSON(); + $jsonData = (array)$jsonData; + // echo 'Hi'; + // print_r($jsonData);die(); + + $invoiceStatus = $jsonData['invoice_status']; + $hiddenStatementId = $jsonData['hidden_statement_id']; + $invoiceNo = $jsonData['invoice_no']; + $invoiceDate = $jsonData['invoice_date']; + + //Update statement table + $parentData = [ + 'invoice_status' => $invoiceStatus, + 'invoice_no' => $invoiceNo, + 'invoice_date' => $invoiceDate, + 'updated_by' => get_session_userid() + ]; + + + + // $this->insurerStatements->update($hiddenStatementId, $parentData); + + // Process child data + $invoiceAmounts = $jsonData['invoice_amount']; + $utrNos = $jsonData['utr_no']; + $paymentDates = $jsonData['payment_date']; + $pks = $jsonData['pk']; + + foreach ($invoiceAmounts as $index => $invoiceAmount) { + $pk = $pks[$index]; // Get the pk for the current record + $utrNo = $utrNos[$index]; + $paymentDate = $paymentDates[$index]; + + // Prepare data for insert/update + $childData = [ + 'inv_amt' => $invoiceAmount, + 'utr_no' => $utrNo, + 'received_date' => $paymentDate, + 'statement_id' => $hiddenStatementId, + 'id' => is_numeric($pk) ? (int)$pk : '', + ]; + if($pk){ $childData['updated_by'] = get_session_userid(); } + else { $childData['created_by'] = get_session_userid(); } + // print_r($childData); + // Insert or update + $this->invPaymentDetailsModel->save($childData); + print_r($this->invPaymentDetailsModel->errors()); + + } + + return $this->respond(['dataStatus' => true, 'code' => 200], 200); + //return $this->response->setJSON(['dataStatus' => 'true']); + } } \ No newline at end of file diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index 6c7c6c1a..a764697b 100644 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -24,6 +24,7 @@ if (!function_exists('change_date_format')) { function change_date_format($data, $source_format, $output_format) { + $data = trim($data); // echo $data, $source_format, $output_format;return true; try { // Create DateTime object with the source format @@ -31,7 +32,8 @@ if (!function_exists('change_date_format')) { // Check if the DateTime object is created successfully if ($dateTime === false) { - throw new Exception('Invalid date or format'); + $errors = DateTime::getLastErrors(); + throw new Exception('Invalid date or format' . implode(', ', $errors['errors'])); } // Format the DateTime object with the output format $formattedDate = $dateTime->format($output_format); diff --git a/app/Models/InsurerStatements.php b/app/Models/InsurerStatements.php new file mode 100644 index 00000000..6b85ed0f --- /dev/null +++ b/app/Models/InsurerStatements.php @@ -0,0 +1,30 @@ +db->table('pt_co_share_details pt_co') + ->select(' + pt_co.id, + pt_co.pt_id, + pt_co.exp_amt, + pt.id AS policy_transaction_id, + pt.endorsement_no, + c.client_name, + pt.created_at, + pt_co.insurer_id, + pt_co.insurer_branch_id, + pt.policy_no, + pt.policy_issue_date, + pt.policy_start_date, + pt.policy_end_date, + pt.status, + pt_co.bp_amt, + pt_co.tp_amt, + pt_co.tep_amt, + pt_co.exp_amt + ') + ->join('policy_transaction pt', 'pt_co.pt_id = pt.id') + ->join('clients c', 'pt.client_id = c.id') + ->where('pt_co.is_active', 1) + ->where('MONTH(pt.created_at)', $month) + ->where('YEAR(pt.created_at)', $year) + ->where('pt_co.insurer_id', $insurer_id) + ->where('pt_co.insurer_branch_id', $insurer_branch_id) + // ->where('pt_co.exp_amt', 0.00) + // ->orWhere('pt_co.exp_amt is null') + ->get() + ->getResultArray(); + } } diff --git a/app/Views/insurer_statement_list.php b/app/Views/insurer_statement_list.php new file mode 100644 index 00000000..29d14a7b --- /dev/null +++ b/app/Views/insurer_statement_list.php @@ -0,0 +1,708 @@ + + + + +
+
+
+
+
+
+

Insurer Statement List

+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Insurer
Month
Statement
Line Items
User/Time
Action
'.$row['first_name'] ?> + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/Views/layout/footer.php b/app/Views/layout/footer.php index 27e232ec..22f12861 100644 --- a/app/Views/layout/footer.php +++ b/app/Views/layout/footer.php @@ -299,7 +299,7 @@ fetchMessages(); - setInterval(fetchMessages, 10000); // Fetch messages every ten seconds + setInterval(fetchMessages, 60000); // Fetch messages every sixty seconds }); $(document).ready(function() { diff --git a/app/Views/layout/header.php b/app/Views/layout/header.php index 03b42981..de039f2b 100644 --- a/app/Views/layout/header.php +++ b/app/Views/layout/header.php @@ -670,6 +670,9 @@
  • BDS
  • +
  • + Statement upload +
  • diff --git a/public/sample_excel/insurer_stament_sample.xlsx b/public/sample_excel/insurer_stament_sample.xlsx new file mode 100644 index 00000000..0cdabdf1 Binary files /dev/null and b/public/sample_excel/insurer_stament_sample.xlsx differ