myLogger = \Config\Services::mylogger(); $this->clientModel = new ClientModel(); $this->userModel = new UserModel(); $this->clientBranchModel = new ClientBranchModel(); $this->clientPolicyModel = new ClientPolicyModel(); $this->levelContactModel = new LevelContactModel(); $this->leadsModel = new LeadsModel(); $this->policyTypeModel = new PolicyTypeModel(); $this->kycEntityTypeModel = new KYCEntityTypeModel(); $this->policyTransactionStatusModel = new PolicyTransactionStatusModel(); $this->insurerBranchModel = new InsurerBranchModel(); $this->tpaBranchModel = new TPABranchModel(); $this->RFQModel = new RFQModel(); $this->insurerModel = new InsurerModel(); $this->occupancyModel = new OccupancyMasterModel(); $this->leadFilesModel = new LeadFilesModel(); $this->leadInstallmentPaymentDetails = new LeadInstallmentPaymentDetails(); $this->gmailSentHistoryModel = new GmailSentHistoryModel(); $this->issuer = [1 => 'JIBS', 2 => 'Nhance']; $this->clientType = [1 => 'Group', 2 => 'Individual']; $this->leadType = [1 => 'Fresh', 2 => 'Renewal', 3 => 'Roll Over']; $data = $this->kycEntityTypeModel->where('is_active', 1)->findAll(); $this->buisnessType = array_column($data, 'name', 'id'); // $this->buisnessType = [1 => 'Public Sector', 2 => 'Private Sector',3=> 'Trust',4 => 'Proprietorship',5 => 'Partnership',6 => 'Private',7 => 'Individual']; $this->leadsStatus = [ 'queued' => 'In-Queued', 'rfq_created' => 'RFQ Created', 'rfq_sent' => 'RFQ Sent', 'qcr_created' => 'QCR Created', 'qcr_sent' => 'QCR Sent', 'lost' => 'Lost', 'co_insurer_pending' => 'Co-Insurer Pending', 'won' => 'Won', 'completed_with_corrections' => 'Completed with Corrections', 'completed_without_corrections' => 'Completed without Corrections', ]; $this->claim_type_for_gpa = [ 'nil' => 'Nil', 'accident_death' => 'Accident Death', 'permanent_total_disablement' => 'Permanent Total Disablement', 'permanent_partial_disablement' => 'Permanent Partial Disablement', 'temporary_total_disablement_benefit' => 'Temporary Total Disablement benefit' ]; $this->cause_of_death = [ 'natural_death' => 'Natural Death', 'suicide' => 'Suicide', 'accident' => 'Accident', 'cardiac_arrest' => 'Cardiac Arrest', 'septic_shock' => 'Septic shock', 'heart_attack' => 'Heart Attack', ]; $this->member_data_excel_columns = [ 'sno' => [ 'col_idx' => 0, 'col_cell_name' => 'A', 'col_name' => 'Sl no', 'is_mandatory' => false, 'data_type' => 'str', 'format' => null, 'allowed_values' => null ], 'emp_code' => [ 'col_idx' => 1, 'col_cell_name' => 'B', 'col_name' => 'Emp Code', 'is_mandatory' => true, 'data_type' => 'str', 'format' => null, 'allowed_values' => null ], 'name' => [ 'col_idx' => 2, 'col_cell_name' => 'C', 'col_name' => 'Name', 'is_mandatory' => true, 'data_type' => 'str', 'format' => null, 'allowed_values' => null ], 'relationship' => [ 'col_idx' => 3, 'col_cell_name' => 'D', 'col_name' => 'Relationship', 'is_mandatory' => true, 'data_type' => 'str', 'format' => null, 'allowed_values' => [ 'Self', 'Spouse', 'Son', 'Daughter', 'Father', 'Mother', 'Father-in-law', 'Mother-in-law', 'self', 'spouse', 'son', 'daughter', 'father', 'mother', 'father-in-law', 'mother-in-law' ], 'custom' => 'check_relationship_for_member_data', 'params' => ['row', 'relationship', 'columns_to_check'] ], 'gender' => [ 'col_idx' => 4, 'col_cell_name' => 'E', 'col_name' => 'Gender', 'is_mandatory' => true, 'data_type' => 'str', 'format' => null, 'allowed_values' => ['M', 'F'] ], 'dob' => [ 'col_idx' => 5, 'col_cell_name' => 'F', 'col_name' => 'DOB', 'is_mandatory' => true, 'data_type' => 'str', 'format' => 'd-M-Y', 'allowed_values' => null, 'age_validation' => true, // 'custom' => 'check_dob_diff', // 'params' => ['row', 'relationship', 'default_age_ratio', 'policy_details'] ], 'age' => [ 'col_idx' => 6, 'col_cell_name' => 'G', 'col_name' => 'Age', 'is_mandatory' => true, 'data_type' => 'int', 'format' => null, 'allowed_values' => null ], 'email' => [ 'col_idx' => 7, 'col_cell_name' => 'H', 'col_name' => 'Email', 'is_mandatory' => false, 'data_type' => 'str', 'format' => null, 'allowed_values' => null ], 'mobile' => [ 'col_idx' => 8, 'col_cell_name' => 'I', 'col_name' => 'Mobile', 'is_mandatory' => false, 'data_type' => 'str', 'format' => null, 'allowed_values' => null ], 'si' => [ 'col_idx' => 9, 'col_cell_name' => 'J', 'col_name' => 'SI', 'is_mandatory' => false, 'data_type' => 'int', 'format' => null, 'allowed_values' => null, ] ]; $this->general_relationships = [ 'self' => [ 'name' => 'Self', 'gender' => 'M', 'age_min' => 18, 'age_max' => null ], 'spouse' => [ 'name' => 'Spouse', 'gender' => 'F', 'age_min' => 18, 'age_max' => null ], 'son' => [ 'name' => 'Son', 'gender' => 'M', 'age_min' => null, 'age_max' => 25 ], 'daughter' => [ 'name' => 'Daughter', 'gender' => 'F', 'age_min' => null, 'age_max' => 25 ], 'father' => [ 'name' => 'Father', 'gender' => 'M', 'age_min' => 18, 'age_max' => null ], 'mother' => [ 'name' => 'Mother', 'gender' => 'F', 'age_min' => 18, 'age_max' => null ], 'father-in-law' => [ 'name' => 'Father in Law', 'gender' => 'M', 'age_min' => 18, 'age_max' => null ], 'mother-in-law' => [ 'name' => 'Mother in Law', 'gender' => 'F', 'age_min' => 18, 'age_max' => null ] ]; } public function viewLeadsList() { $data['tab_name'] = 'Leads'; $data['page_name'] = 'Leads'; // Set basic data $data['issuer'] = $this->issuer; $data['client_type'] = $this->clientType; $data['lead_type'] = $this->leadType; $data['lead_status'] = $this->leadsStatus; // Fetch policy types and entity data $data['policy_type'] = $this->policyTypeModel->where('is_active', 1)->findAll(); $data['entity'] = $this->kycEntityTypeModel->where('is_active', 1)->findAll(); // dd($lastFiveYears); if ($this->request->is('get')) { // Fetch leads data $data['lead_data_list'] = $this->leadsModel->getLeadDataForLising(); // Load layout and pass data $this->loadLayout('lead_filter', $data); } else { $isFromDashboard = $this->request->getPost("is_dashboard"); if (isset($isFromDashboard) && !empty($isFromDashboard) && $isFromDashboard == 1) { $ids = $this->request->getPost('ids'); $ids = array_filter(explode(',', $ids)); if (!empty($ids)) { $idsStr = implode(',', array_map('intval', $ids)); // sanitize IDs to be integers $where = "leads.id IN ($idsStr)"; } else { $where = '1 = 0'; // No valid IDs, return empty result } // dd($where ); $data['lead_data_list'] = $this->leadsModel->getLeadDataForLising($where); $this->loadLayout('lead_filter', $data); } else { $search_data = $this->request->getPost(); $where = []; foreach ($search_data as $search_objects => $key) { if ($key != null && $key != '' && $key != 0 && $search_objects != 'is_dashboard') { if($search_objects == 'status') { $where[('leads.'.$search_objects)] = $key; }else{ $where[$search_objects] = $key; } } } // !dd($where); $data['lead_data_list'] = $this->leadsModel->getLeadDataForLising($where); $html = view('leads_list', $data); return $this->respond(['status' => true, 'html' => $html], 200); } } } public function createLead() { // print_r($this->request->getPost()); die; $id = $this->request->getPost('id'); $data = $this->prepareLeadData(); // print_r($data); die; if (!$id) { return $this->insertNewLead($data); } else { return $this->updateOldLead($id, $data); } } private function prepareLeadData() { $data = $this->request->getPost(); $data['client_type'] = 1; $data['pan'] = ""; if ($data['lead_type'] != 1) { $client_data = $this->clientModel->where('id', $data['client_id'])->where('is_active', 1)->first(); $data['client_name'] = $client_data['client_name']; $data['client_short_name'] = $client_data['short_name']; $data['entity_type_id'] = $client_data['entity_type_id']; $data['client_type'] = $client_data['client_type']; } else { if(!empty($data['client_id'])){ $data['is_client_created'] = $data['client_id']; }else{ $data['client_id'] = 0; $data['client_branch_id'] = 0; $data['source_policy_id'] = 0; } } $data['client_code'] = generate_client_code(); if ($data['client_code'] == 2) { $data['client_code'] = generate_client_code('IC'); } if (isset($data['lead_form_type'])) { $data = $this->prepareSingleLeadData($data); } else { $data = $this->prepareMultipleLeadData($data); } // print_r($data); die; return $data; } private function prepareSingleLeadData($data) { // print_r($data); die; $index_plus_one = 1; $form_file_name = "file_name_" . $index_plus_one; $form_docs_name = "docs_name_" . $index_plus_one; $leads_file_primary_key = $data['leads_file_id'] ?? []; $multi_file_data = []; if (isset($data[$form_docs_name])) { $files = $this->request->getFileMultiple($form_file_name); $multi_file_data = $this->uploadMultiFiles($files, $data[$form_docs_name], $leads_file_primary_key); } // Separate the insurer and insurer branch, handle missing or invalid data if (isset($data['insurer']) && strpos($data['insurer'], '-') !== false) { list($insurer_branch_id, $insurer_id) = explode('-', $data['insurer']); } else { $insurer_branch_id = 0; $insurer_id = 0; } $data['insurer_id'] = $insurer_id; $data['insurer_branch_id'] = $insurer_branch_id; // Separate the insurer and insurer branch, handle missing or invalid data if (isset($data['tpa']) && strpos($data['tpa'], '-') !== false) { list($tpa_branch_id, $tpa_id) = explode('-', $data['tpa']); } else { $tpa_branch_id = 0; $tpa_id = 0; } $data['tpa_id'] = $tpa_id; $data['tpa_branch_id'] = $tpa_branch_id; if (!empty($data['policy_start_date'])) { $data['policy_start_date'] = change_date_format($data['policy_start_date']); } else { $data['policy_start_date'] = null; } if (!empty($data['policy_end_date'])) { $data['policy_end_date'] = change_date_format($data['policy_end_date']); } else { $data['policy_end_date'] = null; } // $data['file_name'] = file_Upload($files, $uploadFilePath); $data['multi_file_data'] = $multi_file_data ?? null; $processcedData[] = $data; // print_r($data);die(); return $processcedData; } private function prepareMultipleLeadData($data) { // print_r($data); die; $processedData = []; foreach ($data['policy_type_id'] as $index => $value) { $index_plus_one = $index + 1; $form_file_name = "file_name_" . $index_plus_one; $form_docs_name = "docs_name_" . $index_plus_one; $leads_file_primary_key = $data['leads_file_id'] ?? []; $files = $this->request->getFileMultiple($form_file_name); $multi_file_data = $this->uploadMultiFiles($files, $data[$form_docs_name], $leads_file_primary_key); // Separate the insurer and insurer branch, handle missing or invalid data if (isset($data['insurer'][$index]) && strpos($data['insurer'][$index], '-') !== false) { list($insurer_branch_id, $insurer_id) = explode('-', $data['insurer'][$index]); } else { $insurer_branch_id = 0; $insurer_id = 0; } // Separate the insurer and insurer branch, handle missing or invalid data if (isset($data['tpa'][$index]) && strpos($data['tpa'][$index], '-') !== false) { list($tpa_branch_id, $tpa_id) = explode('-', $data['tpa'][$index]); } else { $tpa_branch_id = 0; $tpa_id = 0; } // Separate the insurer and insurer branch, handle missing or invalid data if (isset($data['proposed_insurer'][$index]) && strpos($data['proposed_insurer'][$index], '-') !== false) { list($proposed_insurer_branch_id, $proposed_insurer_id) = explode('-', $data['proposed_insurer'][$index]); } else { $proposed_insurer_branch_id = 0; $proposed_insurer_id = 0; } // Separate the TPA and TPA branch, handle missing or invalid data if (isset($data['proposed_tpa'][$index]) && strpos($data['proposed_tpa'][$index], '-') !== false) { list($proposed_tpa_branch_id, $proposed_tpa_id) = explode('-', $data['proposed_tpa'][$index]); } else { $proposed_tpa_branch_id = 0; $proposed_tpa_id = 0; } if (!empty($data['policy_start_date'][$index])) { $policy_start_date = change_date_format($data['policy_start_date'][$index], 'd/m/Y', 'Y-m-d'); } else { $policy_start_date = null; } if (!empty($data['policy_end_date'][$index])) { $policy_end_date = change_date_format($data['policy_end_date'][$index], 'd/m/Y', 'Y-m-d'); } else { $policy_end_date = null; } if (!empty($data['incurred_claim_date'][$index])) { $incurred_claims_date = change_date_format($data['incurred_claim_date'][$index], 'd/m/Y', 'Y-m-d'); } else { $incurred_claims_date = null; } // if (!empty($data['premium_date'][$index])) { // $premium_date = change_date_format($data['premium_date'][$index], 'd/m/Y', 'Y-m-d'); // } else { // $premium_date = null; // } if (!empty($data['source_policy_start_date']) && $data['lead_type'] == 2) { $data['source_policy_start_date'] = change_date_format($data['source_policy_start_date'], 'd/m/Y', 'Y-m-d'); } else { $data['source_policy_start_date'] = null; } if (!empty($data['source_policy_end_date']) && $data['lead_type'] == 2) { $data['source_policy_end_date'] = change_date_format($data['source_policy_end_date'], 'd/m/Y', 'Y-m-d'); } else { $data['source_policy_end_date'] = null; } //convert the date if (!empty($data['next_reminder_date'])) { $data['next_reminder_date'] = change_date_format($data['next_reminder_date']); } else { $data['next_reminder_date'] = null; } //convert 0 and 1 if (isset($data['is_insurer_auto_mail'])) { $data['is_insurer_auto_mail'] = 1; } else { $data['is_insurer_auto_mail'] = 0; } // $file_name = file_Upload($files[$index], $uploadFilePath); $last_3_years_claims = $data['finyear']; $processedData[] = [ 'lead_type' => $data['lead_type'], 'issuer' => $data['issuer'], 'client_type' => $data['client_type'], 'client_name' => $data['client_name'], 'client_short_name' => $data['client_short_name'], 'entity_type_id' => $data['entity_type_id'], 'client_code' => $data['client_code'], 'pan' => $data['pan'], 'gst' => $data['gst'], 'branch_name' => $data['branch_name'], 'branch_code' => $data['branch_code'], 'contact_person_name' => $data['contact_person_name'], 'contact_person_mobile' => $data['contact_person_mobile'], 'contact_person_email' => $data['contact_person_email'], 'client_id' => $data['client_id'] ?? 0, 'client_branch_id' => $data['client_branch_id'] ?? 0, 'is_client_created' => $data['is_client_created'] ?? null, 'source_policy_id' => $data['source_policy_id'] ?? 0, 'policy_type_id' => $value, 'salse_person_id' => $data['salse_person_id'] ?? 0, 'insurer_id' => $insurer_id ?? 0, 'insurer_branch_id' => $insurer_branch_id ?? 0, 'tpa_id' => $tpa_id ?? 0, 'tpa_branch_id' => $tpa_branch_id ?? 0, 'policy_start_date' => $policy_start_date, 'policy_end_date' => $policy_end_date, 'no_of_lives' => $data['no_of_lives'][$index] ?? null, 'incurred_claims' => $data['incurred_claims'][$index] ?? 0, 'location' => $data['location'][$index] ?? null, 'proposed_insurer_id' => $proposed_insurer_id ?? 0, 'proposed_insurer_branch_id' => $proposed_insurer_branch_id ?? 0, 'proposed_tpa_id' => $proposed_tpa_id ?? 0, 'proposed_tpa_branch_id' => $proposed_tpa_branch_id ?? 0, 'renewal_emp_count' => $data['renewal_emp_count'][$index] ?? 0, 'renewal_dept_count' => $data['renewal_dept_count'][$index] ?? 0, 'renewal_no_of_lives' => $data['renewal_no_of_lives'][$index] ?? 0, 'incept_emp_count' => $data['incept_emp_count'][$index] ?? 0, 'incept_dept_count' => $data['incept_dept_count'][$index] ?? 0, 'incept_no_of_lives' => $data['incept_no_of_lives'][$index] ?? 0, 'exp_emp_count' => $data['exp_emp_count'][$index] ?? 0, 'exp_dept_count' => $data['exp_dept_count'][$index] ?? 0, 'exp_no_of_lives' => $data['exp_no_of_lives'][$index] ?? 0, 'incurred_claims_date' => $incurred_claims_date, 'paid_claims' => $data['paid_claims'][$index] ?? 0, 'outstanding_claims' => $data['outstanding_claims'][$index] ?? 0, 'policy_run_days' => $data['policy_run_days'][$index] ?? 0, 'premium_at_inception' => $data['premium_at_inception'][$index] ?? 0, 'premium_date' => $data['premium_date'][$index] ?? 0, 'earned_premium' => $data['earned_premium'][$index] ?? 0, 'annualised_claims' => $data['annualised_claims'][$index] ?? 0, 'incurred_claims_ratio' => $data['incurred_claims_ratio'][$index] ?? 0, 'earned_claims_ratio' => $data['earned_claims_ratio'][$index] ?? 0, 'total_si_at_incept' => $data['total_si_at_incept'][$index] ?? 0, 'total_si_at_renewal' => $data['total_si_at_renewal'][$index] ?? 0, 'total_lives_at_incept' => $data['total_lives_at_incept'][$index] ?? 0, 'premium_at_incept' => $data['premium_at_incept'][$index] ?? 0, 'fin_years_claims' => $last_3_years_claims, // 'file_name' => $file_name, 'multi_file_data' => $multi_file_data ?? null, 'status' => $data['status'] ?? null, 'notes' => $data['notes'] ?? null, 'lead_form_type' => $data['lead_form_type'] ?? 1, 'custom_fields' => $data['custom_fields'] ?? null, 'source_policy_start_date' => $data['source_policy_start_date'] ?? null, 'source_policy_end_date' => $data['source_policy_end_date'] ?? null, 'claim_history' => $data['claim_history'] ?? 0, 'next_reminder_date' => $data['next_reminder_date'] ?? 0, 'is_insurer_auto_mail' => $data['is_insurer_auto_mail'] ?? 0 ]; } // print_r($processedData);die(); return $processedData; } private function insertNewLead($data) { $insertCount = []; foreach ($data as $value) { $insert = $this->leadsModel->insert($value); if ($insert) { $this->insertMultiFilesData($value['multi_file_data'], $insert); } $insertCount[] = $insert; $this->insertLeadStatus($insert, $value['status'], 3); if ($value['lead_form_type'] == 1) { //for this push the job to the calculateMembersDemography() function $job_details = new Jobs(); // $r = Jobs::addJob(['job_name' => 'memberDataListExcelFileFormatValidation', 'payload' => [ // 'lead_id' => $insert, // ]]); $r = Jobs::addJob(['job_name' => 'calculateMembersDemography', 'payload' => [ 'lead_id' => $insert, ]]); } } if (count($insertCount) > 0) { return $this->respond(['status' => true, 'lead_id' => $insert, 'message' => 'New Lead created successfully', 'data' => $data], 200); } return $this->respond(['status' => false, 'lead_id' => $insert, 'message' => "Failed to create Lead", 'data' => $data], 200); } private function updateOldLead($id, $data) { if ($this->leadsModel->where('id', $id)->set($data[0])->update()) { $this->insertMultiFilesData($data[0]['multi_file_data'], $id, $data[0]['lead_form_type']); $this->insertLeadStatus($id, $data[0]['status'], 3); return $this->respond(['status' => true, 'lead_id' => $id, 'message' => "Lead updated successfully", 'data' => $data], 200); } return $this->respond(['status' => false, 'lead_id' => $id, 'message' => "Failed to update Lead", 'data' => $data], 200); } // Get the Single Lead data for edit uisng ajax (do not delete) public function getLeadDataForEdit($id) { $data = $this->leadsModel ->where('leads.id', $id) ->where('leads.is_active', 1) ->first(); $data['lead_edit_data'] = $this->leadsModel ->where('leads.id', $id) ->where('leads.is_active', 1) ->first(); if (!empty($data['policy_start_date'])) { $data['policy_start_date'] = change_date_format($data['policy_start_date'], 'Y-m-d', 'd/m/Y'); } else { $data['policy_start_date'] = null; } if (!empty($data['policy_end_date'])) { $data['policy_end_date'] = change_date_format($data['policy_end_date'], 'Y-m-d', 'd/m/Y'); } else { $data['policy_end_date'] = null; } if (!empty($data['incurred_claims_date'])) { $data['incurred_claims_date'] = change_date_format($data['incurred_claims_date'], 'Y-m-d', 'd/m/Y'); } else { $data['incurred_claims_date'] = null; } // if (!empty($data['premium_date'])) { // $data['premium_date'] = change_date_format($data['premium_date'], 'Y-m-d', 'd/m/Y'); // } else { // $data['premium_date'] = null; // } $data['multi_file_data'] = $this->leadFilesModel ->where('lead_id', $id) ->where('type !=', 2) ->where('is_active', 1) ->first() ?? null; $data['lastFiveYears'] = $this->getLastFiveFinancialYears(); $data['gpaClaimType'] = $this->claim_type_for_gpa; $data['causeOfDeath'] = $this->cause_of_death; if (!empty($data['fin_years_claims'])) { $decoded = json_decode($data['fin_years_claims'], true); $data['lead_edit_data']['fin_years_claims_array'] = isset($decoded['finyear']) ? $decoded['finyear'] : []; } else { $data['lead_edit_data']['fin_years_claims_array'] = []; } $data['html'] = $this->generateViewPageHtml($data['policy_type_id'], $data) ?? ""; // print_r($data); die; if ($data) { return $this->respond(['status' => true, 'data' => $data], 200); } else { return $this->respond(['status' => false], 200); } } private function insertLeadStatus($primaryKey, $status, $statusType) { $statusData = [ 'policy_tran_id' => $primaryKey, 'status' => $status, 'status_type' => $statusType, 'created_by' => get_session_userid(), ]; $this->policyTransactionStatusModel->insert($statusData); } public function uploadMultiFiles($files, $docs_names, $primaryKey) { $uploadFilePath = WRITEPATH . 'uploads/lead_files/'; $multi_file_data = []; foreach ($files as $index => $value) { $file_name = file_Upload_for_lead($value, $uploadFilePath); $multi_file_data[] = [ 'file_name' => $file_name, 'docs_name' => $docs_names[$index], 'id' => $primaryKey[$index] ?? "", ]; } return $multi_file_data; } public function insertMultiFilesData($data, $lead_id, $lead_form_type = null) { log_message('info', 'insertMultiFilesData() called with lead_id: ' . $lead_id); if (!empty($data)) { log_message('info', 'Data is not empty. Total items: ' . count($data)); foreach ($data as $key => $value) { log_message('info', "Processing item at index {$key}: " . json_encode($value)); if (!empty($value['id'])) { log_message('info', "Record with ID {$value['id']} exists. Preparing to update."); $lead_file_data = [ 'lead_id' => $lead_id, 'docs_name' => $value['docs_name'], ]; if (!empty($value['file_name'])) { $lead_file_data['file_name'] = $value['file_name']; log_message('info', "file_name found: {$value['file_name']}"); if (!empty($lead_form_type) && $lead_form_type == 1 && $key == 0) { //for this push the job to the calculateMembersDemography() function $job_details = new Jobs(); // $r = Jobs::addJob(['job_name' => 'memberDataListExcelFileFormatValidation', 'payload' => [ // 'lead_id' => $lead_id, // ]]); $r = Jobs::addJob(['job_name' => 'calculateMembersDemography', 'payload' => [ 'lead_id' => $lead_id, ]]); log_message('info', "calculateMembersDemography JOB PUSHED"); } } log_message('info', "Updating leadFilesModel where id = {$value['id']} with data: " . json_encode($lead_file_data)); $this->leadFilesModel->where('id', $value['id'])->set($lead_file_data)->update(); } else { log_message('info', "No ID found. Preparing to insert new record."); if (!empty($value['file_name'])) { $lead_file_data = [ 'lead_id' => $lead_id, 'docs_name' => $value['docs_name'], 'file_name' => $value['file_name'], ]; log_message('info', "Inserting into leadFilesModel: " . json_encode($lead_file_data)); $this->leadFilesModel->insert($lead_file_data); } else { log_message('warning', "Skipped insert: file_name missing in data at index {$key}"); } } if ($key == 0 && !empty($value['file_name'])) { log_message('info', "Setting first file_name '{$value['file_name']}' to leadsModel for lead_id: {$lead_id}"); $this->leadsModel->where('id', $lead_id)->set('file_name', $value['file_name'])->update(); } } } else { log_message('warning', 'insertMultiFilesData() received empty data array.'); } log_message('info', 'insertMultiFilesData() completed successfully.'); return true; } public function removeMultiFile() { $id = $this->request->getGet('lead_file_id'); if (!empty($id)) { $this->leadFilesModel->where('id', $id)->set(['is_active' => 0])->update(); return $this->respond(['status' => true, 'message' => 'File removed successfully'], 200); } else { return $this->respond(['status' => false, 'message' => 'File could not be removed.'], 200); } } //--------RFQ----------------------------------------------------------------------------------------------- // public function viewRFQ($id, $type = 1) // { // $data['rfq_data'] = $this->RFQModel // ->where('lead_id', $id) // // ->where('type', $type) // ->where('is_active', 1) // ->orderBy('id', 'desc') // ->first(); // // dd($data); // $data['rfq_count'] = $this->RFQModel // ->where('lead_id', $id) // // ->where('type', 1) // ->where('is_active', 1) // ->countAllResults(); // $data['qcr_count'] = $this->RFQModel // ->where('lead_id', $id) // ->where('type', 2) // ->where('is_active', 1) // ->countAllResults(); // // dd(count($data['rfq_data'])); // $data['lead_id'] = $id; // $lead_data = $this->leadsModel // ->select(' // leads.*, // policy_type.question_json, // policy_type.policy_type, // policy_type.long_name, // user_profiles.email as created_person_email // ') // ->join('policy_type', 'leads.policy_type_id = policy_type.id') // ->join('user_profiles', 'leads.created_by = user_profiles.id', 'left') // ->where('leads.id', $id) // ->where('leads.is_active', 1) // ->first(); // // dd($lead_data); // if ($lead_data['lead_type'] != 1) { // $client_policy_data = $this->clientPolicyModel->where('is_active', 1)->where('id', $lead_data['source_policy_id'])->first(); // if (isset($client_policy_data)) { // $data['policy_terms'] = $client_policy_data['policy_terms']; // } // } // $data['question_json'] = $lead_data['question_json']; // $data['page_name'] = $type == 2 ? 'QCR' : 'RFQ'; // $data['insurer'] = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(); // $data['userList'] = $this->userModel->getUserListForRFQ(); // $data['exclusiveUserList'] = $this->userModel->getexclusiveUserListForRFQ(); // $data['lead_data'] = $lead_data; // $data['tpa_list'] = $this->tpaBranchModel->getTpaBranchesWithTpaNames(); // $data['account_manager'] = $this->userModel->where('is_active', 1)->where('role', 3)->findAll(); // $mail_content = ' //

Dear Sir,

//

Greetings From Nhance India!

//

Please find attached the {{RFQ_OR_QCR}} for {{POLICY_TYPE}} policy pertaining to {{CLIENT_NAME}}.

//

Kindly request you to share the competitive quotes at the earliest.

//

In case of any query, please feel free to contact us.

//

Thank You!


//

Best regards,

//
//
{{LOGGED_USER_NAME}}
//
Mobile: {{LOGGED_USER_MOBILE}}
//
// Nhance Logo // '; // if ($data['lead_data']['policy_end_date'] != null) { // $subject = "{{CLIENT_NAME}} _ {{POLICY_TYPE}} _ {{RFQ_OR_QCR}} _ {{POLICY_YEAR}} {{POLICY_END_DATE}}"; // } else { // $subject = "{{CLIENT_NAME}} _ {{POLICY_TYPE}} _ {{RFQ_OR_QCR}} _ {{POLICY_YEAR}}"; // } // if ($lead_data['policy_type_id'] == 1) { // $data['totalSumAssured'] = $this->handleMemberDataGPATotalSumInsurerFromExcel(['lead_id' => $id]); // } else { // $data['totalSumAssured'] = []; // } // $data['mail_content'] = $this->transformMailContent($lead_data, $mail_content, $data['page_name']); // $data['subject'] = $this->transformMailContent($lead_data, $subject, $data['page_name']); // $data['placement_mail_content'] = $this->transformMailContent($lead_data, $mail_content, 'Placement'); // $data['placement_subject'] = $this->transformMailContent($lead_data, $subject, 'Placement'); // $data['multi_file_data'] = $this->leadFilesModel->where('lead_id', $id)->where('is_active', 1)->findAll() ?? null; // $installment_data['installments'] = $this->leadInstallmentPaymentDetails->where('lead_id', $id)->where('is_active', 1)->findAll() ?? null; // $data['lead_data']['installment_data'] = view('rfq/installment_fields', $installment_data) ?? null; // $data['attachment_html'] = view('rfq/attachment_files', $data) ?? ""; // $data['user_team'] = $this->userModel->select("ut.team_id")->join("user_teams ut", "ut.user_id = user_profiles.id and ut.is_active = 1")->where("user_profiles.is_active", 1)->first()['team_id']; // $data['multi_file_data_html'] = $this->renderFileFields($data['multi_file_data']); // // dd($data); // if ($data['lead_data']['lead_form_type'] == 1) { // $data['demogrphy_html_data'] = $this->generateDemographyDataTable(['lead_id' => $id]); // $this->loadLayout('view_rfq.php', $data); // } else if ($data['lead_data']['lead_form_type'] == 2) { // $data['occupancy'] = $this->occupancyModel->findAll(); // // dd($data['occupancy']); // if ($lead_data['lead_type'] != 1 && $data['rfq_count'] == 0) { // $client_policy_data = $this->clientPolicyModel->where('is_active', 1)->where('id', $lead_data['source_policy_id'])->first(); // if (isset($client_policy_data)) { // $data['rfq_data']['json'] = $client_policy_data['placement_json']; // } // } // if (!empty($data['question_json'])) { // $data['policies'] = json_decode($data['question_json'], true)['policies']; // $data["child_table_data"] = json_decode($data['question_json'], true)['child_table_data']; // } // $data['product'] = $this->leadsModel->select("policy_type.policy_type")->join('policy_type', 'leads.policy_type_id = policy_type.id')->where('leads.id', $id)->first()['policy_type']; // // $data['lead_register_data'] = json_decode($data['lead_data']['custom_fields']); // // dd($data['lead_register_data']); // // $data['entity_type'] = $this->kycEntityTypeModel->where('is_active', 1)->findAll(); // $data['buisness_type'] = $this->buisnessType; // // dd($data); // $data['client_type'] = $this->clientType; // $this->loadLayout('view_rfq_non_eb', $data); // } // } public function viewRFQ($id, $type = 1) { // 1. Combine RFQ queries into a single query $rfqStats = $this->RFQModel ->select(' COUNT(*) as total_count, SUM(CASE WHEN type != 2 THEN 1 ELSE 0 END) as rfq_count, SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) as qcr_count ') ->where('lead_id', $id) ->where('is_active', 1) ->first(); $data['rfq_count'] = $rfqStats['rfq_count'] ?? 0; $data['qcr_count'] = $rfqStats['qcr_count'] ?? 0; // 2. Get RFQ data separately (only if needed) $data['rfq_data'] = $this->RFQModel ->where('lead_id', $id) ->where('is_active', 1) ->orderBy('id', 'desc') ->first(); $data['lead_id'] = $id; // 3. Optimize lead data query with specific field selection $lead_data = $this->leadsModel ->select(' leads.*, lead_files.status as demography_file_status, policy_type.question_json, policy_type.policy_type, policy_type.long_name, user_profiles.email as created_person_email ') ->join('policy_type', 'leads.policy_type_id = policy_type.id') ->join('user_profiles', 'leads.created_by = user_profiles.id', 'left') ->join('lead_files', 'leads.id = lead_files.lead_id AND lead_files.type = 2 AND lead_files.is_active = 1', 'left') ->where('leads.id', $id) ->where('leads.is_active', 1) ->first(); if (!$lead_data) { // Handle case where lead doesn't exist throw new \Exception('Lead not found'); } // 4. Conditional query - only fetch if needed if ($lead_data['lead_type'] != 1) { $client_policy_data = $this->clientPolicyModel ->select('policy_terms, placement_json') ->where('is_active', 1) ->where('id', $lead_data['source_policy_id']) ->first(); if ($client_policy_data) { $data['policy_terms'] = $client_policy_data['policy_terms']; // Store for later use in lead_form_type == 2 condition if ($lead_data['lead_form_type'] == 2 && $data['rfq_count'] == 0) { $data['rfq_data']['json'] = $client_policy_data['placement_json']; } } } // 5. Cache decoded JSON to avoid multiple decodes $question_json_decoded = !empty($lead_data['question_json']) ? json_decode($lead_data['question_json'], true) : null; $data['question_json'] = $lead_data['question_json']; $data['tab_name'] = $type == 2 ? 'QCR' : 'RFQ'; $data['page_name'] = $type == 2 ? 'QCR' : 'RFQ'; $data['lead_data'] = $lead_data; // 6. Parallel/batch data fetching for independent queries $data['insurer'] = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(); $data['userList'] = $this->userModel->getUserListForRFQ(); $data['exclusiveUserList'] = $this->userModel->getexclusiveUserListForRFQ(); $data['tpa_list'] = $this->tpaBranchModel->getTpaBranchesWithTpaNames(); $data['account_manager'] = $this->userModel ->where('is_active', 1) ->where('role', 3) ->findAll(); // 7. Define mail templates as constants or config $mail_content = $this->getMailTemplate(); $placement_mail_content = $this->getMailTemplate('placement'); $subject = $this->getSubjectTemplate($lead_data); // 8. Pre-calculate sum assured only for GPA $data['totalSumAssured'] = ($lead_data['policy_type_id'] == 1) ? $this->handleMemberDataGPATotalSumInsurerFromExcel(['lead_id' => $id]) : []; // 9. Transform mail content once $data['mail_content'] = $this->transformMailContent($lead_data, $mail_content, $data['page_name']); $data['subject'] = $this->transformMailContent($lead_data, $subject, $data['page_name']); $data['placement_mail_content'] = $this->transformMailContent($lead_data, $placement_mail_content, 'Placement'); $data['placement_subject'] = $this->transformMailContent($lead_data, $subject, 'Placement'); // 10. Combine related queries $data['multi_file_data'] = $this->leadFilesModel ->where('lead_id', $id) ->where('type !=', 2) ->where('is_active', 1) ->findAll(); $installment_data['installments'] = $this->leadInstallmentPaymentDetails ->where('lead_id', $id) ->where('is_active', 1) ->findAll(); // 11. Generate views efficiently $data['lead_data']['installment_data'] = !empty($installment_data['installments']) ? view('rfq/installment_fields', $installment_data) : null; $data['attachment_html'] = view('rfq/attachment_files', $data); $user_team = $this->userModel ->select("ut.team_id") ->join("user_teams ut", "ut.user_id = user_profiles.id and ut.is_active = 1") ->where("user_profiles.is_active", 1) ->first(); $data['user_team'] = $user_team['team_id'] ?? null; $data['multi_file_data_html'] = $this->renderFileFields($data['multi_file_data']); // 12. Conditional rendering based on lead_form_type if ($lead_data['lead_form_type'] == 1) { $data['demogrphy_html_data'] = $this->generateDemographyDataTable(['lead_id' => $id]); $this->loadLayout('view_rfq.php', $data); } else if ($lead_data['lead_form_type'] == 2) { $data['occupancy'] = $this->occupancyModel->findAll(); // Use cached decoded JSON if ($question_json_decoded) { $data['policies'] = $question_json_decoded['policies'] ?? []; $data["child_table_data"] = $question_json_decoded['child_table_data'] ?? []; } $data['product'] = $lead_data['policy_type']; $data['buisness_type'] = $this->buisnessType; $data['client_type'] = $this->clientType; $this->loadLayout('view_rfq_non_eb', $data); } } // 13. Extract mail template to separate method for reusability private function getMailTemplate( $template_type = "" ) { if($template_type == 'placement'){ return '

Dear Sir,

Greetings From Nhance India!

Please find attached the {{RFQ_OR_QCR}} for {{POLICY_TYPE}} policy pertaining to {{CLIENT_NAME}}.

Kindly request you to issue the policy at the earliest.

In case of any query, please feel free to contact us.

Thank You!


Best regards,

{{LOGGED_USER_NAME}}
Mobile: {{LOGGED_USER_MOBILE}}
Nhance Logo '; }else{ return '

Dear Sir,

Greetings From Nhance India!

Please find attached the {{RFQ_OR_QCR}} for {{POLICY_TYPE}} policy pertaining to {{CLIENT_NAME}}.

Kindly request you to share the competitive quotes at the earliest.

In case of any query, please feel free to contact us.

Thank You!


Best regards,

{{LOGGED_USER_NAME}}
Mobile: {{LOGGED_USER_MOBILE}}
Nhance Logo '; } } // 14. Extract subject template to separate method private function getSubjectTemplate($lead_data) { return $lead_data['policy_end_date'] != null ? "{{CLIENT_NAME}} _ {{POLICY_TYPE}} _ {{RFQ_OR_QCR}} _ {{POLICY_YEAR}} {{POLICY_END_DATE}}" : "{{CLIENT_NAME}} _ {{POLICY_TYPE}} _ {{RFQ_OR_QCR}} _ {{POLICY_YEAR}}"; } public function savePolicyInfo() { $data = $this->request->getPost(); $lead_id = $data['lead_id']; $json_data = $data['registration_json']; $existingJson = $this->RFQModel->where('is_active', 1)->where("lead_id", $lead_id)->first()['registration_json'] ?? null; if (empty($existingJson)) { $this->RFQModel ->where('lead_id', $lead_id) ->where('type', 1) ->where('is_active', 1) ->set('is_active', 0) ->update(); $insertData['lead_id'] = $lead_id; $insertData['registration_json'] = json_encode($json_data); $this->RFQModel->insert($insertData); return $this->respond(['status' => true, "message" => "Policy Inforamtion saved"]); } else { return $this->respond(['status' => true, "message" => "Policy Inforamtion Already saved"]); } } public function createRFQ() { $data = $this->request->getPost(); $lead_id = $data['lead_id'] ?? null; if (!$lead_id) { return $this->respond(['status' => false, 'message' => 'Lead ID is required'], 400); } $rfq_created = $this->RFQModel->where('lead_id', $lead_id)->where('is_active', 1)->countAllResults(); $qcr_created = false; $inputJson = json_decode($data['json'], true); if (isset($inputJson['premium_data']) && !empty($inputJson['premium_data'])) { $sortedJson = $this->reorderProposalsByInsurerTotal($inputJson); $data['json'] = json_encode($sortedJson); $qcr_created = true; } $quote_received_insurer = []; if (($data['submit_type'] ?? "") === 'QCR') { $inputJson = json_decode($data['json'], true); $proposal_data = $inputJson['proposal_data'] ?? array_pop($inputJson); if (isset($proposal_data['over_all_column_data'])) { $proposel_count = $proposal_data['over_all_column_data']; $this->myLogger->logme("error", "insurer id : " . json_encode($proposel_count)); foreach ($proposel_count as $key => $value) { if (!empty($value['insurers'])) { $qcr_created = true; foreach ($value['insurers'] as $insurer => $id) { if (!empty($id['id'])) { $quote_received_insurer[] = $id['id']; } } } } } } $this->myLogger->logme("error", "quote_received_insurer : " . json_encode($quote_received_insurer)); $data['type'] = 1; //update the quote received insurer data to the lead if(count($quote_received_insurer) != 0){ $this->leadsModel->update($lead_id, ['quote_received_insurer' => json_encode($quote_received_insurer ?? [])]); $this->myLogger->logme("error", "quote_received_insurer data updated in the lead: " . json_encode($quote_received_insurer)); } // Deactivate existing RFQs for this lead and type if (!isset($data['rfq_primaryKey']) && empty($data['rfq_primaryKey'])) { $this->RFQModel ->where('lead_id', $lead_id) ->where('type', 1) ->where('is_active', 1) ->set('is_active', 0) ->update(); } // Handle registration_json if (empty($data['registration_json'])) { // Fetch the latest registration_json if not provided $latest = $this->RFQModel ->select('registration_json') ->where('lead_id', $lead_id) ->orderBy('id', 'DESC') ->first(); if (!empty($latest['registration_json'])) { $data['registration_json'] = $latest['registration_json']; } } // print_r($data); die; // $data['json'] = ""; if (isset($data['rfq_primaryKey']) && !empty($data['rfq_primaryKey'])) { $this->RFQModel->update($data['rfq_primaryKey'], $data); $insertId = $data['rfq_primaryKey']; $affectedRows = db_connect()->affectedRows(); } else { // Insert new RFQ $insertId = $this->RFQModel->insert($data); } if ($insertId) { if (empty($rfq_created)) { $this->leadsModel->update($lead_id, ['status' => "rfq_created"]); } if ($qcr_created == true) { $this->leadsModel ->where('id', $lead_id) ->whereNotIn('status', ['qcr_sent', 'lost', 'co_insurer_pending', 'won', 'completed_with_corrections', 'completed_without_corrections']) ->set(['status' => "qcr_created"]) ->update(); } $message = ($data['submit_type'] ?? '') == 'QCR' ? 'QCR saved successfully' : 'RFQ saved successfully'; return $this->respond([ 'status' => true, 'id' => $insertId, 'message' => $message, 'data' => $data, 'affectedRows' => $affectedRows ?? null, ], 200); } $message = ($data['submit_type'] ?? '') == 'QCR' ? 'Failed to save QCR' : 'Failed to save RFQ'; return $this->respond([ 'status' => false, 'id' => null, 'message' => $message, 'data' => $data ], 200); } public function createQCR() { $data = $this->request->getPost(); $lead_id = $data['lead_id']; $data['type'] = 2; $this->RFQModel ->where('lead_id', $lead_id) ->where('type', 2) ->where('is_active', 1) ->set('is_active', 0) ->update(); $result = $this->RFQModel->insert($data); if ($result) { return $this->respond(['status' => true, 'id' => $result, 'message' => 'QCR created successfully', 'data' => $data], 200); } return $this->respond(['status' => false, 'id' => $result, 'message' => "Failed to create QCR", 'data' => $data], 200); } public function reorderProposalsByInsurerTotal(array $data): array { if (!isset($data['premium_data']['data'])) return $data; $original = $data['premium_data']['data']; $proposals = []; $others = []; $emptyKeyData = []; foreach ($original as $key => $value) { // Match only keys that look like 'Proposal X' if (preg_match('/^(Proposal\s+\d+|Existing Renewal|Existing Rollover)$/', $key)) { // Get the insurer entry (not 'Quote Asked') foreach ($value as $subKey => $subVal) { if ($subKey !== 'Quote Asked' && isset($subVal['Total'])) { $proposals[$key] = $value; break; } else { $proposals[$key] = $value; } } } else { if ($key === '' && isset($value['']) && is_array($value[''])) { // Capture empty key to push it later $emptyKeyData[$key] = $value; } else { $others[$key] = $value; } } } foreach ($proposals as $proposalKey => &$proposal) { $quoteAsked = $proposal['Quote Asked']; // Keep Quote Asked separately unset($proposal['Quote Asked']); uasort($proposal, function ($a, $b) { return $a['Total'] <=> $b['Total']; // Ascending by Total }); // Add Quote Asked back at the top $proposal = array_merge(['Quote Asked' => $quoteAsked], $proposal); } // Sort proposals by their insurer's total uasort($proposals, function ($a, $b) { $totalA = 0; $totalB = 0; foreach ($a as $key => $val) { if ($key !== 'Quote Asked' && isset($val['Total'])) { $totalA = floatval($val['Total']); break; } } foreach ($b as $key => $val) { if ($key !== 'Quote Asked' && isset($val['Total'])) { $totalB = floatval($val['Total']); break; } } return $totalA <=> $totalB; }); // Merge back the sorted proposals into the full structure $data['premium_data']['data'] = array_merge($others, $proposals, $emptyKeyData); $data = $this->reorderProposalDataByPremiumOrder($data); return $data; } private function reorderProposalDataByPremiumOrder(array $data): array { if (!isset($data['premium_data']['data'], $data['proposal_data']['over_all_column_data'])) { return $data; } $porposalData = $data['premium_data']['data']; $premiumProposals = array_keys($data['premium_data']['data']); $filteredProposals = []; //Reorder the Insurer based on the Premium data insurer foreach ($porposalData as $key => $value) { if(in_array($key, ['Particulars', ""])){ continue; } // Ensure the premium data is an array and not empty if (!is_array($value) || empty($value)) { continue; } // Step 1: Get the premium display_name order (excluding "Quote Asked") $premiumOrder = array_keys(array_diff_key($value, ["Quote Asked" => ""])); // Skip if no valid order found if (empty($premiumOrder)) { continue; } // usort($data['proposal_data']['over_all_column_data'][$key]['insurers'], function($a, $b) use ($premiumOrder) { // return array_search($a['display_name'], $premiumOrder) - array_search($b['display_name'], $premiumOrder); // }); // Step 2: Reorder proposal insurers based on premium order usort($data['proposal_data']['over_all_column_data'][$key]['insurers'], function($a, $b) use ($premiumOrder) { $posA = array_search($a['display_name'] ?? '', $premiumOrder); $posB = array_search($b['display_name'] ?? '', $premiumOrder); // If not found, push to the end $posA = $posA === false ? PHP_INT_MAX : $posA; $posB = $posB === false ? PHP_INT_MAX : $posB; return $posA - $posB; }); } // Collect proposal keys that match the pattern "Proposal X" foreach ($premiumProposals as $key) { if (preg_match('/^(Proposal\s+\d+|Existing Renewal|Existing Rollover)$/', $key) && isset($data['proposal_data']['over_all_column_data'][$key])) { $filteredProposals[$key] = $data['proposal_data']['over_all_column_data'][$key]; } } // dd($premiumProposals, $filteredProposals); $data['proposal_data']['over_all_column_data'] = $filteredProposals; $data = $this->reorderProposalInHeaderAndData($data); return $data; } private function reorderProposalInHeaderAndData(array $data): array { $tableData = $data['table_data']; $sortedProposalOrder = $data['proposal_data']['over_all_column_data']; $headers = $tableData['headers'] ?? []; $dataRows = $tableData['data'] ?? []; // Step 1: Separate static and proposal headers $staticHeaders = []; $proposalHeaders = []; $actionHeader = []; foreach ($headers as $header) { if (in_array($header['parentHeader'], array_keys($sortedProposalOrder))) { $proposalHeaders[$header['parentHeader']] = $header; } else { if ($header['parentHeader'] == "Action") { $actionHeader[] = $header; } else { $staticHeaders[] = $header; } } } //Reorder the SubHeader of the Proposel foreach ($sortedProposalOrder as $proposalKey => $proposalData) { // Skip if insurers or subHeaders are missing if ( !isset($proposalData['insurers']) || !is_array($proposalData['insurers']) || !isset($proposalHeaders[$proposalKey]['subHeaders']) || !is_array($proposalHeaders[$proposalKey]['subHeaders']) ) { continue; } // Keep "Quote Asked" fixed at index 0 $newSubHeaders = ["Quote Asked"]; // Add insurers in the sorted order foreach ($proposalData['insurers'] as $insurer) { if(in_array($insurer['display_name'], $proposalHeaders[$proposalKey]['subHeaders'])){ $newSubHeaders[] = $insurer['display_name']; } } // Replace the subHeaders in the header array $proposalHeaders[$proposalKey]['subHeaders'] = $newSubHeaders; } // dd($staticHeaders, $proposalHeaders, $sortedProposalOrder); // Step 2: Reorder headers $reorderedHeaders = []; foreach ($sortedProposalOrder as $proposalKey => $proposalValue) { if (isset($proposalHeaders[$proposalKey])) { $reorderedHeaders[] = $proposalHeaders[$proposalKey]; } } // print_rr($reorderedHeaders); die; $proposel_count = 1; foreach ($reorderedHeaders as $key => &$value) { if(!in_array($value['parentHeader'], ["Existing Renewal", "Existing Rollover"])){ $value['parentHeader'] = 'Proposal ' . $proposel_count; $proposel_count++; } } unset($value); //merge the all headers $reorderedHeaders = array_merge($staticHeaders, $reorderedHeaders, $actionHeader); // Step 3: Reorder each row's `data` by matching parentth foreach ($dataRows as $dataRowIndex => &$row) { $staticData = []; $proposalData = []; $actionData = []; foreach ($row['data'] as $entry) { if (in_array($entry['parentth'], array_keys($sortedProposalOrder))) { $proposalData[$entry['parentth']][] = $entry; } else { if ($entry['parentth'] == "Action") { $actionData[] = $entry; } else { $staticData[] = $entry; } } } $reorderedProposalData = []; foreach ($sortedProposalOrder as $proposalKey => $proposalValue) { if (isset($proposalData[$proposalKey])) { foreach ($proposalData[$proposalKey] as $entry) { $reorderedProposalData[] = $entry; } } } $dubParTh = ""; $increament = 0; foreach ($reorderedProposalData as $key => &$value) { if ($dubParTh == $value['parentth']) { if(!in_array($value['parentth'], ["Existing Renewal", "Existing Rollover"])){ $value['parentth'] = 'Proposal ' . ($increament); } } else { $dubParTh = $value['parentth']; if(!in_array($value['parentth'], ["Existing Renewal", "Existing Rollover"])){ $increament = $increament + 1; $value['parentth'] = 'Proposal ' . ($increament); } } } unset($value); //Reorder the Row Data based on the Insurer $reorderedProposalData = $this->reorderProposalRowData($reorderedProposalData, $proposalHeaders); // print_rr($reorderedProposalData); die; $row['data'] = array_merge($staticData, $reorderedProposalData, $actionData); } $data['table_data']['headers'] = $reorderedHeaders; $data['table_data']['data'] = $dataRows; $renumberedArray = $this->renumberProposalKeys($data['proposal_data']['over_all_column_data']); $updatedDataSet = $this->renumberProposalKeys($data['premium_data']['data']); $data['proposal_data']['over_all_column_data'] = !empty($renumberedArray) ? $renumberedArray : $data['proposal_data']['over_all_column_data']; $data['premium_data']['data'] = !empty($updatedDataSet) ? $updatedDataSet : $data['premium_data']['data']; return $data; } private function reorderProposalRowData(array $proposalRowData, array $proposalHeaderData): array { $newRowData = []; // Group rows by parentth $groupedRows = []; foreach ($proposalRowData as $row) { if (!isset($row['parentth'])) { continue; // skip invalid rows } $groupedRows[$row['parentth']][] = $row; } // Reorder each group's rows based on header subHeaders foreach ($proposalHeaderData as $proposalKey => $headerInfo) { if ( !isset($groupedRows[$proposalKey]) || !isset($headerInfo['subHeaders']) || !is_array($headerInfo['subHeaders']) ) { continue; } $order = $headerInfo['subHeaders']; $rows = $groupedRows[$proposalKey]; // Sort whole rows according to subth position in $order usort($rows, function ($a, $b) use ($order) { return array_search($a['subth'], $order) - array_search($b['subth'], $order); }); // Append sorted rows to final array $newRowData = array_merge($newRowData, $rows); } return $newRowData; } private function renumberProposalKeys(array $input): array { $result = []; $counter = 1; foreach ($input as $key => $value) { if (strpos($key, 'Proposal') === 0) { $newKey = 'Proposal ' . $counter++; $result[$newKey] = $value; } else { $result[$key] = $value; } } return $result; } public function removeInstallments() { $id = $this->request->getGet('id'); // print_r($id); die; if (!empty($id)) { $this->leadInstallmentPaymentDetails->whereIn('id', $id)->set(['is_active' => 0])->update(); } else { return $this->respond(['status' => false, 'message' => 'Could not be removed.'], 200); } if ($this->request->getGet('lead_id')) { $lead_id = $this->request->getGet('lead_id'); $data = [ 'no_of_installment' => 0, 'is_installment' => 0 ]; $this->leadsModel->where('id', $lead_id)->set($data)->update(); } return $this->respond(['status' => true, 'message' => 'Removed successfully'], 200); } //-----RFQ and QCR EXPORT------------------------------------------------------------------------------------------------ //export main route function public function exportQCRandRFQ($lead_id, $type, $lead_form_type) { $this->exportExcelForQCRandRFQ($lead_id, $type, $lead_form_type); } //FOR EXCEL public function exportExcelForQCRandRFQ($lead_id, $type, $lead_form_type = 1) { if ($lead_form_type == 2) { $filepath = $this->constructNonEbExcelToSaveTemp($lead_id, $type); } else { $filepath = $this->constructExcelToSaveTemp($lead_id, $type); } $lead_data = $this->RFQModel->getRFQTableDataWithLeadIDAndType($lead_id, $type); // dd($filepath); //Excel merging part if ($lead_data['file_name'] != null && $lead_data['file_name'] != '') { $temp_file_path = $filepath['filePath']; $temp_file_name = $filepath['fileName']; $lead_file_path = WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name']; // dd($lead_data, $temp_file_path, $temp_file_name, $lead_file_path); if ($lead_file_path) { $filePaths = [ ['file_path' => $temp_file_path, 'sheets' => []], ['file_path' => $lead_file_path, 'sheets' => []] ]; // $outputPath = dirname($temp_file_path) . '/' . 'merged_' . $temp_file_name; $result = ExcelMergeHelper::mergeExcelFiles($filePaths, $temp_file_path); // print_rr($result); } } $filepath = $filepath['filePath']; if (file_exists($filepath)) { // Set headers to force download header('Content-Description: File Transfer'); header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="' . basename($filepath) . '"'); header('Content-Length: ' . filesize($filepath)); header('Pragma: public'); // Output the file content readfile($filepath); // Delete the file after download unlink($filepath); exit; } else { echo "File does not exist."; } } //Construct excel file and save the file to the folder and return file path public function constructExcelToSaveTemp($lead_id, $type, $propsal_and_insurer = null) { helper('excel_util_helper'); $rfq_data = $this->RFQModel->getRFQTableDataWithLeadIDAndType($lead_id, $type); $is_placement = false; $length = 0; // dd($rfq_data, $lead_id, $type, $propsal_and_insurer); // print_r($propsal_and_insurer); die; // print_r($is_placement); die; $data = json_decode($rfq_data['json'], true); $sheetName = 'Worksheet'; if ($type == 2) { $sheetName = 'QCR'; // $propsal_and_insurer = "Proposal 1-ICICIPRU-ICICI001"; $data = $this->convertJsonForQCR($data, $type); if ($propsal_and_insurer !== null) { list($proposal_key, $insurer_key) = explode('-', $propsal_and_insurer, 2); $data = $this->transformProposelData($data, $proposal_key, $insurer_key); $is_placement = true; $sheetName = 'Placement'; } } else if ($type == 1) { $sheetName = 'RFQ'; $data = $this->convertJsonForQCR($data, $type); } // dd($data); if ($rfq_data['lead_type'] == 1) { if (in_array($rfq_data['policy_type_id'], [2, 3, 4, 5])) { $lead_data = [ 'Insured' => $rfq_data['client_name'], 'Policy Type' => $this->leadType[$rfq_data['lead_type']] ?? "", 'No of Employees' => $rfq_data['incept_emp_count'], 'No of Dependents' => $rfq_data['incept_dept_count'], 'Total Lives' => $rfq_data['incept_no_of_lives'], 'Period of Insurance ' => !empty($rfq_data['policy_start_date']) && !empty($rfq_data['policy_end_date']) ? date('d-m-Y', strtotime($rfq_data['policy_start_date'])) . ' to ' . date('d-m-Y', strtotime($rfq_data['policy_end_date'])) : "To be decided", // 'Insurer' => $rfq_data['insurer_name'] ?? " - ", // 'TPA' => $rfq_data['tpa_name'] ?? " - ", // 'Policy Run Days' => $rfq_data['policy_run_days'], ]; } else if (in_array($rfq_data['policy_type_id'], [1, 6, 7])) { $lead_data = [ 'Insured' => $rfq_data['client_name'], 'No of Employees at Inception' => $rfq_data['incept_emp_count'], // 'Total Sum Insured at Inception ' => $rfq_data['total_si_at_incept'], 'Policy Period' => !empty($rfq_data['policy_start_date']) && !empty($rfq_data['policy_end_date']) ? date('d-m-Y', strtotime($rfq_data['policy_start_date'])) . ' to ' . date('d-m-Y', strtotime($rfq_data['policy_end_date'])) : "To be decided", // 'Insurer' => $rfq_data['insurer_name'] ?? " - ", // 'TPA' => $rfq_data['tpa_name'] ?? " - ", 'Policy Type' => $this->leadType[$rfq_data['lead_type']] ?? "", ]; } } else { if (in_array($rfq_data['policy_type_id'], [2, 3, 4, 5])) { if($is_placement == true){ $lead_data = [ 'Insured' => $rfq_data['client_name'], 'Policy Type' => $this->leadType[$rfq_data['lead_type']] ?? "", // 'No of Employees at Inception' => $rfq_data['incept_emp_count'], // 'No of Dependents at Inception' => $rfq_data['incept_dept_count'], // 'Total Lives at Inception ' => $rfq_data['incept_no_of_lives'], // 'No of Employees at Expiry' => $rfq_data['exp_emp_count'], // 'No of Dependents at Expiry' => $rfq_data['exp_dept_count'], // 'Total Lives at Expiry ' => $rfq_data['exp_no_of_lives'], 'No of Employees at Renewal' => $rfq_data['renewal_emp_count'], 'No of Dependents at Renewal' => $rfq_data['renewal_dept_count'], 'Total Lives at Renewal ' => $rfq_data['renewal_no_of_lives'], 'Period of Insurance ' => !empty($rfq_data['policy_start_date']) && !empty($rfq_data['policy_end_date']) ? date('d-m-Y', strtotime($rfq_data['policy_start_date'])) . ' to ' . date('d-m-Y', strtotime($rfq_data['policy_end_date'])) : "To be decided", 'Insurer' => $rfq_data['insurer_name'] ?? " - ", 'TPA' => $rfq_data['tpa_name'] ?? " - ", // 'Policy Run Days' => $rfq_data['policy_run_days'], // 'Inception Premium' => formatIndianCurrency($rfq_data['premium_at_inception']), // 'Premium as on (' . date('d-m-Y', strtotime($rfq_data['incurred_claims_date'])) . ')' => formatIndianCurrency($rfq_data['premium_date']), // 'Earned Premium' => formatIndianCurrency(intval($rfq_data['earned_premium'])), // 'Incurred Claims as on (' . date('d-m-Y', strtotime($rfq_data['incurred_claims_date'])) . ')' => formatIndianCurrency($rfq_data['incurred_claims']), // 'Annualised Claims' => formatIndianCurrency(intval($rfq_data['annualised_claims'])), // 'Incurred Claims Ratio' => $rfq_data['incurred_claims_ratio'] . " %", // 'Earned Claims Ratio' => $rfq_data['earned_claims_ratio'] . " %", ]; }else{ $lead_data = [ 'Insured' => $rfq_data['client_name'], 'Policy Type' => $this->leadType[$rfq_data['lead_type']] ?? "", 'No of Employees at Inception' => $is_placement ? '-' : $rfq_data['incept_emp_count'], 'No of Dependents at Inception' => $is_placement ? '-' : $rfq_data['incept_dept_count'], 'Total Lives at Inception ' => $is_placement ? '-' : $rfq_data['incept_no_of_lives'], 'No of Employees at Expiry' => $is_placement ? '-' : $rfq_data['exp_emp_count'], 'No of Dependents at Expiry' => $is_placement ? '-' : $rfq_data['exp_dept_count'], 'Total Lives at Expiry ' => $is_placement ? '-' : $rfq_data['exp_no_of_lives'], 'No of Employees at Renewal' => $rfq_data['renewal_emp_count'], 'No of Dependents at Renewal' => $rfq_data['renewal_dept_count'], 'Total Lives at Renewal ' => $rfq_data['renewal_no_of_lives'], 'Period of Insurance ' => !empty($rfq_data['policy_start_date']) && !empty($rfq_data['policy_end_date']) ? date('d-m-Y', strtotime($rfq_data['policy_start_date'])) . ' to ' . date('d-m-Y', strtotime($rfq_data['policy_end_date'])) : "To be decided", 'Insurer' => $rfq_data['insurer_name'] ?? " - ", 'TPA' => $rfq_data['tpa_name'] ?? " - ", 'Policy Run Days' => $is_placement ? '-' : $rfq_data['policy_run_days'], 'Inception Premium' => $is_placement ? '-' : formatIndianCurrency($rfq_data['premium_at_inception']), 'Premium as on (' . date('d-m-Y', strtotime($rfq_data['incurred_claims_date'])) . ')' => $is_placement ? '-' : formatIndianCurrency($rfq_data['premium_date']), 'Earned Premium' => $is_placement ? '-' : formatIndianCurrency(intval($rfq_data['earned_premium'])), 'Incurred Claims as on (' . date('d-m-Y', strtotime($rfq_data['incurred_claims_date'])) . ')' => $is_placement ? '-' : formatIndianCurrency($rfq_data['incurred_claims']), 'Annualised Claims' => $is_placement ? '-' : formatIndianCurrency(intval($rfq_data['annualised_claims'])), 'Incurred Claims Ratio' => $is_placement ? '-' : $rfq_data['incurred_claims_ratio'] . " %", 'Earned Claims Ratio' => $is_placement ? '-' : $rfq_data['earned_claims_ratio'] . " %", ]; } } else if (in_array($rfq_data['policy_type_id'], [1, 6, 7])) { $lead_data = [ 'Insured' => $rfq_data['client_name'], 'No of Employees at Inception' => $rfq_data['incept_emp_count'], 'Total Sum Insured at Inception' => $rfq_data['total_si_at_incept'], 'Premium at inception' => $rfq_data['premium_at_incept'], 'Policy Period' => !empty($rfq_data['policy_start_date']) && !empty($rfq_data['policy_end_date']) ? date('d-m-Y', strtotime($rfq_data['policy_start_date'])) . ' to ' . date('d-m-Y', strtotime($rfq_data['policy_end_date'])) : "To be decided", 'Policy Type' => $this->leadType[$rfq_data['lead_type']] ?? "", 'Existing Insurer' => $rfq_data['insurer_name'], 'No of Employees at Renewal' => $rfq_data['renewal_emp_count'], 'Total Sum Insured at Renewal' => $rfq_data['total_si_at_renewal'], 'Claims Experience for last 3 years' => "Mentioned in Claims sheet", // 'Insurer' => $rfq_data['insurer_name'] ?? " - ", // 'TPA' => $rfq_data['tpa_name'] ?? " - ", // 'Total Lives at Inception' => $rfq_data['total_lives_at_incept'], ]; } } // print_r($lead_data); die; $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle($sheetName); // Start with lead_data at the top $rowNumber = 1; $mergeRange1 = "A{$rowNumber}:B{$rowNumber}"; // $sheet->mergeCells($mergeRange1); $sheet->setCellValue("A{$rowNumber}", "Nhance India Insurance Broking Pvt Ltd"); $sheet->getStyle("A{$rowNumber}")->applyFromArray([ 'font' => [ 'bold' => true, 'size' => 23 ], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); // Apply center alignment to the cell // $sheet->getStyle("C{$rowNumber}")->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); // $sheet->getStyle("C{$rowNumber}")->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); $rowNumber = $rowNumber + 1; // Initialize max width tracking variables $maxWidthA = 0; $maxWidthB = 0; foreach ($lead_data as $key => $value) { // Merge A:B for key and C:D for value $mergeRangeKey = "A{$rowNumber}:B{$rowNumber}"; // $mergeRangeValue = "C{$rowNumber}"; $sheet->mergeCells($mergeRangeKey); // $sheet->mergeCells($mergeRangeValue); // Set values in merged cells $sheet->setCellValue("A{$rowNumber}", $key); $sheet->setCellValue("C{$rowNumber}", $value); // // Apply styles for alignment and bold text in A:B // $sheet->getStyle($mergeRangeKey)->applyFromArray([ // 'font' => ['bold' => true], // 'alignment' => [ // 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, // 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, // ], // ]); // Apply bold style to B column if the key is "Insured" if ($key == "Insured") { $sheet->getStyle("C{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], ]); } // Track max width needed for columns $maxWidthA = max($maxWidthA, mb_strlen($key)); $maxWidthB = max($maxWidthB, mb_strlen($value)); $rowNumber++; } // Set column width based on max content length (adjusted for padding) $sheet->getColumnDimension('A')->setWidth($maxWidthA * 1.2); // $sheet->getColumnDimension('B')->setWidth($maxWidthA * 1.5); $sheet->getColumnDimension('C')->setWidth(35); // $rowNumber += 2; // Add headers and subheaders $headers = $data['table_data']['headers']; $sheet->setCellValue("A{$rowNumber}", "Details of Coverage"); $sheet->getStyle("A{$rowNumber}")->applyFromArray([ 'font' => [ 'bold' => true, ], 'fill' => [ 'fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'ADD8E6'], ], 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); if($type == 2){ $subheader_count = array_sum( array_map( fn($header) => count(array_filter( $header['subHeaders'], fn($sub) => $sub !== "Quote Asked" )), $data['table_data']['headers'] ) ); }else{ $subheader_count = array_sum(array_map(fn($header) => count($header['subHeaders']), $data['table_data']['headers'])); } if ($is_placement == false) { $subheader_count = $subheader_count - 2; } $headerCount = count($data['table_data']['headers']); $lastColumn = Coordinate::stringFromColumnIndex($subheader_count); // dd( $headerCount, $lastColumn); // Merge cells from A to the last column $mergeRange = "A{$rowNumber}:{$lastColumn}{$rowNumber}"; $sheet->getStyle($mergeRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); $sheet->mergeCells($mergeRange); $rowNumber_for_remove_quote_asked = $rowNumber; $rowNumber = $rowNumber + 1; if ($type == 2) { $subHeaderRow = $rowNumber + 1; } else { // $subHeaderRow = $rowNumber_for_remove_quote_asked; $subHeaderRow = $rowNumber + 1; } $columnLetter = 'A'; $header_actual_count = 0; $headerIndex = 0; foreach ($headers as $header) { // Kint::dump($header); if($is_placement == true){ //for placement proposal only $nxt_ro = $rowNumber + 1; $sheet->mergeCells("C{$rowNumber}:C{$nxt_ro}"); } if (in_array($header['parentHeader'], ['Item Key', 'Action'])) { continue; } if (!in_array($header['parentHeader'], ['Item Key', 'Action', 'Sno', 'Particulars'])) { $header_actual_count++; //Quote asked not showed in the QCR excel so some proposel has only one Quote Asked, So that case avoid the proposel name $subHeaderCount = count($header['subHeaders'] ?? []) ?? 0; if($subHeaderCount <= 1 && $type == 2 && $is_placement == false){ // print_rr($header); continue; } } if ($header['parentHeader'] === 'Sno') { $header['parentHeader'] = 'S.No.'; $sheet->getColumnDimension('A')->setWidth(10); //merge the 2 row cells of the S.No. $nxt_ro = $rowNumber + 1; $sheet->mergeCells("{$columnLetter}{$rowNumber}:{$columnLetter}{$nxt_ro}"); } if ($header['parentHeader'] === 'Particulars') { $sheet->getColumnDimension('B')->setWidth(35); //merge the 2 row cells of the particulars $nxt_ro = $rowNumber + 1; $sheet->mergeCells("{$columnLetter}{$rowNumber}:{$columnLetter}{$nxt_ro}"); } $startColumn = $columnLetter; // Start of the current header range if($type == 2){ $subHeaderCount = count(array_filter($header['subHeaders'], function($subHeader) { return $subHeader !== "Quote Asked"; })); }else{ $subHeaderCount = count($header['subHeaders']); // Number of subheaders for this parent header } // Set parent header value if ($is_placement == true && !in_array($header['parentHeader'], ['Particulars', 'S.No.'])) { $sheet->setCellValue("{$startColumn}{$rowNumber}", "Terms"); } else { if(in_array($header['parentHeader'], ["Existing Renewal", "Existing Rollover"])){ $sheet->setCellValue("{$startColumn}{$rowNumber}", "Existing Terms"); }else if(in_array($header['parentHeader'], ["Particulars", "S.No."])){ $sheet->setCellValue("{$startColumn}{$rowNumber}", $header['parentHeader']); }else{ $headerIndex = $headerIndex + 1; $sheet->setCellValue("{$startColumn}{$rowNumber}", "Proposal Terms " . $headerIndex); } } $sheet->getStyle("{$startColumn}{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); // Merge header cells if it spans multiple subheaders if ($subHeaderCount > 1) { $endColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($startColumn) + $subHeaderCount - 1); $sheet->mergeCells("{$startColumn}{$rowNumber}:{$endColumn}{$rowNumber}"); } else { $endColumn = $startColumn; // No merge needed if only one subheader } // Add subheaders foreach ($header['subHeaders'] as $subHeader) { if($type == 2 && in_array($subHeader, ['Quote Asked'])){ continue; } if ($is_placement == false) { $sheet->setCellValue("{$columnLetter}{$subHeaderRow}", $subHeader); } if ($columnLetter != "A" && $columnLetter != "B" && $columnLetter != "C") { $sheet->getColumnDimension($columnLetter)->setWidth(35); } else { $sheet->getColumnDimension('A')->setWidth(10); } if ($is_placement == false) { $sheet->getStyle("{$columnLetter}{$subHeaderRow}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); } $columnLetter++; // Move to the next column for subheaders // Kint::dump($subHeader); $length++; } } if($header_actual_count == 1 && $type == 1){ $sheet->getColumnDimension('B')->setWidth(80); }else{ $sheet->getColumnDimension('B')->setWidth(35); } // Apply border to the header range $prevColumn1 = $this->getPreviousColumn($columnLetter); $headerRange = "A{$rowNumber}:" . "{$prevColumn1}" . "{$subHeaderRow}"; $sheet->getStyle($headerRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); // Increase row height for headers and subheaders $sheet->getRowDimension($rowNumber)->setRowHeight(25); // Header row height $sheet->getRowDimension($subHeaderRow)->setRowHeight(20); // Subheader row height if ($is_placement == true) { $rowNumber = $subHeaderRow + 1; } else { $rowNumber = $subHeaderRow + 1; } // dd($rowNumber); $column_data = $data['table_data']['data']; $serial_no = 1; $maxColumnWidths = []; // Add table data rows foreach ($column_data as $dataRow) { $columnLetter = 'A'; foreach ($dataRow['data'] as $cellData) { if (in_array($cellData['parentth'], ['Item Key', 'Action'])) { continue; } if($type == 2 && in_array($cellData['subth'], ['Quote Asked'])){ continue; } if ($cellData['parentth'] == 'Sno') { $sheet->setCellValue("{$columnLetter}{$rowNumber}", $serial_no); } else { $sheet->setCellValue("{$columnLetter}{$rowNumber}", $cellData['value']); } $columnLetter++; } $rowNumber++; $serial_no++; } $prevColumn2 = $this->getPreviousColumn($columnLetter); $dataRange = "A" . ($subHeaderRow + 1) . ":" . "{$prevColumn2}" . ($rowNumber - 1); $sheet->getStyle($dataRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); //premium data if ($type == 2) { if($is_placement == true){$columnLetterForPremium = "B";}else{$columnLetterForPremium = "B";} $rowNumber += 2; // Add premium data // dd($data); // $labelArray = ["Premium", "GST (%)", "GST Amount (₹)", "Total"]; $labelArray = ["Premium", "GST Amount (₹)", "Total"]; $premiumData = $data['premium_data']['data']; // dd($premiumData); // $premium = [$labelArray[0]]; // $gst = [$labelArray[1]]; // $gstAmt = [$labelArray[1]]; // $total = [$labelArray[2]]; // if($is_placement == true){ $premium[] = $labelArray[0]; $gstAmt[] = $labelArray[1]; $total[] = $labelArray[2]; // } foreach ($premiumData as $proposal => $insurers) { if ($proposal != 'Particulars') { foreach ($insurers as $insurer => $values) { if($insurer == 'Quote Asked'){ // $premium[] = count($insurers ?? []) > 1 ? $labelArray[0] : ""; // $gst[] = ""; // $gstAmt[] = count($insurers ?? []) > 1 ? $labelArray[1] : ""; // $total[] = count($insurers ?? []) > 1 ? $labelArray[2] : ""; }else{ $premium[] = formatIndianCurrency($values[$labelArray[0]]); // $gst[] = $values[$labelArray[1]]; $gstAmt[] = formatIndianCurrency($values[$labelArray[1]]); $total[] = formatIndianCurrency($values[$labelArray[2]]); } } } } // dd([$premium, $gstAmt, $total]); die; foreach ([$premium, $gstAmt, $total] as $index => $rowData) { $columnLetter = $columnLetterForPremium; foreach ($rowData as $key => $value) { $sheet->setCellValue("{$columnLetter}{$rowNumber}", $value); if (in_array($value, $labelArray)) { $sheet->getStyle("{$columnLetter}{$rowNumber}")->applyFromArray(['font' => ['bold' => true,],]); } $columnLetter++; } $rowNumber++; } if ($is_placement == true) { $prevColumn3 = $this->getPreviousColumn($columnLetter); } else { $prevColumn3 = $this->getPreviousColumn($columnLetter, 2); } $premiumRange = $columnLetterForPremium . ($rowNumber - 3) . ":" . "{$prevColumn3}" . ($rowNumber - 1); // dd($prevColumn3, $premiumRange, $this->getPreviousColumn($columnLetter, 2), $columnLetter, $rowNumber); $sheet->getStyle($premiumRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); } //set imgage and align the row and column if ($type == 2) { if ($is_placement == true) { $columnLetter_img = $this->getPreviousColumn($columnLetter); } else { $columnLetter_img = $this->getPreviousColumn($columnLetter, 2); } } else { $columnLetter_img = $this->getPreviousColumn($columnLetter); } $company_name = $this->getPreviousColumn($columnLetter_img); $mergeRange1 = "A1:{$company_name}1"; $sheet->mergeCells($mergeRange1); $rowCount = count($lead_data); for ($i = 2; $i <= $rowCount + 1; $i++) { $mergeRange1 = "C{$i}:{$columnLetter_img}{$i}"; $sheet->mergeCells($mergeRange1); $sheet->getStyle($mergeRange1)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); } $sheet->getColumnDimension($columnLetter_img)->setWidth(35); $sheet->getRowDimension(1)->setRowHeight(50); // Adjust as needed $drawing = new Drawing(); $path = ROOTPATH . "public/assets/images/Nhance-Logo-Final.png"; // Use FCPATH for server path $drawing->setPath($path); $drawing->setCoordinates("{$columnLetter_img}1"); // Set position in column B $drawing->setHeight(35); // Adjust image $offsetX = 35; $drawing->setOffsetX($offsetX); // Adjust horizontal offset $drawing->setOffsetY(10); // Adjust vertical offset $drawing->setWorksheet($sheet); //end // Auto-size columns // foreach ($sheet->getColumnIterator() as $column) { // $sheet->getColumnDimension($column->getColumnIndex())->setAutoSize(true); // } $dataRange = $sheet->calculateWorksheetDimension(); $sheet->getStyle($dataRange)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER)->setVertical(Alignment::VERTICAL_CENTER)->setWrapText(true); $sheet->getStyle('A1')->applyFromArray([ 'alignment' => [ 'wrapText' => false, // Disables text wrapping for A1 ], ]); // Apply border to the entire sheet preg_match('/([A-Z]+)(\d+):([A-Z]+)(\d+)/', $dataRange, $matches); if ($matches) { $startColumn = $matches[1]; // A $startRow = $matches[2]; // 1 $endColumn = $matches[3]; // G $endRow = $matches[4]; // 75 // Convert column letter to index, reduce by 1, and convert back $endColumnIndex = Coordinate::columnIndexFromString($endColumn) - 1; $newEndColumn = Coordinate::stringFromColumnIndex($endColumnIndex); // Generate the new range (e.g., "A1:F75" instead of "A1:G75") $newDataRange = "{$startColumn}{$startRow}:{$newEndColumn}{$endRow}"; // $sheet->getStyle($newDataRange)->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN); } $lastRow = count($lead_data) + 1; $leadRange = "A1:{$columnLetter_img}{$lastRow}"; $sheet->getStyle($leadRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); // Set filename $string = ($type == 2) ? ($is_placement == true ? 'Placement' : 'QCR') : 'RFQ'; $current_year = date('Y'); $next_year = $current_year + 1; $policy_year = "$current_year-$next_year"; if (!empty($rfq_data['policy_end_date'])) { $policy_expiry = strtotime($rfq_data['policy_end_date']); $formatted_policy = date("d-m-Y", $policy_expiry); $filename = "{$rfq_data['client_name']}_{$rfq_data['policy_type']}_{$string}_" . $policy_year . '(Due On ' . $formatted_policy . ')' . '.xlsx'; } else { $filename = "{$rfq_data['client_name']}_{$rfq_data['policy_type']}_{$string}_" . $policy_year . '_' . '.xlsx'; } //claim history new sheet; if (!empty($rfq_data['fin_years_claims'])) { $claim_details = json_decode($rfq_data['fin_years_claims'], true) ?? []; if (!empty($claim_details['finyear'])) { // Get headers dynamically $headers = array_map(function ($key) { return ucwords(str_replace('_', ' ', $key)); }, array_keys($claim_details['finyear'][0])); $newSheet = new Worksheet($spreadsheet, 'Claims Experience'); $spreadsheet->addSheet($newSheet); $spreadsheet->setActiveSheetIndexByName('Claims Experience'); $sheet = $spreadsheet->getActiveSheet(); // Set headers $sheet->fromArray($headers, NULL, 'A1'); // Apply background color and bold style to headers $headerCellRange = 'A1:' . chr(64 + count($headers)) . '1'; // e.g., A1:G1 $sheet->getStyle($headerCellRange)->getFont()->setBold(true); $sheet->getStyle($headerCellRange)->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB('ADD8E6'); // Add border to header $sheet->getStyle($headerCellRange)->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN); // Fill data and apply borders $row = 2; foreach ($claim_details['finyear'] as $record) { $col = 'A'; foreach ($record as $array_key => $value) { $label = ucwords(str_replace('_', ' ', ($value ?? ""))); if(in_array($array_key, ['sum_insured', 'claim_amount', 'settled'])){ $label = formatIndianCurrency(intval($label)); } $sheet->setCellValue($col . $row, $label); $col++; } // Apply border to each data row $sheet->getStyle('A' . $row . ':' . chr(64 + count($headers)) . $row) ->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN); $row++; } // Auto-size all columns based on header count for ($i = 0; $i < count($headers); $i++) { $colLetter = chr(65 + $i); // 'A', 'B', etc. $sheet->getColumnDimension($colLetter)->setAutoSize(true); } // Enable wrap text for all cells // $maxColLetter = chr(64 + count($headers)); // Last column letter // $sheet->getStyle("A2:{$maxColLetter}{$row}")->getAlignment()->setWrapText(true); // // Optional: center vertically for neatness // $sheet->getStyle("A2:{$maxColLetter}{$row}")->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); $maxColLetter = chr(64 + count($headers)); $dataRange = "A1:{$maxColLetter}" . ($row - 1); $sheet->getStyle($dataRange)->getAlignment() ->setWrapText(true) ->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER) ->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); // Optional: Make row height auto (helps when wrap text is on) for ($i = 2; $i < $row; $i++) { $sheet->getRowDimension($i)->setRowHeight(-1); } } } // Save to temporary location $uploadFilePath = WRITEPATH . 'tmp/' . $filename; $writer = new Xlsx($spreadsheet); $writer->save($uploadFilePath); return [ 'filePath' => $uploadFilePath, 'fileName' => $filename, ]; } //Merge RFQ/QCR file with lead members file public function mergeQuoteExcelFileWithMembersListExcelFile($lead_id, $type, $source_file_path) { $rfq_data = $this->RFQModel->getRFQTableDataWithLeadIDAndType($lead_id, $type); if ($source_file_path && $rfq_data['file_name']) { } return true; } public function calculateMembersDemography($params, $returnType = null) { $lead_id = $params['lead_id']; $lead_data = $this->leadsModel->find((int)$lead_id); $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; if (!$lead_data) { return ['status' => 'failed', 'message' => 'Lead data not found']; } try{ if ($lead_data['file_name']) { // $file_name_with_path = WRITEPATH . "/uploads/lead_files/NonPrintableCharacters.xlsx"; //check physical file if (!file_exists($file_name_with_path)) { //file not found update status and reason $message = "Lead Physcial file not found"; // echo $message; $this->myLogger->logme('error', ($message . ' for file ' . $file_name_with_path)); return ['status' => 'failed', 'message' => 'no physical file']; } $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); //get members data $members_sheet = $spreadsheet->getSheet(0); $highestRowAndColumn = $members_sheet->getHighestRowAndColumn(); // dd($highestRowAndColumn); $uncleaned_members = $members_sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); $members = ExcelSanitizeHelper::sanitizeArrayData($uncleaned_members); //get age band data $age_band_sheet = $spreadsheet->getSheet(1); $highestRowAndColumn = $age_band_sheet->getHighestRowAndColumn(); $age_band_data = $age_band_sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); //check age or dob column $members_heading = $members[0]; $available_col = null; $col_index = null; if (in_array('age', array_map('strtolower', $members_heading))) { $available_col = 'age'; $col_index = array_search('age', array_map('strtolower', $members_heading)); } elseif (in_array('dob', array_map('strtolower', $members_heading))) { $available_col = 'dob'; $col_index = array_search('dob', array_map('strtolower', $members_heading)); } if ($available_col == null) { $message = 'No DOB or Age column '; $this->myLogger->logme('error', ($message . $file_name_with_path)); return ['status' => 'failed', 'message' => $message]; } try { $classifiers = $this->getDemographyData($members, $age_band_data, $members_heading, $available_col, $col_index); } catch (Exception $e) { return ['status' => 'fail', 'message' => $e->getMessage()]; } //for this to view the demography in the RFQ and QCR page to using internal if($returnType == "internal"){ return ['data' => $classifiers]; // print_rr($classifiers); die; } try { $result = $this->generateClassifierSpreadsheet($classifiers, WRITEPATH . 'uploads/lead_files/'); if ($result['success']) { $this->myLogger->logme('error', "Spreadsheet generated successfully!"); echo "Location: " . $result['fullpath'] . "\n"; echo "Filename: " . $result['filename'] . "\n"; $filePaths = [ ['file_path' => WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name'], 'sheets' => [0, 1]], ['file_path' => WRITEPATH . '/uploads/lead_files/' . $result['filename'], 'sheets' => []], ]; $outputPath = WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name']; $result_merge = ExcelMergeHelper::mergeExcelFiles($filePaths, $outputPath); if ($result_merge) { // Call the delete function after the file is successfully created $deleteResponse = $this->deleteGeneratedFile($result['fullpath']); // Add delete message to response $response['deleteMessage'] = $deleteResponse['message']; return ['status' => 'success', 'message' => 'Member_Data Merged Suceesfully']; } } else { echo "Error generating spreadsheet: " . $result['error']; } } catch (Exception $e) { echo "Error: " . $e->getMessage(); return ['status' => 'fail', 'message' => $e->getMessage()]; } } else { $this->myLogger->logme('error', (' no file found ' . $file_name_with_path)); return ['status' => 'failed', 'message' => 'no file found']; } }catch(Exception $e){ $this->myLogger->logme("error", "Exception: " . $e->getMessage() . " --- Line: " . $e->getLine() . " --- Trace: " . $e->getTraceAsString()); return ['status' => 'fail', 'error' => "File not found / Wrong file"]; } } public function getDemographyData($members, $age_band_data, $members_heading, $available_col, $col_index) { $first_loop = 0; // $col_index_si = array_search('si enhancement', array_map('strtolower', $members_heading)); $col_index_si = array_search('si', array_map('strtolower', $members_heading)); $col_index_relationship = array_search('relationship', array_map('strtolower', $members_heading)); $relations = []; $si_amt = ['general']; // Initialize with 'general' as per first loop condition // First pass - collect unique relations and SI amounts foreach ($members as $member) { if ($first_loop == 0) { $first_loop++; continue; } if ($member == null) { continue; } if (!in_array($member[$col_index_relationship], $relations) && $member[$col_index_relationship] != null) { $relations[] = $member[$col_index_relationship]; } if (!in_array($member[$col_index_si], $si_amt) && $member[$col_index_si] != null) { $si_amt[] = $member[$col_index_si]; } } // Initialize classifier array $classifiers = []; foreach ($si_amt as $si) { $classifiers[$si] = []; // Initialize relation counts including Grand Total row foreach ($relations as $relation) { $classifiers[$si][$relation] = []; foreach ($age_band_data as $age_bands) { foreach ($age_bands as $age_interval) { $classifiers[$si][$relation][$age_interval] = 0; } } // Add Grand Total column for each relation echo('test passed 3.5'); $classifiers[$si][$relation]['Grand Total'] = 0; } // Initialize Grand Total row $classifiers[$si]['Grand Total'] = []; foreach ($age_band_data as $age_bands) { foreach ($age_bands as $age_interval) { $classifiers[$si]['Grand Total'][$age_interval] = 0; } } // Add grand total of grand totals $classifiers[$si]['Grand Total']['Grand Total'] = 0; } // Process members and count them foreach ($members as $member) { if ($first_loop == 0) { $first_loop++; continue; } // Get age $age = $this->getAge($available_col, $member, $col_index); $relation = $member[$col_index_relationship]; $member_si = $member[$col_index_si]; // Find the correct age band (only once per member) $found_band = false; foreach ($age_band_data as $age_bands) { if ($found_band) break; foreach ($age_bands as $age_band) { //get Min and Max Age list($min_age, $max_age) = $this->getAgeRange($age_band); // If age fits in this band if ($age >= $min_age && $age <= $max_age) { // Update counts for general category if (isset($classifiers['general'][$relation][$age_band])) { // Increment count for specific relation and age band $classifiers['general'][$relation][$age_band]++; // Update row total (Grand Total column) $classifiers['general'][$relation]['Grand Total']++; // Update column total (Grand Total row) $classifiers['general']['Grand Total'][$age_band]++; // Update grand total of grand totals $classifiers['general']['Grand Total']['Grand Total']++; } // Update counts for specific SI category if (isset($classifiers[$member_si][$relation][$age_band])) { // Increment count for specific relation and age band $classifiers[$member_si][$relation][$age_band]++; // Update row total (Grand Total column) $classifiers[$member_si][$relation]['Grand Total']++; // Update column total (Grand Total row) $classifiers[$member_si]['Grand Total'][$age_band]++; // Update grand total of grand totals $classifiers[$member_si]['Grand Total']['Grand Total']++; } $found_band = true; break; } } } } return $classifiers; } public function generateClassifierSpreadsheet($classifiers, $outputDir = 'exports') { if (!file_exists($outputDir)) { if (!mkdir($outputDir, 0755, true)) { throw new Exception("Failed to create directory: $outputDir"); } } // Check if directory is writable if (!is_writable($outputDir)) { throw new Exception("Directory is not writable: $outputDir"); } // Generate unique filename $timestamp = date('Y-m-d_His'); $filename = "member_classification_{$timestamp}.xlsx"; $filepath = $outputDir . DIRECTORY_SEPARATOR . $filename; // Check if file already exists (shouldn't happen with timestamp, but just in case) if (file_exists($filepath)) { $counter = 1; while (file_exists($outputDir . DIRECTORY_SEPARATOR . "member_classification_{$timestamp}_{$counter}.xlsx")) { $counter++; } $filename = "member_classification_{$timestamp}_{$counter}.xlsx"; $filepath = $outputDir . DIRECTORY_SEPARATOR . $filename; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('Demography_Data'); // Get all age bands $age_bands = array_keys(reset($classifiers['general'])); array_pop($age_bands); // Remove 'Grand Total' $age_bands[] = 'Grand Total'; // Add it back at the end $currentRow = 5; // Start from row 5 to match the example // Function to write section data $writeSectionData = function ($data, $sheet, &$currentRow, $si_type) use ($age_bands) { // Add section header for the SI type $sheet->setCellValue('B' . $currentRow, strtoupper($si_type)); // Style section header $sheet->getStyle('B' . $currentRow)->applyFromArray([ 'font' => ['bold' => true, 'size' => 14], 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER], ]); $currentRow++; // Move to the next row after the section header // Set headers for the data table $sheet->setCellValue('B' . $currentRow, 'Relationship'); $col = 'C'; foreach ($age_bands as $band) { $sheet->setCellValue($col . $currentRow, $band); $col++; } // Style headers $lastCol = chr(ord('B') + count($age_bands)); $headerRange = 'B' . $currentRow . ':' . $lastCol . $currentRow; $sheet->getStyle($headerRange)->applyFromArray([ 'font' => ['bold' => true], 'borders' => [ 'allBorders' => [ 'borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => '000000'], ], ], 'alignment' => [ 'horizontal' => Alignment::HORIZONTAL_CENTER, ], ]); $currentRow++; // Write data rows foreach ($data as $relation => $values) { if ($relation !== 'Grand Total') { $sheet->setCellValue('B' . $currentRow, $relation); $col = 'C'; foreach ($age_bands as $band) { $value = $values[$band] ?: ''; // Convert 0 to empty string $sheet->setCellValue($col . $currentRow, $value); $col++; } // Style data row $dataRange = 'B' . $currentRow . ':' . $lastCol . $currentRow; $sheet->getStyle($dataRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => '000000'], ], ], 'alignment' => [ 'horizontal' => Alignment::HORIZONTAL_CENTER, ], ]); $currentRow++; } } // Add Grand Total row $sheet->setCellValue('B' . $currentRow, 'Grand Total'); $col = 'C'; foreach ($age_bands as $band) { $sheet->setCellValue($col . $currentRow, $data['Grand Total'][$band]); $col++; } // Style Grand Total row $totalRange = 'B' . $currentRow . ':' . $lastCol . $currentRow; $sheet->getStyle($totalRange)->applyFromArray([ 'font' => ['bold' => true], 'borders' => [ 'allBorders' => [ 'borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => '000000'], ], ], 'fill' => [ 'fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'F2F2F2'], ], 'alignment' => [ 'horizontal' => Alignment::HORIZONTAL_CENTER, ], ]); $currentRow += 3; // Add gap after each section }; // Write each SI section with gaps foreach ($classifiers as $si_type => $data) { $writeSectionData($data, $sheet, $currentRow, $si_type); } // Auto-size columns foreach (range('B', chr(ord('B') + count($age_bands))) as $col) { $sheet->getColumnDimension($col)->setAutoSize(true); } // Create Excel file try { // Create Excel file $writer = new Xlsx($spreadsheet); $writer->save($filepath); // Verify file was created successfully if (!file_exists($filepath)) { throw new Exception("Failed to create file: $filepath"); } // Return the file info after creation $response = [ 'success' => true, 'filepath' => $filepath, 'filename' => $filename, 'fullpath' => realpath($filepath) ]; return $response; } catch (Exception $e) { return [ 'success' => false, 'error' => $e->getMessage() ]; } } // Function to delete generated file public function deleteGeneratedFile($filePath) { try { if (file_exists($filePath)) { unlink($filePath); // Delete the file return [ 'success' => true, 'message' => "File deleted successfully" ]; } else { return [ 'success' => false, 'message' => "File does not exist" ]; } } catch (Exception $e) { return [ 'success' => false, 'error' => $e->getMessage() ]; } } public function getAge($available_col, $member, $col_index) { if ($available_col == 'age') { $age = $member[$col_index]; } else { $dob = $member[$col_index]; if ($dob == 'DOB') { return; } $dobDate = \DateTime::createFromFormat('d-M-Y', $dob); $currentDate = new \DateTime(); if ($dobDate == false) { $this->myLogger->logme('error', $dob . 'is not valid'); return; } $age = $currentDate->diff($dobDate)->y; } return $age; } public function getAgeRange($age_band) { $age_band = trim($age_band); // Parse age range if (strpos($age_band, '-') === false) { $min_age = (int)filter_var($age_band, FILTER_SANITIZE_NUMBER_INT); $max_age = PHP_INT_MAX; } else { $parts = explode("-", $age_band); $min_age = (int)$parts[0]; $max_age = (int)$parts[1]; } return array($min_age, $max_age); } //this funciton for send mail to insurer and client with either RFQ/QCR public function sendMailWithAttachement() { helper('excel_util_helper'); helper('MailHelper'); helper('ExcelMergeHelper'); $params = $this->request->getPost(); // print_r($params); die; $lead_id = (int)$params['lead_id']; $file_type = $params['file_type']; //rfq or qcr $recipient_type = $params['recipient_type']; //insurer or client or internal or placement $recipient_mail = $params['recipient_mail']; // - only primary key of contacts $recipient_mail = json_decode($params['recipient_mail'], true); // - only primary key of contacts $propsal_and_insurer = isset($params['proposal_insurer']) ? $params['proposal_insurer'] : null; $mail_content = $params['mail_content']; $mail_subject = $params['subject']; $attachment_file_ids = $params['selected_attachment_files']; $from_mail = getenv('email.fromEmail'); if (in_array($recipient_type, ['placement', 'insurer', 'internal'])) { $from_mail = "im@nhanceindia.in"; } else if (in_array($recipient_type, ['client'])) { $from_mail = "bs@nhanceindia.in"; } $type = ""; $insurer_ids = null; if (in_array($recipient_type, ['placement'])) { $type = "placement"; } else if (in_array($recipient_type, ['insurer'])) { $type = "insurer"; $insurer_ids = json_decode($params['insurer_ids'] ?? "", true) ?? []; }else if (in_array($recipient_type, ['internal'])) { $type = "internal"; }else if (in_array($recipient_type, ['client'])) { $type = "client"; } // print_r($insurer_ids); die; if ($recipient_type === 'placement') { $lead_data = $this->leadsModel->find((int)$lead_id); $data = []; if (!empty($params['policy_start_date'])) { $converted_start = change_date_format($params['policy_start_date']); // converts to Y-m-d if ($converted_start !== $lead_data['policy_start_date']) { $data['policy_start_date'] = $converted_start; } } if (!empty($params['policy_end_date'])) { $converted_end = change_date_format($params['policy_end_date']); // converts to Y-m-d if ($converted_end !== $lead_data['policy_end_date']) { $data['policy_end_date'] = $converted_end; } } if (!empty($data)) { $this->leadsModel->update($lead_id, $data); } } $result_data = []; // dd($recipient_mail); if ($recipient_type == 'insurer' && (!is_array($recipient_mail) || count($recipient_mail) == 0)) { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => '', 'messgae' => 'Recipient mail not found ! '], 200); } // dd(); //gather lead info $lead_data = $this->leadsModel ->select('leads.*,policy_type.long_name,policy_type.policy_type,user_profiles.email as created_person_email') ->join('policy_type', 'leads.policy_type_id = policy_type.id', 'left') ->join('user_profiles', 'leads.created_by = user_profiles.id', 'left') ->where('leads.id', $lead_id) ->first(); // log_message('error', 'Lead Data' . json_encode($lead_data)); // print_r($lead_data ); die; $cc_mails = []; $bcc_mails = []; //get CC Mails if ($recipient_type == 'internal' || $recipient_type == 'insurer' || $recipient_type == 'client') { $cc_data = isset($params['cc']) ? $params['cc'] : ""; $param_cc_mail = json_decode($cc_data, true); if (isset($param_cc_mail) && is_array($param_cc_mail) && count($param_cc_mail) > 0) { // Fetch user data where ID is in the param_cc_mail array $userData = $this->userModel ->where('is_active', 1) ->whereIn('id', $param_cc_mail) ->findAll(); // print_r($userData); die; // Extract emails from the fetched user data $cc_mails = array_column($userData, 'email'); // print_r(json_encode($cc_mails)); die; // If no emails were found, return an error response // if (empty($cc_mails)) { // return $this->respond(['status' => 'failed','code' => 400,'data' => '','message' => 'No valid CC mail addresses found!'], 200); // } } else { // Handle case where param_cc_mail is not valid // return $this->respond(['status' => 'failed','code' => 400,'data' => '','message' => 'CC mail not found!'], 200); } } else if ($recipient_type == 'placement') { $cc_mails = isset($params['cc']) ? json_decode($params['cc'], true) : ""; } //get BCC Mails if ($recipient_type == 'insurer' || $recipient_type == 'client') { $bcc_data = isset($params['bcc']) ? $params['bcc'] : ""; $param_bcc_mail = json_decode($bcc_data, true); if (isset($param_bcc_mail) && is_array($param_bcc_mail) && count($param_bcc_mail) > 0) { // Fetch user data where ID is in the param_cc_mail array $userData = $this->userModel ->where('is_active', 1) ->whereIn('id', $param_bcc_mail) ->findAll(); // print_r($userData); die; // Extract emails from the fetched user data $bcc_mails = array_column($userData, 'email'); // print_r(json_encode($cc_mails)); die; // If no emails were found, return an error response // if (empty($cc_mails)) { // return $this->respond(['status' => 'failed','code' => 400,'data' => '','message' => 'No valid CC mail addresses found!'], 200); // } } else { // Handle case where param_cc_mail is not valid // return $this->respond(['status' => 'failed','code' => 400,'data' => '','message' => 'CC mail not found!'], 200); } } if ($recipient_type == 'client' && ($lead_data['contact_person_email'] == '' || $lead_data['contact_person_email'] == null)) { return $this->respond(['status' => 'failed', 'code' => 400, 'data' => '', 'messgae' => 'Recipient mail not found ! '], 200); } // dd($lead_data); $reply_to = $lead_data['created_person_email'] ?? ""; //get file path to attach if ($lead_data["lead_form_type"] == 2) { $file_info = $this->constructNonEbExcelToSaveTemp($lead_id, ($file_type == 'rfq' ? 1 : 2), $propsal_and_insurer); } else { $file_info = $this->constructExcelToSaveTemp($lead_id, ($file_type == 'rfq' ? 1 : 2), $propsal_and_insurer); } // $file_info = $this->constructExcelToSaveTemp($lead_id, ($file_type == 'rfq' ? 1 : 2), $propsal_and_insurer); log_message('error', 'File Info' . json_encode($file_info)); if ($lead_data['file_name'] != null && $lead_data['file_name'] != '') { $temp_file_path = $file_info['filePath']; $temp_file_name = $file_info['fileName']; $lead_file_path = WRITEPATH . 'uploads/lead_files/' . $lead_data['file_name']; if ($lead_file_path) { $filePaths = [ ['file_path' => $temp_file_path, 'sheets' => []], ['file_path' => $lead_file_path, 'sheets' => []] ]; $outputPath = dirname($temp_file_path) . '/' . $temp_file_name; $result = ExcelMergeHelper::mergeExcelFiles($filePaths, $outputPath); // print_rr($result); } } else { $result = $file_info['filePath']; // return $this->respond(['status' => 'fail', 'code' => 200, 'messgae' => 'File Not Found'], 200); } // print_rr($result); die; // print_rr($file_info); // $file_path = WRITEPATH."uploads/excel/sample/correction.xls"; // $file_name = $file_type.'.xlsx'; // !dd($file_info); $file_path = $result; $file_name = basename($result); // Attacments part $attachments = [['fileName' => $file_name, 'filePath' => $file_path]]; $other_attachments = $this->handleMultiFileAttachments($attachment_file_ids, $lead_id); $attachments = array_merge($attachments, $other_attachments); // print_r($attachments); die; //get recipient address if ($recipient_type == 'insurer' || $recipient_type == 'placement') { $recipient_data = $this->levelContactModel ->where(['contact_type' => 'insurer', 'is_active' => 1]) ->whereIn('id', $recipient_mail) ->findAll(); } else if ($recipient_type == 'client') { $mailIDS = explode(',', $params['contact_mail']); $recipient_data = []; foreach ($mailIDS as $mail) { $recipient_data[] = ['name' => $lead_data['contact_person_name'], 'email' => $mail]; } } else { $recipient_data = [['name' => "Team", 'email' => $params['to']]]; } // print_r($recipient_data); die; $subject = $file_type == 'rfq' ? 'Request for Quotation from ' . $lead_data['client_name'] . ' for ' . $lead_data['policy_type'] : 'Quotation Comparison Report for ' . $lead_data['policy_type']; $original_message = '

Request for Quotation (RFQ)

Dear {{RECIPIENT_NAME}},

We are reaching out to request a quotation for the following insurance coverage. Please review the details below and provide your quote at your earliest convenience.

RFQ Details

Client name{{CLIENT_NAME}}
Coverage Type{{POLICY_LONG_NAME}}
Policy Start Date{{POLICY_START_DATE}}
Policy Duration{{DURATION}}
Please note: Additional terms and details are included in the attachment for your reference.

Please feel free to reach out if you require any further information to prepare the quote. We look forward to receiving your proposal.

Best regards,

Nhance India Pvt Ltd

© Nhance India Pvt Ltd. All rights reserved.

'; //for mail content if (!empty($mail_content)) { $original_message = $mail_content; } //for mail subject if (!empty($mail_subject)) { $subject = $mail_subject; } // print_r($subject); die; $common = ['module' => "leads", 'pk' => $lead_id, 'mail_type' => $type, 'common' => null]; if ($recipient_data) { foreach ($recipient_data as $position => $recipient) { if ($recipient_type == 'insurer'){ $common['common'] = $insurer_ids[$position] ?? null; } $message = $original_message; $message = str_replace("{{RECIPIENT_NAME}}", $recipient['name'] != "" ? $recipient['name'] : " ", $message); $message = str_replace("{{CLIENT_NAME}}", $lead_data['client_name'] != "" ? $lead_data['client_name'] : "", $message); $message = str_replace("{{POLICY_LONG_NAME}}", $lead_data['long_name'] != "" ? $lead_data['long_name'] : "", $message); $message = str_replace("{{POLICY_START_DATE}}", change_date_format($lead_data['policy_start_date'], 'Y-m-d', 'd-m-Y'), $message); $message = str_replace("{{DURATION}}", calculate_days_bw_dates($lead_data['policy_end_date'] ?? "", $lead_data['policy_start_date'] ?? "")->days, $message) ?? '--'; // print_rr($message);calculate_days_bw_dates $string = implode(", ", $cc_mails); $bcc_string = implode(", ", $bcc_mails); $res = MailHelper::send_email(['from_mail' => $from_mail, 'mail' => $recipient['email'], 'cc' => $string, 'subject' => $subject, 'message' => $message, 'attachments' => $attachments, 'reply_to' => $reply_to, 'bcc' => $bcc_string, 'common' => $common]); // !dd($res); $result_data[] = ['mail' => $recipient['email'], 'status' => $res]; } } if($recipient_type == 'placement' && isset($params['acm_email']) && !empty($params['acm_email'])){ $common['mail_type'] = "internal acm"; $acm_mail_content = '

Dear Sir,

The placement for the {{POLICY_TYPE}} policy pertaining to {{CLIENT_NAME}} has been successfully won.

Please proceed with the next steps accordingly.

Thank You!


Best regards,

Nhance Logo '; $acm_mail_content = $this->transformMailContent($lead_data, $acm_mail_content, $data['page_name'] = 'QCR'); $res = MailHelper::send_email(['from_mail' => $from_mail, 'mail' => $params['acm_email'], 'subject' => $subject, 'message' => $acm_mail_content, 'attachments' => $attachments, 'common' => $common]); } $is_placement = false; if ($recipient_type == 'placement') { $is_placement = true; list($proposal_key, $insurer_key) = explode('-', $propsal_and_insurer, 2); $lead_update_data = [ 'proposel_name' => $proposal_key, 'insurer_name' => $insurer_key, 'insurer' => $params['insurer_and_branch'], ]; $data = [ 'proposel_data' => json_encode($lead_update_data), 'status' => 'won', 'placement_date' => !empty($params['placement_date']) ? change_date_format($params['placement_date']) : null, 'payment_date' => !empty($params['payment_date']) ? change_date_format($params['payment_date']) : null, 'utr_no' => $params['utr_no'] ?? null, 'is_cd' => $params['is_cd'] ?? null, 'premium_amount' => $params['premium_amount'] ?? null, 'total_amount' => $params['total_amount'] ?? null, 'cd_amount' => $params['cd_amount'] ?? null, 'no_of_installment' => $params['no_of_installment'] ?? null, 'is_installment' => $params['is_installment'] ?? null, 'acm_id' => $params['acm_pk'] ?? null, 'agreed_percentage' => $params['agreed_percentage'] ?? null, ]; if(isset($params['tpa_id']) && !empty($params['tpa_id'])){ list($tpaBranchId, $tpaId) = explode('-', $params['tpa_id']); $data['tpa_branch_id'] = $tpaBranchId; $data['tpa_id'] = $tpaId; } $this->leadsModel->where('id', $lead_id)->set($data)->update(); if (isset($params['installments']) && !empty($params['installments'])) { $installment_data = json_decode($params['installments'], true); if (!empty($installment_data)) { foreach ($installment_data as $key => $value) { // print_r($value);die $value['payment_date'] = !empty($value['payment_date']) && strtotime($value['payment_date']) ? date('Y/m/d', strtotime($value['payment_date'])) : null; if (isset($value['id']) && !empty($value['id'])) { $this->leadInstallmentPaymentDetails->where('id', $value['id'])->set($value)->update(); } else { $this->leadInstallmentPaymentDetails->insert($value); } } } } } if ($recipient_type == 'client') { $this->leadsModel ->where('id', $lead_id) ->whereNotIn('status', ['lost', 'co_insurer_pending', 'won', 'completed_with_corrections', 'completed_without_corrections']) ->set(['status' => "qcr_sent"]) ->update(); } if ($recipient_type == 'insurer') { $this->leadsModel ->where('id', $lead_id) ->whereNotIn('status', ['qcr_created', 'qcr_sent', 'lost', 'co_insurer_pending', 'won', 'completed_with_corrections', 'completed_without_corrections']) ->set(['status' => "rfq_sent"]) ->update(); } //delete attachment file unlink($file_path); return $this->respond(['status' => 'success', 'code' => 200, 'data' => $result_data, 'is_placement' => $is_placement], 200); } public function getLevelContects() { $data = $this->levelContactModel->getContactForRFQ(); if ($data) { return $this->respond(['status' => true, 'data' => $data], 200); } else { return $this->respond(['status' => false], 200); } } public function getInsurerBranchContacts($insurer_and_branch_id) { if (strpos($insurer_and_branch_id, '-') === false) { return $this->respond(['status' => false, 'message' => 'Invalid ID format'], 400); } // Split the insurer_and_branch_id list($insurerBranchId, $insurerId) = explode('-', $insurer_and_branch_id); $data = $this->levelContactModel->getContactForRFQ($insurerId, $insurerBranchId); if (!empty($data)) { return $this->respond(['status' => true, 'data' => $data], 200); } else { return $this->respond(['status' => false, 'data' => $data, 'message' => 'No contacts were found for the selected insurer.'], 200); } } public function transformProposelData($data, $proposel, $insurer) { // print_r($data['premium_data']['data']); die; $headerData = []; // Default headers: S. No and Particulars $defaultHeaders = [ [ 'parentHeader' => 'Sno', 'subHeaders' => ['-'] ], [ 'parentHeader' => 'Particulars', 'subHeaders' => ['-'] ] ]; // Add default headers to the result $headerData = array_merge($headerData, $defaultHeaders); foreach ($data['table_data']['headers'] as $header) { // Check if the parentHeader matches the target proposal if ($header['parentHeader'] === $proposel) { // Check if subHeaders contain the target insurer key foreach ($header['subHeaders'] as $subHeader) { if ($subHeader === $insurer) { $headerData[] = [ 'parentHeader' => $header['parentHeader'], 'subHeaders' => [ // 'Quote Asked', // Default value $subHeader // Matched insurer key ] ]; break; } } } } $columnData = []; foreach ($data['table_data']['data'] as $entry) { $sno = $entry['SNO']; $items = $entry['items']; $dataEntry = $entry['data']; $result = [ "SNO" => $sno, "items" => $items, "data" => [] ]; foreach ($dataEntry as $item) { // Include Sno and Particulars by default if (in_array($item['parentth'], ['Sno', 'Particulars'])) { $result['data'][] = [ "parentth" => $item['parentth'], "subth" => $item['subth'], "value" => $item['value'], "input_value" => $item['input_value'] ]; } // Include Proposal with Quote Asked by default /* For proposel do not remove it */ // if ($item['parentth'] === $proposel && $item['subth'] === "Quote Asked") { // $result['data'][] = [ // "parentth" => $item['parentth'], // "subth" => $item['subth'], // "value" => $item['value'], // "input_value" => $item['input_value'] // ]; // } // Example of including matching specific proposals and insurers if ($item['parentth'] === $proposel && $item['subth'] === $insurer) { $result['data'][] = [ "parentth" => $item['parentth'], "subth" => $item['subth'], "value" => $item['value'], "input_value" => $item['input_value'] ]; } } // Add to the final result $columnData[] = $result; } $premiumData = []; foreach ($data['premium_data']['data'] as $key => $value) { if ($key === $proposel) { // $premiumData[$key]['Quote Asked'] = $value['Quote Asked']; $premiumData[$key][$insurer] = $value[$insurer]; } } $data['table_data']['headers'] = $headerData; $data['table_data']['data'] = $columnData; $data['premium_data']['data'] = $premiumData; return $data; } public function convertJsonForQCR($json, $type) { if ($json) { // Deep copy of JSON $first_json = json_decode(json_encode($json), true); // dd($first_json); if ($type == 2) { // Column-wise Check: Remove headers and relevant data if qcr == 0 foreach ($json['proposal_data']['over_all_column_data'] as $proposalKey => $proposalData) { if (($proposalData['qcr'] == 0 || $proposalData['qcr'] === false) || ($proposalData['stc'] == 0 || $proposalData['stc'] === false)) { // Remove matching parentHeader in headers foreach ($first_json['table_data']['headers'] as $index => $header) { if ($header['parentHeader'] === $proposalKey) { unset($first_json['table_data']['headers'][$index]); } } // Remove data entries with matching parentth foreach ($first_json['table_data']['data'] as &$item) { $item['data'] = array_values(array_filter($item['data'], function ($entry) use ($proposalKey) { return $entry['parentth'] !== $proposalKey; })); } // Remove proposalKey from over_all_column_data unset($first_json['proposal_data']['over_all_column_data'][$proposalKey]); if ($type == 2) { // Remove proposalKey from premium_data unset($first_json['premium_data']['data'][$proposalKey]); } } // Insurer Check: Remove subHeaders and relevant data for insurers with qcr == 0 foreach ($proposalData['insurers'] as $insurerIndex => $insurer) { if (($insurer['qcr'] === 0 || $insurer['qcr'] === false) || ($insurer['stc'] === 0 || $insurer['stc'] === false)) { foreach ($first_json['table_data']['headers'] as &$header) { if (isset($header['subHeaders'])) { $header['subHeaders'] = array_values(array_filter($header['subHeaders'], function ($sub) use ($insurer) { return $sub !== $insurer['display_name']; })); } } foreach ($first_json['table_data']['data'] as &$item) { $item['data'] = array_values(array_filter($item['data'], function ($entry) use ($insurer) { return $entry['subth'] !== $insurer['display_name']; })); } // Remove insurer from proposal's insurers array unset($first_json['proposal_data']['over_all_column_data'][$proposalKey]['insurers'][$insurerIndex]); if ($type == 2) { unset($first_json['premium_data']['data'][$proposalKey][$insurer['display_name']]); } } } } // Row-wise Check: Remove rows if qcr == 0 for actions foreach ($first_json['table_data']['data'] as $rowKey => $rowData) { foreach ($rowData['data'] as $data) { if ($data['parentth'] === "Action" && (isset($data['input_value']['qcr']) && $data['input_value']['qcr'] == 0) || (isset($data['input_value']['stc']) && $data['input_value']['stc'] == 0)) { unset($first_json['table_data']['data'][$rowKey]); break; } } } // Reindex arrays to maintain proper structure $first_json['table_data']['headers'] = array_values($first_json['table_data']['headers']); $first_json['table_data']['data'] = array_values($first_json['table_data']['data']); $first_json['proposal_data']['over_all_column_data'] = array_map(function ($proposal) { $proposal['insurers'] = array_values($proposal['insurers']); return $proposal; }, $first_json['proposal_data']['over_all_column_data']); } else { //remove insurer as Subheaders for RFQ foreach ($first_json['table_data']['headers'] as &$header) { $header['subHeaders'] = array_filter($header['subHeaders'], function ($subHeader) { return in_array($subHeader, ['Quote Asked', '-']); }); } //Remove insurer Row wise data for RFQ foreach ($first_json['table_data']['data'] as &$row) { // Filter the inner data array $row['data'] = array_filter( $row['data'], function ($item) { return in_array($item['subth'], ['Quote Asked', '-']); } ); $row['data'] = array_values($row['data']); } // Ensure to unset the reference after the loop unset($row); // Remove insurers from Proposal Data key for RFQ foreach ($first_json['proposal_data']['over_all_column_data'] as $key => &$proposal) { if (isset($proposal['insurers'])) { // Set the insurers array to empty $proposal['insurers'] = []; } } // Ensure to reset the reference unset($proposal); } return $first_json; } return null; } //----- Featch Lead data and insert Client ------------------------------------------------------------------------------------------- public function featchLeadDataAndInsertClient($lead_id) { try { $data = $this->leadsModel->where('leads.id', $lead_id)->where('leads.is_active', 1)->first(); if (!$data) { $this->myLogger->logme('featchLeadDataAndInsertClient', "Lead not found or inactive", ['lead_id' => $lead_id]); return $this->respond(['status' => false, 'message' => 'Failed to create Client', 'data' => null], 200); } $result = $this->createClientWithLeadData($data); if ($result) { $policy_data = $this->clientPolicyModel->where('client_id', $result)->where('is_active', 1)->first(); return $this->respond([ 'status' => true, 'message' => 'New Client created successfully', 'client_id' => $result, 'data' => $data, 'client_policy_id' => $policy_data['id'] ?? null, ], 200); } $this->myLogger->logme('featchLeadDataAndInsertClient', "Client creation failed after processing", ['lead_id' => $lead_id]); return $this->respond(['status' => false, 'message' => 'Failed to create client', 'data' => $data], 200); } catch (\Throwable $e) { $this->myLogger->logme('error', 'featchLeadDataAndInsertClient failed'); return $this->respond(['status' => false, 'message' => 'Internal server error', 'error' => $e->getMessage()], 500); } } public function createClientWithLeadData($data) { try { $client_data = $this->prepareClientData($data); $client_id = $this->clientModel->insert($client_data); if ($client_id) { $this->createClientBranchAndContactWithLeadData($data, $client_id); $this->leadsModel->where('id', $data['id'])->set('is_client_created', $client_id)->update(); } return $client_id; } catch (\Throwable $e) { $this->myLogger->logme('error', 'createClientWithLeadData failed'); return false; } } public function createClientBranchAndContactWithLeadData($data, $client_id) { try { $branch_data = $this->prepareClientBranchData($data, $client_id); $branch_id = $this->clientBranchModel->insert($branch_data); if ($branch_id) { $this->leadsModel->where('id', $data['id'])->set('is_client_created', $client_id)->update(); $contact_data = $this->prepareContactData($data, $branch_id); $this->levelContactModel->insert($contact_data); $this->createClientPolicyWithLeadData($data, $client_id, $branch_id); } return $branch_id; } catch (\Throwable $e) { $this->myLogger->logme('error', 'createClientBranchAndContactWithLeadData failed'); return false; } } public function createClientPolicyWithLeadData($data, $client_id, $branch_id) { try { $client_policy_data = $this->prepareClientPolicyData($data, $client_id, $branch_id); $client_policy_id = $this->clientPolicyModel->insert($client_policy_data); if ($client_policy_id) { $this->leadsModel->where('id', $data['id'])->set('is_client_created', $client_id)->update(); $this->leadsModel->where('id', $data['id'])->set('is_policy_created', $client_policy_id)->update(); } return $client_policy_id; } catch (\Throwable $e) { $this->myLogger->logme('error', 'createClientPolicyWithLeadData failed'); return false; } } private function prepareClientData($data) { return [ 'client_type' => 1, 'entity_type_id' => $data['entity_type_id'] ?? null, 'client_code' => $data['client_code'] ?? null, 'client_name' => $data['client_name'] ?? null, 'short_name' => $data['client_short_name'] ?? null, 'pan' => $data['pan'] ?? null, ]; } private function prepareClientBranchData($data, $client_id) { $default_unit = trim(($data['client_short_name'] ?? '') . '-' . ($data['branch_code'] ?? ''), '-'); return [ 'client_id' => $client_id, 'branch_name' => $data['branch_name'], 'branch_code' => $data['branch_code'], 'gst' => $data['gst'], 'units' => json_encode([$default_unit]), ]; } private function prepareContactData($data, $branch_id) { return [ 'name' => $data['contact_person_name'], 'mobile' => $data['contact_person_mobile'], 'email' => $data['contact_person_email'], 'contact_type' => 'client', 'ref_id' => $branch_id, ]; } private function prepareClientPolicyData($data, $client_id, $branch_id) { $proposel_data = json_decode($data['proposel_data'], true); // print_r($proposel_data); die; list($insurer_branch_id, $insurer_id) = explode('-', $proposel_data['insurer'], 2); $client_policy_data = [ 'client_id' => $client_id, 'client_branch_id' => $branch_id, 'policy_type_id' => $data['policy_type_id'], 'insurer_id' => $insurer_id, 'insurer_branch_id' => $insurer_branch_id, 'tpa_id' => $data['tpa_id'], 'tpa_branch_id' => $data['tpa_branch_id'], 'policy_start_date' => $data['policy_start_date'], 'policy_end_date' => $data['policy_end_date'], 'policy_status' => 1, 'policy_entry_from' => 3, 'is_from_lead' => $data['id'], ]; $policy_type_id = $data['policy_type_id']; if (in_array($policy_type_id, [1, 2, 6, 7])) { $client_policy_data['is_addon'] = 1; // Base Policy } elseif (in_array($policy_type_id, [4, 5])) { $client_policy_data['is_addon'] = 2; // SI TOPUP } elseif ($policy_type_id == 3) { // if ($base_policy) { // $data['is_addon'] = 3; // Dependent Addon // } else { $data['is_addon'] = 1; // } } if ($data['lead_form_type'] == 1) { $client_policy_data['policy_terms'] = $this->preparePolicyTermsFromRFQ($data); } else { $placementJson = $this->getPlacementJson($data); if ($placementJson) { $client_policy_data['placement_json'] = $placementJson; $client_policy_data['policy_terms'] = $this->convertNonEbQCRJsonToPolicyTerms(json_decode($placementJson, true)); } } // print_r($client_policy_data); die; return $client_policy_data; } private function preparePolicyTermsFromRFQ($data) { try { $proposel_data = json_decode($data['proposel_data'], true); $QCRData = $this->RFQModel->where('is_active', 1)->where('lead_id', $data['id'])->first(); if (!$QCRData) { throw new \Exception('RFQ Data not found'); } $JSON = json_decode($QCRData['json'], true); $converted_json = $this->transformProposelData($JSON, $proposel_data['proposel_name'], $proposel_data['insurer_name']); // log_message('error', 'Converted JSON: ' . json_encode($converted_json)); return $this->convertQCRJsonToPolicyTerms($converted_json, $data['policy_type_id'], $proposel_data['proposel_name'], $proposel_data['insurer_name']); } catch (\Throwable $e) { $this->myLogger->logme('error', 'preparePolicyTermsFromRFQ'); return null; } } public function featchClientPolicyFromLead($client_id, $branch_id, $lead_id) { $data = $this->leadsModel->where('leads.id', $lead_id)->where('leads.is_active', 1)->first(); if (!$data) { return $this->respond(['status' => false, 'message' => 'Failed to create policy', 'data' => null], 200); } $result = $this->createClientPolicyWithLeadData($data, $client_id, $branch_id); // print_r($result); die; if ($result) { $policy_data = $this->clientPolicyModel->where('id', $result)->where('is_active', 1)->first(); return $this->respond(['status' => true, 'message' => 'New Policy created successfully', 'client_policy_id' => $result, 'data' => $data, 'client_id' => $policy_data['client_id']], 200); } return $this->respond(['status' => false, 'message' => 'Failed to create policy', 'data' => $data], 200); } // --------------------------------------------------------------------------------------------------------------- //Function for convert the RFQ and QCR Json to Policy Terms Json public function convertQCRJsonToPolicyTerms($data, $policy_type, $proposel_name, $insurer_name) { //transform the data into the currernt proposel and insurere ( get single proposel ) $data = $this->transformProposelData($data, $proposel_name, $insurer_name); // Initialize age_ratio based on policy type $age_ratio = $policy_type == 2 ? [ 'self' => ['min' => '18', 'max' => '60'], 'spouse' => ['min' => 0, 'max' => 0], 'child' => ['min' => 0, 'max' => '25'], 'elders' => ['min' => 0, 'max' => 0], ] : [ 'self' => ['min' => '18', 'max' => '60'] ]; foreach ($data['table_data']['data'] as $dataRow) { $item = $dataRow['items'] ?? ''; foreach ($dataRow['data'] as $cellData) { $parentth = $cellData['parentth'] ?? ''; $subth = $cellData['subth'] ?? ''; $input_value = $cellData['input_value'] != "" ? $cellData['input_value'] : ($cellData['value'] ?? ''); $value = $cellData['value'] ?? ''; if( $item == "family_composition" && $subth == $insurer_name && $policy_type == 2){ $age_ratio_array = json_decode($input_value, true)['age_ratio'] ?? null; if(!empty($age_ratio_array)){ $age_ratio = $age_ratio_array; } } // Skip unwanted keys if (in_array($parentth, ['Sno', 'Item Key', 'Particulars', 'Action']) || in_array($subth, ['Quote Asked'])) { continue; } switch (true) { // CASE 1: Handle special conditions case str_starts_with($item, 'special_condition') && $parentth === $proposel_name && $subth === $insurer_name: // log_message("error","INPUT".json_encode($input_value)); $parts = explode('-', $input_value); $labelKey = $policy_type == 1 ? 'gpa_special_condition_label' : 'special_condition_label'; $inputKey = $policy_type == 1 ? 'gpa_special_condition_input' : 'special_condition_input'; $terms_array[$labelKey][] = $parts[0] ?? ''; $terms_array[$inputKey][] = $parts[1] ?? ''; break; // CASE 2: Handle sum insured case in_array($item, ['sum_insured', 'sumInsured2']): $si_amt = explode(',', $value); $terms_array[$item] = $si_amt[0] ?? ''; $terms_array['multiple_sum_insured'] = array_slice($si_amt, 1); // Add age_ratio after Sum insured if ($policy_type == 1) { $terms_array['age_ratio'] = $age_ratio; } break; // CASE 3: Handle family floaters case $item === 'family_composition': $terms_array['family_floaters'] = isJsonString($input_value) ? json_decode($input_value, true) : $input_value; // Add age_ratio after family floaters if ($policy_type == 2) { $terms_array['age_ratio'] = $age_ratio; } break; // DEFAULT CASE : default: // $terms_array[$item] = isJsonString($input_value) ? (json_decode($input_value, true)['key'] ?? '') : $value; $terms_array[$item] = $value; break; } } } return json_encode($terms_array); } public function convertNonEbQCRJsonToPolicyTerms($allTableData) { if (!empty($allTableData)) { array_pop($allTableData); // Remove the last item from the array $terms_array = []; foreach ($allTableData as $TableIndex => $tableGroup) { if ($TableIndex == 0) { continue; } foreach ($tableGroup['table_data']['data'] as $dataRow) { $item = $dataRow['items'] ?? ''; foreach ($dataRow['data'] as $cellData) { $parentth = $cellData['parentth'] ?? ''; $subth = $cellData['subth'] ?? ''; $value = $cellData['display_content'] ?? ''; // Skip unwanted keys if (in_array($parentth, ['SNO', 'Particulars', 'Action']) || $subth === 'Sum Insured' || $subth === 'Fidelity Limit') { continue; } // Skip if item matches parentth if ($item === $parentth) { continue; } // Set the value directly, overwriting with latest encountered if (!empty($item) && !empty($value)) { $finalItem = $item; if (strpos($tableGroup['tableId'], 'summary') !== false) { $policy_type = explode('_', $tableGroup['tableId'])[0] ?? ''; $finalItem = $policy_type . ' - ' . $item; } $terms_array[$finalItem] = $value; } } } } return json_encode($terms_array); } else { return null; } } public function getPlacementJson(array $data): ?string { $proposel_data = json_decode($data['proposel_data'], true); $QCRData = $this->RFQModel ->where('is_active', 1) ->where('lead_id', $data['id']) ->first(); if (!$QCRData || empty($QCRData['json'])) { return null; } $jsonArray = json_decode($QCRData['json'], true); $proposalData = array_pop($jsonArray); // Get last item and remove it from the array if (empty($jsonArray)) { return null; } $placement_json_data = array_map(function ($jsonData) use ($proposel_data) { return $this->transformNonEbProposelData( $jsonData, $proposel_data['proposel_name'] ?? '', $proposel_data['insurer_name'] ?? '', null, 1 ); }, $jsonArray); if (!empty($proposalData)) { foreach ($proposalData['proposal_data']['over_all_column_data'] as $key => &$proposal) { // Keep only the required proposal if ($key !== $proposel_data['proposel_name']) { unset($proposalData['proposal_data']['over_all_column_data'][$key]); } else { // Within the matched proposal, filter insurers if (!empty($proposal['insurers'])) { $proposal['insurers'] = array_values(array_filter($proposal['insurers'], function ($insurer) use ($proposel_data) { return $insurer['display_name'] === $proposel_data['insurer_name']; })); } } } unset($proposal); // Good practice after foreach by reference } $placement_json_data[] = $proposalData; return json_encode($placement_json_data); } //------------------------------------------------------------------------------------------------ public function transformMailContent($lead_data, $mail_content, $page_name) { $current_year = date('Y'); $next_year = $current_year + 1; $policy_year = "$current_year-$next_year"; $page_name = $page_name == "QCR" ? "Quote Comparison Report" : $page_name; $log_path = base_url() . '/public/assets/images/Nhance-Logo-Final.png'; // $log_path ='https://venbait.in/nhance/dev/public/assets/images/Nhance-Logo-Final.png'; // dd($log_path); $policy_expiry = strtotime($lead_data['policy_end_date']); $formatted_policy = date("d-m-Y", $policy_expiry); $logged_user_id = get_session_userid(); $logged_user_data = $this->userModel->where("id", $logged_user_id)->where("is_active", 1)->first(); if ($lead_data) { // Replacing placeholders with actual values $message = $mail_content; $message = str_replace("{{CLIENT_NAME}}", $lead_data['client_name'] ?? "Valued Client", $message); $message = str_replace("{{POLICY_LONG_NAME}}", $lead_data['long_name'] ?? $lead_data['policy_type'] ?? "Insurance Policy", $message); $message = str_replace("{{POLICY_TYPE}}", $lead_data['policy_type'] ?? "Insurance Policy", $message); $message = str_replace("{{RFQ_OR_QCR}}", $page_name, $message); $message = str_replace("{{POLICY_YEAR}}", $policy_year, $message); $message = str_replace("{{POLICY_END_DATE}}", " (Due On " . $formatted_policy . ")", $message); $message = str_replace("{{LOGGED_USER_NAME}}", ucfirst($logged_user_data['first_name'] ?? "") . " " . ucfirst($logged_user_data['last_name'] ?? ""), $message); $message = str_replace("{{LOGGED_USER_EMAIL}}", $logged_user_data['email'] ?? "", $message); $message = str_replace("{{LOGGED_USER_MOBILE}}", $logged_user_data['mobile'] ?? "", $message); $message = str_replace("{{LOGO_PATH}}", $log_path ?? "", $message); return $message; } else { return ''; // Return empty if no lead data found } } public function getLastFiveFinancialYears() { $currentYear = date('Y'); $currentMonth = date('m'); // In India, the financial year starts from April (04) if ($currentMonth < 4) { $currentYear--; // Adjust year if it's Jan-Mar } $financialYears = []; for ($i = 0; $i < 5; $i++) { $startYear = $currentYear - $i - 1; $endYear = $currentYear - $i; $financialYears[] = "$startYear-$endYear"; } return $financialYears; } // ------------ RFQ NON EB FUNCTIONS----------------------------------------------------------------------------------------- public function rfqNonEB() { $this->loadLayout('view_rfq_non_eb'); } // get lead data for edit both EB and NON-EB public function getLeadNonEB($type, $id = null) { // Set basic data $data = [ 'issuer' => $this->issuer, 'client_type' => $this->clientType, 'lead_type' => $this->leadType, 'lead_status' => $this->leadsStatus, 'policy_type' => $this->policyTypeModel->where('is_active', 1)->findAll(), 'entity' => $this->kycEntityTypeModel->where('is_active', 1)->findAll(), 'insurer' => $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(), 'tpa' => $this->tpaBranchModel->getTpaBranchesWithTpaNames(), 'lastFiveYears' => $this->getLastFiveFinancialYears(), 'gpaClaimType' => $this->claim_type_for_gpa, 'causeOfDeath' => $this->cause_of_death, 'selected_lead_type' => $type, ]; // Fetch sales team members who are active in team 5 $data['salse_team'] = $this->userModel ->select('user_profiles.*') ->join('user_teams', 'user_profiles.id = user_teams.user_id') ->where('user_teams.team_id', 5) ->where('user_teams.is_active', 1) ->where('user_profiles.is_active', 1) ->findAll(); if (!empty($id)) { $data['lead_edit_data'] = $this->leadsModel->where('id', $id)->first() ?? []; $data['lead_edit_data']['multi_file_data'] = $this->leadFilesModel ->where('lead_id', $id) ->where('type !=', 2) ->where('is_active', 1) ->findAll() ?? null; $data['lead_edit_data']['lead_file_count'] = count($data['lead_edit_data']['multi_file_data']); // Decode and merge custom fields if present $custom_fields_data = !empty($data['lead_edit_data']['custom_fields']) ? json_decode($data['lead_edit_data']['custom_fields'], true) : []; if (!empty($custom_fields_data) && is_array($custom_fields_data)) { $data['lead_edit_data'] = array_merge($data['lead_edit_data'], $custom_fields_data); } if (!empty($data['lead_edit_data'])) { foreach (['policy_start_date', 'policy_end_date', 'source_policy_start_date', 'source_policy_end_date', 'incurred_claims_date', 'next_reminder_date'] as $dateField) { $data['lead_edit_data'][$dateField] = !empty($data['lead_edit_data'][$dateField]) ? change_date_format($data['lead_edit_data'][$dateField], 'Y-m-d', 'd/m/Y') : null; } $data['lead_edit_data']['fin_years_claims_array'] = !empty($data['lead_edit_data']['fin_years_claims']) ? json_decode($data['lead_edit_data']['fin_years_claims'], true)['finyear'] ?? [] : []; $data['lead_edit_data']['html'] = $this->generateViewPageHtml( $data['lead_edit_data']['policy_type_id'] ?? null, $data ) ?? ""; $html = view('rfq/multi_files', $data); $data['lead_edit_data']['multi_file_html'] = trim($html) !== '' ? $html : null; } if ($data['lead_edit_data']['lead_type'] != 1 && $data['lead_edit_data']['lead_form_type'] == 2) { $data['lead_edit_data']['claims_details_html'] = view('rfq/claims_details_non_eb', $data['lead_edit_data']); } else { $data['lead_edit_data']['claims_details_html'] = ""; } } // dd($data); return $this->loadLayout('leads_form_handler', $data); } public function getLeadEmailHistory($id){ if(!empty($id)){ $result = $this->gmailSentHistoryModel ->where('pk', $id) ->where('module',"leads") ->orderBy('created_at', 'desc') ->findAll(); if(!empty($result)){ $result = !empty($result) ? $result : []; return $this->response->setJSON((['status' => 'success', 'data' => $result]))->setStatusCode(200); }else{ return $this->response->setJSON((['status' => 'error', 'message' => 'No History found']))->setStatusCode(400); } }else{ return $this->response->setJSON((['status' => 'error', 'message' => 'ID not found']))->setStatusCode(404); } // Select * from gmail_sent_history where pk != "" and module = "leads"; // echo $id; } public function getPolicyTypeFields() { $policy_type_id = $this->request->getGET('policy_type_id'); $html = $this->generateViewPageHtml($policy_type_id) ?? ""; if (!empty($html)) { return $this->respond(['status' => true, 'code' => 200, 'message' => 'Policy Type FIELDS are found', 'data' => $html], 200); } else { return $this->respond(['status' => false, 'code' => 400, 'message' => 'Fields not found for this policy type'], 200); } } public function generateViewPageHtml($policy_type_id, $data = []) { $data['insurer'] = $this->insurerBranchModel->getInsurerBranchesWithInsurerNames(); $data['tpa'] = $this->tpaBranchModel->getTpaBranchesWithTpaNames(); $viewMap = [ 1 => 'rfq/gpa', 6 => 'rfq/gpa', 7 => 'rfq/gpa', 2 => 'rfq/gmc', 3 => 'rfq/gmc', 4 => 'rfq/gmc', 5 => 'rfq/gmc', 17 => 'rfq/burglary', 22 => 'rfq/car', 23 => 'rfq/cpm', 24 => 'rfq/cyber_crime', 25 => 'rfq/do', 27 => 'rfq/eo', 49 => 'rfq/money', 19 => 'rfq/cgl', 59 => 'rfq/sfsp', 63 => 'rfq/wc', 15 => 'rfq/blu', 16 => 'rfq/bsu', 44 => 'rfq/marine', 45 => 'rfq/marine', 46 => 'rfq/marine', 47 => 'rfq/marine', 50 => 'rfq/office' ]; return isset($viewMap[$policy_type_id]) ? view($viewMap[$policy_type_id], $data) : ""; } // ------------------- RFQ NON EB EXCEL EXPORT FUNCTION --------------------------------------------------------------------------------------- public function constructNonEbExcelToSaveTemp($lead_id, $type, $propsal_and_insurer = null) { $rfq_data = $this->RFQModel->getRFQTableDataWithLeadIDAndType($lead_id, $type); $claim_history = $rfq_data['claim_history']; // dd($claim_history); $lead_data = json_decode($rfq_data['custom_fields'], true) ?? []; $lead_data['claim_history'] = $claim_history; // dd($lead_data); if (!is_array($lead_data)) { $lead_data = []; } if (isset($lead_data['pincode']) && isset($lead_data['address'])) { // Reorder keys: address first, then pincode, then the rest $reordered = ['address' => $lead_data['address'], 'pincode' => $lead_data['pincode']]; // Remove existing keys unset($lead_data['address'], $lead_data['pincode']); // Merge reordered with the rest $lead_data = $reordered + $lead_data; } $lead_data = array_merge(['Insured' => $rfq_data['client_name']], $lead_data); $policy_registration_data = []; if (isset($rfq_data['registration_json']) && !empty($rfq_data['registration_json'])) { $policy_registration_data = json_decode($rfq_data['registration_json'], true); } $jsonData = json_decode($rfq_data['json'], true); $proposalData = end($jsonData); array_pop($jsonData); $length = 0; // dd($jsonData[0]['table_data']['headers']); foreach ($jsonData as $key => $data) { if ($type == 2) { $data = $this->convertNonEbJsonForQCR($data, $type, $proposalData, $key); // Kint::dump($data, 'Second'); if ($propsal_and_insurer !== null) { list($proposal_key, $insurer_key) = explode('-', $propsal_and_insurer, 2); $data = $this->transformNonEbProposelData($data, $proposal_key, $insurer_key, $key); } unset($data['proposalData']); } else if ($type == 1) { $data = $this->convertNonEbJsonForQCR($data, $type, $proposalData, $key); unset($data['proposalData']); } } // dd($data); foreach ($data['table_data']['headers'] as $header) { if ($header['parentHeader'] != "Action") { foreach ($header['subHeaders'] as $subHeader) { // Kint::dump($header['parentHeader']); // Kint::dump($subHeader); $length++; } } } // dd($length); $columnLetterForTitle = Coordinate::stringFromColumnIndex($length - 1); $columnLetterForImage = Coordinate::stringFromColumnIndex($length); // dd($columnLetter); $sheetName = 'Worksheet'; if ($type == 2) { $sheetName = 'QCR'; if ($propsal_and_insurer !== null) { $sheetName = 'Placement'; } } else if ($type == 1) { $sheetName = 'RFQ'; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle($sheetName); // Start with lead_data at the top $rowNumber = 1; $title = "Nhance India Insurance Broking Pvt Ltd"; $mergeRange1 = "A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"; $sheet->mergeCells($mergeRange1); $sheet->setCellValue("A{$rowNumber}", $title); $sheet->getStyle("A{$rowNumber}")->applyFromArray([ 'font' => [ 'bold' => true, 'size' => 20 ], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); // Calculate title width $maxWidthA = mb_strlen($title); // dd($columnLetterForImage); // Set column width to fit the image properly $sheet->getColumnDimension($columnLetterForImage)->setWidth(40); // Adjust as needed $sheet->getRowDimension($rowNumber)->setRowHeight(40); // Adjust as needed $drawing = new Drawing(); $path = ROOTPATH . "public/assets/images/Nhance-Logo-Final.png"; // Use FCPATH for server path $drawing->setPath($path); $drawing->setCoordinates("{$columnLetterForImage}{$rowNumber}"); // Set position in column C $drawing->setHeight(35); // Adjust image height // Apply center alignment to the cell $sheet->getStyle("{$columnLetterForImage}{$rowNumber}")->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); $sheet->getStyle("{$columnLetterForImage}{$rowNumber}")->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); $rowNumber++; // Initialize max width tracking variables $maxWidthB = 0; //Lead Data foreach ($lead_data as $key => $value) { // if ($key == 'risk_location') { // $key == 'risk_details'; // } // Kint::dump($key); // Kint::dump($value); $formattedKey = ucwords(str_replace('_', ' ', $key)); $formattedKey = $formattedKey == "Risk Location" ? "Risk Details" : $formattedKey; $formattedKey = $formattedKey == "Address" ? "Communication Address" : $formattedKey; $formattedValue = ucwords(str_replace("_", " ", $value)); if ($key == "claim_history") { $formattedValue = $value == "1" ? "Yes" : "No"; $formattedKey = "Claim Experience"; } // Kint::dump($formattedValue); // Merge A:B for key $mergeRangeKey = "A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"; $sheet->mergeCells($mergeRangeKey); // Set values in merged cells $sheet->setCellValue("A{$rowNumber}", $formattedKey); $sheet->setCellValue("{$columnLetterForImage}{$rowNumber}", $formattedValue); // Apply styles for alignment and bold text in A:B $sheet->getStyle($mergeRangeKey)->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); // Apply bold style to C column if the key is "Insured" // if ($key === "Insured") { // $sheet->getStyle("C{$rowNumber}")->applyFromArray([ // 'font' => ['bold' => true], // ]); // } // Track max width needed for columns $maxWidthA = max($maxWidthA, mb_strlen($formattedKey)); // Consider title and keys $maxWidthB = max($maxWidthB, mb_strlen((string) $value)); // if (!empty($policy_registration_data)) { // dd($policy_registration_data); // } $rowNumber++; } // die(); // Set column width based on max content length (adjusted for padding) $sheet->getColumnDimension('A')->setWidth($maxWidthA * 1.2); // $sheet->getColumnDimension('B')->setWidth($maxWidthA * 1.2); // $sheet->getColumnDimension('C')->setWidth($maxWidthB * 1.2); // $rowNumber += 1; //Policy Registration if (!empty($policy_registration_data)) { foreach ($policy_registration_data as $key => $value) { // kint::dump($value); $startRow = $rowNumber; // Track where the block starts // Title Row $titleMergeRangeKey = "A{$rowNumber}:{$columnLetterForImage}{$rowNumber}"; $sheet->mergeCells($titleMergeRangeKey); $sheet->setCellValue("A{$rowNumber}", ucfirst($key) . " Policy Details"); // Title Style $sheet->getStyle($titleMergeRangeKey)->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], 'fill' => [ 'fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'ADD8E6'], ], ]); $rowNumber++; // Move to next row // Policy Type if (isset($value['policyType'])) { $sheet->mergeCells("A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"); $sheet->setCellValue("A{$rowNumber}", "Policy Type"); $sheet->setCellValue("{$columnLetterForImage}{$rowNumber}", $value['policyType']); $sheet->getStyle("A{$rowNumber}:C{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); $rowNumber++; } else { $sheet->mergeCells("A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"); $sheet->setCellValue("A{$rowNumber}", "Policy Type"); $sheet->setCellValue("{$columnLetterForImage}{$rowNumber}", ucfirst($key) . " Policy"); $sheet->getStyle("A{$rowNumber}:C{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); $rowNumber++; } // Type of Business & Nature of Business if (isset($value['productSelection']) && !empty($value['productSelection'])) { // Type of Business $sheet->mergeCells("A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"); $sheet->setCellValue("A{$rowNumber}", "Type of Business"); $sheet->setCellValue("{$columnLetterForImage}{$rowNumber}", $this->buisnessType[$value['productSelection']['type_of_buisness']] ?? ''); $sheet->getStyle("A{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); $rowNumber++; // Nature of Business $sheet->mergeCells("A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"); $sheet->setCellValue("A{$rowNumber}", "Nature of Business"); $sheet->setCellValue("{$columnLetterForImage}{$rowNumber}", $value['productSelection']['buisness_nature'] ?? ''); $sheet->getStyle("A{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); $rowNumber++; } if (isset($value['policyDetails']) && !empty($value['policyDetails'])) { // Type of Business $sheet->mergeCells("A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"); $sheet->setCellValue("A{$rowNumber}", "Terrorism"); $sheet->setCellValue("{$columnLetterForImage}{$rowNumber}", ucfirst($value['policyDetails']['terrorism'] ?? 'No')); $sheet->getStyle("A{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); $rowNumber++; } if (!empty($value['locations'])) { foreach ($value['locations'] as $index => $location) { // Merge title cell $sheet->mergeCells("A{$rowNumber}:{$columnLetterForTitle}{$rowNumber}"); $sheet->setCellValue("A{$rowNumber}", "Risk " . ($location['select_location'] ?? 'Unknown')); // Clean and safe address string $address1 = ucfirst($location['policyRisk']['address1'] ?? ''); $address2 = ucfirst($location['policyRisk']['address2'] ?? ''); $pinCode = $location['policyRisk']['pin_code'] ?? 'No'; $fullAddress = "{$address1}, {$address2}, {$pinCode}"; $sheet->setCellValue("{$columnLetterForImage}{$rowNumber}", $fullAddress); // Style the title cell $sheet->getStyle("A{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); $rowNumber++; } } $endRow = $rowNumber; // Block ends at previous row // Apply border to the whole block $sheet->getStyle("A{$startRow}:{$columnLetterForImage}{$endRow}")->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => '000000'], ], ], ]); // $rowNumber += 1; // Add space before the next block } $rowNumber--; // die(); } //Table Data foreach ($jsonData as $key => $data) { // Kint::dump($data, 'First'); if ($type == 2) { $data = $this->convertNonEbJsonForQCR($data, $type, $proposalData, $key); // Kint::dump($data, 'Second'); if ($propsal_and_insurer !== null) { list($proposal_key, $insurer_key) = explode('-', $propsal_and_insurer, 2); $data = $this->transformNonEbProposelData($data, $proposal_key, $insurer_key, $key); } unset($data['proposalData']); } else if ($type == 1) { $data = $this->convertNonEbJsonForQCR($data, $type, $proposalData, $key); unset($data['proposalData']); } // dd($data); // Add headers and subheaders $headers = $data['table_data']['headers']; // dd($headers); $rowNumber = $rowNumber + 1; $subHeaderRow = $rowNumber + 1; $columnLetter = 'A'; foreach ($headers as $header) { if (in_array($header['parentHeader'], ['Action'])) { continue; } $sheet->getColumnDimension($columnLetter)->setWidth(60); $sheet->getColumnDimension('C')->setWidth(35); if ($header['parentHeader'] == 'Policy') { // $header['parentHeader'] = 'S.No.'; $sheet->getColumnDimension('A')->setWidth(10); } if ($header['parentHeader'] === 'Particulars') { $sheet->getColumnDimension('B')->setWidth(60); } if (strpos($header['parentHeader'], 'Proposal') === 0) { $sheet->getColumnDimension('C')->setWidth(60); $sheet->getColumnDimension('D')->setWidth(35); } $startColumn = $columnLetter; // Start of the current header range $subHeaderCount = count($header['subHeaders']); // Number of subheaders for this parent header // Kint::dump($subHeaderCount); // Set parent header value $sheet->setCellValue("{$startColumn}{$rowNumber}", $header['parentHeader']); $sheet->getStyle("{$startColumn}{$rowNumber}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], 'fill' => [ 'fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'ADD8E6'], ], ]); // Merge header cells if it spans multiple subheaders if ($subHeaderCount > 1) { $endColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($startColumn) + $subHeaderCount - 1); $sheet->mergeCells("{$startColumn}{$rowNumber}:{$endColumn}{$rowNumber}"); } else { $endColumn = $startColumn; // No merge needed if only one subheader } // Kint::dump($header); // Add subheaders foreach ($header['subHeaders'] as $subHeader) { $sheet->setCellValue("{$columnLetter}{$subHeaderRow}", $subHeader); if ($columnLetter != "A" && $columnLetter != "B" && $columnLetter != "C" && $columnLetter != "D") { $sheet->getColumnDimension($columnLetter)->setWidth(35); } else { $sheet->getColumnDimension('A')->setWidth(10); } $sheet->getStyle("{$columnLetter}{$subHeaderRow}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); $columnLetter++; // Move to the next column for subheaders } } // For the subheader row, merge B and C and set the value $sheet->setCellValue("B{$subHeaderRow}", "Sum Insured"); $sheet->mergeCells("B{$subHeaderRow}:C{$subHeaderRow}"); $sheet->getStyle("B{$subHeaderRow}:C{$subHeaderRow}")->applyFromArray([ 'font' => ['bold' => true], 'alignment' => [ 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); // Apply border to the header range $prevColumn4 = $this->getPreviousColumn($columnLetter); $headerRange = "A{$rowNumber}:" . "{$prevColumn4}" . "{$subHeaderRow}"; $sheet->getStyle($headerRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); // Increase row height for headers and subheaders $sheet->getRowDimension($rowNumber)->setRowHeight(25); // Header row height $sheet->getRowDimension($subHeaderRow)->setRowHeight(20); // Subheader row height // $rowNumber = $subHeaderRow + 2; $rowNumber = $subHeaderRow + 1; $column_data = $data['table_data']['data']; // dd($column_data); $serial_no = 1; $maxColumnWidths = []; $RowSpanEnable = false; // Add table data rows foreach ($column_data as $dataRow) { $columnLetter = 'A'; $hasPolicy = in_array('Policy', array_column($dataRow['data'], 'parentth')); // Kint::dump($hasPolicy); foreach ($dataRow['data'] as $cellData) { if (in_array($cellData['parentth'], ['Action'])) { continue; } if ($cellData['parentth'] == 'SNO') { $sheet->setCellValue("{$columnLetter}{$rowNumber}", $serial_no); } else if ($cellData['parentth'] == 'Policy') { $mergeStart = $rowNumber; // Start row for merging $mergeEnd = $rowNumber + ($cellData['rowspan'] - 1); // End row for merging $sheet->setCellValue("{$columnLetter}{$mergeStart}", $dataRow['SNO']); $sheet->mergeCells("{$columnLetter}{$mergeStart}:{$columnLetter}{$mergeEnd}"); $sheet->getStyle("{$columnLetter}{$mergeStart}:{$columnLetter}{$mergeEnd}") ->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); } else { if (!$hasPolicy && $key == 0) { $RowSpanEnable = true; $columnLetter++; $sheet->setCellValue("{$columnLetter}{$rowNumber}", $cellData['display_content']); } else { $sheet->setCellValue("{$columnLetter}{$rowNumber}", $cellData['display_content']); } } if (!($key === 0 && !$hasPolicy)) { $columnLetter++; } } $rowNumber++; $serial_no++; } if ($key == 0 && $RowSpanEnable == true) { $columnLetter++; } // dd($columnLetter); $prevColumn5 = $this->getPreviousColumn($columnLetter); $dataRange = "A" . ($subHeaderRow + 1) . ":" . "{$prevColumn5}" . ($rowNumber - 1); $sheet->getStyle($dataRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); // Auto-size columns // foreach ($sheet->getColumnIterator() as $column) { // $sheet->getColumnDimension($column->getColumnIndex())->setAutoSize(true); // } $dataRange = $sheet->calculateWorksheetDimension(); $sheet->getStyle($dataRange)->getAlignment() ->setHorizontal(Alignment::HORIZONTAL_CENTER) ->setVertical(Alignment::VERTICAL_CENTER) ->setWrapText(true); $sheet->getStyle('A1')->applyFromArray([ 'alignment' => [ 'wrapText' => false, // Disables text wrapping for A1 ], ]); // Apply border to the entire sheet preg_match('/([A-Z]+)(\d+):([A-Z]+)(\d+)/', $dataRange, $matches); if ($matches) { $startColumn = $matches[1]; // A $startRow = $matches[2]; // 1 $endColumn = $matches[3]; // G $endRow = $matches[4]; // 75 // Convert column letter to index, reduce by 1, and convert back $endColumnIndex = Coordinate::columnIndexFromString($endColumn) - 1; $newEndColumn = Coordinate::stringFromColumnIndex($endColumnIndex); // Generate the new range (e.g., "A1:F75" instead of "A1:G75") $newDataRange = "{$startColumn}{$startRow}:{$newEndColumn}{$endRow}"; // $sheet->getStyle($newDataRange)->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN); } $lastRow = count($lead_data) + 1; $leadRange = "A1:{$columnLetterForImage}{$lastRow}"; $sheet->getStyle($leadRange)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['argb' => 'FF000000'], // Black color ], ], ]); } $columnWidth = $sheet->getColumnDimension("C")->getWidth(); // e.g., 20 $cellPixelWidth = $columnWidth * 7; // Approximate conversion (1 unit ≈ 7 pixels) $imagePixelWidth = 250; // Approximate width of your image (in pixels) $offsetX = max(0, ($cellPixelWidth - $imagePixelWidth) / 2); $offsetX = $offsetX + 97; if ($length >= 4) { $offsetX = 35; } else if ($length == 3) { $offsetX = 140; } // dd($offsetX, $cellPixelWidth, $imagePixelWidth); $drawing->setOffsetX($offsetX); // Dynamically center $drawing->setOffsetY(10); // Dynamically center $drawing->setWorksheet($sheet); $sheet->getStyle('C1')->getAlignment() ->setHorizontal(Alignment::HORIZONTAL_CENTER) ->setVertical(Alignment::VERTICAL_CENTER); if (!empty($rfq_data['fin_years_claims']) && $claim_history == 1) { $claim_details = json_decode($rfq_data['fin_years_claims'], true) ?? []; if (!empty($claim_details['finyear'])) { // Get headers dynamically $headers = array_map(function ($key) { return ucwords(str_replace('_', ' ', $key)); }, array_keys($claim_details['finyear'][0])); $newSheet = new Worksheet($spreadsheet, 'Claims Experience'); $spreadsheet->addSheet($newSheet); $spreadsheet->setActiveSheetIndexByName('Claims Experience'); $sheet = $spreadsheet->getActiveSheet(); // Set headers $sheet->fromArray($headers, NULL, 'A1'); // Apply background color and bold style to headers $headerCellRange = 'A1:' . chr(64 + count($headers)) . '1'; // e.g., A1:G1 $sheet->getStyle($headerCellRange)->getFont()->setBold(true); $sheet->getStyle($headerCellRange)->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB('ADD8E6'); // Add border to header $sheet->getStyle($headerCellRange)->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN); // Fill data and apply borders $row = 2; foreach ($claim_details['finyear'] as $record) { $col = 'A'; foreach ($record as $value) { $sheet->setCellValue($col . $row, $value); $col++; } // Apply border to each data row $sheet->getStyle('A' . $row . ':' . chr(64 + count($headers)) . $row) ->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN); $row++; } // Auto-size all columns based on header count for ($i = 0; $i < count($headers); $i++) { $colLetter = chr(65 + $i); // 'A', 'B', etc. $sheet->getColumnDimension($colLetter)->setAutoSize(true); } // Enable wrap text for all cells $maxColLetter = chr(64 + count($headers)); // Last column letter $sheet->getStyle("A2:{$maxColLetter}{$row}")->getAlignment()->setWrapText(true); // Optional: center vertically for neatness $sheet->getStyle("A2:{$maxColLetter}{$row}")->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); // Optional: Make row height auto (helps when wrap text is on) for ($i = 2; $i < $row; $i++) { $sheet->getRowDimension($i)->setRowHeight(-1); } } } // dd($rowNumber); // Set filename $string = ($type == 2) ? 'QCR' : 'RFQ'; $filename = "{$string}_{$rfq_data['client_short_name']}_{$rfq_data['policy_type']}_" . date('YmdHis') . '.xlsx'; // Save to temporary location $uploadFilePath = WRITEPATH . 'tmp/' . $filename; $writer = new Xlsx($spreadsheet); $writer->save($uploadFilePath); return [ 'filePath' => $uploadFilePath, 'fileName' => $filename, ]; } public function convertNonEbJsonForQCR($jsonArr, $type, $proposeldata, $indexOfTheTable) { $first_json = $jsonArr; $first_json = array_merge($first_json, $proposeldata); if ($type == 2) { // Column-wise Check: Remove headers and relevant data if qcr == 0 foreach ($first_json['proposal_data']['over_all_column_data'] as $proposalKey => $proposalData) { if ((isset($proposalData['qcr']) && isset($proposalData['stc'])) && ($proposalData['qcr'] == 0 || $proposalData['qcr'] === false) || ($proposalData['stc'] == 0 || $proposalData['stc'] === false)) { // Remove matching parentHeader in headers foreach ($first_json['table_data']['headers'] as $index => $header) { if ($header['parentHeader'] === $proposalKey) { unset($first_json['table_data']['headers'][$index]); } } // Remove data entries with matching parentth foreach ($first_json['table_data']['data'] as &$item) { $item['data'] = array_values(array_filter($item['data'], function ($entry) use ($proposalKey) { return $entry['parentth'] !== $proposalKey; })); } // Remove proposalKey from over_all_column_data unset($first_json['proposal_data']['over_all_column_data'][$proposalKey]); if ($type == 2) { // Remove proposalKey from premium_data unset($first_json['premium_data']['data'][$proposalKey]); } } // Insurer Check: Remove subHeaders and relevant data for insurers with qcr == 0 foreach ($proposalData['insurers'] as $insurerIndex => $insurer) { $qcr = $insurer['qcr'] ?? null; $stc = $insurer['stc'] ?? null; if (($qcr === 0 || $qcr === false) || ($stc === 0 || $stc === false)) { foreach ($first_json['table_data']['headers'] as &$header) { if (isset($header['subHeaders'])) { $header['subHeaders'] = array_values(array_filter($header['subHeaders'], function ($sub) use ($insurer) { return $sub !== $insurer['display_name']; })); } } foreach ($first_json['table_data']['data'] as &$item) { $item['data'] = array_values(array_filter($item['data'], function ($entry) use ($insurer) { return $entry['subth'] !== $insurer['display_name']; })); } // Remove insurer from proposal's insurers array unset($first_json['proposal_data']['over_all_column_data'][$proposalKey]['insurers'][$insurerIndex]); if ($type == 2) { unset($first_json['premium_data']['data'][$proposalKey][$insurer['display_name']]); } } } } // Row-wise Check: Remove rows if qcr == 0 for actions $groupedRows = []; foreach ($first_json['table_data']['data'] as $rowKey => $rowData) { $groupedRows[$rowData['row_id']][] = $rowData; foreach ($rowData['data'] as $keyIndex => $data) { if ($indexOfTheTable == 0) { if ($data['parentth'] == "Policy" && $data['input_value'] != "Checked") { unset($first_json['table_data']['data'][$rowKey]); break; } } else { if ( isset($data['parentth'], $data['input_value']['qcr'], $data['input_value']['stc']) && $data['parentth'] === "Action" && ($data['input_value']['qcr'] == 0 || $data['input_value']['stc'] == 0) ) { unset($first_json['table_data']['data'][$rowKey]); break; } } } } $finalRows = []; if (!empty($groupedRows)) { // Loop through each row_id group and check for Policy status foreach ($groupedRows as $rowId => $rows) { $hasPolicy = false; $isChecked = false; foreach ($rows as $row) { foreach ($row['data'] as $cell) { if ($cell['parentth'] === 'Policy') { $hasPolicy = true; if (trim(strtolower($cell['input_value'])) === 'checked') { $isChecked = true; } break 2; // Found Policy, no need to continue further } } } // Step 3: If parent Policy is "Checked", retain the entire group if (!$hasPolicy || $isChecked) { foreach ($rows as $r) { $finalRows[] = $r; } } } if (!empty($finalRows)) { // Update the original data $first_json['table_data']['data'] = array_values($finalRows); } } // Reindex arrays to maintain proper structure $first_json['table_data']['headers'] = array_values($first_json['table_data']['headers']); $first_json['table_data']['data'] = array_values($first_json['table_data']['data']); $first_json['proposal_data']['over_all_column_data'] = array_map(function ($proposal) { $proposal['insurers'] = array_values($proposal['insurers']); return $proposal; }, $first_json['proposal_data']['over_all_column_data']); } else { //remove insurer as Subheaders for RFQ foreach ($first_json['table_data']['headers'] as &$header) { // Ensure 'subHeaders' exists and is an array before filtering if (isset($header['subHeaders']) && is_array($header['subHeaders'])) { $header['subHeaders'] = array_filter($header['subHeaders'], function ($subHeader) { return in_array($subHeader, ['Sum Insured', '-'], true); }); } } // Kint::dump($header); //Remove insurer Row wise data for RFQ $groupedRows = []; foreach ($first_json['table_data']['data'] as &$row) { // Filter the inner data array $row['data'] = array_filter( $row['data'], function ($item) { return in_array($item['subth'], ['Sum Insured', '-', "Liability Limit"]); } ); $row['data'] = array_values($row['data']); $groupedRows[$row['row_id']][] = $row; } // Ensure to unset the reference after the loop unset($row); $finalRows = []; if (!empty($groupedRows)) { // Loop through each row_id group and check for Policy status foreach ($groupedRows as $rowId => $rows) { $hasPolicy = false; $isChecked = false; foreach ($rows as $row) { foreach ($row['data'] as $cell) { if ($cell['parentth'] === 'Policy') { $hasPolicy = true; if (trim(strtolower($cell['input_value'])) === 'checked') { $isChecked = true; } break 2; // Found Policy, no need to continue further } } } // Step 3: If parent Policy is "Checked", retain the entire group if (!$hasPolicy || $isChecked) { foreach ($rows as $r) { $finalRows[] = $r; } } } if (!empty($finalRows)) { // Update the original data $first_json['table_data']['data'] = array_values($finalRows); } } // Remove insurers from Proposal Data key for RFQ foreach ($proposeldata['proposal_data']['over_all_column_data'] as $key => &$proposal) { if (isset($proposal['insurers'])) { // Set the insurers array to empty $proposal['insurers'] = []; } } // Ensure to reset the reference unset($proposal); } return $first_json; return null; } public function transformNonEbProposelData(&$data, $proposal, $insurer, $tableCount = null, $actionColumn = null) { // Kint::dump($data, $proposal, $insurer, $tableCount); // Initialize headers with defaults $headerData = []; // Add the first two default headers only once $headerData[] = [ 'parentHeader' => $data['table_data']['headers'][0]['parentHeader'], 'subHeaders' => ['-'] ]; $headerData[] = [ 'parentHeader' => $data['table_data']['headers'][1]['parentHeader'], 'subHeaders' => ['-'] ]; $second_table_name = $data['table_data']['headers'][1]['parentHeader'] ?? ""; // Loop through the headers to find matching proposal and insurer foreach ($data['table_data']['headers'] as $header) { if ($header['parentHeader'] === $proposal) { foreach ($header['subHeaders'] as $subHeader) { if ($subHeader === $insurer) { $headerData[] = [ 'parentHeader' => $header['parentHeader'], 'subHeaders' => ['Sum Insured', $subHeader] ]; break 2; // Exit both loops after match is found } } } } // Update the original data's headers $data['table_data']['headers'] = $headerData; if (!empty($actionColumn)) { $data['table_data']['headers'][] = [ 'parentHeader' => "Action", 'subHeaders' => ['-'] ]; } foreach ($data['table_data']['data'] as &$entry) { $sno = $entry['SNO']; $items = $entry['items']; $row_id = $entry['row_id']; $filteredData = []; foreach ($entry['data'] as $item) { // Always include SNO and Particulars if (in_array($item['parentth'], ['S.NO', "Policy", "", 'Particulars', $second_table_name])) { $filteredData[] = $item; } // Include Proposal with Sum Insured if ($item['parentth'] === $proposal && ($item['subth'] === "Sum Insured" || $item['subth'] === "Liability Limit")) { $filteredData[] = $item; } // Include specific proposal and insurer if ($item['parentth'] === $proposal && $item['subth'] === $insurer) { $filteredData[] = $item; } if (!empty($actionColumn)) { if ($item['parentth'] === "Action") { $filteredData[] = $item; } } } // Update the entry with filtered data $entry['SNO'] = $sno; $entry['items'] = $items; $entry['row_id'] = $row_id; $entry['data'] = $filteredData; } unset($entry); // kint::dump($data); return $data; } public function getPreviousColumn($columnLetter, $decrement = 1) { $colIndex = Coordinate::columnIndexFromString($columnLetter); $colIndex = max(1, $colIndex - $decrement); // ensure column index doesn't go below 1 return Coordinate::stringFromColumnIndex($colIndex); } public function handleMultiFileAttachments($json_string, $lead_id) { log_message('error', 'handleMultiFileAttachments called with lead_id: ' . $lead_id); $attachments = []; if (!empty($json_string)) { log_message('error', 'json_string is not empty'); $fileIds = json_decode($json_string, true); log_message('error', 'Decoded fileIds: ' . print_r($fileIds, true)); $lead_file_path = WRITEPATH . 'uploads/lead_files/'; log_message('error', 'Lead file path: ' . $lead_file_path); foreach ($fileIds as $id) { log_message('error', 'Processing file ID: ' . $id); $lead_file = $this->leadFilesModel ->where('lead_id', $lead_id) ->where('id', $id) ->where('type !=', 2) ->where('is_active', 1) ->first(); if ($lead_file) { log_message('error', 'Found lead file: ' . print_r($lead_file, true)); $fullPath = $lead_file_path . $lead_file['file_name']; log_message('error', 'Full file path: ' . $fullPath); if (file_exists($fullPath)) { log_message('error', 'File exists at path: ' . $fullPath); if (!empty($lead_file['file_name'])) { log_message('error', 'File name is not empty: ' . $lead_file['file_name']); $attachments[] = [ 'fileName' => $lead_file['file_name'], 'filePath' => $fullPath ]; } else { log_message('error', 'File name is empty for ID: ' . $id); } } else { log_message('error', 'File does not exist at path: ' . $fullPath); } } else { log_message('warning', 'No active lead file found for ID: ' . $id . ' and lead_id: ' . $lead_id); } } } else { log_message('error', 'json_string is empty'); } log_message('error', 'Attachments prepared: ' . print_r($attachments, true)); return $attachments; } public function handleMemberDataGPATotalSumInsurerFromExcel($params) { $lead_id = $params['lead_id']; $lead_data = $this->leadsModel->find((int)$lead_id); // dd($lead_data); $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; // dd($file_name_with_path); if (!$lead_data) { return ['status' => 'failed', 'message' => 'Lead data not found']; } if ($lead_data['file_name']) { //check physical file if (!file_exists($file_name_with_path)) { $message = "Lead Physcial file not found"; $this->myLogger->logme('error', ($message . ' for file ' . $file_name_with_path)); return ['status' => 'failed', 'message' => 'no physical file']; } $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); //get members data $members_sheet = $spreadsheet->getSheet(0); $highestRowAndColumn = $members_sheet->getHighestRowAndColumn(); // dd($highestRowAndColumn); $uncleaned_members = $members_sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); // dd($uncleaned_members); $members = ExcelSanitizeHelper::sanitizeArrayData($uncleaned_members); // dd($members); // Check column headings $members_heading = $members[0]; $available_col = []; $lower_headers = array_map('strtolower', $members_heading); foreach ($lower_headers as $index => $header) { if (preg_match('/^(sa\s*-\s*option|proposed\s+sum\s+insured)\s+\d+$/i', $header)) { $column_name = $members_heading[$index]; $sum = 0; for ($i = 1; $i < count($members); $i++) { $cell_raw = $members[$i][$index] ?? ''; $cell_clean = preg_replace('/[^0-9.\-]/', '', $cell_raw); // remove non-numeric chars if ($cell_clean !== '' && is_numeric($cell_clean)) { $sum += (float) $cell_clean; } } $available_col[] = $sum; } } // dd($available_col); return $available_col; } return []; } public function generateDemographyDataTable($param) { $returnData = $this->calculateMembersDemography($param, "internal"); $html = ""; if (isset($returnData['data'])) { $data = $returnData['data']; foreach ($data as $category => $records) { // Extract all column headers (age groups) dynamically $allColumns = []; foreach ($records as $person => $ages) { $allColumns = array_merge($allColumns, array_keys($ages)); } $allColumns = array_unique($allColumns); $allColumns = array_values($allColumns); // reset index $category = ucfirst($category); // Start table with clean styling $html .= "

{$category}

"; $html .= ""; // Table header with light background $html .= ""; $html .= ""; foreach ($allColumns as $col) { $html .= ""; } $html .= ""; // Table rows with clean styling foreach ($records as $relation => $ages) { $html .= ""; $html .= ""; foreach ($allColumns as $col) { $value = isset($ages[$col]) ? $ages[$col] : "-"; $html .= ""; } $html .= ""; } $html .= "
Relation{$col}
{$relation}{$value}
"; } } return $html; } // function for insurer remainder mail cron job public function remainderForQcr() { $lead_data = $this->leadsModel ->select( 'leads.*, user_profiles.email as created_person_email, policy_type.policy_type, policy_type.long_name ') ->join('policy_type', 'leads.policy_type_id = policy_type.id') ->join('user_profiles', 'leads.created_by = user_profiles.id', 'left') ->where('leads.is_active', 1) ->where('user_profiles.is_active', 1) ->whereIn('leads.status', ['rfq_sent', 'qcr_created']) ->where('leads.next_reminder_date', date('Y-m-d')) ->findAll(); // dd($lead_data); if (count($lead_data) == 0) { $this->myLogger->logme("info", "No leads found for reminder mail at " . date('Y-m-d H:i:s')); print_r(["status" => true, "message" => "There is no data to send reminder mail"]); return ["status" => true, "message" => "There is no data to send reminder mail"]; } $from_mail = "im@nhanceindia.in"; $subject = "Reminder for RFQ"; $content_string = '

Dear Sir,

Greetings from Nhance India!

This is a gentle reminder regarding our earlier mail about the RFQ for the {{POLICY_TYPE}} policy pertaining to {{CLIENT_NAME}}.

We kindly request you to share the competitive quotes at the earliest possible convenience.

In case of any clarification, please feel free to contact us.

Thank you for your prompt attention to this matter.


Best regards,

Nhance India

'; $reminder_sended_lead = []; foreach ($lead_data as $lead) { $leadId = $lead['id']; $reply_to = $lead['created_person_email'] ?? ""; if (isset($lead['policy_end_date']) && $lead['policy_end_date'] != null) { $subject = "{{CLIENT_NAME}} _ {{POLICY_TYPE}} _ {{RFQ_OR_QCR}} _ {{POLICY_YEAR}} {{POLICY_END_DATE}}"; } else { $subject = "{{CLIENT_NAME}} _ {{POLICY_TYPE}} _ {{RFQ_OR_QCR}} _ {{POLICY_YEAR}}"; } $mail_content = $this->transformMailContent($lead, $content_string, "RFQ"); $mail_subject = $this->transformMailContent($lead, $subject, "RFQ"); $this->myLogger->logme("info", "Processing lead_id={$leadId} for reminder mails"); // get sales person + created_by emails $sales_person_emails = $this->userModel ->select('email') ->where('is_active', 1) ->whereIn('id', json_decode($lead['salse_person_id'] ?? "[]", true)) ->findAll(); $email_list = array_column($sales_person_emails, 'email'); if (!empty($reply_to)) { $email_list[] = $reply_to; } $email_list = array_filter(array_unique($email_list)); $email_string = implode(',', $email_list); // Get latest sent mail timestamp $createdAtRow = $this->gmailSentHistoryModel ->select("DATE_FORMAT(created_at, '%Y-%m-%d %H:%i') as created_at", false) ->where('isactive', 1) ->where('mail_type', 'insurer') ->where('pk', $leadId) ->orderBy('id', 'desc') ->first(); // dd(db_connect()->getLastQuery(), $createdAtRow); if (!$createdAtRow) { $this->myLogger->logme("warning", "No sent history found for lead_id={$leadId}, skipping..."); continue; } $createdAt = $createdAtRow['created_at']; // Fetch mail data for that timestamp $mail_datas = $this->gmailSentHistoryModel ->where('isactive', 1) ->where('mail_type', "insurer") ->where('pk', $leadId) ->where("DATE_FORMAT(created_at, '%Y-%m-%d %H:%i')", $createdAt) ->findAll(); if (empty($mail_datas)) { $this->myLogger->logme("warning", "No mail data found for lead_id={$leadId} at created_at={$createdAt}"); continue; } // Filter only pending insurers $quote_received_insurer = json_decode($lead['quote_received_insurer'] ?? "[]", true); $reminder_mail_data = []; if (empty($quote_received_insurer)) { $reminder_mail_data = $mail_datas; } else { foreach ($mail_datas as $mail_value) { $insurer_id = $mail_value['common'] ?? ""; if (!in_array($insurer_id, $quote_received_insurer)) { $reminder_mail_data[] = $mail_value; } } } // dd($reminder_mail_data); if (empty($reminder_mail_data)) { $this->myLogger->logme("info", "All insurers already responded for lead_id={$leadId}, no reminder needed"); continue; } $this->myLogger->logme("info", "Sending " . count($reminder_mail_data) . " reminder mail(s) for lead_id={$leadId}"); $common = ['module' => "leads", 'pk' => $leadId, 'mail_type' => "remainder", 'common' => null]; foreach ($reminder_mail_data as $content) { $insurerId = $content['common'] ?? null; $common['common'] = $insurerId; try { if ($lead['is_insurer_auto_mail'] == 1) { // send reminder to insurer $res = MailHelper::send_email([ 'from_mail' => $from_mail, 'mail' => $content['mail'] ?? "", 'cc' => json_decode($content['cc'] ?? "", true) ?? "", 'subject' => $mail_subject ?? "", 'message' => $mail_content ?? "", 'reply_to' => $reply_to, 'bcc' => json_decode($content["bcc"] ?? "", true) ?? "", 'common' => $common ]); $this->myLogger->logme("info", "Reminder mail sent to the insurer | lead_id={$leadId}, insurer_id={$insurerId}, response=" . json_encode($res)); $reminder_sended_lead[] = [ 'lead_id' => $leadId, 'insurer_id' => $insurerId, 'response' => $res ]; } else{ $this->myLogger->logme("info", "Reminder mail disable for this lead_id={$leadId}"); } } catch (\Throwable $e) { $errorDetails = [ 'error_message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'stack_trace' => $e->getTraceAsString(), ]; $this->myLogger->logme("error", "Exception while sending reminder | lead_id={$leadId}, insurer_id={$insurerId}, error=" . json_encode($errorDetails)); $reminder_sended_lead[] = [ 'lead_id' => $leadId, 'insurer_id' => $insurerId, 'response' => ['status' => false, 'error' => $errorDetails] ]; } // send reminder to sales person / creator only $internal_mail_response = MailHelper::send_email([ 'mail' => $from_mail, 'cc' => $email_string, 'subject' => $mail_subject ?? "", 'message' => $mail_content ?? "", 'common' => $common ]); $this->myLogger->logme("info", "Reminder mail sent to sales persons | lead_id={$leadId}, recipients={$email_string}, response=" . json_encode($internal_mail_response)); } } return ['status' => true, "data" => $reminder_sended_lead]; } public function uploadMultiFileFromRfq() { try { $this->myLogger->logme('error', "uploadMultiFileFromRfq START"); $this->myLogger->logme('error', "Files received: " . json_encode($this->request->getPost() ?? [])); $lead_id = $this->request->getPost('lead_id'); $lead_form_type = $this->request->getPost('lead_form_type'); $leads_file_primary_key = $this->request->getPost('leads_file_id') ?? []; $docs_name = $this->request->getPost('docs_name') ?? []; $files = $this->request->getFileMultiple('file_name'); if (empty($files) || empty($docs_name)) { $this->myLogger->logme('error', "No files or document names provided"); return $this->respond([ 'status' => false, 'code' => 400, 'message' => 'No files or document names provided' ], 400); } // Upload process $multi_file_data = $this->uploadMultiFiles($files, $docs_name, $leads_file_primary_key) ?? []; $this->myLogger->logme('error', "uploadMultiFiles result: " . json_encode($multi_file_data ?? [])); if (!empty($multi_file_data)) { $this->insertMultiFilesData($multi_file_data, $lead_id, $lead_form_type); $this->myLogger->logme('error', "Files inserted successfully into DB"); // update lead file name if change if(isset($multi_file_data[0]['file_name']) && !empty($multi_file_data[0]['file_name'])){ $this->leadsModel->where('id', $lead_id)->set('file_name', $multi_file_data[0]['file_name'])->update(); } } else { $this->myLogger->logme('error', "uploadMultiFiles returned empty"); } // Get the updated lead file data $lead_file_data = $this->leadFilesModel ->where('is_active', 1) ->where('type !=', 2) ->where('lead_id', $lead_id) ->findAll(); $this->myLogger->logme('error', "Fetched " . count($lead_file_data) . " lead file records"); $document_data = $this->renderFileFields($lead_file_data); $attch_data['multi_file_data'] = $lead_file_data; $attachment_html = view('rfq/attachment_files', $attch_data) ?? ""; $this->myLogger->logme('error', "uploadMultiFileFromRfq END"); return $this->respond([ 'status' => true, 'code' => 200, 'message' => "File uploaded Successfully", 'document_data' => $document_data, 'attachment_html' => $attachment_html, ], 200); } catch (\Throwable $e) { $errorDetails = [ 'error_message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'stack_trace' => $e->getTraceAsString(), ]; // Catch any error/exception and log with trace $this->myLogger->logme('error', "Exception in uploadMultiFileFromRfq: " . json_encode($errorDetails)); return $this->respond([ 'status' => false, 'code' => 500, 'message' => "File upload failed: " . $e->getMessage(), 'errorDetails' => $errorDetails, ], 500); } } public function renderFileFields($multi_file_data = []) { $uploadFilePath = WRITEPATH . 'uploads/lead_files/'; $html = ''; // If data exists (edit mode) if (!empty($multi_file_data)) { foreach ($multi_file_data as $index => $value) { $sample_dwn_link = ' [ Download ]'; $isFirstField = ($index === 0); $placeholder = $isFirstField ? 'First file must be Demography.' : ''; $first_file_name = $isFirstField ? 'Member List' : ''; $member_data_link = $isFirstField ? $sample_dwn_link : ''; $read_only = $isFirstField ? 'readonly' : ''; $accept = $isFirstField ? '.xls,.xlsx' : ''; $displayIndex = $index + 1; $html .= '
'; } } else { // Default (add mode) $html .= '
'; } return $html; } public function downloadMemberFile($fileName) { $filePath = WRITEPATH . 'uploads/lead_files/' . $fileName; if (!file_exists($filePath)) { $data['message'] = 'The Physical File Not Found'; echo view('errors/404', $data); } // force download return $this->response->download($filePath, null); } // ----------- MEMBER DATA VALIDAATION ------------------------------------------------------------------------------------------------------ public function memberDataListValidation() { $lead_id = $this->request->getPost('lead_id'); $this->memberDataListExcelFileFormatValidation(['lead_id' => $lead_id]); } public function memberDataListExcelFileFormatValidation($params) { helper('excel_util_helper'); $this->myLogger->logme('error', 'Start memberDataListExcelFileFormatValidation'); $this->myLogger->logme('error', "Received params: " . json_encode($params)); $lead_id = $params['lead_id']; $age_validation_check = $params['age_validation'] ?? null; $lead_data = $this->leadsModel->where('id', $lead_id)->first(); // dd($lead_data); $return = []; if (!isset($lead_data)) { $this->myLogger->logme('error', "Lead not found for lead_id: {$lead_id}"); $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => 'failed', 'error_data' => json_encode(['error_summary' => array_count_values([12]),'error_data' => 'file not found in DB'])])->update(); return array('status' => false, 'msg' => 'file not found in DB'); } //get the lead files data $lead_file_data = $this->leadFilesModel->where('is_active', 1)->where('type', 2)->first(); //check the lead file table has the error data entry if not than create new entry if(empty($lead_file_data)){ $data['type'] = 2; $data['file_name'] = $lead_data['file_name']; $data['docs_name'] = "Member List"; $data['lead_id'] = $lead_id; $lead_file_last_insert_id = $this->leadFilesModel->insert($data); $this->myLogger->logme('error', "New lead file entry created for store the error data, insert_id : '{$lead_file_last_insert_id}'"); } $family_composition = []; if($age_validation_check && !empty($lead_data['proposel_data'])){ $family_composition = $this->getAgeRatioFromRfqJson($lead_id, $lead_data['proposel_data']); $this->myLogger->logme('info', 'Family composition :',json_encode($family_composition)); } // dd($family_composition); // get the file path $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; $this->myLogger->logme('error', "File path: {$file_name_with_path}"); //check physical file if (!file_exists($file_name_with_path)) { //file not found update status and reason $message = "Physcial file not found"; $this->myLogger->logme('error', ($message . ' for lead id ' . $lead_id)); $this->leadFilesModel ->where('lead_id', $lead_id) ->where('type', 2) ->set(['status' => 'failed','error_data' => json_encode(['error_summary' => array_count_values([5]),'error_data' => $message])]) ->update(); return array('error_summary' => [5], 'error_data' => $message); } $this->myLogger->logme('info', 'File exists, starting validation process'); //start validation process $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $sheet = $spreadsheet->getActiveSheet(); $highestRowAndColumn = $sheet->getHighestRowAndColumn(); // dd($highestRowAndColumn); $columns_to_check = $this->member_data_excel_columns; $result = ['error_type' => 1, 'error_summary' => [], 'error_data' => []]; $keys = array_keys($columns_to_check); $allowedHighestColumn = end($columns_to_check); $excel_data = $sheet->rangeToArray('A1:' . $allowedHighestColumn['col_cell_name'] . $highestRowAndColumn['row']); $excel_data = ExcelSanitizeHelper::sanitizeArrayData($excel_data); $this->myLogger->logme('error', 'Excel data sanitized count : {row_count}', ['row_count' => count($excel_data)]); // dd($excel_data); //check number of columns in excel $excel_columns = ($excel_data[0]); //check columns order in excel $column_count_res = check_columns_name_exist($columns_to_check, $excel_columns); // dd($column_count_res); if (isset($column_count_res) && count($column_count_res)) { //columns count mismatch $message = implode("\n", $column_count_res); // echo $message; $this->myLogger->logme('error', ($message . ' for lead id ' . $lead_id)); $this->leadFilesModel ->where('lead_id', $lead_id) ->where('type', 2) ->set(['status' => 'failed','error_data' => json_encode(['error_summary' => array_count_values([6]),'error_data' => $message])]) ->update(); return array('error_summary' => [6], 'error_data' => $message); } $relationship = $this->general_relationships; $column_count_res = update_excel_column_indexes($columns_to_check, $excel_columns); // dd($column_count_res); //remove header unset($excel_data[0]); $member_family_data = []; foreach ($excel_data as $row_key => $row) { //1. avoid empty rows if (check_row_is_empty_or_null($row)) { $this->myLogger->logme('error', "Empty row found at index {$row_key}, stopping row iteration"); break; } //iterate each row for columns validations foreach ($row as $col_key => $col) { $is_mandatory = $columns_to_check[$keys[$col_key]]['is_mandatory']; $format = $columns_to_check[$keys[$col_key]]['format']; $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 } } //if is_mandatory is array (action based mandatory check) if (is_array($is_mandatory)) { $allowed_actions = $columns_to_check[$keys[$col_key]]['is_mandatory']; if ($col == "" || $col == NULL) { array_push($result['error_summary'], 1); $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 for this action/event'; } } //format check if (isset($format)) { $format_error = check_excel_date_format($col, $format); if (!$format_error['status']) { array_push($result['error_summary'], 2); $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'][] = $format_error['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); } // dd(($param_values));//die(); $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']; } } } //age validation $age_validation = isset($columns_to_check['dob']['age_validation']) ?? null; if (isset($age_validation) && $age_validation && $age_validation_check && !empty($family_composition)) { $format_error = check_age_validation($row, $family_composition); if (!$format_error['status']) { array_push($result['error_summary'], 2); $result['error_data'][$row_key][$keys[$columns_to_check['dob']['col_idx']]]['col_name'] = $columns_to_check['dob']['col_name']; //push column name $result['error_data'][$row_key][$keys[$columns_to_check['dob']['col_idx']]]['col_idx'] = $columns_to_check['dob']['col_idx']; //push column index $result['error_data'][$row_key][$keys[$columns_to_check['dob']['col_idx']]]['error'][] = $format_error['error']; } } $row['row_index'] = $row_key; $relation_idx = $columns_to_check['relationship']['col_idx']; $emp_code_idx = $columns_to_check['emp_code']['col_idx']; if (isset($row[$relation_idx]) && strtolower($row[$relation_idx]) == 'self' && isset($member_family_data[$row[$emp_code_idx]])) { array_unshift($member_family_data[$row[$emp_code_idx]], $row); } else { $member_family_data[$row[$emp_code_idx]][] = $row; } } // dd($member_family_data); $this->myLogger->logme('info', 'Row validation completed, starting duplicate check'); $check_row_dublicate = check_duplicate_rows_and_contacts($excel_data, $columns_to_check, $result); // dd($check_row_dublicate); if(count($check_row_dublicate)){ $result = $check_row_dublicate; } $this->myLogger->logme('info', 'Starting family validation'); $result = validateFamily($member_family_data, $columns_to_check, $result); // dd($family_validation); 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->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => $status,'error_data' => $failure_reason])->update(); $this->myLogger->logme("error", '{lead_id} uploaded failed for this lead id', ['lead_id' => $lead_id]); } else { $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => 'success','error_data' => ''])->update(); $r = Jobs::addJob(['job_name' => 'calculateMembersDemography', 'payload' => ['lead_id' => $lead_id]]); } return $result; } public function getAgeRatioFromRfqJson($lead_id, $porposel_data) { $age_ratio = []; $rfq_data = $this->RFQModel->where('is_active', 1)->where('lead_id', $lead_id)->orderBy('id', 'desc')->first(); if(empty($rfq_data) || empty($rfq_data['json'])){ return $age_ratio; } $data = json_decode($rfq_data['json'], true); $proposal_and_insurer = json_decode($porposel_data, true); $insurer_key = $proposal_and_insurer['insurer_name'] ?? null; if(isset($data['table_data']['data'])){ foreach ($data['table_data']['data'] as $key => $value) { if($value['items'] == 'family_composition'){ foreach ($value['data'] as $family_composition) { if($family_composition['subth'] == $insurer_key){ $age_ratio = json_decode($family_composition['input_value'] ?? "", true) ?? []; } } } } } return $age_ratio; } public function getMemberDataExcelFileErrors() { $lead_id = $this->request->getGet('lead_id'); // $lead_id = 329; // Render views and capture output $result = $this->getMemberDataListExcelErrorData($lead_id); if ($result != 0) { $result['lead_id'] = $lead_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 getMemberDataListExcelErrorData($lead_id) { try { $file = $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->where('is_active', 1)->first(); $error_data = json_decode($file['error_data']); // dd($error_data); // return $error_data; $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $file['file_name']; //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 ' . $lead_id)); return 0; } $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); $sheet = $spreadsheet->getActiveSheet(); $highestRowAndColumn = $sheet->getHighestRowAndColumn(); $excel_data = $sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); $excelErrorData['excel_header'] = $excel_data[0]; unset($excel_data[0]); // Kint::dump($excel_data); 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 downloadFullMemberDataExcelErrorFile($lead_id, $rowIndex = 1, $colIndex = 1) { // Get file data from the database $file_data = $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->where('is_active', 1)->first(); $error = json_decode($file_data['error_data']); // Check if the file exists if (!$file_data) { $error_message = "File not found"; $this->myLogger->logme('error', $error_message . ' for file id ' . $lead_id); return $error_message; } $fileName = $file_data['file_name']; $filePath = WRITEPATH . '/uploads/lead_files/' . $fileName; // Check if the file exists if (!file_exists($filePath)) { $error_message = "File not found"; $this->myLogger->logme('error', $error_message . ' for file id ' . $lead_id); $data['message'] = 'Physical File Not Found'; return view('errors/404', $data); } // Load the Excel file $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($filePath); $sheet = $spreadsheet->getActiveSheet(); foreach ($error->error_data as $index => $error_data) { $rowIndex = $index + 1; if ($error->error_type == 1) { foreach ($error_data as $key => $value) { $colIndex = $value->col_idx + 1; $originalValue = $sheet->getCell([$colIndex, $rowIndex])->getValue(); $newValue = implode(', ', $value->error); $val = $originalValue . ' ( ' . $newValue . ' )'; $sheet->setCellValue([$colIndex, $rowIndex], $val); $style = [ 'fill' => [ 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => 'ffad99'] // Red color ] ]; $sheet->getStyle([$colIndex, $rowIndex])->applyFromArray($style); } } else if ($error->error_type == 2) { foreach ($error_data as $key => $value) { $originalValue = $sheet->getCell([1, $rowIndex])->getValue(); $newValue = implode(', ', $value->error); $val = $originalValue . ' ( ' . $newValue . ' )'; $sheet->setCellValue([$colIndex, $rowIndex], $val); $style = [ 'fill' => [ 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => 'ffad99'] // Red color ] ]; $sheet->getStyle([$colIndex, $rowIndex])->applyFromArray($style); } } } // Create a new filename for the modified Excel file $newFileName = 'error_with_highlight_' . $fileName; // Save the modified Excel file to a new location $newFilePath = WRITEPATH . '/uploads/lead_files/' . $newFileName; $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet); $writer->save($newFilePath); // Set headers to force download $response = service('response'); $response->setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); $response->setHeader('Content-Disposition', 'attachment;filename="' . $newFileName . '"'); $response->setHeader('Cache-Control', 'max-age=0'); $response->setHeader('Content-Length', filesize($newFilePath)); $response->setBody(file_get_contents($newFilePath)); // Delete the temporary file unlink($newFilePath); // Return the response return $response; } public function savePlacementDataAndValidateMemberDataFile() { try { $this->myLogger->logme('error', '--- savePlacementDataAndValidateMemberDataFile START ---'); $params = $this->request->getPost(); $this->myLogger->logme('error', 'Received params: ' . json_encode($params)); if (empty($params['lead_id'])) { $this->myLogger->logme('error', 'Lead ID missing'); return $this->respond([ 'status' => false, 'code' => 400, 'message' => 'Lead ID is required' ], 400); } $lead_id = $params['lead_id']; $proposal_insurer = $params['proposal_insurer'] ?? ''; // Handle proposal and insurer details if (!empty($proposal_insurer) && strpos($proposal_insurer, '-') !== false) { list($proposal_key, $insurer_key) = explode('-', $proposal_insurer, 2); $lead_update_data = json_encode([ 'proposel_name' => $proposal_key, 'insurer_name' => $insurer_key, 'insurer' => $params['insurer_and_branch'] ?? null, ]); $this->myLogger->logme('error', "Proposal/Insurer parsed successfully: $proposal_key - $insurer_key"); } else { $lead_update_data = null; $this->myLogger->logme('error', 'Proposal/Insurer not provided or invalid format'); } $data = [ 'proposel_data' => $lead_update_data, 'placement_date' => !empty($params['placement_date']) ? change_date_format($params['placement_date']) : null, 'payment_date' => !empty($params['payment_date']) ? change_date_format($params['payment_date']) : null, 'utr_no' => $params['utr_no'] ?? null, 'is_cd' => $params['is_cd'] ?? null, 'premium_amount' => $params['premium_amount'] ?? null, 'total_amount' => $params['total_amount'] ?? null, 'cd_amount' => $params['cd_amount'] ?? null, 'no_of_installment' => $params['no_of_installment'] ?? null, 'is_installment' => $params['is_installment'] ?? null, 'acm_id' => $params['acm_pk'] ?? null, ]; // get lead data $lead_data = $this->leadsModel->where('id', $lead_id)->first(); // Compare and update only if changed the start and end date if (!empty($params['policy_start_date'])) { $converted_start = change_date_format($params['policy_start_date']); if ($converted_start !== $lead_data['policy_start_date']) { $data['policy_start_date'] = $converted_start; $this->myLogger->logme('error', "Policy start date updated: $converted_start"); } } if (!empty($params['policy_end_date'])) { $converted_end = change_date_format($params['policy_end_date']); if ($converted_end !== $lead_data['policy_end_date']) { $data['policy_end_date'] = $converted_end; $this->myLogger->logme('error', "Policy end date updated: $converted_end"); } } // Handle TPA details if (!empty($params['tpa_id']) && strpos($params['tpa_id'], '-') !== false) { list($tpaBranchId, $tpaId) = explode('-', $params['tpa_id']); $data['tpa_branch_id'] = $tpaBranchId; $data['tpa_id'] = $tpaId; $this->myLogger->logme('error', "TPA details added: branch=$tpaBranchId, id=$tpaId"); } $this->myLogger->logme('error', 'Prepared lead update data: ' . json_encode($data)); // Update main lead record $this->leadsModel->update($lead_id, $data); $this->myLogger->logme('error', "Lead updated successfully for ID: $lead_id"); // Save installment details if (!empty($params['installments'])) { $installments = json_decode($params['installments'], true); $this->myLogger->logme('error', "Installments data received: " . json_encode($installments)); if (is_array($installments) && !empty($installments)) { foreach ($installments as $installment) { $installment['payment_date'] = !empty($installment['payment_date']) && strtotime($installment['payment_date']) ? date('Y-m-d', strtotime($installment['payment_date'])) : null; $installment['lead_id'] = $lead_id; if (!empty($installment['id'])) { $this->leadInstallmentPaymentDetails->update($installment['id'], $installment); $this->myLogger->logme('error', "Installment updated: " . json_encode($installment)); } else { $this->leadInstallmentPaymentDetails->insert($installment); $this->myLogger->logme('error', "Installment inserted: " . json_encode($installment)); } } } } else { $this->myLogger->logme('error', "No installments provided"); } // Update lead file status to pending $this->leadFilesModel->where('lead_id', $lead_id)->where('type', 2)->set(['status' => 'pending'])->update(); // Queue job after save $r = Jobs::addJob(['job_name' => 'memberDataListExcelFileFormatValidation', 'payload' => ['lead_id' => $lead_id, 'age_validation' => true]]); $this->myLogger->logme('error', "Job queued successfully: " . json_encode($r)); $this->myLogger->logme('error', "--- savePlacementDataAndValidateMemberDataFile END (SUCCESS) ---"); return $this->respond([ 'status' => true, 'code' => 200, 'message' => 'Placement data saved successfully. File being validated', 'lead_id' => $lead_id, 'data' => $data, 'params' => $params ], 200); } catch (\Exception $e) { $errorDetails = [ 'error_message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'stack_trace' => $e->getTraceAsString(), ]; $this->myLogger->logme('error', "--- savePlacementDataAndValidateMemberDataFile ERROR --- " . json_encode($errorDetails)); return $this->respond([ 'status' => false, 'code' => 500, 'message' => 'Error while validating the member data', 'error' => $errorDetails ], 500); } } public function checkMemberDataFileValidationStatus() { $lead_id = $this->request->getVar('lead_id'); if (empty($lead_id)) { return $this->respond([ 'status' => false, 'code' => 400, 'message' => 'lead_id is required' ], 400); } // Fetch file validation status $lead_file = $this->leadFilesModel ->select('id, lead_id, status') ->where('lead_id', $lead_id) ->where('type', 2) ->first(); if (!$lead_file) { return $this->respond([ 'status' => false, 'code' => 404, 'message' => 'No file found for this lead_id' ], 404); } // If validation is still running if ($lead_file['status'] === 'pending' || $lead_file['status'] === null) { return $this->respond([ 'status' => true, 'code' => 202, // Accepted - still processing 'message' => 'Validation in progress', 'data' => ['status' => $lead_file['status']] ], 200); } // If validation finished (success or failed) return $this->respond([ 'status' => true, 'code' => 200, 'message' => 'Validation completed', 'data' => $lead_file ], 200); } // ----------- END OF MEMBER DATA VALIDAATION ------------------------------------------------------------------------------------------------------ }