nhance_partner_be/app/Controllers/ExcelExportController.php

1944 lines
90 KiB
PHP

<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; // <--- THIS MUST BE HERE
use PhpOffice\PhpSpreadsheet\Style\Alignment;
class ExcelExportController extends ResourceController
{
protected $db;
public function __construct()
{
$this->db = \Config\Database::connect();
}
/**
* Centralized function to create the spreadsheet, apply styling,
* set headers, and stream the file output.
*
* @param array $header Column headers (1D array)
* @param array $data Policy data including the total row (2D array)
* @param string $title Spreadsheet title
* @param string $fileName Output file name
* @param string $totalLabelCol Column letter for the 'TOTAL:' label (e.g., 'C' or 'E')
* @param string $totalValueCol Column letter for the total value (e.g., 'D' or 'F')
* @return void
*/
private function streamExcelFile(array $header, array $data, string $title, string $fileName, bool $showTotal = true): void
{
while (ob_get_level() > 0) {
ob_end_clean();
}
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$columnCount = count($header);
$lastCol = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($columnCount);
$rowCount = count($data);
// 1. Title
$sheet->mergeCells("A1:{$lastCol}1");
$sheet->setCellValue('A1', $title);
$sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14);
$sheet->getStyle('A1')->getAlignment()->setHorizontal('center');
// 2. Headers
$sheet->fromArray($header, NULL, 'A2');
$sheet->getStyle("A2:{$lastCol}2")->getFont()->setBold(true);
$sheet->getStyle("A2:{$lastCol}2")->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('F2F2F2');
// 3. Data
$sheet->fromArray($data, NULL, 'A3');
// 4. Dynamic Total Row Styling
if ($rowCount > 0 && $showTotal === true) {
$totalRowNumber = $rowCount + 2;
// Bold the entire last row
$sheet->getStyle("A{$totalRowNumber}:{$lastCol}{$totalRowNumber}")->getFont()->setBold(true);
// Find the second to last column letter for "Total:" alignment
$labelColLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($columnCount - 1);
// Right-align the "Total:" label (usually second to last column)
$sheet->getStyle($labelColLetter . $totalRowNumber)->getAlignment()->setHorizontal('right');
// Format the last column (the sum) as a number
$sheet->getStyle($lastCol . $totalRowNumber)->getNumberFormat()->setFormatCode('#,##0.00');
}
// 5. Auto-size
for ($i = 1; $i <= $columnCount; $i++) {
$col = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($i);
$sheet->getColumnDimension($col)->setAutoSize(true);
}
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Disposition: attachment; filename=\"{$fileName}\"");
header("Cache-Control: max-age=0");
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$writer->save('php://output');
exit();
}
// 1) Broker generate the Excel file
public function downloadBrokerPoliciesExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
$brokerId = $this->request->getGet('broker_id');
$month = $this->request->getGet('month');
if (empty($managerId) || empty($brokerId) || empty($month)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$msg .= empty($brokerId) ? "broker_id " : "";
$msg .= empty($month) ? "month " : "";
$ref = ['debug_msg' => $msg];
// $ref = ['debug_msg' => 'Missing required parameters: manager_id, broker_id, and month must be provided.'];
return $this->response->setJSON(['status' => 'error','code' => 400,'data' => [],'message' => 'Missing required parameters','ref' => $ref])->setStatusCode(200);
}
$data = $this->getBrokerPoliciesData($managerId, $brokerId, $month);
if (empty($data)) {
throw new \RuntimeException('No policies found...', 404);
}
$lastIndex = count(reset($data)) - 1;
// usort($data, function($a, $b) use ($lastIndex) {
// return (float)$a[$lastIndex] <=> (float)$b[$lastIndex];
// });
usort($data, function($a, $b) use ($lastIndex) {
return (float)$b[$lastIndex] <=> (float)$a[$lastIndex];
});
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
$header = ['S.No',
'Received Date', 'Assigned To',
'Partner Name' , 'Partner Code',
'Insurer Name' ,'Insurer Short Name',
'Insured Name', 'Vehicle Number',
'Payment Mode', 'Plan Type',
'Broker Name', 'Issue Date', 'Policy Number', 'Premium Amount'];
// Calculate and append total
$lastColIndex = count($header) - 1; // Get index of the last column (Premium)
$grandTotal = array_sum(array_column($finalData, $lastColIndex));
$totalRow = array_fill(0, count($header), ''); // Create empty row of same width
$totalRow[$lastColIndex - 1] = 'Total:'; // Put label in 2nd to last
$totalRow[$lastColIndex] = $grandTotal; // Put sum in last
$finalData[] = $totalRow;
$monthName = ($month === 'current') ? date('M_Y') : date('M_Y', strtotime('-1 month'));
$brokerName = $finalData[0][11] ?? 'Broker';
$cleanbrokerName = str_replace(' ', '_', strtolower($brokerName));
$fileName = $cleanbrokerName . '_Policies_Details_' . $monthName . '.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Broker Policies Details for {$monthName}",
$fileName,
true // Pass 'true' to show/bold the total row
);
return;
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['debug_msg'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['debug_msg'] = 'Database Error Occurred: ' . $e->getMessage();
$message = 'Database Error Occurred.';
} else {
$ref['debug_msg'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'Something went wrong. Please try again later.';
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
// 2) Product generate the Excel file
public function downloadProductPoliciesExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
$vehicleType = $this->request->getGet('vehicle_type');
$month = $this->request->getGet('month');
if (empty($managerId) || empty($vehicleType) || empty($month)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$msg .= empty($brokerId) ? "broker_id " : "";
$msg .= empty($month) ? "month " : "";
$ref = ['debug_msg' => $msg];
// $ref = ['debug_msg' => 'Missing required parameters: manager_id, broker_id, and month must be provided.'];
return $this->response->setJSON(['status' => 'error','code' => 400,'data' => [],'message' => 'Missing required parameters','ref' => $ref])->setStatusCode(200);
}
$data = $this->getProductPoliciesData($managerId, $vehicleType, $month);
if (empty($data)) {
throw new \RuntimeException('No policies found for this vehicle type...', 404);
}
$lastIndex = count(reset($data)) - 1;
// usort($data, function($a, $b) use ($lastIndex) {
// return (float)$a[$lastIndex] <=> (float)$b[$lastIndex];
// });
usort($data, function($a, $b) use ($lastIndex) {
return (float)$b[$lastIndex] <=> (float)$a[$lastIndex];
});
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
// $header = ['Vehicle Type', 'Issue Date', 'Policy Number', 'Premium Amount'];
$header = ['S.No',
'Received Date', 'Assigned To',
'Partner Name' , 'Partner Code',
'Insurer Name' ,'Insurer Short Name',
'Insured Name', 'Vehicle Number',
'Payment Mode', 'Plan Type',
'Vehicle Type', 'Issue Date', 'Policy Number', 'Premium Amount'];
// Calculate and append total
$lastColIndex = count($header) - 1; // Get index of the last column (Premium)
$grandTotal = array_sum(array_column($finalData, $lastColIndex));
$totalRow = array_fill(0, count($header), ''); // Create empty row of same width
$totalRow[$lastColIndex - 1] = 'Total:'; // Put label in 2nd to last
$totalRow[$lastColIndex] = $grandTotal; // Put sum in last
$finalData[] = $totalRow;
$monthName = ($month === 'current') ? date('M_Y') : date('M_Y', strtotime('-1 month'));
$vehicleType = $finalData[0][11] ?? 'Vehicle';
$cleanVehicleType = str_replace(' ', '_', strtolower($vehicleType));
$fileName = $cleanVehicleType . '_Policies_Details_' . $monthName . '.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Vehicle Type Policies Details for {$monthName}",
$fileName,
true // This will ignore the bold/alignment logic for the last row
);
return;
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['debug_msg'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['debug_msg'] = 'Database Error Occurred: ' . $e->getMessage();
$message = 'Database Error Occurred.';
} else {
$ref['debug_msg'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'Something went wrong. Please try again later.';
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
// 3) Insurer generate the Excel file
public function downloadInsurerPoliciesExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
$insurerId = $this->request->getGet('insurer_id');
$month = $this->request->getGet('month');
// --- ADDED VALIDATION (Simplified logic for clarity) ---
if (empty($managerId) || empty($insurerId) || empty($month)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$msg .= empty($insurerId) ? "insurer_id " : "";
$msg .= empty($month) ? "month " : "";
$ref = ['debug_msg' => $msg];
// Status code remains 200, but JSON code is 400 as per your preference
return $this->response->setJSON([
'status' => 'error',
'code' => 400,
'data' => [],
'message' => 'Missing required parameters',
'ref' => $ref
])->setStatusCode(200);
}
$data = $this->getInsurerPoliciesData($managerId, $insurerId, $month);
// --- 1. MODIFIED LOGIC: Throw RuntimeException if no data ---
if (empty($data)) {
throw new \RuntimeException('No policies found for this insurer for the specified month.', 404);
}
$lastIndex = count(reset($data)) - 1;
// usort($data, function($a, $b) use ($lastIndex) {
// return (float)$a[$lastIndex] <=> (float)$b[$lastIndex];
// });
usort($data, function($a, $b) use ($lastIndex) {
return (float)$b[$lastIndex] <=> (float)$a[$lastIndex];
});
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
// Define column headers
$header = ['S.No',
'Received Date', 'Assigned To',
'Partner Name' , 'Partner Code',
'Vehicle Number',
'Payment Mode', 'Plan Type',
'Insurer Name', 'Insurer Short Name','Insured Name', 'Policy Issued Date','Policy Number', 'Premium Amount'];
// Calculate and append total
$lastColIndex = count($header) - 1; // Get index of the last column (Premium)
$grandTotal = array_sum(array_column($finalData, $lastColIndex));
$totalRow = array_fill(0, count($header), ''); // Create empty row of same width
$totalRow[$lastColIndex - 1] = 'Total:'; // Put label in 2nd to last
$totalRow[$lastColIndex] = $grandTotal; // Put sum in last
$finalData[] = $totalRow;
$monthName = ($month === 'current') ? date('M_Y') : date('M_Y', strtotime('-1 month'));
$InsurerName = $finalData[0][8] ?? 'Insurer' ;
$cleanInsurerName = str_replace(' ', '_', strtolower($InsurerName));
$fileName = $cleanInsurerName . '_Policies_Details_' . $monthName . '.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Insurer Policies Details for {$monthName}",
$fileName,
true // This will ignore the bold/alignment logic for the last row
);
return; // STOP CI4 rendering anything else
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['debug_msg'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['debug_msg'] = 'Database Error Occurred: ' . $e->getMessage();
$message = 'Database Error Occurred.';
} else {
$ref['debug_msg'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'Something went wrong. Please try again later.';
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
// 4) LowPremium generate the Excel file (Below 5OK)
public function downloadLowPremiumAgentExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
if (empty($managerId)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$ref = ['debug_msg' => $msg];
// $ref = ['debug_msg' => 'Missing required parameters: manager_id, broker_id, and month must be provided.'];
return $this->response->setJSON(['status' => 'error','code' => 400,'data' => [],'message' => 'Missing required parameters','ref' => $ref])->setStatusCode(200);
}
$data = $this->getLowPremiumAgentData($managerId);
if (empty($data)) {
throw new \RuntimeException('No low premium agents found...', 404);
}
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
$header = ['S.No',
'Received Date', 'Assigned To',
'Insurer Name' ,'Insurer Short Name',
'Insured Name', 'Vehicle Number',
'Payment Mode', 'Plan Type',
'Partner Name', 'Partner Code','Partner Status' ,'Policy Number','Issued Date', 'Premium Amount'];
// Calculate and append total
$lastColIndex = count($header) - 1; // Get index of the last column (Premium)
$grandTotal = array_sum(array_column($finalData, $lastColIndex));
$totalRow = array_fill(0, count($header), ''); // Create empty row of same width
$totalRow[$lastColIndex - 1] = 'Total:'; // Put label in 2nd to last
$totalRow[$lastColIndex] = $grandTotal; // Put sum in last
$finalData[] = $totalRow;
// Note: $month variable is undefined, assuming you want current month for filename
$monthName = date('M_Y');
$PartnerName = $finalData[0][9] ?? 'Partner';
$fileName = 'Partners_Low_Premium_Policy_Details.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Partners Low Premium Policy Details",
$fileName,
true // This will ignore the bold/alignment logic for the last row
);
return;
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['debug_msg'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['debug_msg'] = 'Database Error Occurred: ' . $e->getMessage();
$message = 'Database Error Occurred.';
} else {
$ref['debug_msg'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'Something went wrong. Please try again later.';
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
// 5.1) AgentMonthly generate the Excel file
public function downloadAgentMonthlyPoliciesExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
$agentId = $this->request->getGet('agent_id');
// $month = $this->request->getGet('month');
if (empty($managerId) || empty($agentId)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$msg .= empty($agentId) ? "agent_id " : "";
// $msg .= empty($month) ? "month " : "";
$ref = ['debug_msg' => $msg];
return $this->response->setJSON(['status' => 'error','code' => 400,'data' => [],'message' => 'Missing required parameters','ref' => $ref])->setStatusCode(200);
}
// Renamed helper function for consistency: getAgentMonthlyPoliciesData
$data = $this->getMonthlyPoliciesData($managerId, $agentId); // , $month);
if (empty($data)) {
throw new \RuntimeException('No policies found for this agent for the specified month.', 404);
}
$lastIndex = count(reset($data)) - 1;
// usort($data, function($a, $b) use ($lastIndex) {
// return (float)$a[$lastIndex] <=> (float)$b[$lastIndex];
// });
usort($data, function($a, $b) use ($lastIndex) {
return (float)$b[$lastIndex] <=> (float)$a[$lastIndex];
});
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
$header = ['S.No',
'Received Date', 'Assigned To',
'Insurer Name', 'Insurer Short Name',
'Insured Name', 'Vehicle Number',
'Payment Mode', 'Plan Type', 'Issue Date',
'Partner Code', 'Partner Name',
'Policy Number', 'Premium Amount'];
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
// Calculate and append total
$lastColIndex = count($header) - 1; // Get index of the last column (Premium)
$grandTotal = array_sum(array_column($finalData, $lastColIndex));
$totalRow = array_fill(0, count($header), ''); // Create empty row of same width
$totalRow[$lastColIndex - 1] = 'Total:'; // Put label in 2nd to last
$totalRow[$lastColIndex] = $grandTotal; // Put sum in last
$finalData[] = $totalRow;
// $monthName = ($month === 'current') ? date('M_Y') : date('M_Y', strtotime('-1 month'));
$monthName = date('M Y') ;
$PartnerName = $finalData[0][11] ?? 'Partner';
$cleanPartnerName = str_replace(' ', '_', strtolower($PartnerName));
$fileName = $cleanPartnerName . '_Policies_Details_' . $monthName . '.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Partner Policies Details for {$monthName}",
$fileName,
true // This will ignore the bold/alignment logic for the last row
);
return;
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['message'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['message'] = 'Database Error Occurred.';
$message = 'Database Error Occurred.';
} else {
$ref['message'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'An unexpected error occurred: ' . $e->getMessage();
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
// 5.2) Top 50 Agent the Excel file
public function downloadT50AgentPoliciesExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
if (empty($managerId)) {
$msg = "Missing: manager_id";
$ref = ['debug_msg' => $msg];
return $this->response->setJSON(['status' => 'error', 'code' => 400, 'data' => [], 'message' => 'Missing required parameters', 'ref' => $ref])->setStatusCode(200);
}
// Renamed helper function for consistency: getAgentMonthlyPoliciesData
$data = $this->getMonthlyPolicyCountandPremiumAmount($managerId);
$header = ['S.No', 'Partner Code', 'Partner Name', 'Policy Count', 'Premium Amount'];
if (empty($data)) {
throw new \RuntimeException('No policies found.', 404);
}
$lastIndex = count(reset($data)) - 1;
// usort($data, function($a, $b) use ($lastIndex) {
// return (float)$a[$lastIndex] <=> (float)$b[$lastIndex];
// });
usort($data, function($a, $b) use ($lastIndex) {
return (float)$b[$lastIndex] <=> (float)$a[$lastIndex];
});
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
// Calculate and append total
$lastColIndex = count($header) - 1; // Get index of the last column (Premium)
$grandTotal = array_sum(array_column($finalData, $lastColIndex));
$totalRow = array_fill(0, count($header), ''); // Create empty row of same width
$totalRow[$lastColIndex - 1] = 'Total:'; // Put label in 2nd to last
$totalRow[$lastColIndex] = $grandTotal; // Put sum in last
$finalData[] = $totalRow; // Add the total row to the final set
$monthName = date('M Y') ;
$fileName = 'Top_50_Partner_Policies_Details_' . $monthName . '.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Top 50 Partner Policies Details - Monthly Report ".$monthName,
$fileName,
true // This will ignore the bold/alignment logic for the last row
);
return;
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['message'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['message'] = 'Database Error Occurred.';
$message = 'Database Error Occurred.';
} else {
$ref['message'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'An unexpected error occurred: ' . $e->getMessage();
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
// 6) Agents who all are Without Policies generate the Excel file (last 10 days no Policies created by the agents)
public function downloadAgentsWithoutPoliciesExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
if (empty($managerId)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$ref = ['debug_msg' => $msg];
// $ref = ['debug_msg' => 'Missing required parameters: manager_id, broker_id, and month must be provided.'];
return $this->response->setJSON(['status' => 'error','code' => 400,'data' => [],'message' => 'Missing required parameters','ref' => $ref])->setStatusCode(200);
}
$data = $this->getAgentsWithoutPoliciesData($managerId);
if (empty($data)) {
throw new \RuntimeException('No Partners without policies found.', 404);
}
$header = ['S.No','Partner Code','Partner Name', 'Email', 'Mobile'];
$finalData = [];
$serialNo = 1; // Start counter at 1
// 2. Loop through and prepend the serial number
foreach ($data as $row) {
// We create a new array for each row
$finalData[] = [
$serialNo++,
$row['agent_code'],
$row['agent_name'],
$row['email'],
$row['mobile']
];
}
// End Date: Today
$endDate = date('Ymd');
// Start Date: 9 days ago (10th day is today)
$startDate = date('Ymd', strtotime('-9 days'));
// --- Filename Generation ---
$fileName = 'Partners_Without_Policies_' . $startDate . '_to_' . $endDate . '.xlsx';
// Example output: Agents_Without_Policies_20251206_to_20251215.xlsx
// --- CENTRALIZED CALL ---
$this->streamExcelFile(
$header,
$finalData,
"Partners Without Policies (Last 10 Days)",
$fileName,
false // This will ignore the bold/alignment logic for the last row
);
return;
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['message'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['message'] = 'Database Error Occurred.';
} else {
$ref['message'] = 'An unexpected error occurred: ' . $e->getMessage();
}
return $this->respond([
'status' => 'error',
'code' => $e->getCode() ?: 500,
'data' => [],
'ref' => $ref
], 200);
}
}
// 7 Function to generate the Excel file
public function downloadStaffAndProductPoliciesExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
$executiveId = $this->request->getGet('sales_executive_id');
$vehicleType = $this->request->getGet('vehicle_type');
$month = $this->request->getGet('month');
// --- ADDED VALIDATION (Simplified logic for clarity) ---
if (empty($managerId) || empty($executiveId) || empty($vehicleType) || empty($month)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$msg .= empty($executiveId) ? "sales_executive_id " : "";
$msg .= empty($vehicleType) ? "vehicle_type " : "";
$msg .= empty($month) ? "month " : "";
$ref = ['debug_msg' => $msg];
// $ref = ['debug_msg' => 'Missing required parameters: manager_id, broker_id, and month must be provided.'];
return $this->response->setJSON(['status' => 'error','code' => 400,'data' => [],'message' => 'Missing required parameters','ref' => $ref])->setStatusCode(200);
}
$data = $this->getStaffAndProductPoliciesExcel($managerId, $executiveId,$vehicleType, $month);
if (empty($data)) {
throw new \RuntimeException('No policies found for the specified month.', 404);
}
$lastIndex = count(reset($data)) - 1;
// usort($data, function($a, $b) use ($lastIndex) {
// return (float)$a[$lastIndex] <=> (float)$b[$lastIndex];
// });
usort($data, function($a, $b) use ($lastIndex) {
return (float)$b[$lastIndex] <=> (float)$a[$lastIndex];
});
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
$executiveName = $finalData[0][12] ?? 'Sales Executive';
$vehicleType = $finalData[0][13] ?? 'Vehicle Type';
// Define column headers
$header = ['S.No',
'Received Date', 'Assigned To',
'Partner Name' , 'Partner Code',
'Insurer Name' ,'Insurer Short Name',
'Insured Name', 'Vehicle Number',
'Payment Mode', 'Plan Type',
'Sales Executive Name', 'Vehicle Type', 'Policy Number','Issued Date', 'Premium Amount'];
// --- 1. MODIFIED LOGIC: Throw RuntimeException if no data ---
// Calculate and append total
$lastColIndex = count($header) - 1; // Get index of the last column (Premium)
$grandTotal = array_sum(array_column($finalData, $lastColIndex));
$totalRow = array_fill(0, count($header), ''); // Create empty row of same width
$totalRow[$lastColIndex - 1] = 'Total:'; // Put label in 2nd to last
$totalRow[$lastColIndex] = $grandTotal; // Put sum in last
$finalData[] = $totalRow;
$monthName = ($month === 'current') ? date('M_Y') : date('M_Y', strtotime('-1 month'));
$cleanExecutiveName = str_replace(' ', '_', strtolower($executiveName));
$cleanVehicleType = str_replace(' ', '_', strtolower($vehicleType));
$fileName = $cleanExecutiveName . '_' . $cleanVehicleType . '_Policies_Details_' . $monthName . '.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Staff And Product Policies Details for {$monthName}",
$fileName,
true // This will ignore the bold/alignment logic for the last row
);
return; // STOP CI4 rendering anything else
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['message'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['message'] = 'Database Error Occurred.';
$message = 'Database Error Occurred.';
} else {
$ref['message'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'An unexpected error occurred: ' . $e->getMessage();
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
// 8 ZIP inside 3 Excel
public function downloadExcelAsZIP($managerId = null)
{
// Ensure managerId is retrieved correctly if not passed as argument
$managerId = $managerId ?? $this->request->getGet('manager_id');
if (empty($managerId)) {
return $this->response->setJSON([
'status' => 'error',
'code' => 400,
'message' => 'Missing required parameter: manager_id'
]);
}
// 1. Fetch Data First
$monthlyData = $this->getMonthlyPoliciesData($managerId, null);
$lowPremiumData = $this->getLowPremiumAgentData($managerId);
$inactiveData = $this->getAgentsWithoutPoliciesData($managerId);
// 2. Add Total Rows where needed (Premium is usually the last index)
if (!empty($monthlyData)) {
$totalMonthly = array_sum(array_column($monthlyData, 12)); // Index 12 is 'premium_amount'
$monthlyData[] = ['', '', '', '', '', '', '', '', '', '', '', 'Total:', $totalMonthly];
}
if (!empty($lowPremiumData)) {
$totalLow = array_sum(array_column($lowPremiumData, 13)); // Index 13 is 'premium_amount'
$lowPremiumData[] = ['', '', '', '', '', '', '', '', '', '', '', '', 'Total:', $totalLow];
}
// 3. Prepare Report Configuration
$reports = [
'Monthly_Policies_Details.xlsx' => ['data' => $monthlyData, 'header' => ['Received Date', 'Assigned To', 'Insurer', 'Short Name', 'Insured', 'Reg No', 'Mode', 'Plan', 'Agent', 'Code', 'Policy #', 'Issued Date', 'Premium'], 'title' => "Monthly Report",'showTotal' => true],
'Low_Premium_Policies_Details.xlsx' => ['data' => $lowPremiumData, 'header' => ['Received Date', 'Assigned To', 'Insurer', 'Short Name', 'Insured', 'Reg No', 'Mode', 'Plan', 'Agent', 'Code', 'Status', 'Policy #', 'Issued Date', 'Premium'], 'title' => "Low Premium Report",'showTotal' => true],
'Partners_Without_Policies_Details.xlsx' => ['data' => $inactiveData, 'header' => ['Partner Name', 'Partner Code', 'Email', 'Mobile'], 'title' => "Inactive Agents",'showTotal' => false]
];
// 4. Initialize Zip
$zipFileName = 'Agent_Reports_' . date('Y-m-d_H-i') . '.zip';
$zipFilePath = tempnam(sys_get_temp_dir(), 'zip');
$zip = new \ZipArchive();
if ($zip->open($zipFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === TRUE) {
foreach ($reports as $name => $config) {
$excelContent = $this->generateExcelBinary($config['header'], $config['data'], $config['title'],$config['showTotal']);
$zip->addFromString($name, $excelContent);
}
$zip->close();
}
// 5. Direct Download
// Instead of creating a file on disk, we can send the ZIP data directly.
// This avoids the "deleteFileAfterSend" error entirely.
$zipData = file_get_contents($zipFilePath); // Read the zip file into a variable
unlink($zipFilePath); // Delete the temp file immediately
return $this->response->download($zipFileName, $zipData);
}
// GENERATE ZIP
private function generateExcelBinary(array $header, array $data, string $title, bool $showTotal = true): string
{
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 1. Calculate dimensions
$columnCount = count($header);
$lastCol = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($columnCount);
$rowCount = count($data);
// 2. Title Styling
$sheet->mergeCells("A1:{$lastCol}1");
$sheet->setCellValue('A1', $title);
$sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14);
$sheet->getStyle('A1')->getAlignment()->setHorizontal('center');
// 3. Headers (Row 2)
$sheet->fromArray($header, NULL, 'A2');
$sheet->getStyle("A2:{$lastCol}2")->getFont()->setBold(true);
$sheet->getStyle("A2:{$lastCol}2")->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('F2F2F2'); // Light gray background
// 4. Data (Starting Row 3)
$sheet->fromArray($data, NULL, 'A3');
// 5. Bold the Total Row (The last row of data)
if ($rowCount > 0 && $showTotal === true) {
$totalRowNumber = $rowCount + 2; // Row 1 (Title) + Row 2 (Header) + Data Rows
$sheet->getStyle("A{$totalRowNumber}:{$lastCol}{$totalRowNumber}")->getFont()->setBold(true);
// Optional: Add a top border to the total row to make it look professional
// $sheet->getStyle("A{$totalRowNumber}:{$lastCol}{$totalRowNumber}")->getBorders()->getTop()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
}
// 6. Auto-size Columns
// Using column index to avoid issues with double-letter columns (e.g., AA, AB)
for ($i = 1; $i <= $columnCount; $i++) {
$colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($i);
$sheet->getColumnDimension($colLetter)->setAutoSize(true);
}
// 7. Capture Binary Output
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
// Use Output Buffering to grab the file content as a string
ob_start();
$writer->save('php://output');
$excelBinary = ob_get_clean();
return $excelBinary;
}
public function downloadStaffPendingSummaryExcel()
{
try{
$managerId = $this->request->getGet('manager_id');
// --- ADDED VALIDATION (Simplified logic for clarity) ---
if (empty($managerId)) {
$msg = "Missing: manager_id";
$ref = ['debug_msg' => $msg];
return $this->response->setJSON(['status' => 'error', 'code' => 400, 'data' => [], 'message' => 'Missing required parameters', 'ref' => $ref])->setStatusCode(200);
}
$data = $this->getStaffPendingSummaryExcel($managerId);
if (empty($data)) {
throw new \RuntimeException('No summary found.', 404);
}
// Define column headers
$header = ['S.No', 'Staff Name', 'Today Assigned', 'Pending', 'In Progress', 'Completed', 'Previous Pending'];
// Initialize totals
$sums = array_fill(2, 5, 0); // Start from index 2, cover 5 columns
$finalData = [];
$serialNo = 1;
// Process data and calculate sums
foreach ($data as $row) {
// Convert row to indexed array values to ensure merge works correctly
$rowData = array_values($row);
// Add Serial Number
$finalData[] = array_merge([$serialNo++], $rowData);
// Summing columns index 2 to 6
for ($i = 2; $i <= 6; $i++) {
// Use index $i-1 because $row doesn't have S.No yet, but $rowData does
$sums[$i] += (int)($rowData[$i - 1] ?? 0);
}
}
// Create the Total Row
$totalRow = array_fill(0, count($header), ''); // Create empty row
$totalRow[1] = 'Total:'; // Label under "Staff Name"
foreach ($sums as $index => $sumValue) {
// This ensures that even if the sum is 0, it puts the digit '0' in the cell
$totalRow[$index] = $sumValue;
}
// Fill sums into the total row
foreach ($sums as $index => $sumValue) {
$totalRow[$index] = $sumValue;
}
// Add to final data
$finalData[] = $totalRow;
$fileName = 'Staff_Level_Pending_Summary.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
"Staff Level Pending Summary",
$fileName,
true
);
return; // STOP CI4 rendering anything else
} catch (\Throwable $e) {
// ... (Your error handling remains the same) ...
$ref = [];
// Case 1: No Data Found (Soft Success JSON)
if ($e instanceof \RuntimeException && $e->getCode() === 404) {
$ref['message'] = 'No Data Found';
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [],
'message' => 'No Data Found',
'ref' => $ref
], 200);
}
// Case 2: Database or Other Error (Error JSON)
$isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
|| $e instanceof \mysqli_sql_exception
|| $e instanceof \PDOException;
if ($isDbError) {
$ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
$ref['message'] = 'Database Error Occurred.';
$message = 'Database Error Occurred.';
} else {
$ref['message'] = 'An unexpected error occurred: ' . $e->getMessage();
$message = 'An unexpected error occurred: ' . $e->getMessage();
}
return $this->respond([
'status' => 'error',
'code' => 500,
'data' => [],
'message'=> $message,
'ref' => $ref
], 200);
}
}
public function downloadStaffPendingSummaryExcelByID()
{
// try{
$managerId = $this->request->getGet('manager_id');
$staffId = $this->request->getGet('staff_id');
$status = $this->request->getGet('status');
// --- ADDED VALIDATION (Simplified logic for clarity) ---
if (empty($managerId) || empty($staffId) || empty($status)) {
$msg = "Missing: ";
$msg .= empty($managerId) ? "manager_id " : "";
$msg .= empty($staffId) ? "staff_id " : "";
$msg .= empty($status) ? "status " : "";
$ref = ['debug_msg' => $msg];
// $ref = ['debug_msg' => 'Missing required parameters: manager_id, broker_id, and month must be provided.'];
return $this->response->setJSON(['status' => 'error','code' => 400,'data' => [],'message' => 'Missing required parameters','ref' => $ref])->setStatusCode(200);
}
$data = $this->getStaffPendingSummaryExcelByID($managerId,$staffId,$status);
if (empty($data)) {
throw new \RuntimeException('No summary found.', 404);
}
// Define column headers
$header = ['S.No', 'Staff Name', 'REG Number','Received Date'];
// Initialize totals
// Initialize totals
$lastIndex = count(reset($data)) - 1;
// usort($data, function($a, $b) use ($lastIndex) {
// return (float)$a[$lastIndex] <=> (float)$b[$lastIndex];
// });
usort($data, function($a, $b) use ($lastIndex) {
return (float)$b[$lastIndex] <=> (float)$a[$lastIndex];
});
$finalData = [];
$serialNo = 1;
foreach ($data as $row) {
$finalData[] = array_merge([$serialNo++], $row);
}
$staffName = $finalData[0][1] ?? 'Staff';
$fileName = $staffName.'_'.$status.'_Summary.xlsx';
// Calculate and append total
$cleanStaffName = str_replace(' ', '_', strtolower($staffName));
$cleanStatus = ucwords(str_replace('_', ' ', strtolower($status)));
$fileName = $cleanStaffName . '_' . $cleanStatus . '_Summary.xlsx';
// --- CALL CENTRALIZED FUNCTION ---
$this->streamExcelFile(
$header,
$finalData,
$cleanStaffName ." ". $cleanStatus." Summary",
$fileName,
false
);
return; // STOP CI4 rendering anything else
// } catch (\Throwable $e) {
// // ... (Your error handling remains the same) ...
// $ref = [];
// // Case 1: No Data Found (Soft Success JSON)
// if ($e instanceof \RuntimeException && $e->getCode() === 404) {
// $ref['message'] = 'No Data Found';
// return $this->respond([
// 'status' => 'success',
// 'code' => 200,
// 'data' => [],
// 'message' => 'No Data Found',
// 'ref' => $ref
// ], 200);
// }
// // Case 2: Database or Other Error (Error JSON)
// $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException
// || $e instanceof \mysqli_sql_exception
// || $e instanceof \PDOException;
// if ($isDbError) {
// $ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine();
// $ref['message'] = 'Database Error Occurred.';
// $message = 'Database Error Occurred.';
// } else {
// $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage();
// $message = 'An unexpected error occurred: ' . $e->getMessage();
// }
// return $this->respond([
// 'status' => 'error',
// 'code' => 500,
// 'data' => [],
// 'message'=> $message,
// 'ref' => $ref
// ], 200);
// }
}
/**
* Executes the detailed policy query and extracts the data for the spreadsheet.
* @param string $managerId
* @param int $brokerId
* @param string $month ('current' or 'previous')
* @return array
*/
private function getBrokerPoliciesData($managerId, $brokerId, $month): array
{
// --- Correction 1: Initialize Database Connection ---
$data = [];
try {
$builder = $this->db->table('partner_policy pp');
// Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details
$builder->select('
DATE_FORMAT(pe.created_on, "%d-%m-%Y %h:%i %p") AS received_date,
S.name as assigned_to_name,
A.name as agent_name, A.agent_code,
I.name as insurer_name,I.short_name as insurer_short_name,
pe.name as insured_name,
pe.reg_no,
pm.value as payment_mode_value,
ipti.insurance_plan_type,
pb.name AS broker_name, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,CONCAT("\t", pp.policy_number) AS policy_number,
pp.premium_amount');
$builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left');
$builder->join('partner_brokers pb', 'pb.id = pe.broker_id', 'left');
$builder->join('partner_quotation Q', 'Q.enquiry_id = pe.id', 'left');
$builder->join('partner_payment_mode_master pm', 'pm.id = Q.payment_mode_id', 'left');
$builder->join('partner_agent A', 'A.id = pe.agent_id', 'left');
$builder->join('partner_insurance_plan_type_master ipti', 'ipti.id = Q.insurance_plan_type_id', 'left');
$builder->join('insurers I', 'I.id = Q.insurer_id', 'left');
$builder->join('partner_staff S', 'S.id = pe.assigned_to', 'left');
// --- Correction 2: Use Robust Date Range Filtering ---
if ($month === "current") {
// WHERE issued_date >= start_of_current_month AND issued_date < start_of_next_month
$builder->where("pp.issued_date >= DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
}
else if ($month === "previous") {
// WHERE issued_date >= start_of_previous_month AND issued_date < start_of_current_month
$builder->where("pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
}
// Broker and Manager Filter
$builder->where('pp.manager_id', $managerId);
$builder->where('pb.id', $brokerId);
$builder->orderBy('pp.issued_date', 'DESC');
$results = $builder->get()->getResultArray();
// Restructure data for PhpSpreadsheet (2D array of values)
foreach ($results as $row) {
$data[] = array_values($row);
}
} catch (DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
// Re-throw the exception so it is caught by the main function's catch block
throw $e;
}
return $data;
}
/**
* Executes the detailed policy query and extracts the data for the spreadsheet.
* @param string $managerId
* @param string $vehicleType
* @param string $month ('current' or 'previous')
* @return array
*/
private function getProductPoliciesData($managerId, $vehicleType, $month): array
{
// --- Correction 1: Initialize Database Connection ---
$data = [];
try {
$builder = $this->db->table('partner_policy pp');
// Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details
$builder->select('
DATE_FORMAT(pe.created_on, "%d-%m-%Y %h:%i %p") AS received_date,
S.name as assigned_to_name,
A.name as agent_name, A.agent_code,
I.name as insurer_name,I.short_name as insurer_short_name,
pe.name as insured_name,
pe.reg_no,
pm.value as payment_mode_value,
ipti.insurance_plan_type,
pp.vehicle_type, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,CONCAT("\t", pp.policy_number) AS policy_number,
pp.premium_amount');
$builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left');
$builder->join('partner_quotation Q', 'Q.enquiry_id = pe.id', 'left');
$builder->join('partner_payment_mode_master pm', 'pm.id = Q.payment_mode_id', 'left');
$builder->join('partner_agent A', 'A.id = pe.agent_id', 'left');
$builder->join('partner_insurance_plan_type_master ipti', 'ipti.id = Q.insurance_plan_type_id', 'left');
$builder->join('insurers I', 'I.id = Q.insurer_id', 'left');
$builder->join('partner_staff S', 'S.id = pe.assigned_to', 'left');
// --- Correction 2: Use Robust Date Range Filtering ---
if ($month === "current") {
// WHERE issued_date >= start_of_current_month AND issued_date < start_of_next_month
$builder->where("pp.issued_date >= DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
}
else if ($month === "previous") {
// WHERE issued_date >= start_of_previous_month AND issued_date < start_of_current_month
$builder->where("pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
}
// Broker and Manager Filter
$builder->where('pp.manager_id', $managerId);
$builder->where('pp.vehicle_type', $vehicleType);
$results = $builder->get()->getResultArray();
// Restructure data for PhpSpreadsheet (2D array of values)
foreach ($results as $row) {
$data[] = array_values($row);
}
} catch (DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
// Re-throw the exception so it is caught by the main function's catch block
throw $e;
}
return $data;
}
/**
* Executes the detailed policy query and extracts the data for the spreadsheet.
* @param string $managerId
* @param int $insurerId
* @param string $month ('current' or 'previous')
* @return array
*/
private function getInsurerPoliciesData($managerId, $insurerId, $month): array
{
// --- Correction 1: Initialize Database Connection ---
$data = [];
try {
$builder = $this->db->table('partner_policy pp');
// Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details
$builder->select('
DATE_FORMAT(pe.created_on, "%d-%m-%Y %h:%i %p") AS received_date,
S.name as assigned_to_name,
A.name as agent_name, A.agent_code,
pe.reg_no,
pm.value as payment_mode_value,
ipti.insurance_plan_type,
i.name AS insurer_name,i.short_name,pp.insured_name, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,CONCAT("\t", pp.policy_number) AS policy_number, pp.premium_amount');
$builder->join('partner_quotation pq', 'pq.id = pp.quotation_id', 'left');
$builder->join('insurers i', 'i.id = pq.insurer_id', 'left');
$builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left');
$builder->join('partner_payment_mode_master pm', 'pm.id = pq.payment_mode_id', 'left');
$builder->join('partner_agent A', 'A.id = pe.agent_id', 'left');
$builder->join('partner_insurance_plan_type_master ipti', 'ipti.id = pq.insurance_plan_type_id', 'left');
$builder->join('partner_staff S', 'S.id = pe.assigned_to', 'left');
// --- Correction 2: Use Robust Date Range Filtering ---
if ($month === "current") {
// WHERE issued_date >= start_of_current_month AND issued_date < start_of_next_month
$builder->where("pp.issued_date >= DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
}
else if ($month === "previous") {
// WHERE issued_date >= start_of_previous_month AND issued_date < start_of_current_month
$builder->where("pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
}
// Broker and Manager Filter
$builder->where('pp.manager_id', $managerId);
$builder->where('i.id', $insurerId);
$builder->where('i.is_active',1);
$builder->orderBy('pp.issued_date', 'DESC');
// print_r($builder->getCompiledSelect());die;
$results = $builder->get()->getResultArray();
// Restructure data for PhpSpreadsheet (2D array of values)
foreach ($results as $row) {
$data[] = array_values($row);
}
} catch (DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
// Re-throw the exception so it is caught by the main function's catch block
throw $e;
}
return $data;
}
/**
* Executes the detailed policy query and extracts the data for the spreadsheet.
* @param string $managerId
* @param int $executiveId
* @param string $vehicleType
* @param string $month ('current' or 'previous')
* @return array
*/
private function getStaffAndProductPoliciesExcel($managerId, $executiveId,$vehicleType, $month): array
{
// --- Correction 1: Initialize Database Connection ---
$data = [];
try {
$builder = $this->db->table('partner_policy pp');
$builder->select('
DATE_FORMAT(pe.created_on, "%d-%m-%Y %h:%i %p") AS received_date,
S.name as assigned_to_name,
pa.name as agent_name, pa.agent_code,
I.name as insurer_name,I.short_name as insurer_short_name,
pe.name as insured_name,
pe.reg_no,
pm.value as payment_mode_value,
ipti.insurance_plan_type,
pse.name as sales_executive_name, pp.vehicle_type AS vechile_type,CONCAT("\t", pp.policy_number) AS policy_number,DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.premium_amount');
$builder->join('partner_agent pa', 'pa.id = pp.agent_id', 'left');
$builder->join('partner_sales_executive pse', 'pse.id = pa.sales_executive_id', 'left');
$builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left');
$builder->join('partner_brokers pb', 'pb.id = pe.broker_id', 'left');
$builder->join('partner_quotation Q', 'Q.enquiry_id = pe.id', 'left');
$builder->join('partner_payment_mode_master pm', 'pm.id = Q.payment_mode_id', 'left');
$builder->join('partner_insurance_plan_type_master ipti', 'ipti.id = Q.insurance_plan_type_id', 'left');
$builder->join('insurers I', 'I.id = Q.insurer_id', 'left');
$builder->join('partner_staff S', 'S.id = pe.assigned_to', 'left');
// --- Correction 2: Use Robust Date Range Filtering ---
if ($month === "current") {
// WHERE issued_date >= start_of_current_month AND issued_date < start_of_next_month
$builder->where("pp.issued_date >= DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
}
else if ($month === "previous") {
// WHERE issued_date >= start_of_previous_month AND issued_date < start_of_current_month
$builder->where("pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
}
// Broker and Manager Filter
$builder->where('pp.manager_id', $managerId);
$builder->where('pa.sales_executive_id', $executiveId);
$builder->where('pa.sales_executive_id IS NOT NULL');
$builder->where('pse.is_active', 1);
$builder->where('pp.vehicle_type', $vehicleType);
$builder->orderBy('pp.issued_date', 'DESC');
$results = $builder->get()->getResultArray();
// Restructure data for PhpSpreadsheet (2D array of values)
foreach ($results as $row) {
$data[] = array_values($row);
}
} catch (DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
// Re-throw the exception so it is caught by the main function's catch block
throw $e;
}
return $data;
}
/**
* Executes the detailed policy query and extracts the data for the spreadsheet.
* @param string $managerId
* @param int $AgentId
* @param string $month ('current' or 'previous')
* @return array
*/
private function getMonthlyPoliciesData($managerId, $AgentId): array
{
$data = [];
try {
$builder = $this->db->table('partner_policy pp');
// 1. Properly aligned Select Statement
$builder->select('
DATE_FORMAT(pe.created_on, "%d-%m-%Y %h:%i %p") AS received_date,
S.name AS assigned_to_name,
I.name AS insurer_name,
I.short_name AS insurer_short_name,
pe.name AS insured_name,
pe.reg_no,
pm.value AS payment_mode_value,
ipti.insurance_plan_type,
DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,
pa.agent_code AS agent_code,
pa.name AS agent_name,
CONCAT("\t", pp.policy_number) AS policy_number,
pp.premium_amount
');
// 2. Joins
$builder->join('partner_agent pa', 'pp.agent_id = pa.id', 'inner');
$builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left');
$builder->join('partner_brokers pb', 'pb.id = pe.broker_id', 'left');
$builder->join('partner_quotation Q', 'Q.enquiry_id = pe.id', 'left');
$builder->join('partner_payment_mode_master pm', 'pm.id = Q.payment_mode_id', 'left');
$builder->join('partner_insurance_plan_type_master ipti', 'ipti.id = Q.insurance_plan_type_id', 'left');
$builder->join('insurers I', 'I.id = Q.insurer_id', 'left');
$builder->join('partner_staff S', 'S.id = pe.assigned_to', 'left');
// 3. Where Conditions
$builder->where('pp.manager_id', $managerId);
$builder->where('pp.policy_number IS NOT NULL');
$builder->where('pa.id', $AgentId);
// Current Month Date Range Filter
// if ($month === "current") {
// // WHERE issued_date >= start_of_current_month AND issued_date < start_of_next_month
$builder->where("pp.issued_date >= DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
$builder->where("pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
// }
// else if ($month === "previous") {
// // WHERE issued_date >= start_of_previous_month AND issued_date < start_of_current_month
// $builder->where("pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01')", NULL, FALSE);
// $builder->where("pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01')", NULL, FALSE);
// }
// 4. Order and Limit
$builder->orderBy('pp.issued_date', 'DESC');
// 5. Fetch and Restructure
$results = $builder->get()->getResultArray();
foreach ($results as $row) {
// Using array_values ensures we return a indexed 2D array for PhpSpreadsheet
$data[] = array_values($row);
}
} catch (\CodeIgniter\Database\Exceptions\DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
throw $e;
}
return $data;
}
public function getMonthlyPolicyCountandPremiumAmount($manager_id){
$data = [];
try {
$customDate = date('Y-m-d');
$builder = $this->db->table('partner_policy pp');
$builder->select("
pa.agent_code,
pa.name AS agent_name,
COUNT(pp.policy_number) AS policy_count,
SUM(pp.premium_amount) AS total_premium_amount
");
$builder->join('partner_agent pa', 'pp.agent_id = pa.id', 'inner');
$builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left');
$builder->where("MONTH(pp.issued_date) = MONTH('$customDate')", null, false);
$builder->where("YEAR(pp.issued_date) = YEAR('$customDate')", null, false);
$builder->where('pp.manager_id',$manager_id);
$builder->groupBy(['pa.id']);
$builder->orderBy('policy_count', 'DESC');
$builder->limit(50);
$results = $builder->get()->getResultArray();
// Restructure data for PhpSpreadsheet (2D array of values)
foreach ($results as $row) {
$data[] = array_values($row);
}
} catch (DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
// Re-throw the exception so it is caught by the main function's catch block
throw $e;
}
return $data;
}
/**
* Executes the detailed policy query and extracts the data for the spreadsheet.
* @param string $managerId
* @return array
*/
private function getAgentsWithoutPoliciesData($managerId): array
{
$data = [];
try {
$builder = $this->db->table('partner_agent pa');
$builder->select('pa.agent_code,pa.name AS agent_name, pa.email, pa.mobile');
$builder->join(
'partner_policy pp',
'pa.id = pp.agent_id AND pp.issued_date >= DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 10 DAY)',
'left'
);
$builder->where('pa.manager_id', $managerId);
$builder->where('pp.id IS NULL', null, false);
$builder->orderBy('pa.name', 'ASC');
$results = $builder->get()->getResultArray();
foreach ($results as $row) {
$data[] = array_values($row);
}
} catch (\CodeIgniter\Database\Exceptions\DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
throw $e;
}
return $data;
}
/**
* Executes the detailed policy query and extracts the data for the spreadsheet.
* @param string $managerId
* @return array
*/
private function getLowPremiumAgentData($managerId): array
{
// --- Correction 1: Initialize Database Connection ---
$data = [];
try {
$builder = $this->db->table('partner_policy pp');
$builder->select("
DATE_FORMAT(pe.created_on, '%d-%m-%Y %h:%i %p') AS received_date,
S.name as assigned_to_name,
I.name as insurer_name,I.short_name as insurer_short_name,
pe.name as insured_name,
pe.reg_no,
pm.value as payment_mode_value,
ipti.insurance_plan_type,
pa.name AS agent_name,
pa.agent_code,
CASE
WHEN pa.is_active = 1 THEN 'Active Partner'
ELSE 'Inactive Partner'
END AS agent_status,
CONCAT('\t', pp.policy_number) AS policy_number,
DATE_FORMAT(pp.issued_date, '%d-%m-%Y') AS issued_date,
pp.premium_amount
");
$builder->join('partner_agent pa', 'pa.id = pp.agent_id', 'inner');
$builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left');
$builder->join('partner_quotation Q', 'Q.enquiry_id = pe.id', 'left');
$builder->join('partner_payment_mode_master pm', 'pm.id = Q.payment_mode_id', 'left');
$builder->join('partner_insurance_plan_type_master ipti', 'ipti.id = Q.insurance_plan_type_id', 'left');
$builder->join('insurers I', 'I.id = Q.insurer_id', 'left');
$builder->join('partner_staff S', 'S.id = pe.assigned_to', 'left');
// WHERE conditions
$builder->where('pp.manager_id', $managerId);
// $builder->where('pa.id', $agentId);
$builder->where('pp.premium_amount <', 50000);
$builder->orderBy('pp.issued_date', 'DESC');
$results = $builder->get()->getResultArray();
// Restructure data for PhpSpreadsheet (2D array of values)
foreach ($results as $row) {
$data[] = array_values($row);
}
} catch (DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
// Re-throw the exception so it is caught by the main function's catch block
throw $e;
}
return $data;
}
private function getStaffPendingSummaryExcel($managerId): array
{
$data = [];
try {
$results = $this->db->table('partner_enquiry pe')
->select("
ps.name AS staff_name,
COUNT(pe.id) AS total_assigned,
SUM(CASE WHEN DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_assigned,
SUM(CASE WHEN pe.enquiry_status = 'Assigned' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_pending,
SUM(CASE WHEN pe.enquiry_status = 'In progress' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_in_progress,
SUM(CASE WHEN pe.enquiry_status = 'Completed' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_completed,
SUM(CASE WHEN pe.enquiry_status != 'Completed' THEN 1 ELSE 0 END) AS previous_total_pending,
")
->join('partner_staff ps', 'ps.id = pe.assigned_to', 'left')
->where('pe.manager_id', $managerId)
->where('pe.is_active', 1)
->where('pe.assigned_to IS NOT NULL')
->where('pe.assigned_to !=', 0)
->groupBy('pe.assigned_to')
->orderBy('ps.name', 'ASC')
->get()
->getResultArray();
// Restructure data for PhpSpreadsheet (2D array of values)
foreach ($results as $row) {
unset($row['total_assigned']);
$data[] = array_values($row);
}
} catch (DatabaseException $e) {
log_message('error', 'Database Error during Excel fetch: ' . $e->getMessage());
// Re-throw the exception so it is caught by the main function's catch block
throw $e;
}
return $data;
}
private function getStaffPendingSummaryExcelByID($managerId, $staffId, $status): array
{
try {
$builder = $this->db->table('partner_enquiry pe');
// Note: Change 'received_date' back to 'created_on' or update the loop below
$builder->select("
ps.name AS staff_name,
CONCAT('\t', pe.reg_no) AS reg_no,
DATE_FORMAT(pe.created_on, '%d-%m-%Y %h:%i %p') AS created_on
", false);
$builder->join('partner_staff ps', 'ps.id = pe.assigned_to', 'left');
$builder->where('pe.manager_id', $managerId);
$builder->where('pe.assigned_to', $staffId);
$builder->where('pe.is_active', 1);
// Date boundaries
$todayStart = date('Y-m-d 00:00:00');
$todayEnd = date('Y-m-d 23:59:59');
switch ($status) {
case 'today_assigned':
$builder->where('pe.created_on >=', $todayStart);
$builder->where('pe.created_on <=', $todayEnd);
break;
case 'today_pending':
$builder->where('pe.enquiry_status', 'Assigned');
$builder->where('pe.created_on >=', $todayStart);
$builder->where('pe.created_on <=', $todayEnd);
break;
case 'today_in_progress':
$builder->where('pe.enquiry_status', 'In progress');
$builder->where('pe.created_on >=', $todayStart);
$builder->where('pe.created_on <=', $todayEnd);
break;
case 'today_completed':
$builder->where('pe.enquiry_status', 'Completed');
$builder->where('pe.created_on >=', $todayStart);
$builder->where('pe.created_on <=', $todayEnd);
break;
case 'previous_total_pending':
// "Previous Pending" usually means anything NOT completed from BEFORE today
$builder->where('pe.enquiry_status !=', 'Completed');
$builder->where('pe.created_on <', $todayStart);
break;
}
$results = $builder->get()->getResultArray();
$data = [];
foreach ($results as $row) {
$data[] = [
$row['staff_name'] ?? 'N/A',
$row['reg_no'] ?? '-',
$row['created_on'] ?? '-' // Matches the alias in select
];
}
return $data;
} catch (\Exception $e) {
log_message('error', 'Excel Fetch Error: ' . $e->getMessage());
throw $e;
}
}
}