From 78ccef216f30376cd7c02882e7bc2131e37e7922 Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Mon, 1 Dec 2025 12:34:27 +0530 Subject: [PATCH] FEAT_BDS_BULK_UPLOAD --- app/Config/Routes.php | 8 + app/Controllers/EmployeeController.php | 2 + app/Controllers/JobWorker.php | 8 + app/Controllers/MasterController.php | 1 + .../PolicyTransactionController.php | 1204 ++++++++++++++++- app/Helpers/excel_util_helper.php | 389 ++++++ app/Models/BDSDumpModel.php | 55 + app/Models/PTCOShareDetailsModel.php | 1 + app/Models/PolicyTransactionModel.php | 3 + app/Views/bds_dump_file_list.php | 394 ++++++ .../sample_bds_bulk_upload_excel.xlsx | Bin 0 -> 7625 bytes 11 files changed, 2064 insertions(+), 1 deletion(-) create mode 100644 app/Models/BDSDumpModel.php create mode 100644 app/Views/bds_dump_file_list.php create mode 100644 public/sample_excel/sample_bds_bulk_upload_excel.xlsx diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 96252c3f..87e439ab 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -806,3 +806,11 @@ $routes->group('commission', function($routes) { $routes->get('checkRuleUsage',"RuleImportController::checkRuleUsage"); }); +//BDS BULK UPLOAD + +$routes->group('bds_upload', function($routes) { + $routes->match (['get','post'],'list',"PolicyTransactionController::policyBulkUpload"); + $routes->get('downloadBDSDumpFile',"PolicyTransactionController::downloadBDSDumpFile"); + $routes->get('getBdsDumpFileErrorData',"PolicyTransactionController::getBdsDumpFileErrorData"); + $routes->get('getBdsDumpExcelFileErrors/(:any)',"PolicyTransactionController::getBdsDumpExcelFileErrors/$1"); +}); diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 0da7f5a7..eee1b16f 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -483,6 +483,8 @@ class EmployeeController extends AdminController $filePath = ROOTPATH . 'public/sample_excel/Sample_Member_Data.xlsx'; }else if ($actionType == 'all') { $filePath = ROOTPATH . 'public/sample_excel/sample_multievent_file.xlsx'; + }else if ($actionType == 'bds_upload') { + $filePath = ROOTPATH . 'public/sample_excel/sample_bds_bulk_upload_excel.xlsx'; } // Check if the file exists diff --git a/app/Controllers/JobWorker.php b/app/Controllers/JobWorker.php index eadca406..190a1058 100755 --- a/app/Controllers/JobWorker.php +++ b/app/Controllers/JobWorker.php @@ -179,6 +179,14 @@ class JobWorker extends AdminController 'type' => 'CC', // Handler Category 'handler' => 'App\Controllers\MediAssistApiController', ], + 'bdsDumpExcelFileFormatValidation' => [ + 'type' => 'CC', // Handler Category + 'handler' => 'App\Controllers\PolicyTransactionController', + ], + 'insertBulkBdsData' => [ + 'type' => 'CC', // Handler Category + 'handler' => 'App\Controllers\PolicyTransactionController', + ], ]; diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php index d2ce1329..fec5dc4e 100755 --- a/app/Controllers/MasterController.php +++ b/app/Controllers/MasterController.php @@ -1980,6 +1980,7 @@ class MasterController extends AdminController 'files' => WRITEPATH . 'uploads/commission/files', 'rules' => WRITEPATH . 'uploads/commission/rules', 'claim_sample_forms' => ROOTPATH . 'public/claim_sample_forms/', + 'bds_dump_excel' => WRITEPATH . 'uploads/bds_dump_excel/', ]; foreach ($folders as $folderName => $folderPath) { diff --git a/app/Controllers/PolicyTransactionController.php b/app/Controllers/PolicyTransactionController.php index 35425655..a430f4af 100644 --- a/app/Controllers/PolicyTransactionController.php +++ b/app/Controllers/PolicyTransactionController.php @@ -37,6 +37,8 @@ use App\Helpers\MailHelper; use App\Helpers\ExcelSanitizeHelper; use App\Models\NhanceBranchModel; + use App\Models\BDSDumpModel; + use App\Models\VehicleModel; use Exception; class PolicyTransactionController extends BaseController @@ -71,6 +73,10 @@ protected $coShareStmtDetailsModel; protected $BdsPlacementModel; protected $nhanceBranchModel; + protected $bdsDumpModel; + protected $vehicleModel; + protected $bds_bulk_upload_excel_file_column; + public function __construct() { @@ -103,12 +109,439 @@ $this->coShareStmtDetailsModel = new COShareStmtDetailsModel(); $this->BdsPlacementModel = new BdsPlacementModel(); $this->nhanceBranchModel = new NhanceBranchModel(); + $this->bdsDumpModel = new BDSDumpModel(); + $this->vehicleModel = new VehicleModel(); $this->invoiceStatus = [ 'pending' => 'Pending', 'generated' => 'Generated', 'sent' => 'Sent', 'payment_received' => 'Payment
Received', ]; + + $this->bds_bulk_upload_excel_file_column = [ + + 'sno' => [ + 'col_idx' => 0, + 'col_cell_name' => 'A', + 'col_name' => 'S.No.', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'nhance_branch' => [ + 'col_idx' => 1, + 'col_cell_name' => 'B', + 'col_name' => 'Nhance Branch', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_nhance_branch', + 'params' => ['row', 'nhance_branch_data'] + ], + + 'vehicle_no' => [ + 'col_idx' => 2, + 'col_cell_name' => 'C', + 'col_name' => 'Vehicle No', + 'is_mandatory' => true, + 'data_type' => 'vehicle', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_rto_data', + 'params' => ['row', 'rto_master'] + ], + + 'vehicle_type' => [ + 'col_idx' => 3, + 'col_cell_name' => 'D', + 'col_name' => 'Vehicle Type', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_vehicle_type', + 'params' => ['row', 'vehicle_type'] + ], + + 'policy_no' => [ + 'col_idx' => 4, + 'col_cell_name' => 'E', + 'col_name' => 'Policy No', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_policy_no', + 'params' => ['row', 'pt_data'] + ], + + 'insured_name' => [ + 'col_idx' => 5, + 'col_cell_name' => 'F', + 'col_name' => 'Insured Name', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'insured_email' => [ + 'col_idx' => 6, + 'col_cell_name' => 'G', + 'col_name' => 'Insured Email', + 'is_mandatory' => true, + 'data_type' => 'email', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'insurer' => [ + 'col_idx' => 7, + 'col_cell_name' => 'H', + 'col_name' => 'Insurer', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_insurer_exist', + 'params' => ['row', 'insurer_data'] + ], + + 'insurer_branch' => [ + 'col_idx' => 8, + 'col_cell_name' => 'I', + 'col_name' => 'Insurer Branch', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_insurer_branch_exist', + 'params' => ['row', 'insurer_branch_data', 'insurers'] + ], + + 'policy_issue_date' => [ + 'col_idx' => 9, + 'col_cell_name' => 'J', + 'col_name' => 'Policy Issue Date', + 'is_mandatory' => true, + 'data_type' => 'date', + 'format' => 'd/M/Y', + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'policy_start_date' => [ + 'col_idx' => 10, + 'col_cell_name' => 'K', + 'col_name' => 'Policy Start Date', + 'is_mandatory' => true, + 'data_type' => 'date', + 'format' => 'd/M/Y', + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'policy_end_date' => [ + 'col_idx' => 11, + 'col_cell_name' => 'L', + 'col_name' => 'Policy End Date', + 'is_mandatory' => true, + 'data_type' => 'date', + 'format' => 'd/M/Y', + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'revenue_type' => [ + 'col_idx' => 12, + 'col_cell_name' => 'M', + 'col_name' => 'Revenue Type', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => ['NA', 'EA', 'EANR'], + 'custom' => null, + 'params' => null + ], + + 'sales_generated_by' => [ + 'col_idx' => 13, + 'col_cell_name' => 'N', + 'col_name' => 'Sales Generated By', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_user_exist', + 'params' => ['row', 'col_key', 'user_data'] + ], + + 'serviced_by' => [ + 'col_idx' => 14, + 'col_cell_name' => 'O', + 'col_name' => 'Serviced By', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_user_exist', + 'params' => ['row', 'col_key', 'user_data'] + ], + + 'agent_code' => [ + 'col_idx' => 15, + 'col_cell_name' => 'P', + 'col_name' => 'Agent Code', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => 'check_agent_exist', + 'params' => ['row', 'agent_data'] + ], + + 'base_premium' => [ + 'col_idx' => 16, + 'col_cell_name' => 'Q', + 'col_name' => 'Base Premium', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'non_commission_premium_amount' => [ + 'col_idx' => 17, + 'col_cell_name' => 'R', + 'col_name' => 'Non commission permium Amount', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'tp_premium' => [ + 'col_idx' => 18, + 'col_cell_name' => 'S', + 'col_name' => 'TP Premium', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'igst' => [ + 'col_idx' => 19, + 'col_cell_name' => 'T', + 'col_name' => 'IGST', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'cgst' => [ + 'col_idx' => 20, + 'col_cell_name' => 'U', + 'col_name' => 'CGST', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'sgst' => [ + 'col_idx' => 21, + 'col_cell_name' => 'V', + 'col_name' => 'SGST', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'stamp_duty' => [ + 'col_idx' => 22, + 'col_cell_name' => 'W', + 'col_name' => 'Stamp Duty', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'total' => [ + 'col_idx' => 23, + 'col_cell_name' => 'X', + 'col_name' => 'Total', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'agreed_amount' => [ + 'col_idx' => 24, + 'col_cell_name' => 'Y', + 'col_name' => 'Agreed Amount', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'agreed_bp_percentage' => [ + 'col_idx' => 25, + 'col_cell_name' => 'Z', + 'col_name' => 'Agreed BP Percentage', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'agreed_tp_percentage' => [ + 'col_idx' => 26, + 'col_cell_name' => 'AA', + 'col_name' => 'Agreed TP Percentage', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'actual_bp_amount' => [ + 'col_idx' => 27, + 'col_cell_name' => 'AB', + 'col_name' => 'Actual BP Amount', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'actual_tp_amount' => [ + 'col_idx' => 28, + 'col_cell_name' => 'AC', + 'col_name' => 'Actual TP Amount', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'actual_bp_percentage' => [ + 'col_idx' => 29, + 'col_cell_name' => 'AD', + 'col_name' => 'Actual BP Percentage', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'actual_tp_percentage' => [ + 'col_idx' => 30, + 'col_cell_name' => 'AE', + 'col_name' => 'Actual TP Percentage', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'actual_bp_brokerage_amount' => [ + 'col_idx' => 31, + 'col_cell_name' => 'AF', + 'col_name' => 'Actual BP Brokerage Amount', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'actual_tp_brokerage_amount' => [ + 'col_idx' => 32, + 'col_cell_name' => 'AG', + 'col_name' => 'Actual TP Brokerage Amount', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'expected_amount' => [ + 'col_idx' => 33, + 'col_cell_name' => 'AH', + 'col_name' => 'Expected Amount', + 'is_mandatory' => true, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + 'rewards' => [ + 'col_idx' => 34, + 'col_cell_name' => 'AI', + 'col_name' => 'Rewards', + 'is_mandatory' => false, + 'data_type' => '', + 'format' => null, + 'allowed_values' => null, + 'custom' => null, + 'params' => null + ], + + ]; + } // Policy Transaction Inception @@ -3207,7 +3640,6 @@ return [$policyList, $policyListByClient]; } - public function reportBDSNew() { // 🧭 Basic Page Info @@ -3318,6 +3750,776 @@ $this->loadLayout('report_bds_filter', $data); } + // ------------ BDS BULK MOTER POLICY UPLOAD ----------------------------------------------------------------------------------------------- + + public function policyBulkUpload() + { + $data['page_name'] = "BDS Bulk File Upload"; + $data['tab_name'] = "BDS File Upload"; + + // $response = $this->insertBulkBdsData(['file_id' => 2]); + // dd($response); + if ($this->request->is('get')) { + + $data['bds_dump_file_data'] = $this->bdsDumpModel + ->select(' + bds_dump_files.id as file_id, + bds_dump_files.file_name, + bds_dump_files.status, + bds_dump_files.created_at, + up.first_name as user_name + ') + ->join('user_profiles as up', 'bds_dump_files.created_by = up.id', 'left') + ->where('bds_dump_files.is_active', 1) + ->orderBy('bds_dump_files.id', 'desc') + ->findAll(); + + return $this->loadLayout('bds_dump_file_list', $data); + } else { + + $filename = ''; + $fileSize = ''; + + //validate uploaded file + $validated = $this->validate([ + 'bds_dump_list' => [ + 'uploaded[bds_dump_list]', + 'mime_in[bds_dump_list,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]', + 'max_size[bds_dump_list,16384]', + ], + ]); + + if ($validated) { + $avatar = $this->request->getFile('bds_dump_list'); + if (!$avatar) { + $this->myLogger->logme("error", 'File not found'); + return $this->respond(['status' => false, 'code' => 400, 'message' => 'File not found'], 400); + } + + $is_moved = $avatar->move(WRITEPATH . 'uploads/bds_dump_excel/'); + + if ($is_moved) { + $filename = $avatar->getName(); + $fileSize = $avatar->getSize(); // File size in bytes + $fileSize = $fileSize / (1024 * 1024); // Convert to MB + + $this->myLogger->logme("error", 'File move successful'); + } else { + $this->myLogger->logme("error", 'File move failed'); + return $this->respond(['status' => false, 'code' => 500, 'message' => 'File move failed'], 500); + } + } else { + $this->myLogger->logme("error", 'Upload failed Invalid file'); + return $this->respond(['status' => false, 'code' => 404, 'message' => 'Invalid file'], 404); + } + + + $status = 'inprogress'; + $insert_data = [ + 'file_name' => $filename, + 'status' => $status + ]; + + $file_id = $this->bdsDumpModel->insert($insert_data); + $this->myLogger->logme("error", 'claim_dumb_file_id : {file_id}, uploaded success', ['file_id' => $file_id]); + + //after file upload success than call the file formate validation + // $response = $this->bdsDumpExcelFileFormatValidation(["file_id" => $file_id]); + $r = Jobs::addJob(['job_name' => 'bdsDumpExcelFileFormatValidation', 'payload' => ['file_id' => $file_id]]); + + return $this->respond(['status' => true, 'code' => 200, 'message' => 'File uploaded successfully. File being validated'], 200); + } + } + + public function downloadBDSDumpFile($file_id) + { + // $actionType = $this->request->getGet(); + $file_data = $this->bdsDumpModel->where('id', $file_id)->first(); + $fileName = $file_data['file_name']; + + $filePath = WRITEPATH . '/uploads/bds_dump_excel/' . $fileName; + + try { + + // Check if the file exists + if (file_exists($filePath)) { + // Set the appropriate MIME type + $mimeType = mime_content_type($filePath); + + // Send the file to the client for download + return $this->response->download($filePath, null, $mimeType); + } else { + + $data['message'] = 'The Physical File Not Found'; + echo view('errors/404', $data); + } + } catch (\Exception $e) { + // Handle any exceptions + $errorMessage = $e->getMessage(); + $this->myLogger->logme('error', $errorMessage); + // You can return an error response here + echo $errorMessage; + } + } + + public function bdsDumpExcelFileFormatValidation($params) + { + helper('excel_util_helper'); + $file_id = $params['file_id']; + $file = $this->bdsDumpModel->where("id", $file_id)->first(); + + $return = []; + if (empty($file)) { + return array('status' => false, 'message' => 'File not found in Database'); + } + + $file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file['file_name']; + + //check physical file exist + if (!file_exists($file_name_with_path)) { + $message = "Physcial file not found"; + $this->myLogger->logme('error', ($message . ' for file id : ' . $file_id)); + $this->bdsDumpModel->where('id', $file_id)->set(['status' => 'failed', 'reason' => json_encode(['error_summary' => array_count_values([5]), 'error_data' => $message])])->update(); + return array('error_summary' => [5], 'error_data' => $message); + } + + // get the BDS dump excel colums + $columns_to_check = $this->bds_bulk_upload_excel_file_column; + $keys = array_keys($columns_to_check); + $allowedHighestColumn = end($columns_to_check); + + // Read the excel file + $excel_data = $this->extractExcelData($file['file_name'], $allowedHighestColumn['col_cell_name']); + $excel_columns = ($excel_data[0]); + // echo '
'; var_dump($excel_columns);
+
+
+            //check no of columns in excel
+            $total_defined_columns = count($columns_to_check);
+            $excel_columns_count = count($excel_columns);
+
+            if($total_defined_columns != $excel_columns_count)
+            {
+                //columns count mismatch
+                $message = "File columns count mismatch. Expected - $total_defined_columns and received - $excel_columns_count";
+                $this->myLogger->logme('error',($message . ' for file id ' . $file_id));
+                $this->bdsDumpModel->where('id', $file_id)->set(['status' => 'failed','reason' => json_encode(['error_summary' => array_count_values([5]),'error_data' => $message])])->update();
+                return  array('error_summary' => [5], 'error_data' => $message);
+            }
+
+            //check columns order in excel
+            $column_count_res = check_columns_name($columns_to_check, $excel_columns);
+
+            if(isset($column_count_res) && count($column_count_res))
+            {   
+                //columns count mismatch
+                $message = implode("\n", $column_count_res);
+                $this->myLogger->logme('error',($message . ' for file id ' . $file_id));
+                $this->bdsDumpModel->where('id', $file_id)->set(['status' => 'failed','reason' => json_encode(['error_summary' => array_count_values([6]), 'error_data' => $message])])->update();
+                return  array('error_summary' => [6], 'error_data' => $message);
+            }
+
+            //Store the error data by this structure
+            $result = ['error_type' => 1, 'error_summary' => [], 'error_data' => []];
+
+            $insurer_data = $this->insurerModel->where('is_active', 1)->findAll();
+            $insurer_branch_data = $this->insurerBranchModel->where('is_active', 1)->findAll();
+            $pt_data = $this->policyTransactionModel->where('is_active', 1)->findAll();
+            $user_data = $this->userModel->where('is_active', 1)->findAll();
+            $agent_data = db_connect()->table('partner_agent')->where('is_active', 1)->get()->getResultArray();
+            $rto_master = db_connect()->table('rto_master')->where('is_active', 1)->get()->getResultArray();
+            $vehicle_type = db_connect()->table('vehicle_type')->where('is_active', 1)->get()->getResultArray();
+            $nhance_branch_data = db_connect()->table('nhance_branch')->where('is_active', 1)->get()->getResultArray();
+
+
+            //remove header
+            unset($excel_data[0]);
+
+            try {
+                foreach ($excel_data as $row_key => $row) {
+
+                    //avoid empty rows
+                    if (check_row_is_empty_or_null($row)) {
+                        break;
+                    }
+
+                    $insurers = [];
+                    foreach ($row as $col_key => $col) 
+                    {
+                        $is_mandatory = $columns_to_check[$keys[$col_key]]['is_mandatory'];
+                        $format = $columns_to_check[$keys[$col_key]]['format'];
+                        $data_type = $columns_to_check[$keys[$col_key]]['data_type'];
+                        $allowed_values = $columns_to_check[$keys[$col_key]]['allowed_values'];
+                        $custom_function = isset($columns_to_check[$keys[$col_key]]['custom']) ? $columns_to_check[$keys[$col_key]]['custom'] : null;
+                        $binding_params = isset($columns_to_check[$keys[$col_key]]['params']) ? $columns_to_check[$keys[$col_key]]['params'] : null;
+                        
+                        $column_dispaly_name = $columns_to_check[$keys[$col_key]]['col_name'];
+                        $column_index = $columns_to_check[$keys[$col_key]]['col_idx'];
+                        $column_cell = $columns_to_check[$keys[$col_key]]['col_cell_name'];
+
+
+                        //mandatory check
+                        if(is_bool($is_mandatory) && $is_mandatory === true)
+                        {
+                            if($col == "" || $col == NULL) 
+                            {
+                                array_push($result['error_summary'],1); //push error code for summary
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+                                $result['error_data'][$row_key][$keys[$col_key]]['error'][] = 'Value is mandatory'; //push exact error desc
+                            }
+                        }
+
+                        //format check
+                        if(isset($format))
+                        {
+                            $validation = validate_excel_value($col, $data_type, $format, $allowed_values);
+                            if (!$validation['status']) {
+                                array_push($result['error_summary'], 2);
+
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name;
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index;
+                                $result['error_data'][$row_key][$keys[$col_key]]['error'][] = $validation['error'];
+                            }
+                        }
+
+                        //allowed values check
+                        if(($is_mandatory === true && isset($allowed_values) && is_array($allowed_values)) || (is_array($is_mandatory) && (isset($allowed_values) && is_array($allowed_values))))
+                        {
+                            if(!in_array((trim($col)),$allowed_values))
+                            {
+                                array_push($result['error_summary'],3); 
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+                                $result['error_data'][$row_key][$keys[$col_key]]['error'][] = "Value not allowed: Expected ".implode(",",$allowed_values)." and received $col";
+                            }
+                        }
+
+                        //custom function check
+                        if(isset($custom_function))
+                        {
+                            //convert string params into PHP variables
+                            // Create an array of variables to pass custom helper funcitons 
+                            $param_values = [];
+                            foreach($binding_params as $bkey => $bparam) { $param_values[] = ($$bparam); }
+                            $res = call_user_func_array($custom_function,$param_values);
+                            if($res['status'] === false) { 
+                                array_push($result['error_summary'],4);
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_name'] = $column_dispaly_name; //push column name
+                                $result['error_data'][$row_key][$keys[$col_key]]['col_idx'] = $column_index; //push column index
+                                $result['error_data'][$row_key][$keys[$col_key]]['error'][] = $res['error']; 
+                            }
+
+                            if($res['status'] == true && isset($res['insurer'])){
+                                $insurers = $res['insurer'];
+                            }
+                            
+                        }
+
+                    }//col foreach
+
+                }
+            } catch (\Exception $e) {
+                $errorDetails = [
+                    'error_message' => $e->getMessage(),
+                    'file'          => $e->getFile(),
+                    'line'          => $e->getLine(),
+                    'stack_trace'   => $e->getTraceAsString(),
+                ];
+                $message = "Contact system admin";
+                $this->bdsDumpModel->where('id', $file_id)->set(['status' => 'failed', 'reason' => json_encode(['error_summary' => array_count_values([5]), 'error_data' => $message])])->update();
+                $this->myLogger->logme("error", 'Claim dump file format validation failed due to : ' . json_encode($errorDetails ?? []));
+                return $errorDetails;
+            }
+
+            // return $result;
+
+            if (isset($result['error_summary']) && count($result['error_summary'])) {
+                $result['error_summary'] = array_count_values($result['error_summary']);
+                $status = 'failed';
+                $failure_reason = ((json_encode($result)));
+                $this->bdsDumpModel->where('id', $file_id)->set(['status' => $status, 'reason' => $failure_reason])->update();
+                $this->myLogger->logme("error", '{file_id} uploaded failed', ['file_id' => $file_id]);
+            } else { //trigger next data validation via job queue server
+                //proceed next data level validation in JOB queue
+                $r = Jobs::addJob(['job_name' => 'insertBulkBdsData', 'payload' => ['file_id' => $file_id]]);
+                // $response = $this->insertBulkBdsData(['file_id' => $file_id]);
+            }
+
+            return $result;
+        }
+
+        public function insertBulkBdsData($params)
+        {   
+            helper('excel_util_helper');
+            $file_id = $params['file_id'];
+            $file = $this->bdsDumpModel->where("id", $file_id)->first();
+
+            $return = [];
+            if (empty($file)) {
+                return array('status' => false, 'message' => 'File not found in Database');
+            }
+
+            $file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file['file_name'];
+
+            //check physical file exist
+            if (!file_exists($file_name_with_path)) {
+                $message = "Physcial file not found";
+                $this->myLogger->logme('error', ($message . ' for file id : ' . $file_id));
+                $this->bdsDumpModel->where('id', $file_id)->set(['status' => 'failed', 'reason' => json_encode(['error_summary' => array_count_values([5]), 'error_data' => $message])])->update();
+                return  array('error_summary' => [5], 'error_data' => $message);
+            }
+
+            // get the BDS dump excel colums
+            $columns_to_check = $this->bds_bulk_upload_excel_file_column;
+            $keys = array_keys($columns_to_check);
+            $allowedHighestColumn = end($columns_to_check);
+
+            // Read the excel file
+            $excel_data = $this->extractExcelData($file['file_name'], $allowedHighestColumn['col_cell_name']);
+            $excel_columns = ($excel_data[0]);
+
+            //remove header
+            unset($excel_data[0]);
+            // dd($excel_data);
+
+            //Store the error data by this structure
+            $result = ['error_type' => 1, 'error_summary' => [], 'error_data' => []];
+
+            $client_data = $this->clientModel->where('is_active', 1)->where('client_type', 1)->findAll();
+            $insurer_data = $this->insurerModel->where('is_active', 1)->findAll();
+            $insurer_branch_data = $this->insurerBranchModel->where('is_active', 1)->findAll();
+            $vehicle_data = $this->vehicleModel->where('is_active', 1)->findAll();
+            $user_data = $this->userModel->where('is_active', 1)->findAll();
+            $agent_data = db_connect()->table('partner_agent')->where('is_active', 1)->get()->getResultArray();
+            $rto_master = db_connect()->table('rto_master')->where('is_active', 1)->get()->getResultArray();
+            $vehicle_type_data = db_connect()->table('vehicle_type')->where('is_active', 1)->get()->getResultArray();
+            $nhance_branch_data = db_connect()->table('nhance_branch')->where('is_active', 1)->get()->getResultArray();
+
+            try {
+
+                $pt_ids = [];
+                foreach ($excel_data as $row_key => $row) {
+
+                    //avoid empty rows
+                    if (check_row_is_empty_or_null($row)) {
+                        break;
+                    }
+
+                    $vehicle_number = trim($row[2]);
+                    $vehicle_type = trim($row[3]);
+                    $client_name = trim($row[5]);
+                    $client_email = trim($row[6]);
+
+                    $insurer_short_name = trim($row[7]);
+                    $insurer_branch_code = trim($row[8]);
+                    $salse_generated_by = trim($row[13]);
+                    $serviced_by = trim($row[14]);
+                    $agent_code = trim($row[15]);
+                    $nhance_branch                     = trim($row[1]);
+                    
+                    $policy_no                         = trim($row[4]);
+                    $policy_issue_date                 = trim($row[9]);
+                    $policy_start_date                 = trim($row[10]);
+                    $policy_end_date                   = trim($row[11]);
+                    $revenue_type                      = trim($row[12]);
+
+                    $base_premium                      = trim($row[16]);
+                    $non_commission_premium_amount     = trim($row[17]);
+                    $tp_premium                        = trim($row[18]);
+                    $igst                              = trim($row[19]);
+                    $cgst                              = trim($row[20]);
+                    $sgst                              = trim($row[21]);
+                    $stamp_duty                        = trim($row[22]);
+                    $total                             = trim($row[23]);
+                    $agreed_amount                     = trim($row[24]);
+                    $agreed_bp_percentage              = trim($row[25]);
+                    $agreed_tp_percentage              = trim($row[26]);
+                    $actual_bp_amount                  = trim($row[27]);
+                    $actual_tp_amount                  = trim($row[28]);
+                    $actual_bp_percentage              = trim($row[29]);
+                    $actual_tp_percentage              = trim($row[30]);
+                    $actual_bp_brokerage_amount        = trim($row[31]);
+                    $actual_tp_brokerage_amount        = trim($row[32]);
+                    $expected_amount                   = trim($row[33]);
+                    $rewards                           = trim($row[34]);
+
+                    $current_insurer_data = check_insurer_exist($row, $insurer_data)['insurer'] ?? null;
+                    $current_insurer_branch_data = check_insurer_branch_exist($row, $insurer_branch_data, $current_insurer_data)['branch'] ?? null;
+
+                    $current_nhance_branch = check_nhance_branch($row, $nhance_branch_data)['branch'] ?? null;
+                    $current_agent_data = check_agent_exist($row, $agent_data)['agent'] ?? null;
+
+                    $salse = check_user_exist($row, 13, $user_data)['user'] ?? null;
+                    $service = check_user_exist($row, 14, $user_data)['user'] ?? null;
+
+                    $gst_amt = calculate_gst_amount($row) ?? null;
+
+                    $vehicle_id = '';
+                    $client_id = '';
+                    foreach ($vehicle_data as $vehicles) {
+                       if($vehicles['vehicle_no'] == $vehicle_number){
+                            $vehicle_id = $vehicles['id'];
+                            $client_id = $vehicles['owner'];
+                       }
+                    }
+
+                    $second_stage_client_id = '';
+                    if(empty($vehicle_id) && empty($client_id)){
+                        foreach ($client_data as $clients) {
+                            if($clients['email'] == $client_email){
+                                $second_stage_client_id = $clients['id'];
+                            }
+                        }
+                    }
+
+                    if(empty($second_stage_client_id)){
+
+                        $client_insert_data = [
+                            'client_name' => $client_name,
+                            'short_name' => $client_name,
+                            'email' => $client_email,
+                            'entity_type_id' => 7,
+                            'client_type' => 2,
+                        ];
+
+                        $client_id = $this->clientModel->insert($client_insert_data);
+
+                        if($client_id){
+
+                            // Pattern: 2 letters + 2 digits
+                            // if (preg_match('/^([A-Z]{2})([0-9]{2})/i', $vehicle_number, $matches)) {
+                            //     $vehicle_state = strtoupper($matches[1]);   // TN
+                            //     $vehicle_state_code = $matches[2];          // 10
+                            // } else {
+                            //     $vehicle_state = null;
+                            //     $vehicle_state_code = null;
+                            // }
+
+                            // $matched_rto_id = ($m = array_values(array_filter($rto_master, fn($r) => strtoupper($r['rto_state']) === $vehicle_state && (int)$r['rto_code'] === (int)$vehicle_state_code)))[0]['id'] ?? null;
+
+                            $matched_rto_id = check_rto_data($row, $rto_master);
+                            $vehicle_type_id = check_vehicle_type($row, $vehicle_type_data);
+
+                            $vehicle_insert_data = [
+                                'vehicle_no' => $vehicle_number,
+                                'vehicle_type' => $vehicle_type_id['vehicle_type']['id'] ?? null,
+                                'owner' => $client_id,
+                                'rto_id' => $matched_rto_id['rto_data']['id'] ?? null,
+                            ];
+
+                            $vehicle_id = $this->vehicleModel->insert($vehicle_insert_data);
+                        }
+                    }
+
+                    $policy_transaction_data = [
+
+                        'issuer'                => 2,
+                        'issuer_branch'         => $current_nhance_branch['id'] ?? null,
+                        'client_id'             => $client_id,
+                        'policy_type_id'        => 8,
+                        'insurer_id'            => $current_insurer_branch_data['insurer_id'] ?? null,
+                        'insurer_branch_id'     => $current_insurer_branch_data['id'] ?? null,
+                        'policy_no'             => $policy_no,
+                        'vehicle_id'            => $vehicle_id,
+                        'issue_type'            => 1,
+                        'policy_issue_date'     => change_date_format($policy_issue_date, 'd/M/Y', 'Y-m-d'),
+                        'policy_start_date'     => change_date_format($policy_start_date, 'd/M/Y', 'Y-m-d'),
+                        'policy_end_date'       => change_date_format($policy_end_date, 'd/M/Y', 'Y-m-d'),
+                        'action_type'           => 'inception',
+                        'revenue_type'          => $revenue_type,
+                        'co_share'              => 0,
+                        'status'                => 'completed',
+                        'renewal_date'          => change_date_format($policy_end_date, 'd/M/Y', 'Y-m-d'),
+                        'policy_holder_name'    => $client_name,
+                        'month'                 => change_date_format($policy_issue_date, 'd/M/Y', 'Y-m-d'),
+                        'sales_generated_by'    => $salse['id'] ?? null,
+                        'serviced_by'           => $service['id'] ?? null,
+                        'agent_id'              => $current_agent_data['id'] ?? null,
+                        'agent_code'            => $current_agent_data['agent_code'] ?? null,
+                        'file_id'               => $params['file_id'],
+
+                        'endorsement_no'        => null,
+                        'client_branch_id'      => null,
+                        'client_policy_id'      => null,
+                        'ct_type'               => null,
+                        'remarks'               => null,
+
+                    ];
+
+                    $co_share_data = [
+
+                        'pt_id'                     => null,
+                        'insurer_id'                => $current_insurer_branch_data['insurer_id'] ?? null,
+                        'insurer_branch_id'         => $current_insurer_branch_data['id'] ?? null,
+                        'co_share_type'             => 1,  
+                        'co_share_per'              => 100,
+
+                        'bp_amt'                    => $base_premium,
+                        'bp_gst_amt'                => $gst_amt,
+                        'bp_igst'                   => $igst ,
+                        'bp_sgst'                   => $sgst,
+                        'bp_cgst'                   => $cgst,
+
+                        'tp_amt'                    => $tp_premium,
+                        'tp_gst_amt'                => 0,
+                        'tp_igst'                   => 0,
+                        'tp_sgst'                   => 0,
+                        'tp_cgst'                   => 0,
+
+                        'tep_amt'                   => 0,
+                        'tep_gst_amt'               => 0,
+                        'tep_igst'                  => 0,
+                        'tep_sgst'                  => 0,
+                        'tep_cgst'                  => 0,
+
+                        'agreed_amt'                => $agreed_amount,
+                        'agreed_bp_per'             => $agreed_bp_percentage,
+                        'agreed_tp_per'             => $agreed_tp_percentage,
+                        'agreed_tep_per'            => 0,
+
+                        'actual_bp_amt'             => $actual_bp_amount,
+                        'actual_tp_amt'             => $actual_tp_amount,
+                        'actual_tep_amt'            => 0,
+
+                        'actual_bp_per'             => $actual_bp_percentage,
+                        'actual_tp_per'             => $actual_tp_percentage,
+                        'actual_tep_per'            => 0,
+
+                        'actual_bp_brokerage_amt'   => $actual_bp_brokerage_amount,
+                        'actual_tp_brokerage_amt'   => $actual_tp_brokerage_amount,
+                        'actual_tep_brokerage_amt'  => 0,
+
+                        'standerd_bp_per'           => 15.00,
+                        'standerd_tp_per'           => 2.50,
+                        'agreed_tep_per'            => 0,
+
+                        'reward'                    => $rewards,
+                        'variance'                  => 0,
+
+                        'remark'                    => null,
+                        'amount'                    => $total,
+                        'stamp_duty'                => $stamp_duty,
+
+                        'cop_amt'                   => $base_premium,
+                        'cotp_amt'                  => $tp_premium,
+                        'cotep_amt'                 => 0.00,
+
+                        'exp_amt'                   => $expected_amount,
+                        'statement_id'              => null,
+
+                        'follower_policy_no'        => null,
+                        'non_comm_per_amt'          => $non_commission_premium_amount,
+
+                        'pt_policy_issue_date'      => change_date_format($policy_issue_date, 'd/M/Y', 'Y-m-d'),
+
+                        'file_id'                   => $params['file_id']
+                    ];
+
+                    if(!empty($vehicle_id) && !empty($client_id)){
+                        $pt_id = $this->policyTransactionModel->insert($policy_transaction_data);
+                        if($pt_id){
+                            $co_share_data['pt_id'] = $pt_id;
+                            $pt_co_share_id = $this->PTCOShareDetailsModel->insert($co_share_data);
+
+                            $client_policy_insert_data = $this->prepareClientPolicyInsertData($policy_transaction_data);
+                            $client_policy_id = $this->clientPolicyModel->insert($client_policy_insert_data);
+                            $this->policyTransactionModel->update($pt_id, ['client_policy_id' => $client_policy_id]);
+                            $pt_ids[] = $pt_id;
+                            $this->myLogger->logme('error', "BDS entry successfully added with pt_id : $pt_id, pt_co_share_id : $pt_co_share_id, client_policy_id :$client_policy_id");
+
+                        }
+                    }else{
+                        $this->myLogger->logme('error', 'Skipped......... , vehicle id and client id missing');
+                    }
+
+                }
+
+            } catch (\Exception $e) {
+                $errorDetails = [
+                    'error_message' => $e->getMessage(),
+                    'file'          => $e->getFile(),
+                    'line'          => $e->getLine(),
+                    'stack_trace'   => $e->getTraceAsString(),
+                ];
+                $message = "Contact system admin";
+                $this->bdsDumpModel->where('id', $file_id)->set(['status' => 'failed', 'reason' => json_encode(['error_summary' => array_count_values([5]), 'error_data' => $message])])->update();
+                $this->myLogger->logme("error", 'Claim dump file format validation failed due to : ' . json_encode($errorDetails ?? []));
+                return $errorDetails;
+            }
+
+            // return $result;
+
+            if (isset($result['error_summary']) && count($result['error_summary'])) {
+                $result['error_summary'] = array_count_values($result['error_summary']);
+                $status = 'failed';
+                $failure_reason = ((json_encode($result)));
+                $this->bdsDumpModel->where('id', $file_id)->set(['status' => $status, 'reason' => $failure_reason])->update();
+                $this->myLogger->logme("error", '{file_id} uploaded failed', ['file_id' => $file_id]);
+            } else{
+                $result = count($pt_ids);
+            }
+
+            return $result;
+        }
+
+        public function extractExcelData($file_name, $highestColumn)
+        {
+            // $file_name = "claims_dump_form_client.xlsx";
+            // Load the Excel file
+            $file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file_name;
+            $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path);
+            $worksheet = $spreadsheet->getActiveSheet();
+
+            // Get the highest row and column numbers
+            $highestRow = $worksheet->getHighestDataRow();
+            // $highestColumn = $worksheet->getHighestDataColumn();
+            // dd($highestRow, $highestColumn);
+
+            // Get header row (assuming headers are in row 1)
+            // $headerRow = $worksheet->rangeToArray('A1:' . $highestColumn . '1', null, true, false)[0];
+            $excel_data = $worksheet->rangeToArray('A1:' . $highestColumn . $highestRow);
+            // print_rr($excel_data); die;
+
+            //Sanitize the excel data
+            $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data);
+            // dd($excel_data);
+
+            // dd($data);
+            return $excel_data;
+        }
+
+        public function getBdsBulkUploadExcelErrorData($file_id)
+        {
+            try {
+
+                $file = $this->bdsDumpModel->where('id', $file_id)->first();
+                $error_data = json_decode($file['reason']);
+                // dd($error_data);
+
+                $file_name_with_path = WRITEPATH . "/uploads/bds_dump_excel/" . $file['file_name'];
+                // Kint::dump(file_exists($file_name_with_path)); die;
+
+                //check the file exist or not
+                if (!file_exists($file_name_with_path)) {
+                    $error_message = "File not found";
+                    $this->myLogger->logme('error', ($error_message . ' for file id ' . $file_id));
+                    return 0;
+                }
+
+                $columns_to_check = $this->bds_bulk_upload_excel_file_column;
+                $allowedHighestColumn = end($columns_to_check);
+                // Kint::dump($columns_to_check); die;
+
+                $excel_data = $this->extractExcelData($file['file_name'], $allowedHighestColumn['col_cell_name']);
+                $excelErrorData['excel_header'] = $excel_data[0];
+                unset($excel_data[0]);
+
+                // Kint::dump($excel_data); die;
+                if ($error_data->error_type == 1) {
+
+                    $finalArray = [];
+                    foreach ($error_data->error_data as $key => $value) {
+                        foreach ($value as $key2 => $value2) {
+                            $error_data = $value2->error;
+                            $data = ['value' => $excel_data[$key][$value2->col_idx], 'error' => $error_data,];
+                            $excel_data[$key][$value2->col_idx] = $data;
+                        }
+                        array_push($finalArray, $excel_data[$key]);
+                    }
+
+                    foreach ($finalArray as $fkey => $value) {
+                        foreach ($value as $vkey => $arrayData) {
+                            if (!is_array($arrayData)) {
+                                $data = ['value' => $arrayData];
+                                $finalArray[$fkey][$vkey] =  $data;
+                            }
+                        }
+                    }
+
+                    $excelErrorData['excel_data'] = $finalArray;
+                    return $excelErrorData;
+                } else if ($error_data->error_type == 2) {
+
+
+                    $allErrors = [];
+                    $typeTowArray = [];
+
+                    foreach ($error_data->error_data as $index => $item) {
+
+                        foreach ($item as $field) {
+                            if (!isset($allErrors[$index])) {
+                                $allErrors[$index] = [];
+                            }
+                            $allErrors[$index] = array_merge($allErrors[$index], $field->error);
+                        }
+                    }
+
+                    // dd(array_keys($allErrors));
+                    foreach ($allErrors as $key => $value) {
+                        // echo $key;
+                        // print_r($value);
+                        foreach ($excel_data as $excel_data_index => $excel_data_value) {
+                            if ($excel_data_value[0] == $key) {
+                                $data = ['value' => $excel_data[$excel_data_index][1], 'error' => $value,];
+                                $excel_data[$excel_data_index][1] = $data;
+                                array_push($typeTowArray, $excel_data[$excel_data_index]);
+                                break;
+                            }
+                        }
+                    }
+                    // dd($data);
+                    foreach ($typeTowArray as $fkey => $value) {
+                        foreach ($value as $vkey => $arrayData) {
+                            if (!is_array($arrayData)) {
+                                $data = ['value' => $arrayData];
+                                $typeTowArray[$fkey][$vkey] =  $data;
+                            }
+                        }
+                    }
+
+                    $excelErrorData['excel_data'] = $typeTowArray;
+                    return $excelErrorData;
+                }
+
+            } catch (\Exception $e) {
+                // Handle any exceptions
+                $errorMessage = $e->getMessage(); //die();
+                $this->myLogger->logme('error', $errorMessage);
+                return false; // You can return an error response here
+            }
+        }
+
+        public function getBdsdumpFileErrorData()
+        {
+            $file_id = $this->request->getGet('file_id');
+            $file = $this->bdsDumpModel->where('id', $file_id)->first();
+            if (!isset($file)) {
+                return $this->respond(['status' => false, 'code' => 404, 'message' => 'No data found'], 200);
+            } else {
+                return $this->respond(['status' => true, 'code' => 200, 'data' => $file['reason']], 200);
+            }
+        }
+
+        public function getBdsDumpExcelFileErrors($file_id)
+        {
+            // Render views and capture output
+            $result = $this->getBdsBulkUploadExcelErrorData($file_id) ?? [];
+            // dd($result);
+
+            if ($result != 0) {
+
+                $result['file_id'] = $file_id;
+                echo view('excel_errors', $result);
+            } else if ($result == 0) {
+
+                $data['message'] = 'File Not Found Physically';
+                return view('errors/404', $data);
+            } else {
+
+                echo view('errors/html/production');
+            }
+        }
     }
diff --git a/app/Helpers/excel_util_helper.php b/app/Helpers/excel_util_helper.php
index 761d69bb..b5334313 100755
--- a/app/Helpers/excel_util_helper.php
+++ b/app/Helpers/excel_util_helper.php
@@ -2948,3 +2948,392 @@ if (!function_exists('validatet_family_floter_rata_premium')) {
         return $family;
     }
 }
+
+
+if (!function_exists('validate_excel_value')) {
+    function validate_excel_value($value, $data_type, $format = null, $allowed_values = null)
+    {
+        switch ($data_type) {
+
+            case 'date':
+                return validate_date_value($value, $format);
+
+            case 'mobile':
+                return validate_mobile_value($value);
+
+            case 'email':
+                return validate_email_value($value);
+
+            case 'vehicle':
+                return validate_indian_vehicle_number($value);
+
+            default:
+                return [
+                    'status' => true,
+                    'error'  => null
+                ];
+        }
+    }
+}
+
+if (!function_exists('validate_date_value')) {
+    function validate_date_value($value, $format)
+    {
+        if(empty($value)) {
+            return ['status' => true, 'error' => null]; // allow empty
+        }
+
+        $d = DateTime::createFromFormat($format, $value);
+
+        if ($d && $d->format($format) === $value) {
+            return ['status' => true, 'error' => null];
+        }
+
+        return [
+            'status' => false,
+            'error'  => "Invalid date format. Expected format: {$format}"
+        ];
+    }
+}
+
+if (!function_exists('validate_mobile_value')) {
+    function validate_mobile_value($value)
+    {
+        if (preg_match('/^[0-9]{10}$/', $value)) {
+            return ['status' => true, 'error' => null];
+        }
+
+        return [
+            'status' => false,
+            'error'  => "Invalid mobile number. Expected 10 digits."
+        ];
+    }
+}
+
+if (!function_exists('validate_email_value')) {
+    function validate_email_value($value)
+    {
+        if (filter_var($value, FILTER_VALIDATE_EMAIL)) {
+            return ['status' => true, 'error' => null];
+        }
+
+        return [
+            'status' => false,
+            'error'  => "Invalid email address."
+        ];
+    }
+}
+
+if (!function_exists('validate_indian_vehicle_number')) {
+    function validate_indian_vehicle_number($number)
+    {
+        $number = strtoupper(trim($number));
+
+        // Normal Format:
+        // 2 letters (state) + 2 digits (district) + 1 or 2 letters (series) + 4 digits
+        $normalPattern = '/^[A-Z]{2}[0-9]{2}[A-Z]{1,2}[0-9]{4}$/';
+
+        // BH Series: 22BH1234AA
+        $bhPattern = '/^[0-9]{2}BH[0-9]{4}[A-Z]{2}$/';
+
+        if (preg_match($normalPattern, $number)) {
+            return ['status' => true, 'error' => null];
+        }
+
+        if (preg_match($bhPattern, $number)) {
+            return ['status' => true, 'error' => null];
+        }
+
+        return [
+            'status' => false,
+            'error'  => "Invalid Vehicle Number"
+        ];
+    }
+}
+
+if (!function_exists('check_user_exist')) {
+    function check_user_exist($row, $col_key, $user_data)
+    {
+        // Get the uploaded value from the column
+        $input_value = trim($row[$col_key]);
+
+        // Loop DB user list
+        foreach ($user_data as $user) {
+
+            // Check if DB has 'first_name' key and matches input
+            if (isset($user['first_name']) && strtolower(trim($user['first_name'])) === strtolower($input_value)) {
+
+                return [
+                    'status' => true,
+                    'error'  => null,
+                    'user'  => $user,
+                ];
+            }
+        }
+
+        // If no user matched
+        return [
+            'status' => false,
+            'error'  => "User '{$input_value}' not found in database."
+        ];
+    }
+}
+
+if (!function_exists('check_agent_exist')) {
+    function check_agent_exist($row, $agent_data)
+    {
+        // Get agent code from the uploaded row
+        $agent_code = trim($row[15]); // or use index if needed
+
+        // Loop agent data from DB
+        foreach ($agent_data as $agent) {
+            // Assuming DB keys: agent_code
+            if (isset($agent['agent_code']) && $agent['agent_code'] == $agent_code) {
+                return [
+                    'status' => true,
+                    'error'  => null,
+                    'agent'  => $agent,
+                ];
+            }
+        }
+
+        // If not matched
+        return [
+            'status' => false,
+            'error'  => "Agent code '{$agent_code}' not found in database."
+        ];
+    }
+}
+
+if (!function_exists('check_rto_data')) {
+    function check_rto_data($row, $rto_master)
+    {
+        // Vehicle number from uploaded row
+        $vehicle_no = strtoupper(trim($row[2]));  // Example: TN10AB1234
+
+        // Must be at least 4 characters to extract RTO
+        if (strlen($vehicle_no) < 4) {
+            return [
+                'status' => false,
+                'error'  => "Invalid vehicle number format: '{$vehicle_no}'"
+            ];
+        }
+
+        // Extract State (first 2 letters) and RTO Code (next 2 digits)
+        $state_code = substr($vehicle_no, 0, 2);    // TN
+        $rto_code   = substr($vehicle_no, 2, 2);    // 10
+
+        // Validate they are correct format
+        if (!ctype_alpha($state_code) || !ctype_digit($rto_code)) {
+            return [
+                'status' => false,
+                'error'  => "Vehicle number '{$vehicle_no}' has invalid state or RTO code."
+            ];
+        }
+
+        // Loop RTO master data
+        foreach ($rto_master as $rto) {
+
+            // Expected DB fields: rto_state, rto_code
+            if (
+                isset($rto['rto_state']) &&
+                isset($rto['rto_code']) &&
+                strtoupper($rto['rto_state']) === $state_code &&
+                (string)$rto['rto_code'] === $rto_code
+            ) {
+                return [
+                    'status' => true,
+                    'error'  => null,
+                    'rto_data'  => $rto
+                ];
+            }
+        }
+
+        // Not found in RTO master
+        return [
+            'status' => false,
+            'error'  => "RTO '{$state_code} {$rto_code}' not found in RTO master."
+        ];
+    }
+}
+
+if (!function_exists('check_vehicle_type')) {
+    function check_vehicle_type($row, $vehicle_type)
+    {
+        // Vehicle type from uploaded Excel row
+        $input_type = strtolower(trim($row[3]));  // Example: CAR
+
+        // Loop vehicle type master
+        foreach ($vehicle_type as $vt) {
+
+            if (isset($vt['vehicle_type']) && strtolower($vt['vehicle_type']) == $input_type) {
+                return [
+                    'status' => true,
+                    'error'  => null,
+                    'vehicle_type'  => $vt,
+                ];
+            }
+        }
+
+        // Not found in master
+        return [
+            'status' => false,
+            'error'  => "Vehicle type '{$input_type}' not found in master."
+        ];
+    }
+}
+
+if (!function_exists('check_policy_no')) {
+    function check_policy_no($row, $pt_data)
+    {
+        // Get policy number from Excel row
+        $policy_no = strtolower(trim($row[4]));
+
+        // Empty policy number
+        if ($policy_no === '') {
+            return [
+                'status' => false,
+                'error'  => "Policy number is empty."
+            ];
+        }
+
+        // Loop all policy transactions (pt_data)
+        foreach ($pt_data as $pt) {
+
+            // Check policy_no exists in DB list
+            if (isset($pt['policy_no']) && strtolower($pt['policy_no']) == $policy_no) {
+                return [
+                    'status' => false,
+                    'error'  => "Duplicate policy number '{$policy_no}' found in database."
+                ];
+            }
+        }
+
+        // If no match found → not duplicate
+        return [
+            'status' => true,
+            'error'  => null
+        ];
+    }
+}
+
+if (!function_exists('check_insurer_exist')) {
+    function check_insurer_exist($row, $insurer_master)
+    {
+        // Get insurer short name from Excel row (col 7)
+        $short_name = strtolower(trim($row[7]));
+
+        foreach ($insurer_master as $insurer) {
+            if (
+                isset($insurer['short_name']) &&
+                strtolower($insurer['short_name']) === $short_name
+            ) {
+                return [
+                    'status'  => true,
+                    'error'   => null,
+                    'insurer' => $insurer   // return entire insurer row for next validation
+                ];
+            }
+        }
+
+        return [
+            'status' => false,
+            'error'  => "Insurer '{$short_name}' not found in database."
+        ];
+    }
+}
+
+if (!function_exists('check_insurer_branch_exist')) {
+    function check_insurer_branch_exist($row, $insurer_branch_master, $insurer)
+    {
+        // Get branch code from Excel row (col 8)
+        $branch_code = strtolower(trim($row[8]));
+
+        // Loop all branches
+        foreach ($insurer_branch_master as $branch) {
+
+            if (
+                isset($insurer['id']) && $branch['insurer_id'] == $insurer['id'] && 
+                strtolower($branch['branch_code']) == $branch_code 
+            ) {
+                return [
+                    'status' => true,
+                    'error'  => null,
+                    'branch' => $branch
+                ];
+            }
+        }
+
+        return [
+            'status' => false,
+            'error'  => "Branch code '{$branch_code}' not found in database."
+        ];
+    }
+}
+
+if (!function_exists('check_nhance_branch')) {
+    function check_nhance_branch($row, $nhance_branch_master)
+    {
+        // Get branch name from Excel row (col 8)
+        $branch_name = strtolower(trim($row[1]));
+
+        // Loop all branches
+        foreach ($nhance_branch_master as $branch) {
+
+            if (
+                isset($branch['branch_name']) &&
+                strtolower($branch['branch_name']) == $branch_name
+            ) {
+                return [
+                    'status' => true,
+                    'error'  => null,
+                    'branch' => $branch
+                ];
+            }
+        }
+
+        return [
+            'status' => false,
+            'error'  => "Branch '{$branch_name}' not found in database."
+        ];
+    }
+}
+
+if (!function_exists('calculate_gst_amount')) {
+    function calculate_gst_amount($row) {
+
+        // Extract values
+        $base_premium                     = (float)trim($row[16]);
+        $non_commission_premium_amount    = (float)trim($row[17]);
+        $tp_premium                       = (float)trim($row[18]);
+        $igst                             = (float)trim($row[19]);
+        $cgst                             = (float)trim($row[20]);
+        $sgst                             = (float)trim($row[21]);
+
+        // Total GST percentage
+        $gst_percentage = $igst + $cgst + $sgst;
+
+        // Step 1: Choose taxable amount
+        if ($non_commission_premium_amount > 0) {
+            // GST on non-commission premium
+            $taxable_amount = $non_commission_premium_amount;
+        } else {
+            // GST on base premium + TP premium
+            $taxable_amount = $base_premium + $tp_premium;
+        }
+
+        // Step 2: GST Amount calculation
+        $gst_amount = ($taxable_amount * $gst_percentage) / 100;
+
+        return round($gst_amount, 2);
+    }
+}
+
+
+
+
+
+
+
+
+
diff --git a/app/Models/BDSDumpModel.php b/app/Models/BDSDumpModel.php
new file mode 100644
index 00000000..d89da194
--- /dev/null
+++ b/app/Models/BDSDumpModel.php
@@ -0,0 +1,55 @@
+
+
+    .reload:hover {
+        cursor: pointer;
+    }
+
+    .table th,
+    .table td {
+        padding: 8px;
+    }
+
+    table.dataTable tbody td {
+        padding: 4px 4px !important;
+    }
+
+    .addbtnStyle{
+        margin-left: 20px !important;
+    }
+
+    .dataTables_filter {
+        position: absolute;
+    }
+
+    .dataTables_length label {height: 21px !important;}
+
+
+
+
+
+ + + + + + + + + + + + + $file) { + ?> + + + + + + + + + + + +
S.No File nameUser/TimeStatusAction
+ + ' . $file['user_name'] . '' ?> + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/public/sample_excel/sample_bds_bulk_upload_excel.xlsx b/public/sample_excel/sample_bds_bulk_upload_excel.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0bd3d537cbfee798e05ca3b97f89dac4fd19dbd1 GIT binary patch literal 7625 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 DV>#im literal 0 HcmV?d00001