myLogger = \Config\Services::mylogger(); $this->clientModel = new ClientModel(); $this->clientBranchModel = new ClientBranchModel(); $this->policyTypeModel = new PolicyTypeModel(); $this->clientDepositModel = new ClientDepositModel(); $this->clientPolicyModel = new ClientPolicyModel(); $this->insurerBranchModel = new InsurerBranchModel(); $this->insurerModel = new InsurerModel(); $this->policyTransactionModel = new PolicyTransactionModel(); $this->policyTransactionStatusModel = new PolicyTransactionStatusModel(); $this->kycEntityTypeModel = new KYCEntityTypeModel(); $this->clientKYCDocsModel = new ClientKYCDocsModel(); $this->tpaBranchModel = new TPABranchModel(); $this->tpaModel = new TPAModel(); $this->PTFileModel = new PTFileModel(); $this->PTCOShareDetailsModel = new PTCOShareDetailsModel(); $this->employeeModel = new EmployeeModel(); $this->userTeamsModel = new UserTeamsModel(); $this->userModel = new UserModel(); $this->employeePolicyModel = new EmployeePolicyModel(); $this->insurerStatements = new InsurerStatements(); $this->invPaymentDetailsModel = new InvPaymentDetailsModel(); $this->batchFileModel = new BatchFileModel(); $this->filesModel = new FileModel(); $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', 'pos_data'] ], 'base_premium' => [ 'col_idx' => 16, 'col_cell_name' => 'Q', 'col_name' => 'Base Premium', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', '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' => 'positive_number', 'format' => 'positive_number', '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' => 'positive_number', 'format' => 'positive_number', 'allowed_values' => null, 'custom' => null, 'params' => null ], 'igst' => [ 'col_idx' => 19, 'col_cell_name' => 'T', 'col_name' => 'IGST', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', 'allowed_values' => null, 'custom' => 'check_gst_percentage', 'params' => ['row'] ], 'cgst' => [ 'col_idx' => 20, 'col_cell_name' => 'U', 'col_name' => 'CGST', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', 'allowed_values' => null, 'custom' => 'check_gst_percentage', 'params' => ['row'] ], 'sgst' => [ 'col_idx' => 21, 'col_cell_name' => 'V', 'col_name' => 'SGST', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', 'allowed_values' => null, 'custom' => 'check_gst_percentage', 'params' => ['row'] ], 'stamp_duty' => [ 'col_idx' => 22, 'col_cell_name' => 'W', 'col_name' => 'Stamp Duty', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', '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' => 23, 'col_cell_name' => 'X', 'col_name' => 'Agreed Amount', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', 'allowed_values' => null, 'custom' => null, 'params' => null ], 'agreed_bp_percentage' => [ 'col_idx' => 24, 'col_cell_name' => 'Y', 'col_name' => 'Agreed BP Percentage', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', 'allowed_values' => null, 'custom' => null, 'params' => null ], 'agreed_tp_percentage' => [ 'col_idx' => 25, 'col_cell_name' => 'Z', 'col_name' => 'Agreed TP Percentage', 'is_mandatory' => false, 'data_type' => 'positive_number', 'format' => 'positive_number', '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 public function viewInception() { $bds_edit_pt_id = $this->request->getGet('pt_id') ?? null; $view = $this->request->getGet('view') ?? null; $data['tab_name'] = 'Policies'; $data['page_name'] = 'Policies'; // Static arrays for dropdowns $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance']; $data['issuer_branch'] = $this->nhanceBranchModel->where('is_active', 1)->findAll(); $data['client_type'] = [1 => 'Group', 2 => 'Individual']; $data['issuing_type'] = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over']; $data['policy_status'] = [ 'under_process' => 'Under Process', 'client_pending' => 'Client Pending', 'insurer_pending' => 'Insurer Pending', 'co_insurer_pending' => 'Co-Insurer Pending', 'tpa_pending' => 'TPA Pending', 'validated' => 'Validated', 'cancelled' => 'Cancelled', 'instalment_pending' => 'Instalment Pending', 'completed' => 'Completed', 'lost' => 'Lost', ]; $data['invoice_status_array'] = [ 'yet_to_generate' => 'Pending', 'generated' => 'Generated', 'send' => 'Sent', 'recived' => 'Payment Received', ]; // $data['vehicle_type'] = [ // 'two_wheeler' => 'Two Wheeler', // 'four_wheeler' => 'Four Wheeler', // 'truck' => 'Truck', // 'bus' => 'Bus', // 'van' => 'Van', // 'suv' => 'SUV', // 'motorcycle' => 'Motorcycle', // 'bicycle' => 'Bicycle' // ]; $data['vehicle_type'] = db_connect()->table('vehicle_type')->where('is_active', 1)->get()->getResultArray(); $data['rto_details'] = db_connect()->table('rto_master')->where('is_active', 1)->get()->getResultArray(); $data['vehicle_des'] = [ 'commercial' => 'Commercial', 'private' => 'Private', ]; $data['date_type'] = [ 'policy_issue_date' => 'Policy Issue Date', 'policy_start_date' => 'Policy Start Date', 'policy_end_date' => 'Policy End Date', ]; // List rows are loaded via server-side DataTables AJAX. $data['inception_data_list'] = []; $data['inception_filters'] = $this->buildInceptionFiltersFromRequest(); // Fetch additional data $data['client'] = $this->clientModel->where('is_active', 1)->findAll(); $data['client_branch'] = $this->clientBranchModel->where('is_active', 1)->findAll(); $data['policy_type'] = $this->policyTypeModel->where('is_active', 1)->findAll(); $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll(); $data['entity'] = $this->kycEntityTypeModel->where('is_active', 1)->findAll(); $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll(); $data['insurer_branch'] = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(); $data['tpa'] = $this->tpaBranchModel->getTpaBranchesWithTpaNames(); // Fetch PP Teams Data $data['ppTeamsData'] = $this->userModel ->where('is_active', 1) ->findAll(); // // Fetch Sales Team // $data['salse_team'] = $this->userModel // ->select('user_profiles.*,nhance_branch.id as nhance_branch_id, nhance_branch.branch_name as nhance_branch_name') // ->join('user_teams', 'user_profiles.id = user_teams.user_id') // ->join('nhance_branch', 'user_profiles.nhance_branch_id = nhance_branch.id','left') // ->where('user_teams.team_id', 5) // ->where('user_teams.is_active', 1) // ->where('user_profiles.is_active', 1) // ->findAll(); // // Fetch Partner Agent // $data['partner_agent'] = db_connect()->table('partner_agent') // ->where('is_active', 1) // ->get() // ->getResultArray(); // // Fetch ACM // $data['ACM'] = $this->userModel // ->where('role', 3) // Assuming `role` is in `user_profiles` // ->where('is_active', 1) // ->findAll(); // Fetch Sales Team $data['salse_team'] = $this->userModel ->select(' user_profiles.*, nhance_branch.id as nhance_branch_id, nhance_branch.branch_name as nhance_branch_name, rm.first_name AS rm_name ') // ->join('user_teams', 'user_profiles.id = user_teams.user_id') ->join('nhance_branch', 'user_profiles.nhance_branch_id = nhance_branch.id','left') ->join('user_profiles AS rm', 'user_profiles.rm_id = rm.id', 'left') // ->where('user_teams.team_id', 5) // ->where('user_teams.is_active', 1) ->where('user_profiles.is_active', 1) ->groupBy('user_profiles.id', 'asc') ->findAll(); // Fetch Partner Agent $data['partner_agent'] = db_connect()->table('partner_agent') ->where('is_active', 1) ->get() ->getResultArray(); // Fetch ACM $data['ACM'] = $this->userModel ->select(' user_profiles.*, nhance_branch.id AS nhance_branch_id, nhance_branch.branch_name AS nhance_branch_name, rm.first_name AS rm_name ') ->join('user_teams', 'user_profiles.id = user_teams.user_id') ->join('nhance_branch', 'user_profiles.nhance_branch_id = nhance_branch.id', 'left') ->join('user_profiles AS rm', 'user_profiles.rm_id = rm.id', 'left') // ->where('user_profiles.role', 3) ->where('user_profiles.is_active', 1) ->groupBy('user_profiles.id', 'asc') ->findAll(); // dd($data); //Fetch POS $data['pos_data'] = db_connect()->table('partner_pos') ->where('is_active', 1) ->get() ->getResultArray(); // Load view $this->loadLayout('policy_transaction_inception_list', $data); } public function inceptionListDataTable() { if (!$this->request->isAJAX()) { return $this->response->setStatusCode(400)->setJSON([ 'status' => false, 'message' => 'Invalid request.', ]); } $draw = (int) ($this->request->getPost('draw') ?? 0); $start = max(0, (int) ($this->request->getPost('start') ?? 0)); $length = (int) ($this->request->getPost('length') ?? 10); $search = trim((string) ($this->request->getPost('search')['value'] ?? '')); $filters = $this->buildInceptionFiltersFromRequest(); $result = $this->policyTransactionModel->getInceptionTranctionListDataTable( $draw, $start, $length, $search, $filters ); $rows = []; foreach ($result['data'] as $index => $row) { $rows[] = $this->formatInceptionRowForDataTable($row, $start + $index + 1); } return $this->response->setJSON([ 'draw' => $result['draw'], 'recordsTotal' => $result['recordsTotal'], 'recordsFiltered' => $result['recordsFiltered'], 'data' => $rows, 'cache_expires_in_ms' => $result['cache_expires_in_ms'] ?? 300000, ]); } public function clearInceptionListCache() { if (!$this->request->isAJAX()) { return $this->response->setStatusCode(400)->setJSON([ 'status' => false, 'message' => 'Invalid request.', ]); } session()->set('inception_list_cache_version', time()); return $this->response->setJSON([ 'status' => true, 'message' => 'Inception list cache cleared.', ]); } protected function buildInceptionFiltersFromRequest(): array { $normalize = static function ($value) { return (!isset($value) || $value === '' || $value === null) ? 0 : $value; }; $ids = []; if ($this->request->is('post')) { $postIds = $this->request->getPost('ids') ?? ''; $ids = array_filter(explode(',', (string) $postIds)); } return [ 'start_date' => $normalize($this->request->getGet('start_date') ?? $this->request->getPost('start_date')), 'end_date' => $normalize($this->request->getGet('end_date') ?? $this->request->getPost('end_date')), 'client_id' => $normalize($this->request->getGet('client_id') ?? $this->request->getPost('client_id')), 'insurer_id' => $normalize($this->request->getGet('insurer_id') ?? $this->request->getPost('insurer_id')), 'policy_type_id' => $normalize($this->request->getGet('policy_type_id') ?? $this->request->getPost('policy_type_id')), 'date_type' => $normalize($this->request->getGet('date_type') ?? $this->request->getPost('date_type')), 'issuer' => $normalize($this->request->getGet('issuer') ?? $this->request->getPost('issuer')), 'status' => $normalize($this->request->getGet('status') ?? $this->request->getPost('status')), 'ids' => $ids, 'cache_version' => (int) (session()->get('inception_list_cache_version') ?? 1), ]; } protected function formatInceptionRowForDataTable(array $row, int $serialNo): array { $issuerMap = [1 => 'JIBS', 2 => 'Nhance']; $issuingTypeMap = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over']; $clientTypeMap = [1 => 'Group', 2 => 'Individual']; $policyStatusMap = [ 'under_process' => 'Under Process', 'client_pending' => 'Client Pending', 'insurer_pending' => 'Insurer Pending', 'co_insurer_pending' => 'Co-Insurer Pending', 'tpa_pending' => 'TPA Pending', 'validated' => 'Validated', 'cancelled' => 'Cancelled', 'instalment_pending' => 'Instalment Pending', 'completed' => 'Completed', 'lost' => 'Lost', ]; $clientBranch = ((int) ($row['client_type'] ?? 0) === 2) ? (($row['client_name'] ?? 'N/A') . ' - ' . (!empty($row['pan']) ? $row['pan'] : 'N/A')) : (($row['client_short_name'] ?? 'N/A') . ' - ' . ($row['client_branch_name'] ?? 'N/A')); $editAction = 'Edit'; $deleteAction = ''; if ((int) get_role_id() === 5) { $deleteAction = 'Delete'; } $actionHtml = ''; return [ 0 => $serialNo, 1 => $issuerMap[$row['issuer'] ?? 2] ?? 'Nhance', 2 => $issuingTypeMap[$row['issue_type'] ?? 0] ?? 'N/A', 3 => $clientTypeMap[$row['client_type'] ?? 0] ?? 'N/A', 4 => $clientBranch, 5 => $row['insurer_short_name'] ?: 'N/A', 6 => $row['policy_type'] ?: 'N/A', 7 => $row['policy_no'] ?: 'N/A', 8 => empty($row['policy_issue_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_issue_date'])), 9 => empty($row['policy_start_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_start_date'])), 10 => empty($row['policy_end_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_end_date'])), 11 => $row['emp_count'] ?: '0', 12 => $row['dependent_count'] ?: '0', 13 => $policyStatusMap[$row['status'] ?? ''] ?? 'N/A', 14 => $row['user_name'] ?: 'N/A', 15 => $actionHtml, ]; } public function viewInception2() { $bds_edit_pt_id = $this->request->getGet('pt_id') ?? null; $data['tab_name'] = 'Policies'; $data['page_name'] = 'Policies'; // Static arrays for dropdowns $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance']; $data['issuer_branch'] = $this->nhanceBranchModel->where('is_active', 1)->findAll(); $data['client_type'] = [1 => 'Group', 2 => 'Individual']; $data['issuing_type'] = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over']; $data['policy_status'] = [ 'under_process' => 'Under Process', 'client_pending' => 'Client Pending', 'insurer_pending' => 'Insurer Pending', 'co_insurer_pending' => 'Co-Insurer Pending', 'tpa_pending' => 'TPA Pending', 'validated' => 'Validated', 'cancelled' => 'Cancelled', 'instalment_pending' => 'Instalment Pending', 'completed' => 'Completed', 'lost' => 'Lost', ]; $data['invoice_status_array'] = [ 'yet_to_generate' => 'Pending', 'generated' => 'Generated', 'send' => 'Sent', 'recived' => 'Payment Received', ]; // $data['vehicle_type'] = [ // 'two_wheeler' => 'Two Wheeler', // 'four_wheeler' => 'Four Wheeler', // 'truck' => 'Truck', // 'bus' => 'Bus', // 'van' => 'Van', // 'suv' => 'SUV', // 'motorcycle' => 'Motorcycle', // 'bicycle' => 'Bicycle' // ]; $data['vehicle_type'] = db_connect()->table('vehicle_type')->where('is_active', 1)->get()->getResultArray(); $data['rto_details'] = db_connect()->table('rto_master')->where('is_active', 1)->get()->getResultArray(); $data['vehicle_des'] = [ 'commercial' => 'Commercial', 'private' => 'Private', ]; $data['date_type'] = [ 'policy_issue_date' => 'Policy Issue Date', 'policy_start_date' => 'Policy Start Date', 'policy_end_date' => 'Policy End Date', ]; // Filter data $start_date = $this->request->getGet('start_date'); $end_date = $this->request->getGet('end_date'); $client_id = $this->request->getGet('client_id'); $insurer_id = $this->request->getGet('insurer_id'); $policy_type_id = $this->request->getGet('policy_type_id'); $date_type = $this->request->getGet('date_type'); $issuer = $this->request->getGet('issuer'); $status = $this->request->getGet('status'); // Handle null or empty values $start_date = empty($start_date) ? 0 : $start_date; $end_date = empty($end_date) ? 0 : $end_date; $client_id = empty($client_id) ? 0 : $client_id; $insurer_id = empty($insurer_id) ? 0 : $insurer_id; $policy_type_id = empty($policy_type_id) ? 0 : $policy_type_id; $date_type = empty($date_type) ? 0 : $date_type; $issuer = empty($issuer) ? 0 : $issuer; $status = empty($status) ? 0 : $status; // Corrected from `$issuer` if(empty($bds_edit_pt_id)){ if ($this->request->is('get')) { // Fetch inception data list $data['inception_data_list'] = $this->policyTransactionModel->getInceptionTranctionListData( $start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer, $status ); } else { $ids = $this->request->getPost('ids'); $ids = array_filter(explode(',', $ids)); $data['inception_data_list'] = $this->policyTransactionModel->getInceptionTranctionListData( $start_date = 0, $end_date = 0, $client_id = 0, $insurer_id = 0, $policy_type_id = 0, $date_type = 0, $issuer = 0, $status = 0, $ids ); } }else{ $data['inception_data_list'] = []; } // Fetch additional data $data['client'] = $this->clientModel->where('is_active', 1)->findAll(); $data['client_branch'] = $this->clientBranchModel->where('is_active', 1)->findAll(); $data['policy_type'] = $this->policyTypeModel->where('is_active', 1)->findAll(); $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll(); $data['entity'] = $this->kycEntityTypeModel->where('is_active', 1)->findAll(); $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll(); $data['insurer_branch'] = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(); $data['tpa'] = $this->tpaBranchModel->getTpaBranchesWithTpaNames(); // Fetch PP Teams Data $data['ppTeamsData'] = $this->userModel ->where('is_active', 1) ->findAll(); // Fetch Sales Team $data['salse_team'] = $this->userModel ->select(' user_profiles.*, nhance_branch.id as nhance_branch_id, nhance_branch.branch_name as nhance_branch_name, rm.first_name AS rm_name ') ->join('user_teams', 'user_profiles.id = user_teams.user_id') ->join('nhance_branch', 'user_profiles.nhance_branch_id = nhance_branch.id','left') ->join('user_profiles AS rm', 'user_profiles.rm_id = rm.id', 'left') ->where('user_teams.team_id', 5) ->where('user_teams.is_active', 1) ->where('user_profiles.is_active', 1) ->groupBy('user_profiles.id', 'asc') ->findAll(); // Fetch Partner Agent $data['partner_agent'] = db_connect()->table('partner_agent') ->where('is_active', 1) ->get() ->getResultArray(); // Fetch ACM $data['ACM'] = $this->userModel ->select(' user_profiles.*, nhance_branch.id AS nhance_branch_id, nhance_branch.branch_name AS nhance_branch_name, rm.first_name AS rm_name ') ->join('user_teams', 'user_profiles.id = user_teams.user_id') ->join('nhance_branch', 'user_profiles.nhance_branch_id = nhance_branch.id', 'left') ->join('user_profiles AS rm', 'user_profiles.rm_id = rm.id', 'left') ->where('user_profiles.role', 3) ->where('user_profiles.is_active', 1) ->groupBy('user_profiles.id', 'asc') ->findAll(); // echo '
';
        
        // print_r($data['ppTeamsData']); die;

        // dd($data);

        // Load view
        $this->loadLayout('policy_transaction_inception_list_2', $data);
    }

    // policy Transaction Create function start
    public function createInceptionPolicy()
    {
        session()->set('inception_list_cache_version', time());

        $post_data = $this->request->getPost();

        $rules = [
            // ==========================================
            // 1. CLIENT SECTION (5 Fields)
            // ==========================================
            'client_type'       => ['label'  => 'Client Type', 'rules'  => 'required', 'errors' => ['required' => 'Client Type must be selected.']],
            'client_id'     => ['label'  => 'Client', 'rules'  => 'required', 'errors' => ['required' => 'Please select a Client.']],
            'issue_type'  => ['label'  => 'Business Type', 'rules'  => 'required', 'errors' => ['required' => 'Please select a Business Type.']],
            'ref'   => ['label' => 'Reference', 'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9 _-]+$/]', 'errors' => [
                'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
            ]],

            // ==========================================
            // 5. SALES SECTION (12 Fields)
            // ==========================================
            'base_policy'        => ['label' => 'Base Policy', 'rules' => 'permit_empty', 'errors' => []],
            'policy_no'          => [
                'label' => 'Policy Number',
                'rules'  => 'required|regex_match[/^[a-zA-Z0-9\/_-]+$/]',
                'errors' => [
                    'required'    => 'Policy Number is Must.',
                    'regex_match' => 'Policy Number can only contain letters, numbers, and symbols like / - or _'
                ]
            ],
            'policy_issue_date'  => [
                'label' => 'Issue Date',
                'rules'  => 'required|valid_date[Y-m-d]|regex_match[/^\d{4}-\d{2}-\d{2}$/]',
                'errors' => [
                    'required'    => 'Policy Issue Date is required.',
                    'valid_date'  => 'Please provide a valid Policy Issue Date.',
                    'regex_match' => 'The Policy Issue Date format is incorrect. '
                ]
            ],
            'month'              => ['label' => 'Issue Month', 'rules' => 'required', 'errors' => [
                'required' => 'Please select or enter the Policy Issue Month.'
            ]],
            'policy_start_date'  => [
                'label' => 'D.O.C',
                'rules'  => 'required|valid_date[Y-m-d]|regex_match[/^\d{4}-\d{2}-\d{2}$/]',
                'errors' => [
                    'required'   => 'D.O.C (Start Date) is required.',
                    'valid_date'  => 'Please provide a valid D.O.C date.',
                    'regex_match' => 'The D.O.C date format is incorrect. '
                ]
            ],
            'policy_end_date'    => ['label' => 'D.O.E', 'rules' => 'required|valid_date[Y-m-d]|regex_match[/^\d{4}-\d{2}-\d{2}$/]', 'errors' => [
                'required'   => 'D.O.E (Expiry Date) is required.',
                'valid_date'  => 'Please provide a valid D.O.E date.',
                'regex_match' => 'The D.O.E date format is incorrect. '
            ]],
            'emp_count'          => ['label' => 'No of Employees', 'rules' => 'permit_empty|numeric', 'errors' => [
                'numeric' => 'No of Employees must contain only numbers.'
            ]],
            'dependent_count'    => ['label' => 'No of Dependents', 'rules' => 'permit_empty|numeric', 'errors' => [
                'numeric' => 'No of Dependents must contain only numbers.'
            ]],
            'installment'        => ['label' => 'Installment', 'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9 _-]+$/]', 'errors' => [
                'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
            ]],
            'installment_data'   => ['label' => 'Installment Data', 'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9 _-]+$/]', 'errors' => [
                'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
            ]],
            'co_share'           => ['label' => 'CoP Yes', 'rules' => 'permit_empty', 'errors' => []],
            'bro_payable_by'     => ['label' => 'Remuneration Pay By', 'rules' => 'permit_empty', 'errors' => []],
            'renewal_date'       => ['label' => 'Renewal Date', 'rules' => 'required|valid_date[Y-m-d]|regex_match[/^\d{4}-\d{2}-\d{2}$/]', 'errors' => [
                'required'   => 'Renewal Date is required.',
                'valid_date'  => 'Please provide a valid Renewal Date.',
                'regex_match' => 'The Renewal Date format is incorrect. '
            ]],
            'sales_generated_by' => ['label' => 'Sales Generated By', 'rules' => 'permit_empty', 'errors' => [
                // 'required' => 'Please select the person who generated this sale.'
            ]],
            'serviced_by'        => ['label' => 'Serviced By', 'rules' => 'permit_empty', 'errors' => [
                // 'required' => 'Please select the service person for this policy.'
            ]],
            'pos_id'             => ['label' => 'POS', 'rules' => 'permit_empty', 'errors' => []],
            'doc_name.*' => [
                'label'  => 'Policy Document Name',
                'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9 \/_-]+$/]|min_length[2]|max_length[100]',                
                'errors' => [
                    'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
                ]
            ],
            'other_docs_name.*' => [
                'label'  => 'Vehicle Document Name',
                'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9 \/_-]+$/]|min_length[2]|max_length[100]',
                'errors' => [
                    'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
                ]
            ],

            // ==========================================
            // 6. PREMIUM DETAILS (Array Fields - 25 Fields)
            // Use .* because these come from the dynamic table
            // ==========================================
            'follow_insurer_id.*'      => ['label' => 'Insurer', 'rules' => 'required', 'errors' => ['required' => 'Please select an Insurer.']],
            'co_share_type.*'          => ['label' => 'Is Leader', 'rules' => 'permit_empty', 'errors' => []],
            'cd_ac_no_for_child.*'     => ['label' => 'CD Acc No', 'rules' => 'permit_empty', 'errors' => []],
            'cd_current_balance.*'     => ['label' => 'CD Amount', 'rules' => 'permit_empty', 'errors' => []],
            'follower_policy_no.*'     => ['label' => 'Follower Policy No', 'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9\/_-]+$/]', 'errors' => [
                'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
            ]],
            'co_share_per.*'           => ['label' => 'Co-Share %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Co-Share % must be a valid decimal.']],
            'non_comm_per_amt.*'       => ['label' => 'Non-Comm Premium', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Amount must be numeric.']],
            'base_premium.*'           => ['label' => 'Base Premium','rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Base Premium must be numeric.']],
            'tp_premium.*'             => ['label' => 'TP Premium', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'TP Premium must be numeric.']],
            'ter_premium.*'            => ['label' => 'TEP Premium', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'TEP Premium must be numeric.']],
            'co_premium.*'             => ['label' => 'Co-Premium', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Co-Premium must be numeric.']],
            'co_tp_premium.*'          => ['label' => 'Co-TP Premium', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Co-TP Premium must be numeric.']],
            'co_ter_premium.*'         => ['label' => 'Co-TEP Premium', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Co-TEP Premium must be numeric.']],
            'cgst.*'                   => ['label' => 'CGST', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'CGST must be numeric.']],
            'sgst.*'                   => ['label' => 'SGST', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'SGST must be numeric.']],
            'igst.*'                   => ['label' => 'IGST', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'IGST must be numeric.']],
            'gst_amount.*'             => ['label' => 'GST Amount', 'rules'  => 'permit_empty|decimal', 'errors' => ['decimal' => 'GST Amount must be numeric.']],
            'stamp_duty.*'             => ['label' => 'Stamp Duty', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Stamp Duty must be numeric.']],
            'total.*'                  => ['label' => 'Total', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal'  => 'Total must be a numeric value.']],
            'agreed_bp.*'              => ['label' => 'Agreed BP %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Agreed BP % must be numeric.']],
            'agreed_tp.*'              => ['label' => 'Agreed TP %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Agreed TP % must be numeric.']],
            'agreed_ter.*'             => ['label' => 'Agreed TEP %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Agreed TEP % must be numeric.']],
            'agreed_amount.*'          => ['label' => 'Agreed Amount', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Agreed Amount must be numeric.']],
            'actual_bp_amt.*'          => ['label' => 'Actual BP Amount', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Actual BP Amount must be numeric.']],
            'actual_tp_amt.*'          => ['label' => 'Actual TP Amount', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Actual TP Amount must be numeric.']],
            'actual_tep_amt.*'         => ['label' => 'Actual TEP Amount', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Actual TEP Amount must be numeric.']],
            'actual_bp_per.*'          => ['label' => 'Actual BP %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Actual BP % must be numeric.']],
            'actual_tp_per.*'          => ['label' => 'Actual TP %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Actual TP % must be numeric.']],
            'actual_tep_per.*'         => ['label' => 'Actual TEP %', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'Actual TEP % must be numeric.']],
            'actual_bp_brokerage_amt.*' => ['label' => 'BP Remuneration', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'BP Remuneration must be numeric.']],
            'actual_tp_brokerage_amt.*' => ['label' => 'TP Remuneration', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'TP Remuneration must be numeric.']],
            'actual_tep_brokerage_amt.*' => ['label' => 'TEP Remuneration', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'TEP Remuneration must be numeric.']],
            'exp_amt.*'                => ['label' => 'Expected Amount', 'rules' => 'permit_empty|decimal', 'errors' => ['decimal' => 'The Expected Amount field must contain a valid number.']]
        ];

        $isCoShare = !empty($post_data['co_share']);
        $calcPolicyIssueDateRule = [
            'label'  => 'Policy Issue Date',
            'rules'  => 'required',
            'errors' => ['required' => 'Policy Issue Date is required'],
        ];

        if ($isCoShare) {
            $coShareTypes = $post_data['co_share_type'] ?? [];
            if (is_array($coShareTypes)) {
                foreach ($coShareTypes as $index => $type) {
                    if ((int) $type === 1) {
                        $rules["calc_policy_issue_date.$index"] = $calcPolicyIssueDateRule;
                    }
                }
            }
        } else {
            $rules['calc_policy_issue_date.*'] = $calcPolicyIssueDateRule;
        }

        if(isset($post_data['client_type']) && $post_data['client_type'] == 1){
            $rules['client_branch_id'] = ['label'  => 'Client Branch', 'rules'  => 'required', 'errors' => ['required' => 'Client branch is required']];
        }

        $isValid = $this->validate($rules);

        // $Date_of_commencement = $this->request->getPost('policy_start_date');
        // $Date_of_expiry   = $this->request->getPost('policy_end_date');

        // if ($Date_of_commencement && $Date_of_expiry && ($Date_of_expiry < $Date_of_commencement)) {
        //     $this->validator->setError('policy_end_date', '$Date of Commencement and Date of Expiry are mismatched (Date of Expiry cannot be before $Date of Commencement).');
        //     $isValid = false; 
        // }
        
        $start_dates = $this->request->getPost('policy_start_date');
        $end_dates   = $this->request->getPost('policy_end_date');

        if ($start_dates && $end_dates) {
            // Standardize: If it's a single string (Type 2), wrap it in an array
            $starts = is_array($start_dates) ? $start_dates : [$start_dates];
            $ends   = is_array($end_dates)   ? $end_dates   : [$end_dates];

            foreach ($starts as $index => $s_date) {
                $e_date = $ends[$index] ?? null;

                if ($s_date && $e_date) {
                    
                    $f_start = change_date_format($s_date, 'Y-m-d', 'Y-m-d'); // be carefully here we made so many times mistakes on here
                    $f_end   = change_date_format($e_date, 'Y-m-d', 'Y-m-d');// be carefully here we made so many times mistakes on here

                    if ($f_start && $f_end && ($f_end < $f_start)) {
                        $isValid = false;
                        
                        // Determine the error key name
                        // If it's an array, we use index (e.g., policy_end_date.0)
                        $errorKey = is_array($start_dates) ? "policy_end_date.$index" : "policy_end_date";
                        
                        $this->validator->setError($errorKey, 'D.O.E(Date of Expiry) cannot be before D.O.C(Date of Commencement).');
                    }
                }
            }
        }

        if (!$isValid) {
            return $this->response->setStatusCode(400)->setJSON([
                'status' => false,
                'message' => 'Input validation failed',
                'code' => 400,
                'errors' => $this->validator->getErrors()
            ]);
        }

        $post_data = $post_data ? sanitizeInputArrayAdvanced($post_data) : [];

        $this->myLogger->logme('error', 'Policy Trancaction form data : ' . json_encode($post_data));

        $id = $post_data['id'] ?? null;
        $data = $this->preparePolicyData();
        $data['cd_ac_pk'] = $post_data['cd_ac_no'];
        $data['issuer'] = 2;
        $data['status'] = 'completed';
        $this->myLogger->logme('error', 'Policy Trancaction modified form data ( insert data ) : ' . json_encode($data));


        if (!$id) {
            return $this->insertInceptionPolicy($data);
        } else {
            return $this->updateInceptionPolicy($id, $data);
        }
    }

    private function preparePolicyData()
    {
        $request_data = $this->request->getPost();
        $data = sanitizeInputArrayAdvanced($request_data);

        $file_data = $this->request->getFiles() ?? null;
        $data['file_data'] = $file_data ?? null;

        $vehicle_file_data = $this->request->getFiles() ?? null;
        $data['vehicle_file_data'] = $vehicle_file_data ?? null;

        // print_r($data); die;

        if (empty($data['policy_issue_date'])) {
            $data['policy_issue_date'] = null;
        }

        if (empty($data['policy_start_date'])) {
            $data['policy_start_date'] = null;
        }

        if (empty($data['policy_end_date'])) {
            $data['policy_end_date'] = null;
        }

        if (empty($data['renewal_date'])) {
            $data['renewal_date'] = null;
        }

        if (empty($data['rollover_date'])) {
            $data['rollover_date'] = null;
        }

        if (empty($data['last_action_date'])) {
            $data['last_action_date'] = null;
        } else {
            $data['last_action_date'] = change_date_format($data['last_action_date']);
        }

        // Separate Insurer and TPA Branch IDs and IDs
        if (isset($data['insurer_id']) && !empty($data['insurer_id'])) {
            list($data['insurer_branch_id'], $data['insurer_id']) = explode('-', $data['insurer_id']);
            if (isset($data['tpa']) && !empty($data['tpa'])) {
                list($data['tpa_branch_id'], $data['tpa_id']) = explode('-', $data['tpa']);
            }
        }

        $data['tsi'] = generate_tsi_code($data['issue_type']);
        $data['action_type'] = 'inception';

        if (!isset($data['co_share'])) {
            $data['co_share'] = 0;
        } elseif ($data['co_share']) {
            $data['co_share'] = 1;
        }

        if ($data['co_share'] == 1 && !empty($data['follow_insurer_id']) && is_array($data['follow_insurer_id'])) {
            foreach ($data['follow_insurer_id'] as $index => $followInsurer) {
                if (($data['co_share_type'][$index] ?? 2) == 1 && !empty($followInsurer)) {
                    list($data['insurer_branch_id'], $data['insurer_id']) = explode('-', $followInsurer);
                    break;
                }
            }
        }

        // if (!isset($data['bro_payable_by'])) {
        //     $data['bro_payable_by'] = 0;
        // } elseif ($data['bro_payable_by']) {
        //     $data['bro_payable_by'] = 1;
        // }

        if (!isset($data['same_as_proposer'])) {
            $data['same_as_proposer'] = 0;
        } elseif ($data['same_as_proposer']) {
            $data['same_as_proposer'] = 1;
        }

        if (!isset($data['policy_with_corr'])) {
            $data['policy_with_corr'] = 0;
        } elseif ($data['policy_with_corr']) {
            $data['policy_with_corr'] = 1;
        }

        $data['is_cd_reduce_from_bds'] = ($data['policy_type_id'] > 7 && $data['client_type'] == 1) ? 1 : 0;


        if ($data['ct_type'] == "") {
            $data['ct_type'] = 1;
        }

        // $month = '01-'.(string)$this->request->getPost('month');
        // $data['month'] = empty($data['month']) ? null : date('Y-m-d', strtotime($month));    

        // Determine $is_addon value
        $data['is_addon'] = in_array($data['policy_type_id'], [1, 2, 6, 7]) ? 1 : (in_array($data['policy_type_id'], [4, 5]) ? 2 : ($data['policy_type_id'] == 3 && isset($data['base_policy']) ? 3 : 1));

        // print_r($data); die;

        return $data;
    }

    private function insertInceptionPolicy($data)
    {
        // print_r($data); die;

        $insert = $this->policyTransactionModel->insert($data);

        if ($insert) {

            $this->insertTransactionStatus($insert, $data, 1);
            $emp_data = $this->processInsertIndividualMemberInEmpTable($data);

            if (isset($data['follow_insurer_id']) && !empty($data['follow_insurer_id'][0])) {

                $pt_co_share_details = $this->insertOrUpdateCoShareDetails($data, $insert);

                $client_policy_id = null;
                if ($data['ct_type'] == 2) {
                    $client_policy_insert_data = $this->prepareClientPolicyInsertData($data);
                    $client_policy_id = $this->clientPolicyModel->insert($client_policy_insert_data);
                    $this->policyTransactionModel->update($insert, ['client_policy_id' => $client_policy_id]);
                    $emp_policy_insert = $this->InsertIndividualEmpPolicyTable($emp_data, $client_policy_id);
                }

                if ($data['client_type'] == 1 && $data['status'] == 'completed' && $data['is_cd_reduce_from_bds'] == 1) {
                    $this->processCompletedStatus($data, $client_policy_id, $data['insurer_id'], $insert);
                }
            }

            // policy file upload 
            if(isset($data['doc_name']) && isset($data['file_data']) && !empty($data['doc_name']) && !empty($data['file_data'])){
                $this->uploadFile($data['doc_name'], $data['file_data'], $insert);
            }

            // policy file upload 
            if(
                isset($data['other_docs_name']) && isset($data['vehicle_file_data']) && isset($data['client_id']) && isset($data['vehicle_id']) && 
                !empty($data['other_docs_name']) && !empty($data['vehicle_file_data']) && !empty($data['client_id']) && !empty($data['vehicle_id'])
            )
            {
                $vdd = [
                    'other_docs_name' => $data['other_docs_name'],
                    'file_data' => $data['vehicle_file_data'],
                    'client_id' => $data['client_id'],
                    'vehicle_id' => $data['vehicle_id'],
                ];
                $clientController = new ClientController();
                $clientController->uploadVehicleFile($vdd);
            }
            

            $client_data = $this->clientModel->where('id', $data['client_id'])->first();
            $data['client_kyc'] = $this->clientKYCDocsModel->where('client_id',  $data['client_id'])->findAll();
            
            $clientController = new ClientController();
            $data['client_kyc_primary_table']  =  $clientController->generateKycPrimaryTable($data['client_id']);
            $data['client_kyc_other_table']  =  $clientController->generateKycOthersTable($data['client_id']);
            // $data['client_kyc_single_table']  =  $clientController->generateKycSingleTable($data['client_id']);
            $data['entity_type_id'] =  $client_data['entity_type_id'];

            return $this->respondSuccess($insert, "Policy transaction created successfully", $data);
        }

        return $this->respondError("Failed to create policy transaction");
    }

    private function updateInceptionPolicy($id, $data)
    {
        // print_r($data); die;
        $data['updated_by']  = get_session_userid();
        $old_pt_data = $this->policyTransactionModel->where('is_active', 1)->where("id", $id)->first();
        $old_pt_co_share_data = $this->PTCOShareDetailsModel->where('is_active', 1)->where("id", $id)->first();
        if ($this->policyTransactionModel->update($id, $data)) {

            if (!empty($old_pt_data) && isset($data['policy_no'])) {
                $this->updateRelatedPolicyTransactionPolicyNo(
                    (int) $id,
                    (string) ($old_pt_data['policy_no'] ?? ''),
                    (string) $data['policy_no']
                );
            }

            $this->insertTransactionStatus($id, $data, 1);
            $emp_data = $this->processInsertIndividualMemberInEmpTable($data);

            if (isset($data['follow_insurer_id']) && !empty($data['follow_insurer_id'][0])) {

                $this->insertOrUpdateCoShareDetails($data, $id);

                if ($data['ct_type'] == 1) {
                    $this->policyTransactionModel->update($id, ['client_policy_id' => $data['client_policy_id']]);
                }

                if (empty($data['client_policy_id']) || $data['client_policy_id'] == 0) {

                    if ($data['ct_type'] == 2) {
                        $client_policy_insert_data = $this->prepareClientPolicyInsertData($data);
                        $client_policy_id = $this->clientPolicyModel->insert($client_policy_insert_data);
                        $this->policyTransactionModel->update($id, ['client_policy_id' => $client_policy_id]);
                        $this->InsertIndividualEmpPolicyTable($emp_data, $client_policy_id);
                    }
                } else {
                    if (isset($data['emp_policy_id']) && !empty($data['emp_policy_id'][0])) {
                        $this->InsertIndividualEmpPolicyTable($emp_data, $data['client_policy_id']);
                    }
                }

                // if($old_pt_data['status'] != "completed"){
                //     if ($data['status'] == 'completed' && $data['ct_type'] == 2) {
                //         if ($data['client_type'] == 1 && $data['is_cd_reduce_from_bds'] == 1) {
                //             $this->processCompletedStatus($data, $data['client_policy_id'], $data['insurer_id'], $id);
                //         }
                //     }
                // }

                $data['pt_co_share_details'] = $this->PTCOShareDetailsModel->where('pt_id', $id)->where('is_active', 1)->findAll();
            }

            if(isset($data['cd_amt_changed']) && !empty($data['cd_amt_changed'])){
                $policy_data = $this->policyTransactionModel->where('is_active', 1)->where('id', $id)->first();
                $this->cdCorrection($policy_data, $data['cd_amt_changed'], $id);
            }

            $client_data = $this->clientModel->where('id', $data['client_id'])->first();
            $data['client_kyc']       = $this->clientKYCDocsModel->where('client_id',  $data['client_id'])->findAll();
            
            $clientController = new ClientController();
            $data['client_kyc_primary_table']  =  $clientController->generateKycPrimaryTable($data['client_id']);
            $data['client_kyc_other_table']  =  $clientController->generateKycOthersTable($data['client_id']);
            // $data['client_kyc_single_table']  =  $clientController->generateKycSingleTable($data['client_id']);

            $data['entity_type_id'] =  $client_data['entity_type_id'];

            return $this->respondSuccess($id, "Policy transaction updated successfully", $data);
        }

        return $this->respondError("Failed to update policy transaction");
    }

    /**
     * Sync policy_no on related policy_transaction rows when inception policy number changes.
     */
    private function updateRelatedPolicyTransactionPolicyNo(
        int $inceptionPtId,
        string $oldPolicyNo,
        string $newPolicyNo
    ): array {
        $oldPolicyNo = trim($oldPolicyNo);
        $newPolicyNo = trim($newPolicyNo);

        if ($oldPolicyNo === '' || $newPolicyNo === '' || $oldPolicyNo === $newPolicyNo) {
            return ['status' => false, 'message' => 'No policy number change detected', 'updated_ids' => []];
        }

        $relatedRecords = $this->policyTransactionModel
            ->where('is_active', 1)
            ->where('id !=', $inceptionPtId)
            ->where('policy_no', $oldPolicyNo)
            ->findAll();

        if (empty($relatedRecords)) {
            return ['status' => true, 'message' => 'No related policy transactions found', 'updated_ids' => []];
        }

        $updatedIds = [];
        $updatedBy = get_session_userid();

        foreach ($relatedRecords as $record) {
            $this->policyTransactionModel
                ->where('id', $record['id'])
                ->set(['policy_no' => $newPolicyNo, 'updated_by' => $updatedBy])
                ->update();

            if ($this->policyTransactionModel->affectedRows() > 0) {
                $updatedIds[] = $record['id'];
            }
        }

        $this->myLogger->logme('error', 'Updated policy_no on related policy_transaction records: ' . json_encode([
            'inception_pt_id' => $inceptionPtId,
            'old_policy_no' => $oldPolicyNo,
            'new_policy_no' => $newPolicyNo,
            'updated_ids' => $updatedIds,
        ]));

        return [
            'status' => true,
            'message' => 'Related policy transaction policy numbers updated',
            'updated_ids' => $updatedIds,
        ];
    }

    private function insertOrUpdateCoShareDetails($data, $pt_id)
    {
        // Prepare data for insertion and updating
        $coShareDetails = [];
        if (isset($data['co_share_id']) && !empty($data['co_share_id'])) {
            $this->removePtCoShareRecords($data['co_share_id'], $pt_id);
        }

        if (isset($data['follow_insurer_id'])) {

            foreach ($data['follow_insurer_id'] as $index => $insurer) {

                // Separate the insurer and insurer branch
                if (isset($insurer) && !empty($insurer)) {
                    list($insurer_branch_id, $insurer_id) = explode('-', $insurer);
                } else {
                    $insurer_branch_id = null;
                    $insurer_id = null;
                }

                if ($data['bro_payable_by'] == 1) {
                    $cop_amt = isset($data['co_premium'][$index]) && ($data['co_premium'][$index] != "0.00" && !empty($data['co_premium'][$index])) ? $data['co_premium'][$index] : ($data['base_premium'][$index] ?? 0);
                    // print_r($cop_amt);die();
                } else {
                    $cop_amt = $data['co_premium'][$index] ?? 0;
                }

                if(isset($data['calc_policy_issue_date'][$index])){
                    $data['calc_policy_issue_date'][$index] = change_date_format($data['calc_policy_issue_date'][$index]);
                }

                $co_share_type_value = (($data['co_share'] ?? 0) == 1) ? ($data['co_share_type'][$index] ?? 1) : 1;

                // Prepare each co-share detail entry
                $coShareDetails[] = [
                    'pt_id' => $pt_id,
                    'insurer_id' => $insurer_id ?? 0,
                    'insurer_branch_id' => $insurer_branch_id ?? 0,
                    'co_share_type' => $co_share_type_value,
                    'co_share_per' => $data['co_share_per'][$index] ?? 0,
                    'bp_amt' => $data['base_premium'][$index] ?? 0,
                    'bp_gst_amt' => $data['gst_amount'][$index] ?? 0,
                    'bp_igst' => $data['igst'][$index] ?? 0,
                    'bp_sgst' => $data['sgst'][$index] ?? 0,
                    'bp_cgst' => $data['cgst'][$index] ?? 0,
                    'tp_amt' => $data['tp_premium'][$index] ?? 0,
                    'tep_amt' => $data['ter_premium'][$index] ?? 0,
                    'cotp_amt' => $data['co_tp_premium'][$index] ?? 0,
                    'cotep_amt' => $data['co_ter_premium'][$index] ?? 0,
                    'agreed_amt' => $data['agreed_amount'][$index] ?? 0,
                    'agreed_bp_per' => $data['agreed_bp'][$index] ?? 0,
                    'agreed_tp_per' => $data['agreed_tp'][$index] ?? 0,
                    'agreed_tep_per' => $data['agreed_ter'][$index] ?? 0,
                    'standerd_bp_per' => $data['standard_bp'][$index] ?? 0,
                    'standerd_tp_per' => $data['standard_tp'][$index] ?? 0,
                    'standerd_tep_per' => $data['standard_ter'][$index] ?? 0,
                    'actual_bp_amt' => $data['actual_bp_amt'][$index] ?? 0,
                    'actual_tp_amt' => $data['actual_tp_amt'][$index] ?? 0,
                    'actual_tep_amt' => $data['actual_tep_amt'][$index] ?? 0,
                    'actual_bp_per' => $data['actual_bp_per'][$index] ?? 0,
                    'actual_tp_per' => $data['actual_tp_per'][$index] ?? 0,
                    'actual_tep_per' => $data['actual_tep_per'][$index] ?? 0,
                    'actual_bp_brokerage_amt' => $data['actual_bp_brokerage_amt'][$index] ?? 0,
                    'actual_tp_brokerage_amt' => $data['actual_tp_brokerage_amt'][$index] ?? 0,
                    'actual_tep_brokerage_amt' => $data['actual_tep_brokerage_amt'][$index] ?? 0,
                    'exp_amt' => isset($data['exp_amt'][$index]) && !empty($data['exp_amt'][$index]) ? $data['exp_amt'][$index] : expected_amount_calc($data, $index),
                    'amount' => $data['total'][$index] ?? 0,
                    'stamp_duty' => $data['stamp_duty'][$index] ?? 0,
                    'cop_amt' => $cop_amt,
                    'variance' => $data['variance'][$index] ?? 0,
                    'reward' => $data['reward'][$index] ?? null,
                    'created_by' => get_session_userid() ?? null,
                    'updated_by' => get_session_userid() ?? null,
                    'id' => $data['co_share_id'][$index] ?? null, // Assuming this is the ID to identify existing records
                    'follower_policy_no' => $data['follower_policy_no'][$index] ?? null,
                    'non_comm_per_amt' => $data['non_comm_per_amt'][$index] ?? null,
                    'pt_policy_issue_date' => $data['calc_policy_issue_date'][$index] ?? null,
                ];
            }

            // print_r($pt_id); 
            // print_r($coShareDetails); 
            // die;

            // Separate data into insert and update batches
            $insertData = array_filter($coShareDetails, function ($detail) {
                return empty($detail['id']); // Only insert new records
            });

            $updateData = array_filter($coShareDetails, function ($detail) {
                return !empty($detail['id']); // Only update existing records
            });

            // Insert new records
            if (!empty($insertData)) {
                $this->PTCOShareDetailsModel->insertBatch($insertData);
            }

            // Update existing records
            if (!empty($updateData)) {
                $this->PTCOShareDetailsModel->updateBatch($updateData, 'id'); // Assuming 'id' is the unique identifier
            }

            // print_r($this->PTCOShareDetailsModel->getLastQuery()); die;
            // print_r($coShareDetails); 
            // die;

            return true;
        }

        // print_r($data); 
        // die;
    }

    private function prepareClientPolicyInsertData($data)
    {
        return [
            'client_id' => $data['client_id'] ?? null,
            'insurer_id' => $data['insurer_id'] ?? null,
            'insurer_branch_id' => $data['insurer_branch_id'] ?? null,
            'tpa_id' => $data['tpa_id'] ?? null,
            'tpa_branch_id' => $data['tpa_branch_id'] ?? null,
            'policy_type_id' => $data['policy_type_id'] ?? null,
            'policy_start_date' => $data['policy_start_date'] ?? null,
            'policy_end_date' => $data['policy_end_date'] ?? null,
            'policy_status' => 1,
            'is_addon' => $data['is_addon'] ?? null,
            'base_policy' => $data['base_policy'] ?? 0,
            'created_by' => get_session_userid(),
            'policy_no' => $data['policy_no'] ?? null,
            'client_branch_id' => $data['client_branch_id'] ?? 0,
            'cd_ac_pk' => $data['cd_ac_no'] ?? null,
            'gst' => 18,
            'policy_entry_from' => 2,
        ];
    }

    private function insertTransactionStatus($policyTranId, $data, $statusType)
    {
        $statusData = [
            'policy_tran_id' => $policyTranId,
            'status' => $data['status'],
            'last_action_date' => $data['last_action_date'],
            'status_type' => $statusType,
            'created_by' => get_session_userid(),
        ];
        $this->policyTransactionStatusModel->insert($statusData);
    }

    private function processCompletedStatus($data, $client_policy_id, $insurer_id, $policyTranId)
    {
        $totalAmount = (int)$data['total'][0] ?? 0;
        $description = 'The following amount of Rs. ' . $totalAmount . '/- has been debited for the ' . $data['emp_count'] . ' employees at Inception (BDS).';

        $cdTransactionData = [
            'amount' => $totalAmount,
            'sub_type_id' => 4,
            'client_id' => $data['client_id'],
            'client_policy_id' => $client_policy_id ?? 0,
            'endorsement_no' => null,
            'cd_ac_no' => $data['cd_ac_no'] ?? null,
            'insurer_id' => $insurer_id,
            'description' => $description,
            'transaction_type' => 'Debit',
            'updated_by' => get_session_userid(),
            'event_name' => 'inception',
            'is_active' => 1,
            'cd_ac_pk'  => $data['cd_ac_pk'],
            'pt_id' => $policyTranId ?? null,
        ];

        $result = DepositHelper::saveDeposit($cdTransactionData, get_session_userid());

        if(isset($result) && $result['success'] == true){
            $update_data['ct_tran_id'] = $result['insert_id'];
            $this->policyTransactionModel->where('id', $policyTranId)->set($update_data)->update();
        }
    }

    private function cdCorrection($data, $amt, $policyTranId)
    {
        $totalAmount = (int)($amt ?? 0);
        $description = 'The following amount of Rs. ' . $totalAmount . '/- has been debited towards the difference arising from the change in the BDS base premium.';

        $cdTransactionData = [
            'amount' => abs($totalAmount),
            'sub_type_id' => 4,
            'client_id' => $data['client_id'],
            'client_policy_id' => $data['client_policy_id'] ?? 0,
            'endorsement_no' => null,
            'cd_ac_no' => $data['cd_ac_no'] ?? null,
            'insurer_id' => $data['insurer_id'],
            'description' => $description,
            'transaction_type' => $totalAmount < 0 ? 'Credit' : 'Debit',
            'updated_by' => get_session_userid(),
            'event_name' => 'inception',
            'is_active' => 1,
            'cd_ac_pk'  => $data['cd_ac_pk'],
            'pt_id' => $policyTranId ?? null,
        ];

        DepositHelper::saveDeposit($cdTransactionData, get_session_userid());
    }

    private function processInsertIndividualMemberInEmpTable($data)
    {
        // print_r($data);
        if (isset($data['family_name']) && !empty($data['family_name'])) {

            $emp_data = [];
            $emp_ids = [];
            $random_code = generateRandomCode(); // Generate random code once

            foreach ($data['family_name'] as $index => $val) {

                // Determine the gender based on the relationship
                $relationship = $data['relationship'][$index] ?? '';
                $gender = 'M'; // Default to Male

                // Set gender based on relationship
                if (in_array($relationship, ['Mother', 'Daughter', 'Mother in law', 'Spouse'])) {
                    $gender = 'F';
                }

                $emp_data[] = [
                    'client_id' => $data['client_id'] ?? 0,
                    'client_branch_id' => $data['client_branch_id'] ?? 0,
                    'name' => $val,
                    'relationship' => $relationship,
                    'gender' => $gender,
                    'emp_status' => 'active',
                    'created_by' => get_session_userid(),
                    'emp_code' => $random_code, // Use the same random code for all
                    'id' => $data['emp_id'][$index] ?? null
                ];

                $emp_ids[] = $data['emp_id'][$index] ?? 0;
            }


            // print_r($emp_data); die;

            // Separate data into insert and update batches
            $insertData = array_filter($emp_data, function ($detail) {
                return empty($detail['id']); // Only insert new records
            });

            $updateData = array_filter($emp_data, function ($detail) {
                return !empty($detail['id']); // Only update existing records
            });

            // Insert new records
            if (!empty($insertData)) {
                $this->employeeModel->insertBatch($insertData);
            }

            // Update existing records
            if (!empty($updateData)) {
                $this->employeeModel->updateBatch($updateData, 'id'); // Assuming 'id' is the unique identifier
            }

            return $emp_ids;
        }
    }

    private function InsertIndividualEmpPolicyTable($emp_ids, $client_policy_id)
    {
        if (!empty($emp_ids)) {

            $emp_policy_data = [];

            foreach ($emp_ids as $index => $emp_id) {

                $emp_policy_data[] = [
                    'employee_id' => $emp_id ?? 0,
                    'client_policy_id' => $client_policy_id ?? 0,
                    'created_by' => get_session_userid(),
                    'status' => 'active',
                ];
            }

            // print_r($emp_policy_data); die;

            // Insert new records
            if (!empty($emp_policy_data)) {
                $this->employeePolicyModel->insertBatch($emp_policy_data);
            }


            return true;
        }
    }

    private function respondSuccess($id, $message, $data)
    {
        return $this->respond(['status' => true, 'pt_id' => $id, 'message' => $message, 'data' => $data], 200);
    }

    private function respondError($message)
    {
        return $this->respond(['status' => false, 'message' => $message], 200);
    }
    // policy Transaction Create function End

    // Get the Single Inception Tranction data for edit
    public function getInceptionDataForEdit($id)
    {
        $data = $this->policyTransactionModel
            ->select('
                        policy_transaction.*, 
                        clients.short_name as client_short_name, 
                        clients.client_type, 
                        clients.entity_type_id, 
                        policy_type.policy_type,
                        client_policy.tpa_id as master_tpa_id,
                        client_policy.tpa_branch_id as master_tpa_branch_id,
                        client_policy.policy_type_id as master_policy_type_id,
                        client_policy.is_addon,
                        client_policy.base_policy,
                        ( 
                            select last_action_date
                            from policy_transaction_status
                            where policy_tran_id = policy_transaction.id
                            and status = policy_transaction.status
                            order by id desc
                            limit 1

                        ) as last_action_date
                    ')
            ->join('clients', 'clients.id = policy_transaction.client_id')
            ->join('client_policy', 'policy_transaction.client_policy_id = client_policy.id', 'left')
            ->join('policy_type', 'client_policy.policy_type_id = policy_type.id', 'left')
            ->where('policy_transaction.id', $id)
            ->where('policy_transaction.is_active', 1)
            ->first();

        $data['created_at'] = (isset($data['created_at']) && $data['created_at'] !== null && $data['created_at'] !== '')
            ? date('d/m/Y h:i:s A', strtotime($data['created_at']))
            : null;

        $data['updated_at'] = (isset($data['updated_at']) && $data['updated_at'] !== null && $data['updated_at'] !== '')
            ? date('d/m/Y h:i:s A', strtotime($data['updated_at']))
            : null;


        if (!empty($data['policy_issue_date'])) {
            $data['policy_issue_date'] =  change_date_format($data['policy_issue_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_start_date'])) {
            $data['policy_start_date'] =  change_date_format($data['policy_start_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_end_date'])) {
            $data['policy_end_date'] =  change_date_format($data['policy_end_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['renewal_date'])) {
            $data['renewal_date'] =  change_date_format($data['renewal_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['rollover_date'])) {
            $data['rollover_date'] =  change_date_format($data['rollover_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['endorse_eff_date'])) {
            $data['endorse_eff_date'] =  change_date_format($data['endorse_eff_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['last_action_date'])) {
            $data['last_action_date'] =  change_date_format($data['last_action_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['month'])) {
            $data['month'] =  change_date_format($data['month'], 'Y-m-d', 'M/Y');
        } else {
            $data['month'] = null;
        }

        // print_r($data); die;

        $data['renewal_policy'] = $this->clientPolicyModel
            ->select('client_policy.*, policy_type.policy_type')
            ->join('policy_type', 'policy_type.id = client_policy.policy_type_id')
            ->where('client_policy.client_id', $data['client_id'])
            ->where('client_policy.client_branch_id', $data['client_branch_id'])
            ->where('client_policy.is_active', 1)
            ->findAll();

        $data['base_policy_data'] = $this->clientPolicyModel
            ->select('client_policy.*, policy_type.policy_type')
            ->join('policy_type', 'policy_type.id = client_policy.policy_type_id')
            ->where('client_policy.client_id', $data['client_id'])
            ->where('client_policy.client_branch_id', $data['client_branch_id'])
            ->whereIn('client_policy.policy_type_id', [2, 3])
            ->where('client_policy.is_active', 1)
            ->findAll();

        $pt_bp_amt = $this->PTCOShareDetailsModel
            ->select('bp_amt, amount')
            ->where('pt_id', $id)
            ->where('co_share_type', 1)
            ->where('is_active', 1)
            ->first();

        // dd(db_connect()->getLastQuery() ,$pt_bp_amt);
        $data['base_cd_amount'] = $pt_bp_amt['amount'] ?? null;


        $ptFileQuery = $this->PTFileModel
            ->select('pt_files.*')
            ->join('policy_transaction', 'pt_files.pt_id = policy_transaction.id')
            ->where('pt_files.pt_id', $id)
            ->where('pt_files.is_active', 1);

        if (!in_array(get_role_id(), [1, 5]) && empty(array_intersect(user_team(), [MANAGEMENT_TEAM_ID, FINANCE_TEAM_ID, BUSINESS_TEAM_ID]))) {

            if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) {
                $ptFileQuery->where('pt_files.created_by', get_session_userid());
            }
        }

        $data['pt_files'] = $ptFileQuery->findAll();



        $data['pt_co_share_details'] = $this->PTCOShareDetailsModel
            ->select("
                    pt_co_share_details.*,
            
                    (
                        SELECT
                            COUNT(*)
                        FROM
                            co_share_stmt_details
                        WHERE
                            co_share_stmt_details.co_share_id = pt_co_share_details.id
                            AND co_share_stmt_details.is_active = 1
                    ) AS record_count,

                        (
                            SELECT 
                                SUM(actual_bp_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_bp_amount,
                        
                        (
                            SELECT 
                                SUM(actual_tp_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tp_amount,
                        
                        (
                            SELECT 
                                SUM(actual_tep_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tep_amount,
                        
                        (
                            SELECT 
                                SUM(actual_bp_per) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_bp_percentage,
                        
                        (
                            SELECT 
                                SUM(actual_tp_per) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tp_percentage,
                        
                        (
                            SELECT 
                                SUM(actual_tep_per) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tep_percentage,
                        
                        
                        (
                            SELECT 
                                SUM(actual_bp_brokerage_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_bp_brokerage_amount,
                        
                        
                        (
                            SELECT 
                                SUM(actual_tp_brokerage_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tp_brokerage_amount,
                        
                        
                        (
                            SELECT 
                                SUM(actual_tep_brokerage_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tep_brokerage_amount,

                        DATE_FORMAT(pt_policy_issue_date, '%d/%m/%Y') AS pt_policy_issue_date

                ")
            ->where('pt_id', $id)
            ->where('is_active', 1)
            ->orderBy('id', 'asc')
            ->findAll();

        $data['emp_data'] = $this->employeeModel
            ->select('employees.*, employee_polices.id as emp_policy_id')
            ->join('employee_polices', 'employees.id = employee_polices.employee_id', 'left')
            ->where('employees.client_id', $data['client_id'])
            ->where('employees.is_active', 1)->findAll();
        // $data['client_kyc']   = $this->clientKYCDocsModel->where('client_id',  $data['client_id'])->findAll();

        $clientController = new ClientController();
        $data['client_kyc_primary_table']  =  $clientController->generateKycPrimaryTable($data['client_id']);
        $data['client_kyc_other_table']  =  $clientController->generateKycOthersTable($data['client_id']);
        $data['client_kyc_single_table']  =  $clientController->generateKycSingleTable($data['client_id']);
        $data['client_kyc_dd_data']  = $clientController->fetch_dropdown($data['client_id']);

        $data['vehicle_docs'] = $this->clientKYCDocsModel
            ->where('client_id',  $data['client_id'])
            ->where('vehicle_id', $data['vehicle_id'])
            ->findAll();

        // print_r( $data['pt_co_share_details']); die;
        // return $data;
        if ($data) {
            return $this->respond(['status' => true, 'data' => $data], 200);
        } else {
            return $this->respond(['status' => false], 200);
        }
    }

    // Get the Single Inception Tranction data for edit
    public function getInceptionDataForEdit2($id)
    {
        $data = $this->policyTransactionModel
            ->select('
                        policy_transaction.*, 
                        clients.short_name as client_short_name, 
                        clients.client_type, 
                        clients.entity_type_id, 
                        policy_type.policy_type,
                        client_policy.tpa_id as master_tpa_id,
                        client_policy.tpa_branch_id as master_tpa_branch_id,
                        client_policy.policy_type_id as master_policy_type_id,
                        client_policy.is_addon,
                        client_policy.base_policy,
                        ( 
                            select last_action_date
                            from policy_transaction_status
                            where policy_tran_id = policy_transaction.id
                            and status = policy_transaction.status
                            order by id desc
                            limit 1

                        ) as last_action_date
                    ')
            ->join('clients', 'clients.id = policy_transaction.client_id')
            ->join('client_policy', 'policy_transaction.client_policy_id = client_policy.id', 'left')
            ->join('policy_type', 'client_policy.policy_type_id = policy_type.id', 'left')
            ->where('policy_transaction.id', $id)
            ->where('policy_transaction.is_active', 1)
            ->first();

        $data['created_at'] = (isset($data['created_at']) && $data['created_at'] !== null && $data['created_at'] !== '')
            ? date('d/m/Y h:i:s A', strtotime($data['created_at']))
            : null;

        $data['updated_at'] = (isset($data['updated_at']) && $data['updated_at'] !== null && $data['updated_at'] !== '')
            ? date('d/m/Y h:i:s A', strtotime($data['updated_at']))
            : null;


        if (!empty($data['policy_issue_date'])) {
            $data['policy_issue_date'] =  change_date_format($data['policy_issue_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_start_date'])) {
            $data['policy_start_date'] =  change_date_format($data['policy_start_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_end_date'])) {
            $data['policy_end_date'] =  change_date_format($data['policy_end_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['renewal_date'])) {
            $data['renewal_date'] =  change_date_format($data['renewal_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['rollover_date'])) {
            $data['rollover_date'] =  change_date_format($data['rollover_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['endorse_eff_date'])) {
            $data['endorse_eff_date'] =  change_date_format($data['endorse_eff_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['last_action_date'])) {
            $data['last_action_date'] =  change_date_format($data['last_action_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['month'])) {
            $data['month'] =  change_date_format($data['month'], 'Y-m-d', 'M/Y');
        } else {
            $data['month'] = null;
        }

        // print_r($data); die;

        $data['renewal_policy'] = $this->clientPolicyModel
            ->select('client_policy.*, policy_type.policy_type')
            ->join('policy_type', 'policy_type.id = client_policy.policy_type_id')
            ->where('client_policy.client_id', $data['client_id'])
            ->where('client_policy.client_branch_id', $data['client_branch_id'])
            ->where('client_policy.is_active', 1)
            ->findAll();

        $data['base_policy_data'] = $this->clientPolicyModel
            ->select('client_policy.*, policy_type.policy_type')
            ->join('policy_type', 'policy_type.id = client_policy.policy_type_id')
            ->where('client_policy.client_id', $data['client_id'])
            ->where('client_policy.client_branch_id', $data['client_branch_id'])
            ->whereIn('client_policy.policy_type_id', [2, 3])
            ->where('client_policy.is_active', 1)
            ->findAll();

        $pt_bp_amt = $this->PTCOShareDetailsModel
            ->select('bp_amt, amount')
            ->where('pt_id', $id)
            ->where('co_share_type', 1)
            ->where('is_active', 1)
            ->first();

        // dd(db_connect()->getLastQuery() ,$pt_bp_amt);
        $data['base_cd_amount'] = $pt_bp_amt['amount'] ?? null;


        $ptFileQuery = $this->PTFileModel
            ->select('pt_files.*')
            ->join('policy_transaction', 'pt_files.pt_id = policy_transaction.id')
            ->where('pt_files.pt_id', $id)
            ->where('pt_files.is_active', 1);

        if (!in_array(get_role_id(), [1, 5]) && empty(array_intersect(user_team(), [MANAGEMENT_TEAM_ID, FINANCE_TEAM_ID, BUSINESS_TEAM_ID]))) {

            if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) {
                $ptFileQuery->where('pt_files.created_by', get_session_userid());
            }
        }

        $data['pt_files'] = $ptFileQuery->findAll();



        $data['pt_co_share_details'] = $this->PTCOShareDetailsModel
            ->select("
                    pt_co_share_details.*,
            
                    (
                        SELECT
                            COUNT(*)
                        FROM
                            co_share_stmt_details
                        WHERE
                            co_share_stmt_details.co_share_id = pt_co_share_details.id
                            AND co_share_stmt_details.is_active = 1
                    ) AS record_count,

                        (
                            SELECT 
                                SUM(actual_bp_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_bp_amount,
                        
                        (
                            SELECT 
                                SUM(actual_tp_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tp_amount,
                        
                        (
                            SELECT 
                                SUM(actual_tep_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tep_amount,
                        
                        (
                            SELECT 
                                SUM(actual_bp_per) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_bp_percentage,
                        
                        (
                            SELECT 
                                SUM(actual_tp_per) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tp_percentage,
                        
                        (
                            SELECT 
                                SUM(actual_tep_per) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tep_percentage,
                        
                        
                        (
                            SELECT 
                                SUM(actual_bp_brokerage_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_bp_brokerage_amount,
                        
                        
                        (
                            SELECT 
                                SUM(actual_tp_brokerage_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tp_brokerage_amount,
                        
                        
                        (
                            SELECT 
                                SUM(actual_tep_brokerage_amt) 
                            FROM 
                                co_share_stmt_details 
                            WHERE 
                                co_share_id = pt_co_share_details.id 
                                AND is_active = 1
                                
                        ) AS actual_tep_brokerage_amount,

                        DATE_FORMAT(pt_policy_issue_date, '%d/%m/%Y') AS pt_policy_issue_date

                ")
            ->where('pt_id', $id)
            ->where('is_active', 1)
            ->orderBy('id', 'asc')
            ->findAll();

        $data['emp_data'] = $this->employeeModel
            ->select('employees.*, employee_polices.id as emp_policy_id')
            ->join('employee_polices', 'employees.id = employee_polices.employee_id', 'left')
            ->where('employees.client_id', $data['client_id'])
            ->where('employees.is_active', 1)->findAll();
        // $data['client_kyc']   = $this->clientKYCDocsModel->where('client_id',  $data['client_id'])->findAll();

        $clientController = new ClientController();
        $data['client_kyc_primary_table']  =  $clientController->generateKycPrimaryTable($data['client_id']);
        $data['client_kyc_other_table']  =  $clientController->generateKycOthersTable($data['client_id']);
        $data['client_kyc_single_table']  =  $clientController->generateKycSingleTable($data['client_id']);
        $data['client_kyc_dd_data']  = $clientController->fetch_dropdown($data['client_id']);

        $data['vehicle_docs'] = $this->clientKYCDocsModel
            ->where('client_id',  $data['client_id'])
            ->where('vehicle_id', $data['vehicle_id'])
            ->findAll();

        // print_r( $data['pt_co_share_details']); die;
        // return $data;
        if ($data) {
            return $this->respond(['status' => true, 'data' => $data], 200);
        } else {
            return $this->respond(['status' => false], 200);
        }
    }

    public function removePolicyTransaction($id, $type = 0)
    {   
        if ($id) {
            $data['is_active']  = 0;
            $data['updated_by']  = get_session_userid();
            $policy_transaction_data = $this->policyTransactionModel->where('id', $id)->first();
            if($policy_transaction_data['policy_type_id'] > 7 && $type == 0){

                $this->policyTransactionModel->where('id', $id)->set($data)->update();
                $this->PTCOShareDetailsModel->where('pt_id', $id)->set($data)->update();
                $this->clientPolicyModel->where('id', $policy_transaction_data['client_policy_id'])->set($data)->update();
                $this->policyTransactionModel->where('client_policy_id', $policy_transaction_data['client_policy_id'])->set($data)->update();

                $cd_transaction_model = new ClientDepositModel();
                $cd_transaction_model->where('policy_transaction_id', $id)->set($data)->update();

            }else{
                $this->policyTransactionModel->where('id', $id)->set($data)->update();
                $this->PTCOShareDetailsModel->where('pt_id', $id)->set($data)->update();
                
                $cd_transaction_model = new ClientDepositModel();
                $cd_transaction_model->where('policy_transaction_id', $id)->set($data)->update();

            }
            return $this->respond(['status' => true, 'code' => 200, 'message' => 'Policy Transaction removed successfully'], 200);
        } else {

            return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to remove policy transaction'], 200);
        }
    }

    //function for soft delete for pt_co_share_details records
    public function removePtCoShareRecords($primaryKeys, $pt_id)
    {
        if (empty($primaryKeys)) {
            return false;
        }

        // Convert array to a comma-separated string of placeholders for query binding
        $placeholders = implode(',', array_fill(0, count($primaryKeys), '?'));

        // Prepare the query with proper binding
        $sql = "UPDATE pt_co_share_details SET is_active = 0 WHERE pt_id = ? AND id NOT IN ($placeholders)";

        // Merge pt_id with primary keys for binding
        $params = array_merge([$pt_id], $primaryKeys);

        // Execute the query with bound parameters
        return db_connect()->query($sql, $params);
    }


    //------------------------------------------------------------------------------------------------

    // Policy Transaction Endorsement
    public function viewEndorsement()
    {
        // echo '
';
        // !dd($this->getEndorsementDataForEdit(17));
        $bds_edit_pt_id = $this->request->getGet('pt_id') ?? null;
        $data['tab_name'] = 'Endorsement';
        $data['page_name'] = 'Endorsement';
        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['issuer_branch'] = $this->nhanceBranchModel->where('is_active', 1)->findAll();
        $data['client_type'] = [1 => 'Group', 2 => 'Individual'];

        $data['policy_status'] = [
            'under_process' => 'Under Process',
            'client_pending' => 'Client Pending',
            'insurer_pending' => 'Insurer Pending',
            'co_insurer_pending' => 'Co-Insurer Pending',
            'tpa_pending' => 'TPA Pending',
            'validated' => 'Validated',
            'cancelled' => 'Cancelled',
            'instalment_pending' => 'Instalment Pending',
            'completed' => 'Completed',
        ];

        $data['invoice_status'] = [
            'yet_to_generate' => 'Pending',
            'generated' => 'Generated',
            'send' => 'Sent',
            'recived' => 'Payment Received',
        ];

        $data['action_type'] = [
            'addition' => 'Addition',
            'deletion' => 'Deletion',
            'addition_deletion' => 'Addition & Deletion',
            'si_enhancement' => 'SI Enhancement',
            'combo_a_d_si' => 'Combo A, D & SI',
            'correction' => 'Correction',
            'baby_addition' => 'Baby Addition',
            'policy_instalment' => 'Policy Instalment',
            'addition_inception' => 'Addition-Inception',
            'bds_correction' => 'BDS Correction',
            'policy_correction' => 'Policy Correction',
            'policy_cancellation' => 'Policy Cancellation',
        ];

        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
        ];

        $data['endorsement_data_list'] = [];
        $data['endorsement_filters']   = $this->buildEndorsementFiltersFromRequest();
        $data['client'] = $this->clientModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();

        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        // $data['tpa']           = $this->tpaModel->where('is_active', 1)->findAll();
        $data['insurer_branch']      = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames();
        $data['tpa']           = $this->tpaBranchModel->getTpaBranchesWithTpaNames();
        list($policyList, $policyListByClient) = $this->getPolicyForEndorsment();

        $data['endorsementPolicies'] = $policyList;
        $data['endorsementPolicyListByClient'] = $policyListByClient;

        // dd($data);
        // print_r($data['endorsementPolicies']);die();

        $this->loadLayout('policy_transaction_endorsement_list', $data);
    }

    public function endorsementListDataTable()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setStatusCode(400)->setJSON([
                'status'  => false,
                'message' => 'Invalid request.',
            ]);
        }

        $draw   = (int) ($this->request->getPost('draw') ?? 0);
        $start  = max(0, (int) ($this->request->getPost('start') ?? 0));
        $length = (int) ($this->request->getPost('length') ?? 10);
        $search = trim((string) ($this->request->getPost('search')['value'] ?? ''));

        $filters = $this->buildEndorsementFiltersFromRequest();
        $result  = $this->policyTransactionModel->getEndorsementTranctionListDataTable(
            $draw,
            $start,
            $length,
            $search,
            $filters
        );

        $rows = [];
        foreach ($result['data'] as $index => $row) {
            $rows[] = $this->formatEndorsementRowForDataTable($row, $start + $index + 1);
        }

        return $this->response->setJSON([
            'draw'            => $result['draw'],
            'recordsTotal'    => $result['recordsTotal'],
            'recordsFiltered' => $result['recordsFiltered'],
            'data'            => $rows,
            'cache_expires_in_ms' => $result['cache_expires_in_ms'] ?? 300000,
        ]);
    }

    public function clearEndorsementListCache()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setStatusCode(400)->setJSON([
                'status'  => false,
                'message' => 'Invalid request.',
            ]);
        }

        session()->set('endorsement_list_cache_version', time());

        return $this->response->setJSON([
            'status'  => true,
            'message' => 'Endorsement list cache cleared.',
        ]);
    }

    protected function buildEndorsementFiltersFromRequest(): array
    {
        $normalize = static function ($value) {
            return (!isset($value) || $value === '' || $value === null) ? 0 : $value;
        };

        return [
            'start_date'     => $normalize($this->request->getGet('start_date') ?? $this->request->getPost('start_date')),
            'end_date'       => $normalize($this->request->getGet('end_date') ?? $this->request->getPost('end_date')),
            'client_id'      => $normalize($this->request->getGet('client_id') ?? $this->request->getPost('client_id')),
            'insurer_id'     => $normalize($this->request->getGet('insurer_id') ?? $this->request->getPost('insurer_id')),
            'policy_type_id' => $normalize($this->request->getGet('policy_type_id') ?? $this->request->getPost('policy_type_id')),
            'date_type'      => $normalize($this->request->getGet('date_type') ?? $this->request->getPost('date_type')),
            'issuer'         => $normalize($this->request->getGet('issuer') ?? $this->request->getPost('issuer')),
            'status'         => $normalize($this->request->getGet('status') ?? $this->request->getPost('status')),
            'cache_version'  => (int) (session()->get('endorsement_list_cache_version') ?? 1),
        ];
    }

    protected function formatEndorsementRowForDataTable(array $row, int $serialNo): array
    {
        $issuerMap = [1 => 'JIBS', 2 => 'Nhance'];
        $policyStatusMap = [
            'under_process' => 'Under Process',
            'client_pending' => 'Client Pending',
            'insurer_pending' => 'Insurer Pending',
            'co_insurer_pending' => 'Co-Insurer Pending',
            'tpa_pending' => 'TPA Pending',
            'validated' => 'Validated',
            'cancelled' => 'Cancelled',
            'instalment_pending' => 'Instalment Pending',
            'completed' => 'Completed',
        ];
        $actionTypeMap = [
            'addition' => 'Addition',
            'deletion' => 'Deletion',
            'addition_deletion' => 'Addition & Deletion',
            'si_enhancement' => 'SI Enhancement',
            'combo_a_d_si' => 'Combo A, D & SI',
            'correction' => 'Correction',
            'baby_addition' => 'Baby Addition',
            'policy_instalment' => 'Policy Instalment',
            'addition_inception' => 'Addition-Inception',
            'bds_correction' => 'BDS Correction',
            'policy_correction' => 'Policy Correction',
            'policy_cancellation' => 'Policy Cancellation',
        ];

        $editAction = 'Edit';
        $deleteAction = '';
        if ((int) get_role_id() === 5) {
            $deleteAction = 'Delete';
        }

        $actionHtml = '';

        return [
            0  => $serialNo,
            1  => $issuerMap[$row['issuer'] ?? 0] ?? 'N/A',
            2  => $row['client_short_name'] ?: 'N/A',
            3  => $row['client_branch_name'] ?: 'N/A',
            4  => $row['insurer_short_name'] ?: 'N/A',
            5  => $row['policy_type'] ?: 'N/A',
            6  => $actionTypeMap[$row['action_type'] ?? ''] ?? 'N/A',
            7  => $row['endorsement_no'] ?: 'N/A',
            8  => empty($row['data_received_date']) ? 'N/A' : date('d/m/Y', strtotime($row['data_received_date'])),
            9  => $row['emp_count'] ?: '0',
            10 => $row['dependent_count'] ?: '0',
            11 => empty($row['policy_issue_date']) ? 'N/A' : date('d/m/Y', strtotime($row['policy_issue_date'])),
            12 => $policyStatusMap[$row['status'] ?? ''] ?? 'N/A',
            13 => $actionHtml,
        ];
    }

    public function viewEndorsement2()
    {
        // echo '
';
        // !dd($this->getEndorsementDataForEdit(17));
        $bds_edit_pt_id = $this->request->getGet('pt_id') ?? null;
        $data['tab_name'] = 'Endorsements';
        $data['page_name'] = 'Endorsements';
        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['issuer_branch'] = $this->nhanceBranchModel->where('is_active', 1)->findAll();
        $data['client_type'] = [1 => 'Group', 2 => 'Individual'];

        $data['policy_status'] = [
            'under_process' => 'Under Process',
            'client_pending' => 'Client Pending',
            'insurer_pending' => 'Insurer Pending',
            'co_insurer_pending' => 'Co-Insurer Pending',
            'tpa_pending' => 'TPA Pending',
            'validated' => 'Validated',
            'cancelled' => 'Cancelled',
            'instalment_pending' => 'Instalment Pending',
            'completed' => 'Completed',
        ];

        $data['invoice_status'] = [
            'yet_to_generate' => 'Pending',
            'generated' => 'Generated',
            'send' => 'Sent',
            'recived' => 'Payment Received',
        ];

        $data['action_type'] = [
            'addition' => 'Addition',
            'deletion' => 'Deletion',
            'addition_deletion' => 'Addition & Deletion',
            'si_enhancement' => 'SI Enhancement',
            'combo_a_d_si' => 'Combo A, D & SI',
            'correction' => 'Correction',
            'baby_addition' => 'Baby Addition',
            'policy_instalment' => 'Policy Instalment',
            'addition_inception' => 'Addition-Inception',
            'bds_correction' => 'BDS Correction',
            'policy_correction' => 'Policy Correction',
            'policy_cancellation' => 'Policy Cancellation',
        ];

        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
        ];

        //filter datas
        $start_date = $this->request->getGet('start_date');
        $end_date = $this->request->getGet('end_date');
        $client_id = $this->request->getGet('client_id');
        $insurer_id = $this->request->getGet('insurer_id');
        $policy_type_id = $this->request->getGet('policy_type_id');
        $date_type = $this->request->getGet('date_type');
        $issuer = $this->request->getGet('issuer');
        $status = $this->request->getGet('status');

        $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : $start_date;
        $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : $end_date;

        $client_id = (!isset($client_id) || $client_id === '' || $client_id === null) ? 0 : $client_id;
        $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id;
        $policy_type_id = (!isset($policy_type_id) || $policy_type_id === '' || $policy_type_id === null) ? 0 : $policy_type_id;
        $date_type = (!isset($date_type) || $date_type === '' || $date_type === null) ? 0 : $date_type;
        $issuer = (!isset($issuer) || $issuer === '' || $issuer === null) ? 0 : $issuer;
        $status = (!isset($status) || $status === '' || $status === null) ? 0 : $status;

        if($bds_edit_pt_id == null){
            $data['endorsement_data_list'] = $this->policyTransactionModel->getEndorsementTranctionListData($start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer, $status);
        }else{
            $data['endorsement_data_list'] = [];
        }
        $data['client'] = $this->clientModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();

        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        // $data['tpa']           = $this->tpaModel->where('is_active', 1)->findAll();
        $data['insurer_branch']      = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames();
        $data['tpa']           = $this->tpaBranchModel->getTpaBranchesWithTpaNames();
        list($policyList, $policyListByClient) = $this->getPolicyForEndorsment();

        $data['endorsementPolicies'] = $policyList;
        $data['endorsementPolicyListByClient'] = $policyListByClient;

        // dd($data);
        // print_r($data['endorsementPolicies']);die();

        $this->loadLayout('policy_transaction_endorsement_list_2', $data);
    }

    public function createEndorsementPolicy()
    {
        session()->set('endorsement_list_cache_version', time());

        // $id = $this->request->getPost('id');
        $rules = [
                // ==========================================
                // 1. CLIENT SECTION
                // ==========================================
                'client_id' => [
                    'label'  => 'Client',
                    'rules'  => 'required',
                    'errors' => ['required' => 'Client selection is mandatory.']
                ],
                'client_policy_id' => [
                    'label'  => 'Policy',
                    'rules'  => 'required',
                    'errors' => ['required' => 'Please select the policy to endorse.']
                ],
                'client_type'      => ['rules' => 'permit_empty','errors' => []],
                'client_branch_id' => ['rules' => 'permit_empty','errors' => []],

                // ==========================================
                // 2. ENDORSEMENT SECTION
                // ==========================================
                'action_type' => [
                    'label'  => 'Endorsement Type',
                    'rules'  => 'required',
                    'errors' => ['required' => 'Select an Endorsement Type.']
                ],
                'endorsement_no' => ['label'  => 'Endorsement No','rules'  => 'permit_empty|regex_match[/^[a-zA-Z0-9\/_-]+$/]',
                                        'errors' => [ 'regex_match' => 'Endorsement No can only contain letters, numbers, and symbols like / - or _' ]],
                'data_received_date' => [
                    'label'  => 'Data Received Date',
                    'rules'  => 'required|valid_date[d/m/Y]',
                    'errors' => ['required' => 'Data Received Date is required.', 'valid_date'  => 'Please provide a valid Data Received Date.']
                ],
                'policy_issue_date' => [
                    'label'  => 'Endorsement Issue Date',
                    'rules'  => 'required|valid_date[d/m/Y]',
                    'errors' => ['required' => 'Endorsement Issue Date is required.', 'valid_date'  => 'Please provide a valid Endorsement Issue Date.']
                ],
                // ==========================================
                // ENDORSEMENT SECTION
                // ==========================================
                'month' => [
                    'label'  => 'Endorsement Issue Month',
                    'rules'  => 'required',
                    'errors' => ['required' => 'Endorsement Issue Month (MM/YYYY) is required.']
                ],
                'endorse_eff_date' => [
                    'label'  => 'Endorsement Effective Date',
                    'rules'  => 'permit_empty|valid_date[d/m/Y]',
                    'errors' => ['valid_date'  => 'Please provide a valid Endorsement Effective Date.']
                ],
                'emp_count' => [
                    'label'  => 'No of Employees',
                    'rules'  => 'permit_empty|numeric',
                    'errors' => ['numeric' => 'No of Employees must be a number.']
                ],
                'dependent_count' => [
                    'label'  => 'No of Dependents',
                    'rules'  => 'permit_empty|numeric',
                    'errors' => ['numeric' => 'No of Dependents must be a number.']
                ],
                'last_action_date' => [
                    'label'  => 'Latest Action Date',
                    'rules'  => 'permit_empty|valid_date[d/m/Y]',
                    'errors' => ['valid_date'  => 'Please provide a valid Latest Action Date.']
                ],
                'install_due_date' => [
                    'label'  => 'Installment Due Date',
                    'rules'  => 'permit_empty|valid_date[d/m/Y]',
                    'errors' => ['valid_date'  => 'Please provide a valid Installment Due Date.']
                ],

                // ==========================================
                // PREMIUM DETAILS (ARRAY FIELDS .*)
                // ==========================================
                'follow_insurer_id.*' => [
                    'label'  => 'Insurer',
                    'rules'  => 'required',
                    'errors' => ['required' => 'Please select an Insurer.']
                ],
                'calc_policy_issue_date.*' => [
                    'label' => 'Premium Endorsement Issue Date', 
                    'rules'  => 'required',
                    'errors' => ['required' => 'Endorsement Issue Date is required.']
                ],
                'co_share_per.*' => [
                    'label'  => 'Co-Share %',
                    'rules'  => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Co-Share % must be a valid decimal.']
                ],
                'base_premium.*' => [
                    'label'  => 'Base Premium',
                    'rules' => 'permit_empty|decimal','errors' => ['decimal'  => 'Base Premium must be a valid amount.']
                ],
                'total.*' => [
                    'label'  => 'Total Premium',
                    'rules'  => 'permit_empty|decimal',
                    'errors' => ['decimal'  => 'Total Premium must be a valid amount.'],
                ],

                // Decimal validation with Labels
                'non_comm_per_amt.*' => [
                    'label' => 'Non-Comm Premium',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Non-Comm Premium must be numeric.']
                ],
                'tp_premium.*' => [
                    'label' => 'TP Premium',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'TP Premium must be numeric.']
                ],
                'ter_premium.*' => [
                    'label' => 'TEP Premium',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'TEP Premium must be numeric.']
                ],
                'co_premium.*' => [
                    'label' => 'Co-Premium',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Co-Premium must be numeric.']
                ],
                'co_tp_premium.*' => [
                    'label' => 'Co-TP Premium',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Co-TP Premium must be numeric.']
                ],
                'co_ter_premium.*' => [
                    'label' => 'Co-TEP Premium',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Co-TEP Premium must be numeric.']
                ],
                'cgst.*' => [
                    'label' => 'CGST',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'CGST must be numeric.']
                ],
                'sgst.*' => [
                    'label' => 'SGST',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'SGST must be numeric.']
                ],
                'igst.*' => [
                    'label' => 'IGST',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'IGST must be numeric.']
                ],
                'gst_amount.*' => [
                    'label' => 'GST Amount',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'GST Amount must be numeric.']
                ],
                'stamp_duty.*' => [
                    'label' => 'Stamp Duty',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Stamp Duty must be numeric.']
                ],
                'agreed_bp.*' => [
                    'label' => 'Agreed BP %',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Agreed BP % must be numeric.']
                ],
                'agreed_tp.*' => [
                    'label' => 'Agreed TP %',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Agreed TP % must be numeric.']
                ],
                'agreed_ter.*' => [
                    'label' => 'Agreed TEP %',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Agreed TEP % must be numeric.']
                ],
                'agreed_amount.*' => [
                    'label' => 'Agreed Amount',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Agreed Amount must be numeric.']
                ],

                // Finance/Management Specific Labels
                'actual_bp_amt.*' => [
                    'label' => 'Actual BP Amount',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Actual BP Amount must be numeric.']
                ],
                'actual_tp_amt.*' => [
                    'label' => 'Actual TP Amount',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Actual TP Amount must be numeric.']
                ],
                'actual_tep_amt.*' => [
                    'label' => 'Actual TEP Amount',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Actual TEP Amount must be numeric.']
                ],
                'actual_bp_per.*' => [
                    'label' => 'Actual BP %',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Actual BP % must be numeric.']
                ],
                'actual_tp_per.*' => [
                    'label' => 'Actual TP %',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Actual TP % must be numeric.']
                ],
                'actual_tep_per.*' => [
                    'label' => 'Actual TEP %',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Actual TEP % must be numeric.']
                ],
                'actual_bp_brokerage_amt.*' => [
                    'label' => 'BP Remuneration',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'BP Remuneration must be numeric.']
                ],
                'actual_tp_brokerage_amt.*' => [
                    'label' => 'TP Remuneration',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'TP Remuneration must be numeric.']
                ],
                'actual_tep_brokerage_amt.*' => [
                    'label' => 'TEP Remuneration',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'TEP Remuneration must be numeric.']
                ],
                'exp_amt.*' => [
                    'label' => 'Expected Amount',
                    'rules' => 'permit_empty|decimal',
                    'errors' => ['decimal' => 'Expected Amount must be numeric.']
                ],
                'co_share_type.*'      => ['label' => 'Is Leader', 'rules' => 'permit_empty','errors' => []],
                'follower_policy_no.*' => ['label' => 'Follower Policy No', 'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9 _-]+$/]','errors' => ['regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.']],
                'co_share_id.*'        => ['label' => 'Record ID', 'rules' => 'permit_empty','errors' => []],
                'doc_name.*' => [
                    'label'  => 'Policy Document Name',
                    'rules' => 'permit_empty|regex_match[/^[a-zA-Z0-9 \/_-]+$/]|min_length[2]|max_length[100]',                    
                    'errors' => [
                        'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
                    ]
                ],
            ];

            if (!$this->validate($rules)) {
                return $this->response->setStatusCode(400)->setJSON([
                    'status' => false,
                    'message' => 'Input validation failed',
                    'code' => 400,
                    'errors' => $this->validator->getErrors()
                ]);
            }

        $data = $this->preparePolicyTransactionData();

        $id = (isset($data['id']) && !empty($data['id'])) ? $data['id'] : null;

        $data['status'] = 'completed';

        if (!$id) {
            return $this->insertEndorsementTransaction($data);
        } else {
            return $this->updateEndorsementTransaction($id, $data);
        }

    }

    private function preparePolicyTransactionData()
    {
        $request_post_data   = $this->request->getPost();
        $data = sanitizeInputArrayAdvanced($request_post_data);
        // echo '
';
        // print_r($data); 
        // die;

        $file_data = $this->request->getFiles() ?? null;
        $data['file_data'] = $file_data ?? null;

        if (!isset($data['policy_with_corr'])) {
            $data['policy_with_corr'] = 0;
        } elseif ($data['policy_with_corr']) {
            $data['policy_with_corr'] = 1;
        }

        // if (!isset($data['is_cd_reduce_from_bds'])) {
        //     $data['is_cd_reduce_from_bds'] = 0;
        // } elseif ($data['is_cd_reduce_from_bds']) {
        //     $data['is_cd_reduce_from_bds'] = 1;
        // }

        if (empty($data['data_received_date'])) {
            $data['data_received_date'] = null;
        } else {
            $data['data_received_date'] =  change_date_format($data['data_received_date'], 'd/m/Y', 'Y-m-d');
        }

        if (empty($data['policy_issue_date'])) {
            $data['policy_issue_date'] = null;
        } else {
            $data['policy_issue_date'] =  change_date_format($data['policy_issue_date'], 'd/m/Y', 'Y-m-d');
        }

        if (empty($data['endorse_eff_date'])) {
            $data['endorse_eff_date'] = null;
        } else {
            $data['endorse_eff_date'] =  change_date_format($data['endorse_eff_date'], 'd/m/Y', 'Y-m-d');
        }

        if (empty($data['install_due_date'])) {
            $data['install_due_date'] = null;
        } else {
            $data['install_due_date'] =  change_date_format($data['install_due_date'], 'd/m/Y', 'Y-m-d');
        }

        if (!empty($data['month'])) {
            $month = '01/' . $data['month'];
            $data['month'] =  change_date_format($month, 'd/M/Y', 'Y-m-d');
        }

        if (empty($data['last_action_date'])) {
            $data['last_action_date'] = null;
        } else {
            $data['last_action_date'] = change_date_format($data['last_action_date']);
        }

        // print_r($data); die;   

        // Separate Insurer and TPA Branch IDs and IDs
        if (isset($data['insurer_id']) && !empty($data['insurer_id'])) {
            list($data['insurer_branch_id'], $data['insurer_id']) = explode('-', $data['insurer_id']);
            if (isset($data['tpa']) && !empty($data['tpa'])) {
                list($data['tpa_branch_id'], $data['tpa_id']) = explode('-', $data['tpa']);
            }
        }

        $issue_type = $this->policyTransactionModel
            ->where('action_type', 'inception')
            ->where('client_id', $this->request->getPost('client_id'))
            // ->where('client_policy_id', $this->request->getPost('client_policy_id'))
            ->where('id', $this->request->getPost('client_policy_id'))
            ->where('policy_transaction.is_active', 1)
            ->first();

        $data['tsi'] = generate_tsi_code($issue_type['issue_type'] ?? 1);

        if (!isset($data['client_branch_id']) || $data['client_branch_id'] == "") {
            $client_branch_id = $issue_type['client_branch_id'];
        }else{
            $client_branch_id = $data['client_branch_id'];
        }

        $data['is_cd_reduce_from_bds'] = (isset($issue_type['policy_type_id']) && $issue_type['policy_type_id'] > 7 && $data['client_type'] == 1) ? 1 : 0;

        // if($data['bro_payable_by'] == ""){
        //     $data['bro_payable_by'] = $issue_type['bro_payable_by'];
        // }

        if (!$data['id']) {

            $data += [
                'issuer' => 2,
                'issuer_branch' => $data['issuer_branch'] ?? 1,
                'client_type' => $data['client_type'] ?? $issue_type['client_type'] ?? null,
                'policy_type_id' => $issue_type['policy_type_id'] ?? null,
                'issue_type' => $issue_type['issue_type'] ?? null,
                'source_client_policy_id' => $issue_type['source_client_policy_id'] ?? null,
                'cd_ac_no' => isset($data['cd_ac_no']) && !empty($data['cd_ac_no']) ? $data['cd_ac_no'] : $issue_type['cd_ac_no'] ?? null,
                'cd_ac_pk' => isset($data['cd_ac_pk']) && !empty($data['cd_ac_pk']) ? $data['cd_ac_pk'] : $issue_type['cd_ac_pk'] ?? null,
                // 'policy_issue_date' => $issue_type['policy_issue_date'] ?? null,
                'policy_start_date' => $issue_type['policy_start_date'] ?? null,
                'policy_end_date' => $issue_type['policy_end_date'] ?? null,
                'revenue_type' =>  $issue_type['revenue_type'] ?? null,
                'co_share' => $issue_type['co_share'] ?? 0,
                'bro_payable_by' =>  $data['bro_payable_by'] == "" ? $issue_type['bro_payable_by'] ?? 0 :  $data['bro_payable_by'],
                'installment' => $issue_type['installment'] ?? null,
                'installment_data' => $issue_type['installment_data'] ?? null,
                'location' => $issue_type['location'] ?? null,
                'links' =>  $issue_type['links'] ?? null,
                'stage' => $issue_type['stage'] ?? null,
                'etat' => $issue_type['etat'] ?? null,
                'etat_band' => $issue_type['etat_band'] ?? null,
                'edate' => $issue_type['edate'] ?? null,
                'renewal_date' => $issue_type['renewal_date'] ?? null,
                'rollover_date' => $issue_type['rollover_date'] ?? null,
                'policy_holder_name' => $issue_type['policy_holder_name'] ?? null,
                'same_as_proposer' => $issue_type['same_as_proposer'] ?? 1,
                'ref' => $issue_type['ref'] ?? null,
                'spl' => $issue_type['spl'] ?? null,
                'fund_received' => $issue_type['fund_received'] ?? null,
                'listed_insurers' => $issue_type['listed_insurers'] ?? null,
                'ppteam' => $issue_type['ppteam'] ?? null,
                'sales_generated_by' => $issue_type['sales_generated_by'] ?? null,
                'serviced_by' => $issue_type['serviced_by'] ?? null,
                'salse_person_manager_id' => $issue_type['salse_person_manager_id'] ?? null,
                'service_person_manager_id' => $issue_type['service_person_manager_id'] ?? null,
                'service_person_branch_id' => $issue_type['service_person_branch_id'] ?? null,
                'agent_id' => $issue_type['agent_id'] ?? null,
                'agent_code' => $issue_type['agent_code'] ?? null,
                'pos_id' => $issue_type['pos_id'] ?? null,
            ];

            $data['client_branch_id'] = $client_branch_id;
        }

        // print_r($issue_type); 
        // print_r($data); 
        // die;

        return $data;
    }

    private function insertEndorsementTransaction($data)
    {
        $insert = $this->policyTransactionModel->insert($data);

        if ($insert) {

            $this->insertTransactionStatus($insert, $data, 1);
            $this->handleCompletedStatus($data, $insert);
            $this->insertOrUpdateCoShareDetails($data, $insert);

            // policy file upload 
            if(isset($data['doc_name']) && isset($data['file_data']) && !empty($data['doc_name']) && !empty($data['file_data'])){
                $this->uploadFile($data['doc_name'], $data['file_data'], $insert);
            }

            return $this->respond(['status' => true, 'message' => 'Endorsement transaction created successfully'], 200);
        }

        return $this->respond(['status' => false, 'message' => 'Endorsement transaction creation failed'], 400);
    }

    private function updateEndorsementTransaction($id, $data)
    {   
        $data['updated_by']  = get_session_userid();
        $old_endorse_data =  $this->policyTransactionModel->where('id', $id)->where('is_active', 1)->first();
        $update = $this->policyTransactionModel->where('id', $id)->set($data)->update();

        if ($update) {

            $this->insertTransactionStatus($id, $data, 1);
            // if($old_endorse_data['status'] != "completed"){
            //     $this->handleCompletedStatus($data, $id);
            // }
            $this->insertOrUpdateCoShareDetails($data, $id);


            return $this->respond(['status' => true, 'message' => 'Endorsement transaction updated successfully'], 200);
        }

        return $this->respond(['status' => false, 'message' => 'Endorsement transaction update failed'], 400);
    }

    private function handleCompletedStatus($data, $policy_tran_id)
    {   
        if ($data['client_type'] == 1 && $data['status'] == 'completed' && $data['is_cd_reduce_from_bds'] == 1) {

            $tolamt = (int) $data['total'][0] ?? 0;

            if(!empty($tolamt)){
                $description = 'The following amount of Rs. ' . round($tolamt, 2) . '/- has been' .
                    ($data['action_type'] == 'deletion' ? ' Credit ' : ' Debit ') . 'from the policy transaction (BDS)';
                
                $cd_tranction_data = [
                    'amount' => abs($tolamt),
                    'sub_type_id' => $data['action_type'] == 'deletion' ? 3 : 4,
                    'client_id' => $data['client_id'],
                    'client_policy_id' => $data['client_policy_id'],
                    'endorsement_no' => null,
                    'cd_ac_no' => $data['cd_ac_no'] ?? null,
                    'insurer_id' => $data['insurer_id'],
                    'description' => $description,
                    'transaction_type' => $data['action_type'] == 'deletion' ? 'Credit' : 'Debit',
                    'updated_by' => get_session_userid(),
                    'event_name' => $data['action_type'],
                    'is_active' => 1,
                    'cd_ac_pk' => $data['cd_ac_pk'] ?? null,
                    'pt_id' => $policy_tran_id ?? null,
                ];

                $result = DepositHelper::saveDeposit($cd_tranction_data, get_session_userid());

                if(isset($result['success']) && $result['success']){
                    $update_data['ct_tran_id'] = $result['insert_id'];
                    $this->policyTransactionModel->where('id', $policy_tran_id)->set($update_data)->update();
                }
            }

        }
    }

    public function getEndorsementDataForEdit($id)
    {
        $data = $this->policyTransactionModel
            ->select('
                        policy_transaction.*, 
                        clients.short_name as client_short_name, 
                        clients.client_type, 
                        ( 
                            select last_action_date
                            from policy_transaction_status
                            where policy_tran_id = policy_transaction.id
                            and status = policy_transaction.status
                            order by id desc
                            limit 1

                        ) as last_action_date
                    ')
            ->join('clients', 'clients.id = policy_transaction.client_id')
            ->join('client_policy', 'policy_transaction.client_policy_id = client_policy.id', 'left')
            ->where('policy_transaction.id', $id)
            ->where('policy_transaction.is_active', 1)
            ->orderBy('id', 'asc')
            ->first();

        $pt_id = null;   

        if(!empty($data)){
            $inception_data = $this->policyTransactionModel
                    ->where('policy_no', $data['policy_no'])
                    ->where('client_id', $data['client_id'])
                    ->where('action_type', 'inception')
                    ->first();
            $pt_id = $inception_data['id'];
        }    

        if (!empty($data['policy_start_date'])) {
            $data['policy_start_date'] =  change_date_format($data['policy_start_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_end_date'])) {
            $data['policy_end_date'] =  change_date_format($data['policy_end_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['data_received_date'])) {
            $data['data_received_date'] =  change_date_format($data['data_received_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_issue_date'])) {
            $data['policy_issue_date'] =  change_date_format($data['policy_issue_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['endorse_eff_date'])) {
            $data['endorse_eff_date'] =  change_date_format($data['endorse_eff_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['install_due_date'])) {
            $data['install_due_date'] =  change_date_format($data['install_due_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['last_action_date'])) {
            $data['last_action_date'] =  change_date_format($data['last_action_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['month'])) {
            $data['month'] =  change_date_format($data['month'], 'Y-m-d', 'M/Y');
        }

        // print_r($data); die;

        //get PT Co-Share Details
        $data['pt_co_share_details'] = $this->PTCOShareDetailsModel

            ->select("
                        pt_co_share_details.*,
                
                        (
                            SELECT
                                COUNT(*)
                            FROM
                                co_share_stmt_details
                            WHERE
                                co_share_stmt_details.co_share_id = pt_co_share_details.id
                                AND co_share_stmt_details.is_active = 1
                        ) AS record_count,
    
                            (
                                SELECT 
                                    SUM(actual_bp_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_bp_amount,
                            
                            (
                                SELECT 
                                    SUM(actual_tp_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tp_amount,
                            
                            (
                                SELECT 
                                    SUM(actual_tep_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tep_amount,
                            
                            (
                                SELECT 
                                    SUM(actual_bp_per) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_bp_percentage,
                            
                            (
                                SELECT 
                                    SUM(actual_tp_per) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tp_percentage,
                            
                            (
                                SELECT 
                                    SUM(actual_tep_per) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tep_percentage,
                            
                            
                            (
                                SELECT 
                                    SUM(actual_bp_brokerage_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_bp_brokerage_amount,
                            
                            
                            (
                                SELECT 
                                    SUM(actual_tp_brokerage_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tp_brokerage_amount,
                            
                            
                            (
                                SELECT 
                                    SUM(actual_tep_brokerage_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tep_brokerage_amount, 
                                
                            DATE_FORMAT(pt_policy_issue_date, '%d/%m/%Y') AS pt_policy_issue_date
    
                    ")
            ->where('pt_id', $id)
            ->where('is_active', 1)
            ->orderBy('id', 'asc')
            ->findAll();

        // print_r($data['endorse_eff_date']); die;

        $pt_bp_amt = $this->PTCOShareDetailsModel
            ->select('bp_amt, amount')
            ->where('pt_id', $id)
            ->where('co_share_type', 1)
            ->where('is_active', 1)
            ->first();

        // dd(db_connect()->getLastQuery() ,$pt_bp_amt);
        $data['base_cd_amount'] = $pt_bp_amt['amount'] ?? null;

        $ptFileQuery = $this->PTFileModel
            ->select('pt_files.*')
            ->join('policy_transaction', 'pt_files.pt_id = policy_transaction.id')
            ->where('pt_files.pt_id', $id)
            ->where('pt_files.is_active', 1);

        if (!in_array(get_role_id(), [1, 5]) && empty(array_intersect(user_team(), [MANAGEMENT_TEAM_ID, FINANCE_TEAM_ID, BUSINESS_TEAM_ID]))) {

            if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) {
                $ptFileQuery->where('pt_files.created_by', get_session_userid());
            }
        }

        $data['pt_files'] = $ptFileQuery->findAll();

        if ($data) {
            return $this->respond(['status' => true, 'data' => $data, 'pt_id' => $pt_id], 200);
        } else {
            return $this->respond(['status' => false], 200);
        }
    }

    public function getEndorsementDataForEdit2($id)
    {
        $data = $this->policyTransactionModel
            ->select('
                        policy_transaction.*, 
                        clients.short_name as client_short_name, 
                        clients.client_type, 
                        ( 
                            select last_action_date
                            from policy_transaction_status
                            where policy_tran_id = policy_transaction.id
                            and status = policy_transaction.status
                            order by id desc
                            limit 1

                        ) as last_action_date
                    ')
            ->join('clients', 'clients.id = policy_transaction.client_id')
            ->join('client_policy', 'policy_transaction.client_policy_id = client_policy.id', 'left')
            ->where('policy_transaction.id', $id)
            ->where('policy_transaction.is_active', 1)
            ->orderBy('id', 'asc')
            ->first();

        $pt_id = null;   

        if(!empty($data)){
            $inception_data = $this->policyTransactionModel
                    ->where('policy_no', $data['policy_no'])
                    ->where('client_id', $data['client_id'])
                    ->where('action_type', 'inception')
                    ->first();
            $pt_id = $inception_data['id'];
        }    

        if (!empty($data['policy_start_date'])) {
            $data['policy_start_date'] =  change_date_format($data['policy_start_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_end_date'])) {
            $data['policy_end_date'] =  change_date_format($data['policy_end_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['data_received_date'])) {
            $data['data_received_date'] =  change_date_format($data['data_received_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['policy_issue_date'])) {
            $data['policy_issue_date'] =  change_date_format($data['policy_issue_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['endorse_eff_date'])) {
            $data['endorse_eff_date'] =  change_date_format($data['endorse_eff_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['install_due_date'])) {
            $data['install_due_date'] =  change_date_format($data['install_due_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['last_action_date'])) {
            $data['last_action_date'] =  change_date_format($data['last_action_date'], 'Y-m-d', 'd/m/Y');
        }

        if (!empty($data['month'])) {
            $data['month'] =  change_date_format($data['month'], 'Y-m-d', 'M/Y');
        }

        // print_r($data); die;

        //get PT Co-Share Details
        $data['pt_co_share_details'] = $this->PTCOShareDetailsModel

            ->select("
                        pt_co_share_details.*,
                
                        (
                            SELECT
                                COUNT(*)
                            FROM
                                co_share_stmt_details
                            WHERE
                                co_share_stmt_details.co_share_id = pt_co_share_details.id
                                AND co_share_stmt_details.is_active = 1
                        ) AS record_count,
    
                            (
                                SELECT 
                                    SUM(actual_bp_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_bp_amount,
                            
                            (
                                SELECT 
                                    SUM(actual_tp_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tp_amount,
                            
                            (
                                SELECT 
                                    SUM(actual_tep_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tep_amount,
                            
                            (
                                SELECT 
                                    SUM(actual_bp_per) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_bp_percentage,
                            
                            (
                                SELECT 
                                    SUM(actual_tp_per) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tp_percentage,
                            
                            (
                                SELECT 
                                    SUM(actual_tep_per) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tep_percentage,
                            
                            
                            (
                                SELECT 
                                    SUM(actual_bp_brokerage_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_bp_brokerage_amount,
                            
                            
                            (
                                SELECT 
                                    SUM(actual_tp_brokerage_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tp_brokerage_amount,
                            
                            
                            (
                                SELECT 
                                    SUM(actual_tep_brokerage_amt) 
                                FROM 
                                    co_share_stmt_details 
                                WHERE 
                                    co_share_id = pt_co_share_details.id 
                                    AND is_active = 1
                                    
                            ) AS actual_tep_brokerage_amount, 
                                
                            DATE_FORMAT(pt_policy_issue_date, '%d/%m/%Y') AS pt_policy_issue_date
    
                    ")
            ->where('pt_id', $id)
            ->where('is_active', 1)
            ->orderBy('id', 'asc')
            ->findAll();

        // print_r($data['endorse_eff_date']); die;

        $pt_bp_amt = $this->PTCOShareDetailsModel
            ->select('bp_amt, amount')
            ->where('pt_id', $id)
            ->where('co_share_type', 1)
            ->where('is_active', 1)
            ->first();

        // dd(db_connect()->getLastQuery() ,$pt_bp_amt);
        $data['base_cd_amount'] = $pt_bp_amt['amount'] ?? null;

        if ($data) {
            return $this->respond(['status' => true, 'data' => $data, 'pt_id' => $pt_id], 200);
        } else {
            return $this->respond(['status' => false], 200);
        }
    }

    //------------------------------------------------------------------------------------------------

    //file upload function 
    public function uploadFile($docs_name = null, $files = null, $pt_id = null)
    {
        $GoogleDriveController = new GoogleDriveController();


        if(empty($docs_name) && empty($files) && empty($pt_id) && $this->request){
            $files = $this->request->getFiles();
            $docs_name = $this->request->getPost('doc_name');
            $pt_id = $this->request->getPost('pt_id');
            $client_policy_id = $this->request->getPost('client_policy_id');

            $rules = [
                'doc_name.*' => [
                    'label'  => 'Policy Document Name',
                    'rules'  => 'permit_empty|required|regex_match[/^[a-zA-Z0-9 _-]+$/]|min_length[2]|max_length[100]',
                    'errors' => [
                        'required' => "Policy Document Name is required",
                        'regex_match' => 'The {field} can only contain letters, numbers, spaces, dashes, and underscores.'
                    ]
                ],
            ];

            if (!$this->validate($rules)) {
                return $this->response->setStatusCode(400)->setJSON([
                    'status' => false,
                    'message' => 'Input validation failed',
                    'code' => 400,
                    'errors' => $this->validator->getErrors()
                ]);
            }
        }

        $uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents';

        $uploadData = [];

        foreach ($docs_name as $key => $docName) {

            // Get the corresponding file for this document name
            $file = $files['file'][$key];

            if (!empty($docName) && $file->isValid() && !$file->hasMoved()) {

                // Upload via FileStorageService (S3-only when enabled; unique storage key)
                $uploadedFileName = storage_file_Upload($file, $uploadFilePath, UPLOAD_EXT_POLICY_DOCS);

                if ($uploadedFileName) {
                    // Prepare data for each document upload
                    $docData = [
                        'pt_id' => $pt_id,
                        'doc_name' => $docName,
                        'file_name' => $uploadedFileName,
                        'created_by' => get_session_userid(),
                    ];

                    // $uploadFilePath = $uploadFilePath . '/' . $uploadedFileName;

                    // $GoogleDriveController->uploadFiletoGdrive(client_policy_id: $client_policy_id, doc_type: 'POLICY', file_path: $uploadFilePath, file_name: $uploadedFileName);

                    // Insert into database
                    $insert = $this->PTFileModel->insert($docData);

                    if ($insert) {
                        $uploadData[] = $docData;
                    }
                }
            }
        }

        if(!empty($docs_name) && !empty($files) && !empty($pt_id) && !$this->request){
            return true;
        }

        // print_r($uploadData); die;

        // $uploadData = uploadFilesToGoogleDrive($files['file'], $doc_name, $pt_id);

        if (!empty($uploadData)) {

            $ptFileQuery = $this->PTFileModel
                ->select('pt_files.*')
                ->join('policy_transaction', 'pt_files.pt_id = policy_transaction.id')
                ->where('pt_files.pt_id', $pt_id)
                ->where('pt_files.is_active', 1);

            if (!in_array(get_role_id(), [1, 5]) && empty(array_intersect(user_team(), [MANAGEMENT_TEAM_ID, FINANCE_TEAM_ID, BUSINESS_TEAM_ID]))) {

                if (get_role_id() == 4 && in_array(POS_TEAM_ID, user_team())) {
                    $ptFileQuery->where('pt_files.created_by', get_session_userid());
                }
            }

            $data['pt_files'] = $ptFileQuery->findAll();

            return $this->respond(['status' => true, 'message' => 'File uploaded successfully in G-Drive', 'data' => $data]);
        } else {
            return $this->respond(['status' => false, 'message' => 'Failed to upload file in G-Drive']);
        }
    }

    // update Invoice Status 
    public function updateInvoiceStatus()
    {
        $ids = $this->request->getPost('ids');
        $ids = json_decode($ids);

        // var_dump($ids); die;

        $data['invoice_status'] = $this->request->getPost('invoice_status');
        if ($this->request->getPost('invoice_status') == 'generated') {
            $data['invoice_no'] = $this->request->getPost('invoice_no');
        }


        $update = $this->policyTransactionModel
            ->whereIn('id', $ids)
            ->set($data)
            ->update();


        if ($update) {

            return $this->respond(['status' => true, 'data' => $ids, 'message' => 'Invoice status updated successfully'], 200);
        } else {
            return $this->respond(['status' => true, 'data' => $ids, 'message' => 'Failed to update invoice status'], 200);
        }
    }

    public function removeCoShareData($id)
    {
        $this->myLogger->logme('error', 'PT Co Share Detailes Remove function called');

        $data = [
            'updated_by' => get_session_userid(),
            'is_active' => 0
        ];

        $update = $this->PTCOShareDetailsModel->where('id', $id)->set($data)->update();

        if ($update) {
            return $this->respond(['status' => true, 'code' => 200, 'message' => 'Data removed successfully'], 200);
        } else {
            return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to remove data'], 200);
        }
    }

    public function getPTCOShareCount($client_id, $client_policy_id)
    {
        $totalCount = $this->PTCOShareDetailsModel
            ->select("
                    pt_co_share_details.*,
                    policy_transaction.bro_payable_by,
                    policy_transaction.cd_ac_pk,
                    (
                        select cd_ac_no
                        from cd_master
                        where id = policy_transaction.cd_ac_pk
                    ) as cd_account_no,
                    (
                        select balance
                        from cash_deposit
                        where cd_ac_pk = policy_transaction.cd_ac_pk
                        and is_active = 1
                        order by id desc
                        limit 1
                    ) as cd_amount,
                ")
            ->join('policy_transaction', 'policy_transaction.id = pt_co_share_details.pt_id')
            ->where('policy_transaction.client_id', $client_id)
            // ->where('policy_transaction.client_policy_id', $client_policy_id)
            ->where('policy_transaction.id', $client_policy_id)
            ->where('policy_transaction.action_type', 'inception')
            ->where('policy_transaction.is_active', 1)
            ->findAll();

        $is_copay_yes = $this->policyTransactionModel
            ->where('client_id', $client_id)
            // ->where('client_policy_id', $client_policy_id)
            ->where('id', $client_policy_id)
            ->where('action_type', 'inception')
            ->where('is_active', 1)
            ->first();

        $cd_ac_no = db_connect()->table('cd_master')->where('id', $is_copay_yes['cd_ac_pk'] ?? null)->get()->getRowArray();

        if ($totalCount) {
            return $this->respond(['status' => true, 'code' => 200, 'data' => $totalCount, 'is_copay_yes' => $is_copay_yes, "cd_master_data" => $cd_ac_no], 200);
        } else {
            $insurer_data = $this->clientPolicyModel->where('id', $client_policy_id)->where('is_active', 1)->first();
            return $this->respond(['status' => false, 'code' => 404, 'message' => 'There is no policy inception data.'], 200);
        }
    }

    public function checkInvoiceStatus($pt_id)
    {
        $data = $this->policyTransactionModel
            ->join('pt_co_share_details', 'policy_transaction.id = pt_co_share_details.pt_id')
            ->join('insurer_statements', 'pt_co_share_details.statement_id = insurer_statements.id')
            ->where('policy_transaction.id', $pt_id)
            ->where('policy_transaction.is_active', 1)
            ->where('pt_co_share_details.is_active', 1)
            ->where('pt_co_share_details.statement_id IS NOT NULL')
            ->where('insurer_statements.invoice_no IS NOT NULL')
            ->countAllResults();

        if ($data) {
            return $this->respond(['status' => true, 'count' => $data,  'code' => 200], 200);
        } else {
            return $this->respond(['status' => false, 'count' => 0, 'message' => 'No Data Found', 'code' => 404], 200);
        }
    }

    public function getBasePolicy($client_id, $client_branch_id)
    {
        $data = $this->clientPolicyModel
            ->select('client_policy.*, policy_type.policy_type')
            ->join('policy_type', 'policy_type.id = client_policy.policy_type_id')
            ->where('client_policy.client_id', $client_id)
            ->where('client_policy.client_branch_id', $client_branch_id)
            ->whereIn('client_policy.policy_type_id', [2, 3])
            ->where('client_policy.is_active', 1)
            ->findAll();

        if ($data) {
            return $this->respond(['status' => true, 'data' => $data,  'code' => 200], 200);
        } else {
            return $this->respond(['status' => false, 'count' => 0, 'message' => 'No Data Found', 'code' => 404], 200);
        }
    }

    //---------------------------------------------------------------------------------------------------

    //get BDS Reports data old function
    public function reportBDSOld()
    {
        $data['tab_name'] = 'BDS Report';
        $data['page_name'] = 'BDS Report';

        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['client_type'] = [1 => 'Group', 2 => 'Individual'];
        $data['issuing_type'] = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over'];
        $data['policy_status'] = [
            'pending' => 'Pending',
            'exported_to_insurer' => 'Exported to Insurer',
            'imported_from_insurer' => 'Imported from Insurer',
            'exported_to_tpa' => 'Exported to TPA',
            'imported_from_tpa' => 'Imported from TPA',
            'completed' => 'Completed'
        ];
        $data['invoice_status_array'] = [
            'yet_to_generate' => 'Yet to Generate',
            'generated' => 'Generated',
            'send' => 'Send',
            'recived' => 'Recived',
        ];
        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
            'data_received_date' => 'Data Received Date',
            'closure_date' => 'Closure Date',
        ];

        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();
        $data['clients'] = $this->clientModel->where('is_active', 1)->findAll();

        //filter datas
        $start_date = $this->request->getGet('start_date');
        $end_date = $this->request->getGet('end_date');
        $client_id = $this->request->getGet('client_id');
        $insurer_id = $this->request->getGet('insurer_id');
        $policy_type_id = $this->request->getGet('policy_type_id');
        $date_type = $this->request->getGet('date_type');
        $issuer = $this->request->getGet('issuer');

        $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : $start_date;
        $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : $end_date;

        $client_id = (!isset($client_id) || $client_id === '' || $client_id === null) ? 0 : $client_id;
        $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id;
        $policy_type_id = (!isset($policy_type_id) || $policy_type_id === '' || $policy_type_id === null) ? 0 : $policy_type_id;
        $date_type = (!isset($date_type) || $date_type === '' || $date_type === null) ? 0 : $date_type;
        $issuer = (!isset($issuer) || $issuer === '' || $issuer === null) ? 0 : $issuer;


        //Actual data for the list
        $data['report_list'] = $this->policyTransactionModel->getBDSReportList($start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer);
        // dd($data);

        $this->loadLayout('report_bds_filter', $data);
    }

    //get BDS Reports data New Function
    public function reportBDS()
    {

        $data['tab_name'] = 'BDS Report';
        $data['page_name'] = 'BDS Report';

        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['client_type'] = [1 => 'Group', 2 => 'Individual'];
        $data['issuing_type'] = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over'];
        $data['policy_status'] = [
            'pending' => 'Pending',
            'exported_to_insurer' => 'Exported to Insurer',
            'imported_from_insurer' => 'Imported from Insurer',
            'exported_to_tpa' => 'Exported to TPA',
            'imported_from_tpa' => 'Imported from TPA',
            'completed' => 'Completed'
        ];
        $data['invoice_status_array'] = [
            'yet_to_generate' => 'Yet to Generate',
            'generated' => 'Generated',
            'send' => 'Send',
            'recived' => 'Recived',
        ];
        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
            'data_received_date' => 'Data Received Date',
            'closure_date' => 'Closure Date',
            'statement_month' => 'Statement Month',
        ];

        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();
        $data['clients'] = $this->clientModel->where('is_active', 1)->findAll();
        $data['users'] = $this->userModel->where('is_active', 1)->findAll();
        $data['policy_count'] = $this->policyTransactionModel->where('is_active', 1)->countAllResults();

        // List data loaded via server-side DataTables AJAX
        $data['report_list'] = [];
        $data['bds_filters'] = $this->buildBDSReportFiltersFromRequest();
        // dd($data);

        $this->loadLayout('report_bds_filter', $data);
    }

    /**
     * Server-side DataTables endpoint for BDS report list.
     */
    public function reportBDSDataTable()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setStatusCode(400)->setJSON([
                'status'  => false,
                'message' => 'Invalid request.',
            ]);
        }

        $draw   = (int) ($this->request->getPost('draw') ?? 0);
        $start  = max(0, (int) ($this->request->getPost('start') ?? 0));
        $length = (int) ($this->request->getPost('length') ?? 10);
        $search = trim((string) ($this->request->getPost('search')['value'] ?? ''));

        $filters = $this->buildBDSReportFiltersFromRequest();

        $result = $this->policyTransactionModel->getBDSReportListDataTable(
            $draw,
            $start,
            $length,
            $search,
            $filters
        );

        $serialStart = $start + 1;
        $data        = [];

        foreach ($result['data'] as $index => $row) {
            $data[] = $this->formatBdsReportRowForDataTable($row, $serialStart + $index);
        }

        return $this->response->setJSON([
            'draw'            => $result['draw'],
            'recordsTotal'    => $result['recordsTotal'],
            'recordsFiltered' => $result['recordsFiltered'],
            'data'            => $data,
            'totals'          => $result['totals'],
        ]);
    }

    public function clearReportBDSCache()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setStatusCode(400)->setJSON([
                'status'  => false,
                'message' => 'Invalid request.',
            ]);
        }

        session()->set('bds_report_cache_version', time());

        return $this->response->setJSON([
            'status'  => true,
            'message' => 'BDS report cache cleared.',
        ]);
    }

    /**
     * Normalize BDS report filter params from the current request.
     */
    protected function buildBDSReportFiltersFromRequest(): array
    {
        $start_date        = $this->request->getGet('start_date') ?? $this->request->getPost('start_date');
        $end_date          = $this->request->getGet('end_date') ?? $this->request->getPost('end_date');
        $client_id         = $this->request->getGet('client_id') ?? $this->request->getPost('client_id');
        $insurer_id        = $this->request->getGet('insurer_id') ?? $this->request->getPost('insurer_id');
        $policy_type_id    = $this->request->getGet('policy_type_id') ?? $this->request->getPost('policy_type_id');
        $date_type         = $this->request->getGet('date_type') ?? $this->request->getPost('date_type');
        $issuer            = $this->request->getGet('issuer') ?? $this->request->getPost('issuer');
        $client_branch_id  = $this->request->getGet('client_branch_id') ?? $this->request->getPost('client_branch_id');
        $insurer_branch_id = $this->request->getGet('insurer_branch_id') ?? $this->request->getPost('insurer_branch_id');
        $client_policy_id  = $this->request->getGet('client_policy_id') ?? $this->request->getPost('client_policy_id');
        $user_id           = $this->request->getGet('user_id') ?? $this->request->getPost('user_id');

        if ($date_type == 'statement_month' && $start_date && $end_date) {
            $start_date = (string) date('Y-m-01', strtotime($start_date)); 
            $end_date   = (string) date('Y-m-t', strtotime($end_date)); 
        }

        $normalize = static function ($value) {
            return (!isset($value) || $value === '' || $value === null) ? 0 : $value;
        };

        $where = '';
        if ($this->request->is('post')) {
            $request_post_data   = $this->request->getPost();
            $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data);
            $isFromDashboard     = $sanitized_post_data['is_dashboard'] ?? null;

            if (isset($isFromDashboard) && !empty($isFromDashboard) && (int) $isFromDashboard === 1) {
                $ids = array_filter(explode(',', $sanitized_post_data['ids'] ?? ''));

                if (!empty($ids)) {
                    $idsStr = implode(',', array_map('intval', $ids)); 
                    $where  = "policy_transaction.id IN ($idsStr)";
                } else {
                    $where = [];
                }
            }
        }

        return [
            'start_date'        => $normalize($start_date),
            'end_date'          => $normalize($end_date),
            'client_id'         => $normalize($client_id),
            'insurer_id'        => $normalize($insurer_id),
            'policy_type_id'    => $normalize($policy_type_id),
            'date_type'         => $normalize($date_type),
            'issuer'            => $normalize($issuer),
            'client_branch_id'  => $normalize($client_branch_id),
            'insurer_branch_id' => $normalize($insurer_branch_id),
            'client_policy_id'  => $normalize($client_policy_id),
            'user_id'           => $normalize($user_id),
            'where'             => $where,
            'cache_version'     => (int) (session()->get('bds_report_cache_version') ?? 1),
        ];
    }

    /**
     * Format a single BDS report row for DataTables output.
     */
    protected function formatBdsReportRowForDataTable(array $row, int $serialNo): array
    {
        $hasIrda      = ((float) ($row['total_irda_amt'] ?? 0)) != 0.0;
        $actionType  = strtolower((string) ($row['action_type'] ?? ''));
        $editBaseUrl = $actionType === 'policy'
            ? base_url('policy_tranction/inception/list')
            : base_url('policy_tranction/endorsement/list');
        $editLink    = $editBaseUrl . '?pt_id=' . ($row['id'] ?? '');
        $totalIrdaAmt = $row['total_irda_amt'] ?? '0.00';
        $unbilled     = isset($row['unbilled_amount']) ? number_format((float) $row['unbilled_amount'], 2, '.', '') : '0.00';

        $fmtDate = static function ($value) {
            return empty($value) ? 'N/A' : change_date_format($value, 'Y-m-d', 'd/m/Y');
        };

        $fmtNum = static function ($value, int $decimals = 2) {
            return number_format((float) ($value ?? 0), $decimals, '.', '');
        };

        $na = static function ($value) {
            return ($value !== null && $value !== '') ? $value : 'N/A';
        };

        $cells = [
            $serialNo . '   ',
            $na($row['user_name'] ?? null),
            $na($row['policy_issue_month'] ?? null),
            $na($row['revenue_type'] ?? null),
            $na($row['client_type'] ?? null),
            $na($row['client_name'] ?? null),
            $na($row['action_type'] ?? null),
            $na($row['policy_type'] ?? null),
            $na($row['bap'] ?? null),
            $na($row['vehicle_no'] ?? null),
            $na($row['policy_no'] ?? null),
            $na($row['endorsement_no'] ?? null),
            $na($row['insurer_branch_name'] ?? null),
            $fmtDate($row['endorse_eff_date'] ?? null),
            $fmtDate($row['policy_start_date'] ?? null),
            $fmtDate($row['policy_end_date'] ?? null),
            $na($row['ref'] ?? null),
            $na($row['remarks'] ?? null),
            $hasIrda ? ($row['bp_amt'] ?: '0.00') : '0.00',
            $hasIrda ? ($row['tp_or_ter'] ?: '0.00') : '0.00',
            $hasIrda ? ($row['premium_wo_gst'] ?: '0.00') : '0.00',
            $hasIrda ? ($row['total_premium'] ?: '0.00') : '0.00',
            ($hasIrda ? ($row['agreed_bp_per'] ?: '0.00') : '0.00') . '%',
            ($hasIrda ? ($row['agreed_tp_or_ter_per'] ?: '0.00') : '0.00') . '%',
            isset($row['reward']) ? $row['reward'] : '0.00',
            '' . $totalIrdaAmt . '',
            '' . (empty($row['billed_amt']) ? '0.00' : $row['billed_amt']) . '',
            '' . $unbilled . '',
            $na($row['salse_person_name'] ?? null),
            $na($row['service_person_name'] ?? null),
            $na($row['nhance_branch'] ?? null),
            $na($row['installment'] ?? null),
            $fmtDate($row['data_received_date'] ?? null),
            $fmtDate($row['renewal_date'] ?? null),
            $row['co_share'] ?? 'No',
            $row['bro_payable_by'] ?? 'No',
            $na($row['salse_manager_name'] ?? null),
            $na($row['service_manager_name'] ?? null),
            $na($row['service_branch'] ?? null),
            $fmtDate($row['rollover_date'] ?? null),
            $na($row['policy_holder_name'] ?? null),
            $row['same_as_proposer'] ?? 'No',
            $na($row['follower_policy_no'] ?? null),
            $fmtNum($row['co_share_per'] ?? 0),
            $fmtNum($row['non_comm_per_amt'] ?? 0),
            $fmtNum($row['bp_igst'] ?? 0),
            $fmtNum($row['bp_sgst'] ?? 0),
            $fmtNum($row['bp_cgst'] ?? 0),
            $fmtNum($row['stamp_duty'] ?? 0),
            $fmtNum($row['standerd_bp_per'] ?? 0),
            $fmtNum($row['standerd_tp_per'] ?? 0),
            $fmtNum($row['actual_bp_amt'] ?? 0),
            $fmtNum($row['actual_tp_amt'] ?? 0),
            $fmtNum($row['actual_bp_per'] ?? 0),
            $fmtNum($row['actual_tp_per'] ?? 0),
            $fmtNum($row['actual_tep_brokerage_amt'] ?? 0),
            $fmtNum($row['actual_tp_brokerage_amt'] ?? 0),
            $na($row['cd_ac_no'] ?? null),
        ];

        $rowData = ['DT_RowAttr' => ['data-id' => $row['pt_id'] ?? '']];
        foreach ($cells as $index => $cell) {
            $rowData[$index] = $cell;
        }

        return $rowData;
    }

    public function reportVarience()
    {
        $data['tab_name'] = 'Variance Report';
        $data['page_name'] = 'Variance Report';

        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();
        $data['clients'] = $this->clientModel->where('is_active', 1)->findAll();
        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
            'data_received_date' => 'Data Received Date',
            'closure_date' => 'Closure Date',
        ];

        //filter datas
        $start_date = $this->request->getGet('start_date');
        $end_date = $this->request->getGet('end_date');
        $client_id = $this->request->getGet('client_id');
        $insurer_id = $this->request->getGet('insurer_id');
        $policy_type_id = $this->request->getGet('policy_type_id');
        $date_type = $this->request->getGet('date_type');
        $issuer = $this->request->getGet('issuer');
        $client_branch_id = $this->request->getGet('client_branch_id');
        $insurer_branch_id = $this->request->getGet('insurer_branch_id');
        $client_policy_id = $this->request->getGet('client_policy_id');


        $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : $start_date;
        $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : $end_date;

        $client_id = (!isset($client_id) || $client_id === '' || $client_id === null) ? 0 : $client_id;
        $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id;
        $policy_type_id = (!isset($policy_type_id) || $policy_type_id === '' || $policy_type_id === null) ? 0 : $policy_type_id;
        $date_type = (!isset($date_type) || $date_type === '' || $date_type === null) ? 0 : $date_type;
        $issuer = (!isset($issuer) || $issuer === '' || $issuer === null) ? 0 : $issuer;

        $client_branch_id = (!isset($client_branch_id) || $client_branch_id === '' || $client_branch_id === null) ? 0 : $client_branch_id;
        $insurer_branch_id = (!isset($insurer_branch_id) || $insurer_branch_id === '' || $insurer_branch_id === null) ? 0 : $insurer_branch_id;
        $client_policy_id = (!isset($client_policy_id) || $client_policy_id === '' || $client_policy_id === null) ? 0 : $client_policy_id;


        $data['varience_list'] = $this->policyTransactionModel->getVarienceReportLIst($start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer, $client_branch_id, $insurer_branch_id, $client_policy_id);
        // !dd($data['varience_list']);
        $this->loadLayout('variance_report_list', $data);
    }


    public function reportBusinessList()
    {
        $data['tab_name'] = 'Business Report';
        $data['page_name'] = 'Business Report';

        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();
        $data['clients'] = $this->clientModel->where('is_active', 1)->findAll();
        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
            'data_received_date' => 'Data Received Date',
            'closure_date' => 'Closure Date',
        ];

        //filter datas
        $start_date = $this->request->getGet('start_date');
        $end_date = $this->request->getGet('end_date');
        $client_id = $this->request->getGet('client_id');
        $insurer_id = $this->request->getGet('insurer_id');
        $policy_type_id = $this->request->getGet('policy_type_id');
        $date_type = $this->request->getGet('date_type');
        $issuer = $this->request->getGet('issuer');

        $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : $start_date;
        $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : $end_date;

        $client_id = (!isset($client_id) || $client_id === '' || $client_id === null) ? 0 : $client_id;
        $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id;
        $policy_type_id = (!isset($policy_type_id) || $policy_type_id === '' || $policy_type_id === null) ? 0 : $policy_type_id;
        $date_type = (!isset($date_type) || $date_type === '' || $date_type === null) ? 0 : $date_type;
        $issuer = (!isset($issuer) || $issuer === '' || $issuer === null) ? 0 : $issuer;


        $data['business_list'] = $this->policyTransactionModel->getBusinessReportList($start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer);
        $this->loadLayout('business_team_list', $data);
    }


    public function reportFinanceList()
    {
        $data['tab_name'] = 'Finance Report';
        $data['page_name'] = 'Finance Report';

        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();
        $data['clients'] = $this->clientModel->where('is_active', 1)->findAll();
        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
            'data_received_date' => 'Data Received Date',
            'closure_date' => 'Closure Date',
        ];

        //filter datas
        $start_date = $this->request->getGet('start_date');
        $end_date = $this->request->getGet('end_date');
        $client_id = $this->request->getGet('client_id');
        $insurer_id = $this->request->getGet('insurer_id');
        $policy_type_id = $this->request->getGet('policy_type_id');
        $date_type = $this->request->getGet('date_type');
        $issuer = $this->request->getGet('issuer');

        $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : $start_date;
        $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : $end_date;

        $client_id = (!isset($client_id) || $client_id === '' || $client_id === null) ? 0 : $client_id;
        $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id;
        $policy_type_id = (!isset($policy_type_id) || $policy_type_id === '' || $policy_type_id === null) ? 0 : $policy_type_id;
        $date_type = (!isset($date_type) || $date_type === '' || $date_type === null) ? 0 : $date_type;
        $issuer = (!isset($issuer) || $issuer === '' || $issuer === null) ? 0 : $issuer;



        $data['finance_list'] = $this->policyTransactionModel->getFinanceReportList($start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer);
        $this->loadLayout('finance_team_list', $data);
    }

    public function reportOutstanding()
    {
        $data['tab_name'] = 'Outstanding Report';
        $data['page_name'] = 'Outstanding Report';

        $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance'];
        $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll();
        $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll();
        $data['clients'] = $this->clientModel->where('is_active', 1)->findAll();
        $data['date_type'] = [
            'policy_issue_date' => 'Policy Issue Date',
            'policy_start_date' => 'Policy Start Date',
            'policy_end_date' => 'Policy End Date',
            'data_received_date' => 'Data Received Date',
            'closure_date' => 'Closure Date',
        ];

        //filter datas
        $start_date = $this->request->getGet('start_date');
        $end_date = $this->request->getGet('end_date');
        $client_id = $this->request->getGet('client_id');
        $insurer_id = $this->request->getGet('insurer_id');
        $insurer_branch_id = $this->request->getGet('insurer_branch_id');

        $start_date = (!isset($start_date) || $start_date === '' || $start_date === null) ? 0 : change_date_format($start_date, 'd-m-Y', 'Y-m-01');
        $end_date = (!isset($end_date) || $end_date === '' || $end_date === null) ? 0 : change_date_format($end_date, 'd-m-Y', 'Y-m-t');
        // dd([$start_date,$end_date]);


        $insurer_id = (!isset($insurer_id) || $insurer_id === '' || $insurer_id === null) ? 0 : $insurer_id;
        $insurer_branch_id = (!isset($insurer_branch_id) || $insurer_branch_id === '' || $insurer_branch_id === null) ? 0 : $insurer_branch_id;

        $data['outstanting_list'] = $this->policyTransactionModel->getOutstandingReportLIst($start_date, $end_date, $insurer_id, $insurer_branch_id);
        // dd($this->policyTransactionModel->getLastQuery());
        // dd($data);
        $this->loadLayout('outstanding_report_list', $data);
    }

    //---------------------------------------------------------------------------------------------------

    //insurer statement list page
    public function statementList()
    {
        // dd($this->updateInsurerStatement(['file_id' => 133])); // for check validateInsurerStatementfunction with hard coded file id always un command
        $data['insurers'] = $this->insurerModel->where('is_active',1)->findAll();
        $today = date('Y-m-d');
        $fromday = $from_date = date('Y-m-d', strtotime('-180 days', strtotime($today)));
        // echo $fromday;die();
        $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,
                                                        (SELECT SUM(pt_co_share_details.exp_amt) 
                                                        FROM pt_co_share_details 
                                                        WHERE pt_co_share_details.is_active = 1 
                                                            AND pt_co_share_details.statement_id = insurer_statements.id
                                                        ) AS exp_inv_amt,
                                                        (SELECT SUM(inv_payment_details.inv_amt) + SUM(inv_payment_details.tds)  + SUM(inv_payment_details.gst)
                                                        FROM inv_payment_details 
                                                        WHERE inv_payment_details.is_active = 1 
                                                            AND inv_payment_details.statement_id = insurer_statements.id
                                                        ) AS received_inv_amt'
            )
            ->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')
            ->where('insurer_statements.is_active', 1)
            ->where('insurers.is_active', 1)
            ->where('insurer_branch.is_active', 1)
            // ->where('insurer_statements.file_status','success')
            ->where('date(insurer_statements.created_at) >= ', $from_date)
            ->where('date(insurer_statements.created_at) <= ', $today)
            ->orderBy('insurer_statements.id', 'DESC')
            ->findAll();

        // dd( $this->insurerStatements->getLastQuery());
        $data['tab_name'] = 'Statement Upload';
        $data['page_name'] = 'Statement Upload';

        $this->loadLayout('insurer_statement_list',  $data);
    }

    // public function failedStatementList(){
    //     $today = date('Y-m-d');
    //     $fromday = $from_date = date('Y-m-d', strtotime('-180 days', strtotime($today)));
    //     // echo $fromday;die();
    //      $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,
    //                                                       (SELECT SUM(pt_co_share_details.exp_amt) 
    //                                                        FROM pt_co_share_details 
    //                                                        WHERE pt_co_share_details.is_active = 1 
    //                                                          AND pt_co_share_details.statement_id = insurer_statements.id
    //                                                       ) AS exp_inv_amt,
    //                                                       (SELECT SUM(inv_payment_details.inv_amt) + SUM(inv_payment_details.tds)  + SUM(inv_payment_details.gst)
    //                                                        FROM inv_payment_details 
    //                                                        WHERE inv_payment_details.is_active = 1 
    //                                                          AND inv_payment_details.statement_id = insurer_statements.id
    //                                                       ) AS received_inv_amt'
    //                                             )
    //                                             ->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')
    //                                             ->where('insurer_statements.is_active', 1)
    //                                             ->where('insurer_statements.file_status','failed')
    //                                             ->where('date(insurer_statements.created_at) >= ', $from_date)
    //                                             ->where('date(insurer_statements.created_at) <= ', $today)
    //                                             ->orderBy('insurer_statements.id', 'DESC')
    //                                             ->findAll();
    //         if($data['insurer_statement_list']){
    //             return $this->respond(['status' => true, 'code' => 200,'data'=>$data ], 200);
    //         }else{
    //             return $this->respond(['status'=>false,'message'=>'Data Not Fount'],404);
    //         }

    // }

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

            $filename = storage_file_Upload($avatar, WRITEPATH . 'uploads/statements/', UPLOAD_EXT_EXCEL);
            if ($filename !== '') {
                $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 = $month . '-01';
        // print_r($month);die;
        $month = change_date_format($month, 'Y-M-d', 'Y-m-d');
        $stmt_sno = $this->request->getPost('statement_no');
        // 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, 'stmt_sno' => $stmt_sno]); //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);
        }

        if (isset($file_id) || $validation_result['status']) {
            $this->insurerStatements->where('id', $file_id)->set(['invoice_status' => 'pending'])->update();
        }



        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 validateInsurerStatementOld($params)
    {
        helper('excel_util_helper');
        //get file info
        $file_id = $params['file_id'];
        $file = $this->insurerStatements->find((int)$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 = storage_ensure_local_file(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]);
        $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data);
        // Kint::dump($excel_data); // die();
        //get no of line items and update in DB
        $line_items = 0;
        // get uploaded month transactions data
        $source_data = $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactions(insurer_id: $file['insurer_id'], insurer_branch_id: $file['branch_id'], month: $file['month']);
        // var_dump($source_data);die();
        // Kint::dump($source_data);die();


        // 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_row_empty = check_row_is_empty_or_null($excel_row);

            if (!$is_row_empty) {

                // $excel_row = ExcelSanitizeHelper::sanitizeArrayData($excel_row);
                $is_source_found = 0;
                // Kint::dump($excel_key,$excel_row[1],$excel_row[2]);
                // $policy_start_date = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[4]); //policy_start_date from excel
                // $policy_end_date = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[5]); //policy_end_date from excel
                
                $policy_no = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[1]); //policy_end_date from excel
                $policy_no = preg_replace(  '/[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{00A0}\x{200E}\x{200F}\x{202A}-\x{202E}]/u', '',  $excel_row[1]); //policy_end_date from excel
                
                // $client_name = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[3]); //clientname from excel
                
                $endorsement_no = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[2]??''); //policy_end_date from excel
                $endorsement_no = preg_replace(  '/[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{00A0}\x{200E}\x{200F}\x{202A}-\x{202E}]/u', '',  $excel_row[2]??''); //policy_end_date from excel

                // Kint::dump($excel_key,$policy_no,$endorsement_no,$policy_start_date,$policy_end_date);//die();
                foreach ($source_data as $source_key => $source_row) {
                    $source_endorsement_no = $source_row['endorsement_no'] !== null ? $source_row['endorsement_no'] : null;
                    // Kint::dump($source_row, $source_endorsement_no, $policy_no, $endorsement_no);
                    
                    // if (($policy_no == $source_row['policy_no']) && $endorsement_no == $source_endorsement_no  && change_date_format($policy_start_date, 'd-m-Y', 'Y-m-d') == $source_row['policy_start_date'] &&  change_date_format($policy_end_date, 'd-m-Y', 'Y-m-d') == $source_row['policy_end_date'] && $client_name == $source_row['client_name']) 
                    // {
                    //     $is_source_found = 1;
                    //     $line_items = $line_items + 1;
                    //     unset($source_data[$source_key]);
                    //     continue 2;
                    // }  
                    
                    if (($policy_no == $source_row['policy_no']) && $endorsement_no == $source_endorsement_no) 
                    {
                        $is_source_found = 1;
                        $line_items = $line_items + 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 } } } // dd($error_data); 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 validateInsurerStatementOLD1($params) { helper('excel_util_helper'); $file_id = $params['file_id']; try { //get file info $file = $this->insurerStatements->find((int)$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; $return = []; if (!isset($file)) { //file not found in DB $this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed', 'reason' => json_encode(['error_code' => 0, 'error_data' => 'statement file not found in DB'])])->update(); return array('status' => false, 'msg' => 'statement file not found in DB'); } $file_name_with_path = storage_ensure_local_file(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, 'error_data' => $message); //0 - Physcial file not found } //get excel data to php array $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $sheet = $spreadsheet->getActiveSheet(); $highestRow = $sheet->getHighestRow(); $highestColumn = $sheet->getHighestColumn(); $excel_data = $sheet->rangeToArray('A1:' . $highestColumn . $highestRow); unset($excel_data[0]); $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data); // dd($excel_data); //get no of line items and update in DB $line_items = 0; // get uploaded month transactions data $source_data = $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactions(insurer_id: $file['insurer_id'], insurer_branch_id: $file['branch_id'], month: $file['month']); // dd($source_data); // check policy no,insurer and etc in DB for this month // if all good return true, otherwise return false with messssage $matched_entry = []; $error_messages = []; // row-wise error storage foreach ($excel_data as $excel_key => $excel_row) { $row_number = $excel_key; $is_row_empty = check_row_is_empty_or_null($excel_row); $policy_source_found = 0; $endorsement_source_found = 0; $dublicate_found = 0; if (!$is_row_empty) { $policy_no = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[1]); //policy_number from excel $policy_no = preg_replace('/[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{00A0}\x{200E}\x{200F}\x{202A}-\x{202E}]/u', '', $excel_row[1]); //policy_number from excel $endorsement_no = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[2] ?? ''); //endorsement number from excel $endorsement_no = preg_replace('/[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{00A0}\x{200E}\x{200F}\x{202A}-\x{202E}]/u', '', $excel_row[2] ?? ''); //endorsement number from excel foreach ($source_data as $source_key => $source_row) { $source_endorsement_no = $source_row['endorsement_no'] !== null ? $source_row['endorsement_no'] : null; if (($policy_no == $source_row['policy_no']) ){ $policy_source_found = 1; } if( $endorsement_no == $source_endorsement_no) { $endorsement_source_found = 1; } // Duplicate check if (isset($matched_entry[$policy_no . '|' . $endorsement_no])) { $dublicate_found = 1; continue 2; } if (($policy_no == $source_row['policy_no']) && $endorsement_no == $source_endorsement_no) { $line_items = $line_items + 1; $matched_entry[] = $policy_no . '|' . $endorsement_no; unset($source_data[$source_key]); continue 2; } } // Policy number mismatch if ($policy_source_found == 0) { $error_messages[$row_number]['policy_no_mismatch'] = "Policy number ({$policy_no}) not in NHance."; } // Endorsement number mismatch if (!empty($endorsement_no) && $endorsement_source_found == 0) { $error_messages[$row_number]['endorsement_no_mismatch'] = "Endorsement number ({$endorsement_no}) not in NHance."; } // Duplicate check if ($dublicate_found == 1) { $error_messages[$row_number]['duplicate'] = "Duplicate entry found. This policy and endorsement ({$policy_no} '|' {$endorsement_no}) combination has already been matched."; } } } // print_rr($error_messages);die; if (!empty($error_messages)) { $error_data['error_code'] = 2; $error_data['error_data'] = $error_messages; $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']); } catch (\Throwable $th) { $errorData = [ 'message' => $th->getMessage(), 'file' => $th->getFile(), 'line' => $th->getLine(), 'code' => $th->getCode(), 'trace' => $th->getTraceAsString(), 'trace_array' => $th->getTrace(), // full array version (optional) 'function' => $th->getTrace()[0]['function'] ?? null, 'class' => $th->getTrace()[0]['class'] ?? null, ]; $this->myLogger->logme("error", "POLICY-TRANSACTION-CONTROLLER - validateInsurerStatement: Exception: " . json_encode($errorData ?? [])); $this->insurerStatements->where('id', $file_id)->set(['line_items' => 0, 'file_status' => 'failed', 'reason' => json_encode($errorData)])->update(); return array('status' => false, 'error_code' => [], 'error_data' => $errorData); } } public function updateInsurerStatementOLD($params) { helper('excel_util_helper'); //get file info $file_id = $params['file_id']; $file = $this->insurerStatements->find((int)$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 = storage_ensure_local_file(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]); $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data); // 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(insurer_id: $file['insurer_id'], insurer_branch_id: $file['branch_id'], month: $file['month']); // Kint::dump($source_data);//die; // Kint::dump($excel_data); // die; // check policy no,insurer and etc in DB for this month // if all good return true, otherwise return false with messssage $data_to_update = []; try{ foreach ($excel_data as $excel_key => $excel_row) { $is_row_empty = check_row_is_empty_or_null($excel_row); if (!$is_row_empty) { $is_source_found = 0; // $policy_start_date = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[4]); //policy_start_date from excel // $policy_end_date = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[5]); //policy_end_date from excel $policy_no = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[1]); //policy_end_date from excel $policy_no = preg_replace('/[\x{200C}\x{200B}]/u', '', $excel_row[1]); // // $client_name = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[3]); //clientname from excel $endorsement_no = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[2]); //policy_end_date from excel foreach ($source_data as $source_key => $source_row) { // Kint::dump(change_date_format($excel_row[3],'d-m-Y','Y-m-d')); $source_endorsement_no = $source_row['endorsement_no'] !== null ? $source_row['endorsement_no'] : null; // if (($policy_no == $source_row['policy_no']) && $endorsement_no == $source_endorsement_no && change_date_format($policy_start_date, 'd-m-Y', 'Y-m-d') == $source_row['policy_start_date'] && change_date_format($policy_end_date, 'd-m-Y', 'Y-m-d') == $source_row['policy_end_date'] && $client_name == $source_row['client_name']) { if (($policy_no == $source_row['policy_no']) && $endorsement_no == $source_endorsement_no) { $is_source_found = 1; //calculate percentage first $total_amt = 0; // $actual_bp_per = trim($excel_row[9]); //commented becoz this filed removed tfrom excel file $actual_bp_per = 0; //set default value 0 for maintaining existing code flow $actual_bp_brokerage = (int) trim($excel_row[5]); $actual_bp_amt = (int) trim($excel_row[3]); 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 == 0) && !empty($actual_bp_amt)) { $actual_bp_per = (int) 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]);//commented becoz this filed removed tfrom excel file $actual_tp_per = 0;//set default value 0 for maintaining existing code flow $actual_tp_brokerage = (int) trim($excel_row[6]); $actual_tp_amt = (int) trim($excel_row[4]); 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 == "") && !empty($actual_tp_amt)) { $actual_tp_per = (int) round(($actual_tp_brokerage / $actual_tp_amt) * 100, 2); } } 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]); $actual_tep_per = 0; $actual_tep_brokerage = 0; $actual_tep_amt = 0; 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 == "") && !empty($actual_tep_amt)) { $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[] = ['co_share_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[7]), 'statement_id' => $file_id]; unset($source_data[$source_key]); continue 2; } } } } }catch (\Throwable $th) { $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - updateInsurerStatement: Exception: " . $th->getMessage() . " --- Line: " . $th->getLine() . " --- Trace: " . $th->getTraceAsString()); $errorData = [ 'message' => $th->getMessage(), 'file' => $th->getFile(), 'line' => $th->getLine(), 'code' => $th->getCode(), 'trace' => $th->getTraceAsString(), 'trace_array' => $th->getTrace(), // full array version (optional) 'function' => $th->getTrace()[0]['function'] ?? null, 'class' => $th->getTrace()[0]['class'] ?? null, ]; return ['status' => 'failed', 'code' => 500, 'message' => $th->getMessage(), 'error_data' => $errorData]; } // dd($data_to_update); $this->coShareStmtDetailsModel->insertBatch($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), 'invoice_status' => 'pending'])->update(); return array('status' => $ret_status, 'error_code' => $error_data['error_code'], 'error_data' => $error_data['error_data']); } public function validateInsurerStatement($params) { /* * Changes made: 12-06-2024 * - Added safe file_id handling and DB file record validation before using file details. * - Fixed physical file missing response and error message. * - Skips empty Excel rows and collects unique policy numbers from the uploaded statement. * - Fetches NHance source records only for those uploaded policy numbers. * - Sanitizes policy and endorsement numbers before comparison to avoid hidden-space mismatch. * - Validates each row by policy number + endorsement number combination. * - Detects duplicate policy + endorsement rows and returns row-wise validation errors. */ helper('excel_util_helper'); $file_id = $params['file_id'] ?? 0; try { $error_data = ['error_code' => '', 'error_data' => []]; $status = 'success'; $ret_status = true; //get file info $file = $this->insurerStatements->find((int)$file_id); // dd($file); if (empty($file)) { //file not found in DB $this->insurerStatements->where('id', $file_id)->set(['file_status' => 'failed', 'reason' => json_encode(['error_code' => 0, 'error_data' => 'statement file not found in DB'])])->update(); return array('status' => false, 'error_code' => 0, 'error_data' => 'statement file not found in DB'); } $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/statements', $file['file_name']); //check physical file if (!file_exists($file_name_with_path)) { //file not found update status and reason $message = "Physical 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, 'error_data' => $message); //0 - Physcial file not found } //get excel data to php array $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $sheet = $spreadsheet->getActiveSheet(); $highestRow = $sheet->getHighestRow(); $highestColumn = $sheet->getHighestColumn(); $excel_data = $sheet->rangeToArray('A1:' . $highestColumn . $highestRow); unset($excel_data[0]); $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data); // dd($excel_data); //get no of line items and update in DB $line_items = 0; $policyNos = []; foreach ($excel_data as $row) { if (check_row_is_empty_or_null($row)) { continue; } // row[1] => second column (B column) $policyNo = $this->sanitizeStatementLookupValue($row[1] ?? ''); if ($policyNo !== '') { $policyNos[] = $policyNo; } } $policyNos = array_values(array_unique($policyNos)); // get uploaded month transactions data // $source_data = $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactions(insurer_id: $file['insurer_id'], insurer_branch_id: $file['branch_id'], month: $file['month']); $source_data = !empty($policyNos) ? $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactionByPolicyAndEndorsement(insurer_id: $file['insurer_id'], insurer_branch_id: $file['branch_id'], policy_no: $policyNos) : []; // dd($source_data); $source_lookup = []; $source_policy_lookup = []; $source_endorsement_lookup = []; foreach ($source_data as $source_row) { $source_policy_no = $this->sanitizeStatementLookupValue($source_row['policy_no'] ?? ''); $source_endorsement_no = $this->sanitizeStatementLookupValue($source_row['endorsement_no'] ?? ''); $source_entry_key = $source_policy_no . '|' . $source_endorsement_no; $source_lookup[$source_entry_key] = true; $source_policy_lookup[$source_policy_no] = true; $source_endorsement_lookup[$source_policy_no][$source_endorsement_no] = true; } // check policy no,insurer and etc in DB for this month // if all good return true, otherwise return false with messssage $matched_entry = []; $error_messages = []; // row-wise error storage foreach ($excel_data as $excel_key => $excel_row) { $row_number = $excel_key; $is_row_empty = check_row_is_empty_or_null($excel_row); $policy_source_found = 0; $endorsement_source_found = 0; $duplicate_found = 0; if (!$is_row_empty) { $policy_no = $this->sanitizeStatementLookupValue($excel_row[1] ?? ''); //policy_number from excel $endorsement_no = $this->sanitizeStatementLookupValue($excel_row[2] ?? ''); //endorsement number from excel $entry_key = $policy_no . '|' . $endorsement_no; if (isset($matched_entry[$entry_key])) { $duplicate_found = 1; } elseif (isset($source_lookup[$entry_key])) { $line_items = $line_items + 1; $matched_entry[$entry_key] = true; continue; } $policy_source_found = isset($source_policy_lookup[$policy_no]) ? 1 : 0; $endorsement_source_found = isset($source_endorsement_lookup[$policy_no][$endorsement_no]) ? 1 : 0; // Policy number mismatch if ($policy_source_found == 0) { $error_messages[$row_number]['policy_no_mismatch'] = "Policy number ({$policy_no}) not in NHance."; } // Endorsement number mismatch if ($policy_source_found == 1 && $endorsement_source_found == 0) { $error_messages[$row_number]['endorsement_no_mismatch'] = "Endorsement number ({$endorsement_no}) not in NHance for policy ({$policy_no})."; } // Duplicate check if ($duplicate_found == 1) { $error_messages[$row_number]['duplicate'] = "Duplicate entry found. This policy and endorsement ({$policy_no} | {$endorsement_no}) combination has already been matched."; } } } // print_rr($error_messages);die; if (!empty($error_messages)) { $error_data['error_code'] = 2; $error_data['error_data'] = $error_messages; $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']); } catch (\Throwable $th) { $errorData = [ 'message' => $th->getMessage(), 'file' => $th->getFile(), 'line' => $th->getLine(), 'code' => $th->getCode(), 'trace' => $th->getTraceAsString(), 'trace_array' => $th->getTrace(), // full array version (optional) 'function' => $th->getTrace()[0]['function'] ?? null, 'class' => $th->getTrace()[0]['class'] ?? null, ]; $this->myLogger->logme("error", "POLICY-TRANSACTION-CONTROLLER - validateInsurerStatement: Exception: " . json_encode($errorData ?? [])); $this->insurerStatements->where('id', $file_id)->set(['line_items' => 0, 'file_status' => 'failed', 'reason' => json_encode($errorData)])->update(); return array('status' => false, 'error_code' => [], 'error_data' => $errorData); } } private function sanitizeStatementLookupValue($value): string { $value = trim((string)($value ?? '')); $value = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $value); return preg_replace('/[\x{200B}\x{200C}\x{200D}\x{FEFF}\x{00A0}\x{200E}\x{200F}\x{202A}-\x{202E}]/u', '', $value); } public function updateInsurerStatement($params) { /* * Changes made: 12-06-2024 * - Added safe file_id handling and DB file record validation before using file details. * - Fixed physical file missing response and error message. * - Skips empty Excel rows and collects unique policy numbers from the uploaded statement. * - Fetches NHance source records only for those uploaded policy numbers. * - Uses the same sanitized policy number + endorsement number matching as validation. * - Inserts statement details only for matched rows and skips empty or unmatched Excel rows. * - Added safe default handling for amount and reward columns before calculation/insert. */ helper('excel_util_helper'); $file_id = $params['file_id'] ?? 0; $error_data = ['error_code' => '', 'error_data' => []]; $status = 'success'; $ret_status = true; //get file info $file = $this->insurerStatements->find((int)$file_id); // dd($file); if (empty($file)) { //file not found in DB return array('status' => false, 'error_code' => 0, 'error_data' => 'statement file not found in DB'); } $file_name_with_path = storage_ensure_local_file(WRITEPATH . 'uploads/statements', $file['file_name']); //check physical file if (!file_exists($file_name_with_path)) { //file not found update status and reason $message = "Physical 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, 'error_data' => $message); //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]); $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data); // dd($excel_data); $policyNos = []; foreach ($excel_data as $row) { if (check_row_is_empty_or_null($row)) { continue; } $policyNo = $this->sanitizeStatementLookupValue($row[1] ?? ''); if ($policyNo !== '') { $policyNos[] = $policyNo; } } $policyNos = array_values(array_unique($policyNos)); // get uploaded month transactions data // $source_data = $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactions(insurer_id: $file['insurer_id'], insurer_branch_id: $file['branch_id'], month: $file['month']); $source_data = !empty($policyNos) ? $this->PTCOShareDetailsModel->getNonReconcileredPolicyTransactionByPolicyAndEndorsement(insurer_id: $file['insurer_id'], insurer_branch_id: $file['branch_id'], policy_no: $policyNos) : []; // Kint::dump($source_data);//die; // Kint::dump($excel_data); // die; $source_lookup = []; foreach ($source_data as $source_row) { $source_policy_no = $this->sanitizeStatementLookupValue($source_row['policy_no'] ?? ''); $source_endorsement_no = $this->sanitizeStatementLookupValue($source_row['endorsement_no'] ?? ''); $source_lookup[$source_policy_no . '|' . $source_endorsement_no][] = $source_row; } // check policy no,insurer and etc in DB for this month // if all good return true, otherwise return false with messssage $data_to_update = []; try { foreach ($excel_data as $excel_row) { if (check_row_is_empty_or_null($excel_row)) { continue; } // $policy_start_date = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[4]); //policy_start_date from excel // $policy_end_date = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[5]); //policy_end_date from excel $policy_no = $this->sanitizeStatementLookupValue($excel_row[1] ?? ''); //policy_number from excel // $client_name = preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $excel_row[3]); //clientname from excel $endorsement_no = $this->sanitizeStatementLookupValue($excel_row[2] ?? ''); //endorsement number from excel $entry_key = $policy_no . '|' . $endorsement_no; if (empty($source_lookup[$entry_key])) { continue; } $source_row = array_shift($source_lookup[$entry_key]); //calculate percentage first $total_amt = 0; // $actual_bp_per = trim($excel_row[9]); //commented becoz this filed removed tfrom excel file $actual_bp_per = 0; //set default value 0 for maintaining existing code flow $actual_bp_brokerage = (int) trim((string)($excel_row[5] ?? 0)); $actual_bp_amt = (int) trim((string)($excel_row[3] ?? 0)); 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 == 0) && !empty($actual_bp_amt)) { $actual_bp_per = (int) 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]);//commented becoz this filed removed tfrom excel file $actual_tp_per = 0;//set default value 0 for maintaining existing code flow $actual_tp_brokerage = (int) trim((string)($excel_row[6] ?? 0)); $actual_tp_amt = (int) trim((string)($excel_row[4] ?? 0)); 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 == "") && !empty($actual_tp_amt)) { $actual_tp_per = (int) round(($actual_tp_brokerage / $actual_tp_amt) * 100, 2); } } 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]); $actual_tep_per = 0; $actual_tep_brokerage = 0; $actual_tep_amt = 0; 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 == "") && !empty($actual_tep_amt)) { $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[] = ['co_share_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((string)($excel_row[7] ?? '')), 'statement_id' => $file_id]; } } catch (\Throwable $th) { $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - updateInsurerStatement: Exception: " . $th->getMessage() . " --- Line: " . $th->getLine() . " --- Trace: " . $th->getTraceAsString()); $errorData = [ 'message' => $th->getMessage(), 'file' => $th->getFile(), 'line' => $th->getLine(), 'code' => $th->getCode(), 'trace' => $th->getTraceAsString(), 'trace_array' => $th->getTrace(), // full array version (optional) 'function' => $th->getTrace()[0]['function'] ?? null, 'class' => $th->getTrace()[0]['class'] ?? null, ]; return ['status' => 'failed', 'code' => 500, 'message' => $th->getMessage(), 'error_data' => $errorData]; } // dd($data_to_update); $this->coShareStmtDetailsModel->insertBatch($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), 'invoice_status' => 'pending'])->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((int)$statement_id); $inv_payment_details = $this->invPaymentDetailsModel ->where('statement_id', $statement_id) ->where('is_active', 1) ->get() ->getResultArray(); if (!$inv_details['invoice_value']) { $stmt_level_value = $this->coShareStmtDetailsModel->select('sum(actual_tep_brokerage_amt) + sum(actual_tp_brokerage_amt) + sum(actual_bp_brokerage_amt) + sum(reward) as invoice_value') ->where('statement_id', $statement_id) ->groupBy('statement_id') ->get() ->getResultArray(); // print_r($stmt_level_value); if ($stmt_level_value && count($stmt_level_value) && isset($stmt_level_value[0])) { $inv_details['invoice_value'] = $stmt_level_value[0]['invoice_value']; } } // ~dd($inv_details); $data = [ 'invoice_status' => $inv_details['invoice_status'], 'gst_per' => isset($inv_details['gst_per']) ? $inv_details['gst_per'] : 18, 'invoice_value' => $inv_details['invoice_value'], 'gst_value' => $inv_details['gst_value'], 'invoice_no' => $inv_details['invoice_no'], 'invoice_amount' => $inv_details['invoice_amount'], 'invoice_date' => isset($inv_details['invoice_date']) ? change_date_format($inv_details['invoice_date'], 'Y-m-d', 'd/m/Y') : null ]; $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 = change_date_format($jsonData['invoice_date'], 'd/m/Y', 'Y-m-d'); $invoice_amount = $jsonData['invoice_amount']; $invoice_value = $jsonData['invoice_value']; $gst_per = $jsonData['invoice_gst_per']; $gst_value = $jsonData['invoice_gst']; //Update statement table $parentData = [ 'invoice_status' => $invoiceStatus, 'invoice_no' => $invoiceNo, 'invoice_date' => $invoiceDate, 'invoice_amount' => $invoice_amount, 'gst_per' => $gst_per, 'gst_value' => $gst_value, 'invoice_value' => $invoice_value, 'updated_by' => get_session_userid() ]; $this->insurerStatements->update($hiddenStatementId, $parentData); // Process child data $receivedAmounts = $jsonData['received_amount']; $utrNos = $jsonData['utr_no']; $tdsTotal = $jsonData['tds']; $gstTotal = $jsonData['gst_amount']; $paymentDates = $jsonData['payment_date']; $pks = $jsonData['pk']; foreach ($receivedAmounts as $index => $receivedAmount) { $pk = $pks[$index]; // Get the pk for the current record $utrNo = $utrNos[$index]; $tds = $tdsTotal[$index]; $gst = $gstTotal[$index]; $paymentDate = $paymentDates[$index]; if($utrNo == "" && $tds == "" && $gst == "" && $receivedAmount == "") { continue; } // Prepare data for insert/update $childData = [ 'inv_amt' => $receivedAmount, 'utr_no' => $utrNo, 'tds' => $tds, 'gst' => $gst, 'received_date' => change_date_format($paymentDate, 'd/m/Y', 'Y-m-d'), 'statement_id' => $hiddenStatementId ]; if ($pk) { $childData['updated_by'] = get_session_userid(); $childData['id'] = (int)$pk; } 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']); } public function deletePaymentEntry() { $payment_id = $this->request->getUri()->getSegment(4); //echo $payment_id; $this->invPaymentDetailsModel->update($payment_id, ['is_active' => 0]); return $this->respond(['dataStatus' => true, 'code' => 200], 200); } public function downloadSampleInsurerStatement() { $filePath = ROOTPATH . 'public/sample_excel/insurer_stament_sample.xlsx'; // 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 { // File not found, show an error message or redirect echo view('errors/html/production'); } } public function downloadInsurerStatement($id) { $statement = $this->insurerStatements ->where('id', (int) $id) ->where('is_active', 1) ->first(); if (empty($statement) || empty($statement['file_name'])) { throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Statement file not found'); } $fileName = basename($statement['file_name']); $storage = \Config\Services::getFileStorageService(); $result = $storage->download(WRITEPATH . 'uploads/statements', $fileName); if (! ($result['success'] ?? false)) { throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Statement file not found'); } $downloadAs = storage_upload_display_name($fileName); if (! empty($result['path']) && is_file($result['path'])) { return $this->response->download($result['path'], null)->setFileName($downloadAs); } if (! empty($result['content'])) { return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs); } throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('Statement file not found'); } public function getFileErr() { $file_id = $this->request->getUri()->getSegment(4); $file = $this->insurerStatements->find((int)$file_id); return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $file['reason']], 200); } public function dmsSearch() { // echo 'scbsc';die(); if ($this->request->is('post')) { // $jsonData = (array)$this->request->getJSON(); $request_data = $this->request->getPost(); $data = sanitizeInputArrayAdvanced($request_data); $customer_id = $data['customer_id']; $policy_id = $data['policy_id']; $cus_doc_name = $data['cus_doc_name']; $policy_doc_name = $data['policy_doc_name']; $pt_files = []; $kyc_files = []; $batch_files = []; $files = []; // print_r($jsonData);die(); if ($policy_id != "") { //get policy docs from policy transation related tables $pt_files = $this->PTFileModel->getPolicyDriveFilesIndex($policy_id, $policy_doc_name); $batch_files = $this->batchFileModel->getBatchFilesDataForDocumentSearch($policy_id, $policy_doc_name); $files = $this->filesModel->getFilesDataForDocumentSearch($policy_id, $policy_doc_name); // dd($files); // dd($this->PTFileModel->getLastQuery()); // ~dd($pt_files); } if ($customer_id != "") { $kyc_files = $this->clientKYCDocsModel->getClientKYCDriveFilesIndex($customer_id, $cus_doc_name); // dd($this->clientKYCDocsModel->getLastQuery()); // !dd($kyc_files); } $data['files'] = array_merge($pt_files, $kyc_files, $batch_files, $files); // dd($data['files']); } $data['tab_name'] = 'Documents Search'; $data['page_name'] = 'Documents'; $data['customers'] = $this->clientModel->select('id,client_name,short_name as display_value')->where('is_active', 1)->get()->getResultarray(); $data['policies'] = $this->clientPolicyModel->select("client_policy.id,client_policy.policy_no,policy_type.policy_type,concat(policy_type.policy_type,' - ',client_policy.policy_no) as display_value") ->join('policy_type', 'client_policy.policy_type_id = policy_type.id') ->where('client_policy.is_active', 1)->get()->getResultarray(); // dd($data); $this->loadLayout('dms_search', $data); } //--------------------------------------------------------------------------------------------------- public function getCoShareStatementDetails($pt_id) { if (!$pt_id) { return $this->respond([ 'status' => false, 'code' => 400, 'message' => 'No data found' ], 200); } // Fetch data from the database $data = db_connect()->table("co_share_stmt_details") ->select(" co_share_stmt_details.*, insurer_statements.month, insurer_statements.invoice_status, insurer_statements.invoice_date, insurer_statements.invoice_no, insurer_statements.invoice_amount, insurer_statements.stmt_sno, (co_share_stmt_details.actual_bp_amt + co_share_stmt_details.actual_tp_amt + co_share_stmt_details.actual_tep_amt) AS sum_of_actual_amt ") ->join('insurer_statements', 'co_share_stmt_details.statement_id = insurer_statements.id') ->where([ 'co_share_stmt_details.is_active' => 1, 'insurer_statements.is_active' => 1, 'co_share_stmt_details.co_share_id' => $pt_id ]) ->get() ->getResultArray(); // Check if data exists before formatting if ($data) { foreach ($data as &$row) { // Check if invoice_date is not null before formatting $row['invoice_date'] = $row['invoice_date'] ? change_date_format($row['invoice_date'], 'Y-m-d', 'd/m/Y') : null; // Check if month is not null before formatting $row['month'] = $row['month'] ? change_date_format($row['month'], 'Y-m-d', 'M-Y') : null; } return $this->respond([ 'status' => true, 'code' => 200, 'data' => $data ], 200); } else { return $this->respond([ 'status' => false, 'code' => 400, 'message' => 'No data found' ], 200); } } public function getClientPolicyDataBasedOnClientAndInsuer() { $client_id = $this->request->getGet('client_id') ?? 0; $client_branch_id = $this->request->getGet('client_branch_id') ?? 0; $insurer_id = $this->request->getGet('insurer_id') ?? 0; $insurer_branch_id = $this->request->getGet('insurer_branch_id') ?? 0; $policy_type_id = $this->request->getGet('policy_type_id') ?? 0; $builder = db_connect()->table("client_policy") ->select(" client_policy.*, policy_type.policy_type, ") ->join('policy_type', 'client_policy.policy_type_id = policy_type.id') ->where([ 'client_policy.is_active' => 1, ]); if (!empty($client_id)) { $builder->where('client_policy.client_id', $client_id); } if (!empty($client_branch_id)) { $builder->where('client_policy.client_branch_id', $client_branch_id); } if (!empty($insurer_id)) { $builder->where('client_policy.insurer_id', $insurer_id); } if (!empty($insurer_branch_id)) { $builder->where('client_policy.insurer_branch_id', $insurer_branch_id); } if (!empty($policy_type_id)) { $builder->where('client_policy.policy_type_id', $policy_type_id); } $result = $builder->get()->getResultArray(); if ($result) { return $this->respond(['status' => true, 'code' => 200, 'data' => $result, 'getData' => $this->request->getGet()], 200); } else { return $this->respond(['status' => false, 'code' => 400, 'message' => 'No data found'], 200); } } public function checkCDAmountForBasePremium() { $base_premium = $this->request->getGet('base_premium') ?? 0; $cd_ac_no = $this->request->getGet('cd_ac_no') ?? 0; // Validate inputs if (empty($cd_ac_no)) { return $this->respond(['status' => false, 'code' => 400, 'message' => 'CD Account Number is required'], 200); } // Build query $db = db_connect(); $builder = $db->table("cash_deposit") ->where('cd_ac_pk', $cd_ac_no) ->where('is_active', 1) ->orderBy('id', 'desc') ->limit(1); $result = $builder->get()->getRowArray(); if ($result) { // Check if base premium exceeds balance $base_premium_greater_than_balance = $base_premium > $result['balance']; return $this->respond([ 'status' => true, 'code' => 200, 'data' => $result, 'base_premium' => $base_premium, 'cd_ac_no' => $cd_ac_no, 'base_premium_greater_than_balance' => $base_premium_greater_than_balance, ], 200); } return $this->respond(['status' => false, 'code' => 400, 'message' => 'No data found for this CD'], 200); } public function getInsurerStatementMonth() { $insurer_id = $this->request->getGet('insurer_id'); $month = $this->request->getGet('month'); // echo $month; $insurer_branch_id = explode('-', $insurer_id)[1]; $insurer_id = explode('-', $insurer_id)[0]; $month = $month . '-01'; $month = change_date_format($month, 'Y-M-d', 'Y-m-d'); // echo $month; $res_data = $this->insurerStatements ->where('insurer_id', $insurer_id) ->where('branch_id', $insurer_branch_id) ->where('month', $month) ->where('is_active', 1) ->where('file_status', 'success') ->findAll(); return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => $res_data], 200); } public function deleteStatement($id) { // echo $id;die(); $this->coShareStmtDetailsModel->where('statement_id', $id) ->set(['is_active' => 0]) ->update(); $this->invPaymentDetailsModel->where('statement_id', $id) ->set(['is_active' => 0]) ->update(); $this->insurerStatements->where('id', $id) ->set(['is_active' => 0]) ->update(); return $this->respond(['dataStatus' => true, 'code' => 200], 200); } public function sendInstallmentRemainderMail() { $this->myLogger->logme("error", "Cron Job For Send Installment Remainder Mail Started"); try { /** @var BdsConfig $bdsConfig */ $bdsConfig = config(BdsConfig::class); if (!$bdsConfig->shouldFetchInstallmentRemindersToday()) { $this->myLogger->logme( 'error', 'Installment reminder fetch skipped (bds.installmentReminder.enabled / daily / days config)' ); CLI::write('Installment reminder fetch skipped per .env configuration'); return ['status' => false, 'message' => 'Fetch skipped per configuration', 'response' => []]; } $bdsInstallmentData = []; try { $bdsInstallmentData = $this->BdsPlacementModel->getLeadInstallmentDetails(); } catch (Exception $e) { $this->myLogger->logme('error', 'Exception: ' . $e->getMessage() . 'Page: ' . $e->getFile() . ' Line: ' . $e->getLine()); } $this->myLogger->logme("error", "Data for BDS Installment " . json_encode($bdsInstallmentData)); // dd($bdsInstallmentData);die(); if (empty($bdsInstallmentData)) { $this->myLogger->logme("error", "No Client Installment is Due in the 5th Day"); CLI::write("No Client Installment is Due in the 5th Day"); return ['status' => false, 'message' => 'No data found', 'response' => []]; } $results = []; $successCount = 0; $failedCount = 0; $skippedCount = 0; foreach ($bdsInstallmentData as $installmentData) { $installmentId = $installmentData['id'] ?? 'unknown'; $leadId = $installmentData['lead_id'] ?? 'unknown'; try { $mailData = $this->PrepareBDSMailData($installmentData); if (empty($mailData) || empty($mailData['to_mail'])) { $this->myLogger->logme( 'error', "Installment {$installmentId} (lead {$leadId}): skipped โ€” no valid recipient emails" ); $skippedCount++; $results[] = [ 'installment_id' => $installmentId, 'lead_id' => $leadId, 'status' => 'skipped', 'message' => 'No valid recipient emails', ]; continue; } $to_mail = $mailData['to_mail']; $message = $mailData['message']; $subject = $mailData['subject']; $this->myLogger->logme("error", "Installment Pending for " . $subject); $common = ['mail_type' => 'installment_amount_due_remainder_mail']; $res = MailHelper::send_email(['mail' => $to_mail, 'subject' => $subject, 'message' => $message, 'common' => $common]); $res = json_decode($res); $this->myLogger->logme( 'error', "Installment {$installmentId} (lead {$leadId}) mail result: " . json_encode($res) ); if ($res->status == 'success') { $successCount++; CLI::write("Mail sent successfully for installment {$installmentId} to " . count($to_mail) . " recipients"); $results[] = [ 'installment_id' => $installmentId, 'lead_id' => $leadId, 'status' => 'success', ]; } else { $failedCount++; CLI::write("Mail failed for installment {$installmentId}"); $results[] = [ 'installment_id' => $installmentId, 'lead_id' => $leadId, 'status' => 'failed', 'response' => $res, ]; } } catch (Exception $e) { $failedCount++; $this->myLogger->logme( 'error', "Installment {$installmentId} (lead {$leadId}) exception: " . $e->getMessage() ); $results[] = [ 'installment_id' => $installmentId, 'lead_id' => $leadId, 'status' => 'failed', 'message' => $e->getMessage(), ]; } } $totalProcessed = count($bdsInstallmentData); $summaryMessage = "Processed {$totalProcessed} installment(s): {$successCount} sent, {$failedCount} failed, {$skippedCount} skipped"; return [ 'status' => $successCount > 0, 'message' => $summaryMessage, 'response' => $results, ]; } catch (Exception $e) { $this->myLogger->logme('error', 'Exception: ' . $e->getMessage() . 'Page: ' . $e->getFile() . ' Line: ' . $e->getLine()); } } protected function PrepareBDSMailData($data) { try { helper('excel_util_helper'); $installment_amount = (float) ($data['installment_amount'] ?? 0); $payment_date = date('d-m-Y', strtotime($data['payment_date'])); $client = $data['client_name']; $branch = $data['branch_name']; $sales_person_mail = $data['sales_person']; $policy_no = trim((string) ($data['policy_no'] ?? '')); $client_short_name = isset($data['short_name']) && $data['short_name'] != null ? $data['short_name'] : $data['client_name']; $formatted_amount = 'โ‚น ' . formatIndianCurrency(number_format($installment_amount, 2, '.', '')); $is_overdue = strtotime($data['payment_date']) < strtotime(date('Y-m-d')); $policy_label = $policy_no !== '' ? "Policy #{$policy_no}" : 'Policy Pending'; $policy_period = ''; if (!empty($data['policy_start_date']) && !empty($data['policy_end_date'])) { $policy_period = date('d-m-Y', strtotime($data['policy_start_date'])) . ' to ' . date('d-m-Y', strtotime($data['policy_end_date'])); } $subject = $is_overdue ? "Overdue Installment Reminder - {$client_short_name} | {$policy_label} | Due {$payment_date}" : "Installment Payment Reminder - {$client_short_name} | {$policy_label} | Due {$payment_date}"; $message = view('bds_installment_reminder_email_template', [ 'client_name' => $client, 'branch_name' => $branch, 'policy_no' => $policy_no !== '' ? $policy_no : 'Not Assigned', 'policy_type' => $data['policy_type'] ?? '', 'insurer_name' => $data['insurer_name'] ?? '', 'policy_period' => $policy_period, 'payment_date' => $payment_date, 'installment_amount' => $formatted_amount, 'is_overdue' => $is_overdue, 'generated_on' => date('d-m-Y H:i'), ]); $contactPersonEmail = trim((string) ($data['contact_person_email'] ?? '')); $to_mail = array_merge( [$data['acm_email']], [$sales_person_mail], $contactPersonEmail !== '' ? [$contactPersonEmail] : [] ); $to_mail = array_values(array_unique(array_filter($to_mail, static function ($email) { return is_string($email) && filter_var(trim($email), FILTER_VALIDATE_EMAIL); }))); $this->myLogger->logme("error", "Selected To Address : " . json_encode($to_mail)); return [ 'to_mail' => $to_mail, 'message' => $message, 'subject' => $subject ]; } catch (Exception $e) { $this->myLogger->logme('error', 'Exception: ' . $e->getMessage() . 'Page: ' . $e->getFile() . ' Line: ' . $e->getLine()); } } public function getMoreInfo() { $pt_id = $this->request->getPost("pt_id"); $data_to_send['bds_data'] = $this->BdsPlacementModel->where("is_active", 1)->where("pt_id", $pt_id)->findAll(); foreach ($data_to_send['bds_data'] as &$data) { $data['payment_date'] = (new \DateTime($data['payment_date']))->format('d-m-Y'); } if (!empty($data_to_send)) { return $this->respond(['status' => true, "data" => $data_to_send], 200); } else { return $this->respond(['status' => false, "No Data Found For the Policy Transaction"], 404); } } public function saveInstallment() { $installments = $this->request->getPost('installments'); if (!$installments || !is_array($installments)) { return $this->respond(['status' => false, 'message' => 'No data received'], 400); } $this->myLogger->logme("error", json_encode($installments)); // die(); foreach ($installments as &$row) { // Convert date from d-m-Y to Y-m-d if (!empty($row['payment_date'])) { $date = \DateTime::createFromFormat('d-m-Y', $row['payment_date']); if ($date) { $row['payment_date'] = $date->format('Y-m-d'); } } $this->BdsPlacementModel->save($row); } return $this->respond(['status' => true, 'message' => 'Data saved successfully'], 200); } protected function getPolicyForEndorsment() { $policyList = []; $policyListByClient = []; $clients = $this->clientModel ->select("*, DATE_FORMAT(dob, '%d-%m-%Y') as dob") ->where('is_active', 1) ->findAll(); $clientIds = array_column($clients, 'id'); // $policies = $this->clientPolicyModel // ->select(" // client_policy.*, // policy_type.policy_type, // policy_type.ebp, // policy_type.etp, // policy_type.iep, // policy_type.itp, // policy_type.bap, // policy_type.allocg, // DATE_FORMAT(client_policy.policy_start_date, '%d/%m/%Y') as policy_start_date, // DATE_FORMAT(client_policy.policy_end_date, '%d/%m/%Y') as policy_end_date // ") // ->join('policy_type', 'policy_type.id = client_policy.policy_type_id') // ->join('policy_transaction pt', 'pt.client_policy_id = client_policy.id and pt.action_type = "inception" and pt.is_active = 1 and pt.client_policy_id is not null') // ->whereIn('client_policy.client_id', $clientIds) // ->where('client_policy.is_active', 1) // ->findAll(); // Only columns needed for policy_transaction_endorsement_list appendPolicies() JSON โ€” not policy_transaction.* // (full rows + json_encode duplicated memory and exceeded PHP memory_limit on large datasets). $policies = $this->policyTransactionModel ->select(" policy_transaction.id, policy_transaction.client_id, policy_transaction.client_branch_id, policy_transaction.policy_no, policy_transaction.policy_type_id, policy_transaction.insurer_id, policy_transaction.insurer_branch_id, policy_transaction.tpa_id, policy_transaction.tpa_branch_id, policy_transaction.cd_ac_no, policy_type.policy_type, policy_type.ebp, policy_type.etp, policy_type.iep, policy_type.itp, policy_type.bap, policy_type.allocg, DATE_FORMAT(policy_transaction.policy_start_date, '%d/%m/%Y') as policy_start_date, DATE_FORMAT(policy_transaction.policy_end_date, '%d/%m/%Y') as policy_end_date ") ->join('policy_type', 'policy_type.id = policy_transaction.policy_type_id') ->whereIn('policy_transaction.client_id', $clientIds) ->where('policy_transaction.is_active', 1) ->where('policy_transaction.action_type', "inception") ->findAll(); foreach ($policies as $policy) { $policyList[$policy['client_branch_id']][] = $policy; $policyListByClient[$policy['client_id']][] = $policy; } return [$policyList, $policyListByClient]; } public function reportBDSNew() { // ๐Ÿงญ Basic Page Info $data['tab_name'] = 'BDS Report'; $data['page_name'] = 'BDS Report'; // ๐Ÿ“‹ Dropdown Data $data['issuer'] = [1 => 'JIBS', 2 => 'Nhance']; $data['client_type'] = [1 => 'Group', 2 => 'Individual']; $data['issuing_type'] = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over']; $data['policy_status'] = [ 'pending' => 'Pending', 'exported_to_insurer' => 'Exported to Insurer', 'imported_from_insurer'=> 'Imported from Insurer', 'exported_to_tpa' => 'Exported to TPA', 'imported_from_tpa' => 'Imported from TPA', 'completed' => 'Completed' ]; $data['invoice_status_array'] = [ 'yet_to_generate' => 'Yet to Generate', 'generated' => 'Generated', 'send' => 'Send', 'recived' => 'Recived', ]; $data['date_type'] = [ 'policy_issue_date' => 'Policy Issue Date', 'policy_start_date' => 'Policy Start Date', 'policy_end_date' => 'Policy End Date', 'data_received_date' => 'Data Received Date', 'closure_date' => 'Closure Date', 'statement_month' => 'Statement Month', ]; // ๐Ÿข Fetch Active Data $data['insurer'] = $this->insurerModel->where('is_active', 1)->findAll(); $data['policy_types'] = $this->policyTypeModel->where('is_active', 1)->findAll(); $data['clients'] = $this->clientModel->where('is_active', 1)->findAll(); $data['users'] = $this->userModel->where('is_active', 1)->findAll(); $data['policy_count'] = $this->policyTransactionModel->where('is_active', 1)->countAllResults(); // ๐Ÿ• Filters $start_date = $this->request->getGet('start_date'); $end_date = $this->request->getGet('end_date'); $client_id = $this->request->getGet('client_id'); $insurer_id = $this->request->getGet('insurer_id'); $policy_type_id = $this->request->getGet('policy_type_id'); $date_type = $this->request->getGet('date_type'); $issuer = $this->request->getGet('issuer'); $client_branch_id = $this->request->getGet('client_branch_id'); $insurer_branch_id = $this->request->getGet('insurer_branch_id'); $client_policy_id = $this->request->getGet('client_policy_id'); $user_id = $this->request->getGet('user_id'); // Handle statement month range if ($date_type == 'statement_month') { $start_date = (string) date('Y-m-01', strtotime($start_date)); $end_date = (string) date('Y-m-t', strtotime($end_date)); } // Ensure default values $start_date = $start_date ?: 0; $end_date = $end_date ?: 0; $client_id = $client_id ?: 0; $insurer_id = $insurer_id ?: 0; $policy_type_id = $policy_type_id ?: 0; $date_type = $date_type ?: 0; $issuer = $issuer ?: 0; $client_branch_id = $client_branch_id ?: 0; $insurer_branch_id = $insurer_branch_id ?: 0; $client_policy_id = $client_policy_id ?: 0; $user_id = $user_id ?: 0; // ๐Ÿงพ Handle POST requests (Dashboard filters) if ($this->request->is('post')) { $isFromDashboard = $this->request->getPost('is_dashboard'); if (!empty($isFromDashboard) && $isFromDashboard == 1) { $ids = array_filter(explode(',', $this->request->getPost('ids'))); if (!empty($ids)) { $idsStr = implode(',', array_map('intval', $ids)); // sanitize IDs $where = "policy_transaction.id IN ($idsStr)"; } else { $where = []; // No valid IDs } } } // ๐Ÿ“Š Fetch report data $data['report_list'] = $this->policyTransactionModel->reportBDSNew( $start_date, $end_date, $client_id, $insurer_id, $policy_type_id, $date_type, $issuer, $client_branch_id, $insurer_branch_id, $client_policy_id, $user_id, $where ?? '' ); $data['list_new'] = true; // ๐Ÿงฉ Load View $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' => 17]); // 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, bds_dump_files.created_by, 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(); if (in_array(get_role_id(), [2, 3, 4])) { $data['bds_dump_file_data'] = array_values(array_filter($data['bds_dump_file_data'], function ($file) { return (int) ($file['created_by'] ?? 0) === (int) get_session_userid(); })); } 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); } $filename = storage_file_Upload($avatar, WRITEPATH . 'uploads/bds_dump_excel/', UPLOAD_EXT_EXCEL); if ($filename !== '') { $fileSize = method_exists($avatar, 'getSize') ? ($avatar->getSize() / (1024 * 1024)) : 0; $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, 'created_by' => get_session_userid() ]; $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) { $file_data = $this->bdsDumpModel->where('id', $file_id)->first(); if (empty($file_data) || empty($file_data['file_name'])) { $data['message'] = 'File record not found'; return view('errors/404', $data); } $fileName = basename((string) $file_data['file_name']); $storage = \Config\Services::getFileStorageService(); $result = $storage->download(WRITEPATH . 'uploads/bds_dump_excel', $fileName); try { if ($result['success'] ?? false) { $downloadAs = storage_upload_display_name($fileName); if (! empty($result['path']) && is_file($result['path'])) { return $this->response->download($result['path'], null)->setFileName($downloadAs); } if (! empty($result['content'])) { return $this->response->download($downloadAs, $result['content'])->setFileName($downloadAs); } } $data['message'] = 'The Physical File Not Found'; return view('errors/404', $data); } catch (\Exception $e) { $this->myLogger->logme('error', $e->getMessage()); $data['message'] = 'The Physical File Not Found'; return view('errors/404', $data); } } 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 = storage_ensure_local_file(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();
        $pos_data = db_connect()->table('partner_pos')->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 = storage_ensure_local_file(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();
        $pos_data = db_connect()->table('partner_pos')->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                  = cleanNumber($row[16]);
                $non_commission_premium_amount = cleanNumber($row[17]);
                $tp_premium                    = cleanNumber($row[18]);
                $igst                          = cleanNumber($row[19]);
                $cgst                          = cleanNumber($row[20]);
                $sgst                          = cleanNumber($row[21]);
                $stamp_duty                    = cleanNumber($row[22]);
                $agreed_amount                 = cleanNumber($row[23]);
                $agreed_bp_percentage          = cleanNumber($row[24]);
                $agreed_tp_percentage          = cleanNumber($row[25]);

                // $total                             = trim($row[23]);
                // $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]);
                $actual_bp_amount                  = 0;
                $actual_tp_amount                  = 0;
                $actual_bp_percentage              = 0;
                $actual_tp_percentage              = 0;
                $actual_bp_brokerage_amount        = 0;
                $actual_tp_brokerage_amount        = 0;
                $expected_amount                   = 0;
                $rewards                           = 0;

                $calculation = calculateMotorPolicyAmounts([
                    'base_premium' => $base_premium,
                    'non_commission_premium_amount' => $non_commission_premium_amount,
                    'tp_premium' => $tp_premium,
                    'igst' => $igst,
                    'cgst' => $cgst,
                    'sgst' => $sgst,
                    'stamp_duty' => $stamp_duty,
                    'agreed_amount' => $agreed_amount,
                    'agreed_bp_percentage' => $agreed_bp_percentage,
                    'agreed_tp_percentage' => $agreed_tp_percentage,
                    'standard_bp_percentage' => 15.00, 
                    'standard_tp_percentage' => 2.5 
                ]);

                log_message('error', 'Motor Policy Calculation: ' . json_encode($calculation));


                $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;
                $current_agent_data = check_agent_exist($row, $pos_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;

                // get the client and vehicle id
                $vehicle_and_client_ids = $this->getClientAndVehicleId($row, $vehicle_data, $client_data, $rto_master, $vehicle_type_data);
                $vehicle_id = $vehicle_and_client_ids['vehicle_id'] ?? null;
                $client_id = $vehicle_and_client_ids['client_id'] ?? null;

                $policy_transaction_data = [

                    'issuer'                => 2,
                    'issuer_branch'         => $salse['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,
                    'salse_person_manager_id'   => $salse['rm_id'] ?? null,
                    'service_person_manager_id' => $service['rm_id'] ?? null,
                    'service_person_branch_id'  => $service['nhance_branch_id'] ?? null,
                    // 'agent_id'              => $current_agent_data['id'] ?? null,
                    // 'agent_code'            => $current_agent_data['agent_code'] ?? null,
                    'pos_id'                => $current_agent_data['id'] ?? null,
                    'file_id'               => $params['file_id'],
                    'created_by'            => $file['created_by'] ?? null,
                    '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'                => $calculation['gst_amount'] ?? $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'                    => $calculation['total_amount'] ?? 0,
                    'stamp_duty'                => $stamp_duty,

                    'cop_amt'                   => $base_premium,
                    'cotp_amt'                  => $tp_premium,
                    'cotep_amt'                 => 0.00,

                    'exp_amt'                   => $calculation['expected_amount'] ?? $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'],
                    'created_by'                => $file['created_by'] ?? null,
                ];

                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);
            $status = 'success';
            $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 success', ['file_id' => $file_id]);
        }

        return $result;
    }

    public function extractExcelData($file_name, $highestColumn)
    {
        // $file_name = "claims_dump_form_client.xlsx";
        // Load the Excel file
        $file_name_with_path = storage_ensure_local_file(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 = storage_ensure_local_file(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');
        }
    }

    public function getClientAndVehicleId($row, $vehicle_data, $client_data, $rto_master, $vehicle_type_data)
    {
        $vehicle_number = trim($row[2]);
        $client_name = trim($row[5]);
        $client_email = trim($row[6]);

        $vehicle_id = null;
        $client_id  = null;

        // -------------------------------------------
        // 1. First Stage: Check if vehicle already exists
        // -------------------------------------------

        if(strtolower(trim($vehicle_number)) != 'new'){
            foreach ($vehicle_data as $v) {
                if (strcasecmp(trim($v['vehicle_no']), $vehicle_number) === 0) {
                    $vehicle_id = $v['id'];
                    $client_id  = $v['owner'];
                    break;
                }
            }
        }

        // -------------------------------------------
        // 2. Second Stage: Vehicle not found -> check client by email
        // -------------------------------------------
        $second_stage_client_id = null;

        if (empty($vehicle_id) && empty($client_id)) {

            if(strtolower(trim($vehicle_number)) != 'new'){
                foreach ($client_data as $c) {
                    if (strcasecmp(trim($c['email']), $client_email) === 0) {
                        $second_stage_client_id = $c['id'];
                        break;
                    }
                }
            }

            if (!empty($second_stage_client_id)) {

                // Existing client โ€“ Insert vehicle
                $matched_rto_id  = check_rto_data($row, $rto_master);
                $vehicle_type_id = check_vehicle_type($row, $vehicle_type_data);

                $vehicle_insert = [
                    'vehicle_no'   => $vehicle_number,
                    'vehicle_type' => $vehicle_type_id['vehicle_type']['id'] ?? null,
                    'owner'        => $second_stage_client_id,
                    'rto_id'       => $matched_rto_id['rto_data']['id'] ?? null,
                ];

                $vehicle_id = $this->vehicleModel->insert($vehicle_insert);
                $client_id  = $second_stage_client_id;
            } else {

                // -------------------------------------------
                // 3. Third Stage: No existing client โ†’ Insert new client then insert vehicle
                // -------------------------------------------
                $client_insert = [
                    '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);

                if ($client_id) {

                    $matched_rto_id  = check_rto_data($row, $rto_master);
                    $vehicle_type_id = check_vehicle_type($row, $vehicle_type_data);

                    $vehicle_insert = [
                        '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);
                }
            }
        }

        return [
            'client_id'  => $client_id,
            'vehicle_id' => $vehicle_id,
        ];
    }

    public function truncateBdsBulkUploadData()
    {
        $file_id = $this->request->getGet('file_id') ?? null;
        if (empty($file_id)) {
            return array('status' => false, 'message' => 'file_id is required');
        }

        $data['is_active'] = 0;
        $this->policyTransactionModel->where('file_id', $file_id)->set($data)->update();
        $this->PTCOShareDetailsModel->where('file_id', $file_id)->set($data)->update();

        return $this->respond(['status' => true, 'code' => 200, 'message' => 'BDS bulk upload data truncated successfully'], 200);
    }

    // ------------------------------------------------------------------------------------------------------------------
    
    /**
     * Cron job: Daily BDS Report
     * Fetches today's BDS entries, generates Excel (matching report_bds.php column order), and emails to recipients from .env.
     * Recipients: comma-separated emails in bds.reportEmails
     * File stored temporarily in writable/tmp/ and deleted after sending.
    */
    public function cronDailyBDSReport()
    {
       
        helper('excel_import_export_helper');

        $filePath = null;
        try {

            $today = date('Y-m-d', strtotime('-1 day'));
            $reportList = $this->policyTransactionModel->getBDSReportList($today, $today,0,0,0,'created_at',0,0,0,0,0,[]);
            
            if (empty($reportList)) {
                $this->myLogger->logme('error', "cronDailyBDSReport: No BDS records for {$today}");
                return $this->respond(['status' => 'success', 'message' => 'No BDS records for today. No report sent.'], 200);
            }

            // Column headers exactly matching report_bds.php order (including display:none columns)
            $headers = [
                'S. No', 'User', 'Month', 'Business Type', 'Client Type', 'Insured Name', 'Transaction Type',
                'Policy Type', 'BAP Group', 'Vehicle Number', 'Policy No', 'Endorsement No', 'Insurer Branch',
                'Endorsement Effective Date', 'Policy Effective Date', 'Policy Expiry Date', 'Reference', 'Remarks',
                'BP Premium', 'TP Premium', 'Premium (without GST)', 'Total Premium', 'Agreed BP %', 'Agreed TP %',
                'Rewards', 'Agreed Amount', 'Invoiced Amount', 'Outstanding Amount',
                'Salse Person', 'Service Person', 'Salse Person Branch', 'Installment', 'Data Received Date', 'Renewal Date',
                'Co-Premium', 'Remuneration Pay By Leader', 'Salse Person Manager', 'Service Person Manager',
                'Service Person Branch', 'Rollover Date', 'Policyholder Name', 'Insured (Same as Proposer)',
                'Follower Policy No', 'Co-Share %', 'Non Commissional Premium Amount', 'CGST', 'SGST', 'IGST',
                'Stamp Duty', 'Standard BP %', 'Standard TP %', 'Actual BP Amount', 'Actual TP Amount',
                'Actual BP %', 'Actual TP %', 'Actual BP Remuneration Amount', 'Actual TP Remuneration Amount',
                'CD Account No'
            ];

            $excelData = [];
            foreach ($reportList as $idx => $row) {
                $totalIrda = (float)($row['total_irda_amt'] ?? 0);
                $billedAmt = (float)($row['billed_amt'] ?? 0);
                $unbilledAmt = $totalIrda - $billedAmt;
                if ($totalIrda == 0) {
                    $unbilledAmt = abs($unbilledAmt);
                }
                $unbilledAmt = ($unbilledAmt == 0 && $billedAmt == 0) ? $totalIrda : $unbilledAmt;

                $hasIrda = ($totalIrda != 0);

                $excelData[] = [
                    $idx + 1,
                    $row['user_name'] ?? 'N/A',
                    $row['policy_issue_month'] ?? 'N/A',
                    $row['revenue_type'] ?? 'N/A',
                    $row['client_type'] ?? 'N/A',
                    $row['client_name'] ?? 'N/A',
                    $row['action_type'] ?? 'N/A',
                    $row['policy_type'] ?? 'N/A',
                    $row['bap'] ?? 'N/A',
                    $row['vehicle_no'] ?? 'N/A',
                    $row['policy_no'] ?? 'N/A',
                    $row['endorsement_no'] ?? 'N/A',
                    $row['insurer_branch_name'] ?? 'N/A',
                    !empty($row['endorse_eff_date']) ? change_date_format($row['endorse_eff_date'], 'Y-m-d', 'd/m/Y') : 'N/A',
                    !empty($row['policy_start_date']) ? change_date_format($row['policy_start_date'], 'Y-m-d', 'd/m/Y') : 'N/A',
                    !empty($row['policy_end_date']) ? change_date_format($row['policy_end_date'], 'Y-m-d', 'd/m/Y') : 'N/A',
                    $row['ref'] ?? 'N/A',
                    $row['remarks'] ?? 'N/A',
                    $hasIrda ? ($row['bp_amt'] ?? '0.00') : '0.00',
                    $hasIrda ? ($row['tp_or_ter'] ?? '0.00') : '0.00',
                    $hasIrda ? ($row['premium_wo_gst'] ?? '0.00') : '0.00',
                    $hasIrda ? ($row['total_premium'] ?? '0.00') : '0.00',
                    $hasIrda ? ($row['agreed_bp_per'] ?? '0.00') . '%' : '0.00%',
                    $hasIrda ? ($row['agreed_tp_or_ter_per'] ?? '0.00') . '%' : '0.00%',
                    $row['reward'] ?? '0.00',
                    $row['total_irda_amt'] ?? '0.00',
                    !empty($row['billed_amt']) ? $row['billed_amt'] : '0.00',
                    number_format((float)$unbilledAmt, 2, '.', ''),
                    $row['salse_person_name'] ?? 'N/A',
                    $row['service_person_name'] ?? 'N/A',
                    $row['nhance_branch'] ?? 'N/A',
                    $row['installment'] ?? 'N/A',
                    !empty($row['data_received_date']) ? change_date_format($row['data_received_date'], 'Y-m-d', 'd/m/Y') : 'N/A',
                    !empty($row['renewal_date']) ? change_date_format($row['renewal_date'], 'Y-m-d', 'd/m/Y') : 'N/A',
                    $row['co_share'] ?? 'No',
                    $row['bro_payable_by'] ?? 'No',
                    $row['salse_manager_name'] ?? 'N/A',
                    $row['service_manager_name'] ?? 'N/A',
                    $row['service_branch'] ?? 'N/A',
                    !empty($row['rollover_date']) ? change_date_format($row['rollover_date'], 'Y-m-d', 'd/m/Y') : 'N/A',
                    $row['policy_holder_name'] ?? 'N/A',
                    $row['same_as_proposer'] ?? 'No',
                    $row['follower_policy_no'] ?? 'N/A',
                    number_format((float)($row['co_share_per'] ?? 0), 2),
                    number_format((float)($row['non_comm_per_amt'] ?? 0), 2),
                    number_format((float)($row['bp_cgst'] ?? 0), 2),
                    number_format((float)($row['bp_sgst'] ?? 0), 2),
                    number_format((float)($row['bp_igst'] ?? 0), 2),
                    number_format((float)($row['stamp_duty'] ?? 0), 2),
                    number_format((float)($row['standerd_bp_per'] ?? 0), 2),
                    number_format((float)($row['standerd_tp_per'] ?? 0), 2),
                    number_format((float)($row['actual_bp_amt'] ?? 0), 2),
                    number_format((float)($row['actual_tp_amt'] ?? 0), 2),
                    number_format((float)($row['actual_bp_per'] ?? 0), 2),
                    number_format((float)($row['actual_tp_per'] ?? 0), 2),
                    number_format((float)($row['actual_tep_brokerage_amt'] ?? 0), 2),
                    number_format((float)($row['actual_tp_brokerage_amt'] ?? 0), 2),
                    $row['cd_ac_no'] ?? 'N/A'
                ];
            }

            $today = date('d-m-Y', strtotime($today));
            $fileName = 'BDS_Daily_Report_' . $today . '.xlsx';
            $tmpDir = WRITEPATH . 'tmp' . DIRECTORY_SEPARATOR;
            if (!is_dir($tmpDir)) {
                mkdir($tmpDir, 0755, true);
            }
            $filePath = $tmpDir . $fileName;

            $generated = generate_excel($headers, $excelData, $filePath);
            if (!$generated) {
                $this->myLogger->logme('error', 'cronDailyBDSReport: Excel generation failed');
                return $this->respond(['status' => false, 'message' => 'Excel generation failed'], 500);
            }

            $emailList = getenv('bds.dailyReportEmails') ?: '';
            $recipientEmails = array_filter(array_map('trim', explode(',', $emailList)));
            if (empty($recipientEmails)) {
                @unlink($filePath);
                $this->myLogger->logme('error', 'cronDailyBDSReport: No recipients in bds.dailyReportEmails. Report generated but not sent.');
                return $this->respond([
                    'status' => 'success',
                    'message' => 'Report generated. No recipients configured (set bds.dailyReportEmails in .env).',
                    'file' => $fileName
                ], 200);
            }

            $subject = "BDS Report Up to - {$today}";
            $message = "

Please find attached the BDS report up to {$today}.

"; $message .= "

Total records: " . count($reportList) . "

"; $attachments = [ ['filePath' => $filePath, 'fileName' => $fileName] ]; $res = MailHelper::send_email([ 'mail' => $recipientEmails, 'subject' => $subject, 'message' => $message, 'attachments' => $attachments ]); @unlink($filePath); $resDecoded = is_string($res) ? json_decode($res, true) : $res; if (isset($resDecoded['status']) && $resDecoded['status'] === 'success') { $this->myLogger->logme('error', "cronDailyBDSReport: Report sent to " . count($recipientEmails) . " recipients"); return $this->respond([ 'status' => true, 'message' => 'Report generated and emailed successfully.', 'recipients' => count($recipientEmails) ], 200); } $this->myLogger->logme('error', 'cronDailyBDSReport: Email send failed - ' . json_encode($resDecoded)); return $this->respond(['status' => false, 'message' => 'Report generated but email send failed'], 500); } catch (Exception $e) { if ($filePath && is_file($filePath)) { @unlink($filePath); } $this->myLogger->logme('error', 'cronDailyBDSReport Exception: ' . $e->getMessage()); return $this->respond(['status' => false, 'message' => $e->getMessage()], 500); } } /** * Download policy transaction (pt_files) document from local/S3 storage. */ public function downloadPtDocument($fileOrId = null) { if ($fileOrId === null || $fileOrId === '') { $data['message'] = 'No file specified.'; return view('errors/404', $data); } $uploadFilePath = WRITEPATH . 'uploads/client_kyc_documents'; $storedFileName = null; $downloadAs = null; if (ctype_digit((string) $fileOrId)) { $record = $this->PTFileModel->find((int) $fileOrId); if (empty($record) || empty($record['file_name'])) { $data['message'] = 'File record not found'; return view('errors/404', $data); } $storedFileName = basename((string) $record['file_name']); $downloadAs = storage_upload_display_name($storedFileName); } else { $storedFileName = basename((string) $fileOrId); $downloadAs = storage_upload_display_name($storedFileName); } $storage = \Config\Services::getFileStorageService(); $result = $storage->download($uploadFilePath, $storedFileName); if (! ($result['success'] ?? false)) { $data['message'] = 'The Physical File Not Found'; return view('errors/404', $data); } if (! empty($result['path']) && is_file($result['path'])) { return $this->response->download($result['path'], null)->setFileName($downloadAs); } if (! empty($result['content'])) { return $this->response ->download($downloadAs, $result['content']) ->setFileName($downloadAs); } $data['message'] = 'The Physical File Not Found'; return view('errors/404', $data); } }