diff --git a/app/Controllers/JobWorker.php b/app/Controllers/JobWorker.php index a0d5f694..fcaf2096 100755 --- a/app/Controllers/JobWorker.php +++ b/app/Controllers/JobWorker.php @@ -126,6 +126,10 @@ class JobWorker extends AdminController 'employeesEnrollmentInsert' => [ 'type' => 'CC', // Handler Category 'handler' => 'App\Controllers\EmployeeServiceController', + ], + 'calculateMembersDemography' => [ + 'type' => 'CC', // Handler Category + 'handler' => 'App\Controllers\LeadsController', ] ]; diff --git a/app/Controllers/LeadsController.php b/app/Controllers/LeadsController.php index 856fb649..a1169767 100644 --- a/app/Controllers/LeadsController.php +++ b/app/Controllers/LeadsController.php @@ -4,10 +4,14 @@ namespace App\Controllers; use CodeIgniter\API\ResponseTrait; + +use Exception; + use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\Border; use PhpOffice\PhpSpreadsheet\Style\Alignment; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; +use PhpOffice\PhpSpreadsheet\Style\Fill; use App\Models\UserModel; use App\Models\ClientModel; @@ -24,13 +28,15 @@ use App\Models\RFQModel; use App\Models\InsurerModel; use App\Helpers\MailHelper; +use App\Helpers\ExcelMergeHelper; +use Google\Service\CloudSearch\PushItem; use Kint; class LeadsController extends BaseController -{ +{ use ResponseTrait; - + //log message protected $myLogger; @@ -89,18 +95,20 @@ class LeadsController extends BaseController } public function viewLeadsList() - { + { // $d = $this->constructExcelToSaveTemp(24, 1, $propsal_and_insurer = null); - // $d = $this->calculateMembersDemography(['lead_id' => 34]); + $job_details = new Jobs(); + // $r = Jobs::addJob(['job_name' => 'calculateMembersDemography', 'payload' => ['lead_id' => 24]]); + // $d = $this->calculateMembersDemography(['lead_id' => 24]); //$this->mergeQuoteExcelFileWithMembersListExcelFile(24, 1, $propsal_and_insurer = null); // dd($d); $data['page_name'] = 'Leads'; // Set basic data - $data['issuer'] = $this->issuer; - $data['client_type'] = $this->clientType; - $data['lead_type'] = $this->leadType; + $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 @@ -136,45 +144,45 @@ class LeadsController extends BaseController $data = $this->prepareLeadData(); // print_r($this->request->getPost()); die; - + if (!$id) { return $this->insertNewLead($data); } else { return $this->updateOldLead($id, $data); } } - + private function prepareLeadData() { $data = $this->request->getPost(); - - if($data['lead_type'] == 2){ + + if ($data['lead_type'] == 2) { $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{ + } 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){ + if ($data['client_code'] == 2) { $data['client_code'] = generate_client_code('IC'); } - + $data = $this->prepareMultipleLeadData($data); // print_r($data); die; return $data; } private function prepareMultipleLeadData($data) - { + { // print_r($data); die; $processedData = []; - foreach($data['policy_type_id'] as $index => $value){ + foreach ($data['policy_type_id'] as $index => $value) { // Separate the insurer and insurer branch, handle missing or invalid data @@ -191,7 +199,7 @@ class LeadsController extends BaseController $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) { @@ -209,18 +217,18 @@ class LeadsController extends BaseController $proposed_tpa_id = 0; } - if(!empty($data['policy_start_date'][$index])){ + 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{ + } else { $policy_start_date = null; } - - if(!empty($data['policy_end_date'][$index])){ + + 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{ + } else { $policy_end_date = null; } - + $processedData[] = [ 'lead_type' => $data['lead_type'], 'issuer' => $data['issuer'], @@ -242,18 +250,18 @@ class LeadsController extends BaseController '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, - 'claims' => $data['claims'][$index] ?? null, - '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, + '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, + 'claims' => $data['claims'][$index] ?? null, + '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, 'status' => $data['status'] ?? null, @@ -263,59 +271,58 @@ class LeadsController extends BaseController return $processedData; } - + private function insertNewLead($data) - { + { $insertCount = []; - foreach($data as $value){ + foreach ($data as $value) { $insert = $this->leadsModel->insert($value); $insertCount[] = $insert; $this->insertLeadStatus($insert, $value['status'], 3); } if (count($insertCount) > 0) { - return $this->respond(['status' => true, 'lead_id' => $insert, 'message' => 'New Lead created successfully', 'data' =>$data], 200); + 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); + 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->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' => 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); + return $this->respond(['status' => false, 'lead_id' => $id, 'message' => "Failed to update Lead", 'data' => $data], 200); } // Get the Single Lead data for edit public function getLeadDataForEdit($id) - { + { $data = $this->leadsModel - ->where('leads.id', $id) - ->where('leads.is_active', 1) - ->first(); + ->where('leads.id', $id) + ->where('leads.is_active', 1) + ->first(); - if(!empty($data['policy_start_date'])){ + if (!empty($data['policy_start_date'])) { $data['policy_start_date'] = change_date_format($data['policy_start_date'], 'Y-m-d', 'd/m/Y'); - }else{ + } else { $data['policy_start_date'] = null; } - if(!empty($data['policy_end_date'])){ + if (!empty($data['policy_end_date'])) { $data['policy_end_date'] = change_date_format($data['policy_end_date'], 'Y-m-d', 'd/m/Y'); - }else{ + } else { $data['policy_end_date'] = null; } - - if($data){ + + if ($data) { return $this->respond(['status' => true, 'data' => $data], 200); - }else{ + } else { return $this->respond(['status' => false], 200); } - } private function insertLeadStatus($primaryKey, $status, $statusType) @@ -333,39 +340,40 @@ class LeadsController extends BaseController //--------RFQ----------------------------------------------------------------------------------------------- - public function viewRFQ($id, $type = 1){ + public function viewRFQ($id, $type = 1) + { $data['rfq_data'] = $this->RFQModel - ->where('lead_id', $id) - ->where('type', $type) - ->where('is_active', 1) - ->first(); + ->where('lead_id', $id) + ->where('type', $type) + ->where('is_active', 1) + ->first(); $data['rfq_count'] = $this->RFQModel - ->where('lead_id', $id) - ->where('type', 1) - ->where('is_active', 1) - ->countAllResults(); + ->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(); + ->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') - ->join('policy_type', 'leads.policy_type_id = policy_type.id') - ->where('leads.id', $id) - ->where('leads.is_active', 1) - ->first(); + ->select('leads.*, policy_type.question_json') + ->join('policy_type', 'leads.policy_type_id = policy_type.id') + ->where('leads.id', $id) + ->where('leads.is_active', 1) + ->first(); // dd($lead_data); - if($lead_data['lead_type'] == 2){ + if ($lead_data['lead_type'] == 2) { $client_policy_data = $this->clientPolicyModel->where('is_active', 1)->where('id', $lead_data['source_policy_id'])->first(); $data['policy_terms'] = $client_policy_data['policy_terms']; } @@ -380,7 +388,8 @@ class LeadsController extends BaseController $this->loadLayout('view_rfq.php', $data); } - public function createRFQ(){ + public function createRFQ() + { $data = $this->request->getPost(); $lead_id = $data['lead_id']; @@ -395,14 +404,14 @@ class LeadsController extends BaseController $result = $this->RFQModel->insert($data); if ($result) { - return $this->respond(['status' => true, 'id' => $result, 'message' => 'RFQ created successfully', 'data' =>$data], 200); + return $this->respond(['status' => true, 'id' => $result, 'message' => 'RFQ created successfully', 'data' => $data], 200); } - return $this->respond(['status' => false, 'id' => $result, 'message' => "Failed to create RFQ", 'data' =>$data], 200); - + return $this->respond(['status' => false, 'id' => $result, 'message' => "Failed to create RFQ", 'data' => $data], 200); } - public function createQCR(){ + public function createQCR() + { $data = $this->request->getPost(); $lead_id = $data['lead_id']; @@ -418,10 +427,10 @@ class LeadsController extends BaseController $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' => 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); + return $this->respond(['status' => false, 'id' => $result, 'message' => "Failed to create QCR", 'data' => $data], 200); } @@ -429,16 +438,17 @@ class LeadsController extends BaseController //export main route function - public function exportQCRandRFQ($lead_id, $type, $export_type){ - $this-> exportExcelForQCRandRFQ($lead_id, $type); + public function exportQCRandRFQ($lead_id, $type, $export_type) + { + $this->exportExcelForQCRandRFQ($lead_id, $type); } //FOR EXCEL public function exportExcelForQCRandRFQ($lead_id, $type) { - //$filepath = $this->constructExcelToSaveTemp($lead_id, $type); + $filepath = $this->constructExcelToSaveTemp($lead_id, $type); $filepath = $filepath['filePath']; - + if (file_exists($filepath)) { // Set headers to force download header('Content-Description: File Transfer'); @@ -446,24 +456,24 @@ class LeadsController extends BaseController 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) - { + { $rfq_data = $this->RFQModel->getRFQTableDataWithLeadIDAndType($lead_id, $type); - + // dd($rfq_data, $lead_id, $type); $lead_data = [ @@ -471,20 +481,20 @@ class LeadsController extends BaseController 'Insurer' => $rfq_data['insurer_name'] . ' - ' . $rfq_data['insurer_branch_name'], 'TPA' => $rfq_data['tpa_name'] . ' - ' . $rfq_data['tpa_branch_name'], ]; - + $data = json_decode($rfq_data['json'], true); - if($type == 2){ + if ($type == 2) { $data = $this->convertJsonForQCR($data, 'stc'); - if($propsal_and_insurer !== null){ + if ($propsal_and_insurer !== null) { list($proposal_key, $insurer_key) = explode('-', $propsal_and_insurer, 2); $data = $this->transformProposelData($data, $proposal_key, $insurer_key); } } - + $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - + // Start with lead_data at the top $rowNumber = 1; foreach ($lead_data as $key => $value) { @@ -504,26 +514,26 @@ class LeadsController extends BaseController ], ]); - + $rowNumber += 2; // Add headers and subheaders $headers = $data['table_data']['headers']; $subHeaderRow = $rowNumber + 1; $columnLetter = 'A'; - + foreach ($headers as $header) { if (in_array($header['parentHeader'], ['Item Key', 'Action'])) { continue; } - + if ($header['parentHeader'] === 'Sno') { $header['parentHeader'] = 'S.No.'; } - + $startColumn = $columnLetter; // Start of the current header range $subHeaderCount = count($header['subHeaders']); // Number of subheaders for this parent header - + // Set parent header value $sheet->setCellValue("{$startColumn}{$rowNumber}", $header['parentHeader']); $sheet->getStyle("{$startColumn}{$rowNumber}")->applyFromArray([ @@ -533,7 +543,7 @@ class LeadsController extends BaseController 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, ], ]); - + // Merge header cells if it spans multiple subheaders if ($subHeaderCount > 1) { $endColumn = chr(ord($startColumn) + $subHeaderCount - 1); // Calculate the end column @@ -541,7 +551,7 @@ class LeadsController extends BaseController } else { $endColumn = $startColumn; // No merge needed if only one subheader } - + // Add subheaders foreach ($header['subHeaders'] as $subHeader) { $sheet->setCellValue("{$columnLetter}{$subHeaderRow}", $subHeader); @@ -555,7 +565,7 @@ class LeadsController extends BaseController $columnLetter++; // Move to the next column for subheaders } } - + // Apply border to the header range $headerRange = "A{$rowNumber}:" . chr(ord($columnLetter) - 1) . "{$subHeaderRow}"; $sheet->getStyle($headerRange)->applyFromArray([ @@ -570,7 +580,7 @@ class LeadsController extends BaseController // Increase row height for headers and subheaders $sheet->getRowDimension($rowNumber)->setRowHeight(30); // Header row height $sheet->getRowDimension($subHeaderRow)->setRowHeight(25); // Subheader row height - + $rowNumber = $subHeaderRow + 2; $column_data = $data['table_data']['data']; $serial_no = 1; @@ -604,18 +614,18 @@ class LeadsController extends BaseController ], ], ]); - - if($type == 2){ + + if ($type == 2) { $rowNumber += 2; - + // Add premium data $premiumData = $data['premium_data']['data']; $premium = ['Premium']; $gst = ['GST']; $total = ['Total']; - + foreach ($premiumData as $proposal => $insurers) { foreach ($insurers as $insurer => $values) { $premium[] = $values['Premium']; @@ -623,7 +633,7 @@ class LeadsController extends BaseController $total[] = $values['Total']; } } - + foreach ([$premium, $gst, $total] as $index => $rowData) { $columnLetter = 'B'; foreach ($rowData as $key => $value) { @@ -645,23 +655,22 @@ class LeadsController extends BaseController ], ], ]); - } - + // Auto-size columns foreach ($sheet->getColumnIterator() as $column) { $sheet->getColumnDimension($column->getColumnIndex())->setAutoSize(true); } - + // 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, @@ -670,60 +679,54 @@ class LeadsController extends BaseController //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']) - { - + if ($source_file_path && $rfq_data['file_name']) { } return true; } public function calculateMembersDemography($params) - { + { $lead_id = $params['lead_id']; $lead_data = $this->leadsModel->find($lead_id); - // print_rr($lead_data); - if($lead_data['file_name']) - { - $file_name_with_path = WRITEPATH."/uploads/lead_files/".$lead_data['file_name']; - + if ($lead_data['file_name']) { + $file_name_with_path = WRITEPATH . "/uploads/lead_files/" . $lead_data['file_name']; + //check physical file - if(!file_exists($file_name_with_path)) - { + if (!file_exists($file_name_with_path)) { //file not found update status and reason - $message = "Lead Physcial file not found"; + $message = "Lead Physcial file not found"; // echo $message; - $this->myLogger->logme('error',($message . ' for file ' . $file_name_with_path)); - return ['status' => 'failed','message' => 'no physcial file']; + $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); + $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file_name_with_path); - //get members data - $members_sheet = $spreadsheet->getSheet(0); - $highestRowAndColumn = $members_sheet->getHighestRowAndColumn(); - // dd($highestRowAndColumn); - $members = $members_sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); - // dd($members); + //get members data + $members_sheet = $spreadsheet->getSheet(0); + $highestRowAndColumn = $members_sheet->getHighestRowAndColumn(); + // dd($highestRowAndColumn); + $members = $members_sheet->rangeToArray('A1:' . $highestRowAndColumn['column'] . $highestRowAndColumn['row']); + // dd($members[6]); - //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']); - print_r($age_band_data); + //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]; - Kint::dump($members_heading); - $available_col = null; + + //check age or dob column + $members_heading = $members[0]; + $available_col = null; $col_index = null; - if (in_array('age', array_map('strtolower',$members_heading))) { + if (in_array('age', array_map('strtolower', $members_heading))) { $available_col = 'age'; - $col_index = array_search('age',array_map('strtolower',$members_heading)); + $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)); @@ -731,28 +734,358 @@ class LeadsController extends BaseController if ($available_col == null) { $message = 'No DOB or Age column '; - $this->myLogger->logme('error',($message . $file_name_with_path)); - return ['status' => 'failed','message' => $message]; + $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()]; } - //convert age slab data into array - - } - else - { - $this->myLogger->logme('error',(' no file found ' . $file_name_with_path)); - return ['status' => 'failed','message' => 'no file found']; - } + try { + $result = $this->generateClassifierSpreadsheet($classifiers, 'writable/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' => 'writable/uploads/lead_files/' . $result['filename'], 'sheets' => []], + ]; + $outputPath = WRITEPATH . 'uploads/lead_files/Member_Data.xlsx'; + $result = ExcelMergeHelper::mergeExcelFiles($filePaths, $outputPath); + if ($result) { + 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']; + } } - + 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_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(); + + // 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) use ($age_bands) { + // Set headers + $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); + } + + // 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 [ + 'success' => true, + 'filepath' => $filepath, + 'filename' => $filename, + 'fullpath' => realpath($filepath) + ]; + } 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->getGet(); // print_r($params); die; $lead_id = $params['lead_id']; @@ -777,9 +1110,9 @@ class LeadsController extends BaseController ->first(); $cc_mails = []; - + //get CC Mails - if($recipient_type == 'internal' || $recipient_type == 'placement'){ + if ($recipient_type == 'internal' || $recipient_type == 'placement') { $cc_data = isset($params['cc']) ? $params['cc'] : ""; $param_cc_mail = json_decode($cc_data, true); @@ -796,18 +1129,17 @@ class LeadsController extends BaseController $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); + 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); + 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); } @@ -817,12 +1149,28 @@ class LeadsController extends BaseController //get file path to attach $file_info = $this->constructExcelToSaveTemp($lead_id, ($file_type == 'rfq' ? 1 : 2), $propsal_and_insurer); + 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) . '/' . 'merged_' . $temp_file_name; + $result = ExcelMergeHelper::mergeExcelFiles($filePaths, $outputPath); + // print_rr($result); + } + } + // print_rr($lead_data); + // print_rr($file_info); // $file_path = WRITEPATH."uploads/excel/sample/correction.xls"; // $file_name = $file_type.'.xlsx'; // !dd($file_info); - - $file_path = $file_info['filePath']; - $file_name = $file_info['fileName']; + + $file_path = $result; + $file_name = basename($result); $attachments = [['fileName' => $file_name, 'filePath' => $file_path]]; //get recipient address @@ -837,9 +1185,9 @@ class LeadsController extends BaseController // print_r($recipient_data); die; - } else if($recipient_type == 'client') { + } else if ($recipient_type == 'client') { $recipient_data = [['name' => $lead_data['contact_person_name'], 'email' => $lead_data['contact_person_email']]]; - }else{ + } else { $recipient_data = [['name' => "Team", 'email' => $params['to']]]; } // print_r($recipient_data); die; @@ -847,7 +1195,7 @@ class LeadsController extends BaseController $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 = '
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.
| Client name | {{CLIENT_NAME}} |
|---|---|
| Coverage Type | {{POLICY_LONG_NAME}} |
| Policy Start Date | {{POLICY_START_DATE}} |
| Policy Duration | {{DURATION}} |
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.