diff --git a/app/Config/Routes.php b/app/Config/Routes.php index becdca8..1b6acd4 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -135,6 +135,11 @@ $routes->group('api', ['filter' => 'appSignature'], function ($routes) { $routes->get("dashboard/partnerDashboard", "DashboardController::partnerDashboard"); $routes->get("dashboard/productivityDashboard", "DashboardController::productivityDashboard"); + $routes->get("dashboard/downloadBrokerPoliciesExcel", "DashboardController::downloadBrokerPoliciesExcel"); + $routes->get("dashboard/downloadInsurerPoliciesExcel", "DashboardController::downloadInsurerPoliciesExcel"); + $routes->get("dashboard/downloadProductPoliciesExcel", "DashboardController::downloadProductPoliciesExcel"); + + //invoice $routes->get('invoice/list', 'InvoiceController::invoiceList'); $routes->get('invoice/details', 'InvoiceController::findInvoiceWithItems'); @@ -153,10 +158,20 @@ $routes->group('api', ['filter' => 'appSignature'], function ($routes) { }); - // $routes->get("policy/searchThePolicies", "PolicyController::searchThePolicies"); - // $routes->get("dashboard/businessDashboard", "DashboardController::businessDashboard"); - // $routes->get("dashboard/partnerDashboard", "DashboardController::partnerDashboard"); - // $routes->get("dashboard/productivityDashboard", "DashboardController::productivityDashboard"); + $routes->get("policy/searchThePolicies", "PolicyController::searchThePolicies"); + $routes->get("dashboard/businessDashboard", "DashboardController::businessDashboard"); + $routes->get("dashboard/partnerDashboard", "DashboardController::partnerDashboard"); + $routes->get("dashboard/productivityDashboard", "DashboardController::productivityDashboard"); + + $routes->get("dashboard/downloadBrokerPoliciesExcel", "DashboardController::downloadBrokerPoliciesExcel"); + $routes->get("dashboard/downloadInsurerPoliciesExcel", "DashboardController::downloadInsurerPoliciesExcel"); + $routes->get("dashboard/downloadProductPoliciesExcel", "DashboardController::downloadProductPoliciesExcel"); + $routes->get("dashboard/partnerDashboard", "DashboardController::partnerDashboard"); + $routes->get("dashboard/partnerDashboard", "DashboardController::partnerDashboard"); + $routes->get("dashboard/partnerDashboard", "DashboardController::partnerDashboard"); + $routes->get("dashboard/productivityDashboard", "DashboardController::productivityDashboard"); + + // $routes->get('agent/agentList', 'AgentController::agentList'); // $routes->get('salesExecutive/executiveList', 'SalesExecutive::salesExecutiveList'); // $routes->get('salesExecutive/findExecutive', 'SalesExecutive::findSalesExecutive'); diff --git a/app/Controllers/DashboardController.php b/app/Controllers/DashboardController.php index 067e71e..7ea291b 100644 --- a/app/Controllers/DashboardController.php +++ b/app/Controllers/DashboardController.php @@ -3,6 +3,9 @@ namespace App\Controllers; use CodeIgniter\RESTful\ResourceController; +use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Writer\Xlsx; +use PhpOffice\PhpSpreadsheet\Style\Border; class DashboardController extends ResourceController { @@ -428,14 +431,12 @@ class DashboardController extends ResourceController public function businessDashboard() { - $raw = false; + $raw = false;$ref = []; $manager_id = $this->request->getGet('manager_id'); $raw_param = strtolower(trim($this->request->getGet('raw') ?? '')); $raw = in_array($raw_param, ['true', '1'], true); - // Initialize the details array to ensure the final output is always structured. $details = [ 'brokerWise' => [], 'productWise' => [], 'insurerWise' => []]; - $code = 200; $message = "Business Dashboard Data Retrieved Successfully"; try { @@ -443,9 +444,11 @@ class DashboardController extends ResourceController $details['brokerWise'] = $this->brokerWise($manager_id,$raw); $details['productWise'] = $this->productWise($manager_id,$raw); $details['insurerWise'] = $this->insurerWise($manager_id,$raw); - $counts['brokerWise_total_records'] = is_array($details['brokerWise']) ? count($details['brokerWise']) : 0; - $counts['productWise_total_records'] = is_array($details['productWise']) ? count($details['productWise']) : 0 ; - $counts['insurerWise_total_records'] = is_array($details['insurerWise']) ? count($details['insurerWise']) : 0; + + $ref['message'] = $message; + $ref['brokerWise_total_records'] = is_array($details['brokerWise']) ? count($details['brokerWise']) : 0; + $ref['productWise_total_records'] = is_array($details['productWise']) ? count($details['productWise']) : 0 ; + $ref['insurerWise_total_records'] = is_array($details['insurerWise']) ? count($details['insurerWise']) : 0; // 2. Check for overall emptiness (optional, but good practice) $is_empty = array_reduce($details, function ($carry, $item) { @@ -458,40 +461,27 @@ class DashboardController extends ResourceController } // 3. Return a successful, combined JSON response - return $this->response->setJSON([ - 'status' => 'success', - 'data' => $details, // Contains the nested arrays: brokerWise, productWise, insurerWise - 'code' => 200, - 'message' => $message, - 'ref' => 'NIL', - 'counts' => $counts - ])->setStatusCode(200); + return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $details, 'ref' => $ref ], 200); } catch (\Throwable $e) { - // --- Centralized Error Handling Logic --- - $code = ($e->getCode() && $e->getCode() >= 100 && $e->getCode() < 600) - ? $e->getCode() : 500; - + + if ($e instanceof \RuntimeException && $e->getCode() === 404) { + $ref['message'] = 'No Data Found'; + return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'ref' => $ref], 200); + } + $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { - // Log the full error, but return minimal info for security - $ref = $e->getFile() . " / LN : " . $e->getLine(); + $ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine(); + $ref['message'] = 'Database Error Occurred.'; } else { - // This catches the \RuntimeException for "No Data found" (code 404) - $ref = "Application exception occurred"; + $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } - // Return an error JSON response - return $this->response->setJSON([ - 'status' => 'error', - 'data' => [], // Return empty data on error - 'code' => $e->getCode(), - 'message' => $e->getMessage(), - 'ref' => $ref, - ])->setStatusCode($code); + return $this->respond([ 'status' => 'error', 'code' => $e->getCode(), 'data' => [], 'ref' => $ref], 200); } } @@ -499,13 +489,12 @@ class DashboardController extends ResourceController public function partnerDashboard() { - $raw = false; + $raw = false;$ref = []; $manager_id = $this->request->getGet('manager_id'); $raw_param = strtolower(trim($this->request->getGet('raw') ?? '')); $raw = in_array($raw_param, ['true', '1'], true); // Initialize the details array to ensure the final output is always structured. - $code = 200; $message = "Partner Dashboard Data Retrieved Successfully"; $details = [ 'monthlyPolicyCount' => [],'noPolicyTimeRange' => [],'below50tPremiumTimeRange' => []]; // 'agentNoPolicyLast10Days' => [],// 'agentBelow50tPremiumLast10Days' => [], @@ -520,9 +509,9 @@ class DashboardController extends ResourceController $details['noPolicyTimeRange'] = $this->agentNoPolicyTimeRange($manager_id,$raw); $details['below50tPremiumTimeRange'] = $this->agentBelow50tPremiumTimeRange($manager_id,$raw); - $counts['monthlyPolicyCountAndPremiumAmount_total_records'] = is_array($details['monthlyPolicyCount']) ? count($details['monthlyPolicyCount']) : 0; - $counts['noPolicyTimeRange_total_records'] = is_array($details['noPolicyTimeRange']) ? count($details['noPolicyTimeRange']) : 0; - $counts['below50tPremiumTimeRange_total_records'] = is_array($details['below50tPremiumTimeRange']) ? count($details['below50tPremiumTimeRange']) : 0; + $ref['monthlyPolicyCountAndPremiumAmount_total_records'] = is_array($details['monthlyPolicyCount']) ? count($details['monthlyPolicyCount']) : 0; + $ref['noPolicyTimeRange_total_records'] = is_array($details['noPolicyTimeRange']) ? count($details['noPolicyTimeRange']) : 0; + $ref['below50tPremiumTimeRange_total_records'] = is_array($details['below50tPremiumTimeRange']) ? count($details['below50tPremiumTimeRange']) : 0; // 2. Check for overall emptiness (optional, but good practice) @@ -535,60 +524,46 @@ class DashboardController extends ResourceController } // 3. Return a successful, combined JSON response - return $this->response->setJSON([ - 'status' => 'success', - 'data' => $details, // Contains the nested arrays: brokerWise, productWise, insurerWise - 'code' => 200, - 'message' => $message, - 'ref' => 'NIL', - 'counts' => $counts - ])->setStatusCode(200); + return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $details, 'ref' => $ref ], 200); } catch (\Throwable $e) { - // --- Centralized Error Handling Logic --- - $code = ($e->getCode() && $e->getCode() >= 100 && $e->getCode() < 600) - ? $e->getCode() : 500; - + + if ($e instanceof \RuntimeException && $e->getCode() === 404) { + $ref['message'] = 'No Data Found'; + return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'ref' => $ref], 200); + } + $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { - // Log the full error, but return minimal info for security - $ref = $e->getFile() . " / LN : " . $e->getLine(); + $ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine(); + $ref['message'] = 'Database Error Occurred.'; } else { - // This catches the \RuntimeException for "No Data found" (code 404) - $ref = "Application exception occurred"; + $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } - // Return an error JSON response - return $this->response->setJSON([ - 'status' => 'error', - 'data' => [], // Return empty data on error - 'code' => $e->getCode(), - 'message' => $e->getMessage(), - 'ref' => $ref, - ])->setStatusCode($code); + return $this->respond([ 'status' => 'error', 'code' => $e->getCode(), 'data' => [], 'ref' => $ref], 200); } } public function productivityDashboard(){ - $raw = false; + $raw = false;$ref = []; $manager_id = $this->request->getGet('manager_id'); $raw_param = strtolower(trim($this->request->getGet('raw') ?? '')); $raw = in_array($raw_param, ['true', '1'], true); // Initialize the details array to ensure the final output is always structured. $details = [ 'StaffWise' => []]; - $code = 200; $message = "Productivity Dashboard Data Retrieved Successfully"; try { // 1. Fetch all data concurrently (or sequentially, as shown) $details['StaffWise'] = $this->staffWiseProductList($manager_id,$raw); - $counts['StaffWise_total_records'] = is_array($details['StaffWise']) + $ref['StaffWise_total_records'] = is_array($details['StaffWise']) ? count($details['StaffWise']) : 0; @@ -604,40 +579,27 @@ class DashboardController extends ResourceController } // 3. Return a successful, combined JSON response - return $this->response->setJSON([ - 'status' => 'success', - 'data' => $details, - 'code' => 200, - 'message' => $message, - 'ref' => 'NIL', - 'counts' => $counts - ])->setStatusCode(200); + return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $details, 'ref' => $ref ], 200); } catch (\Throwable $e) { - // --- Centralized Error Handling Logic --- - $code = ($e->getCode() && $e->getCode() >= 100 && $e->getCode() < 600) - ? $e->getCode() : 500; - + + if ($e instanceof \RuntimeException && $e->getCode() === 404) { + $ref['message'] = 'No Data Found'; + return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'ref' => $ref], 200); + } + $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { - // Log the full error, but return minimal info for security - $ref = $e->getFile() . " / LN : " . $e->getLine(); + $ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine(); + $ref['message'] = 'Database Error Occurred.'; } else { - // This catches the \RuntimeException for "No Data found" (code 404) - $ref = "Application exception occurred"; + $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } - // Return an error JSON response - return $this->response->setJSON([ - 'status' => 'error', - 'data' => [], // Return empty data on error - 'code' => $e->getCode(), - 'message' => $e->getMessage(), - 'ref' => $ref, - ])->setStatusCode($code); + return $this->respond([ 'status' => 'error', 'code' => $e->getCode(), 'data' => [], 'ref' => $ref], 200); } } @@ -655,7 +617,7 @@ class DashboardController extends ResourceController CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) - THEN pp.client_policy_id + THEN pp.policy_number ELSE NULL END ) AS total_policies_current_month, @@ -673,7 +635,7 @@ class DashboardController extends ResourceController CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') - THEN pp.client_policy_id + THEN pp.policy_number ELSE NULL END ) AS total_policies_pre_month, @@ -703,6 +665,10 @@ class DashboardController extends ResourceController $builder->groupBy('pq.insurer_id'); $builder->orderBy('pq.insurer_id'); + if ($raw === true) { + return $builder->getCompiledSelect(); + } + $query = $builder->get(); $result = $query->getResultArray(); return $result; @@ -720,7 +686,7 @@ class DashboardController extends ResourceController CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) - THEN pp.client_policy_id + THEN pp.policy_number ELSE NULL END ) AS total_policies_current_month, @@ -738,7 +704,7 @@ class DashboardController extends ResourceController CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') - THEN pp.client_policy_id + THEN pp.policy_number ELSE NULL END ) AS total_policies_pre_month, @@ -784,7 +750,7 @@ class DashboardController extends ResourceController CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) - THEN pp.client_policy_id + THEN pp.policy_number ELSE NULL END ) AS total_policies_current_month, @@ -802,7 +768,7 @@ class DashboardController extends ResourceController CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') - THEN pp.client_policy_id + THEN pp.policy_number ELSE NULL END ) AS total_policies_pre_month, @@ -1016,7 +982,7 @@ class DashboardController extends ResourceController CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) - THEN pp.client_policy_id + THEN pp.policy_number END ) AS total_policies_current_month, @@ -1032,7 +998,7 @@ class DashboardController extends ResourceController CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') - THEN pp.client_policy_id + THEN pp.policy_number END ) AS total_policies_pre_month, @@ -1100,5 +1066,1219 @@ class DashboardController extends ResourceController return array_values($final); } + // Function to 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'); + + // --- ADDED VALIDATION (Simplified logic for clarity) --- + 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 = ['message' => 'Missing required parameters: manager_id, broker_id, and month must be provided.']; + // 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->getBrokerPoliciesData($managerId, $brokerId, $month); + // Define column headers + $header = ['Broker Name', 'Issue Date', 'Policy Number', 'Premium Amount']; + + // --- 1. MODIFIED LOGIC: Throw RuntimeException if no data --- + if (empty($data)) { + throw new \RuntimeException('No policies found for this broker for the specified month.', 404); + } + + $grandTotal = 0; + foreach ($data as $row) { $grandTotal += (float)$row[3]; } + + // Create and append the "Total" row + $totalRow = ['','','Total:',$grandTotal]; + $data[] = $totalRow; + + // Determine file name and date string + $monthName = ($month === 'current') ? date('Ym') : date('Ym', strtotime('-1 month')); + $brokerName = $data[0][0]; + + // 2. Prepare PhpSpreadsheet (assuming $spreadsheet, $writer, etc. are created here) + while (ob_get_level() > 0) { + ob_end_clean(); + } + + // Create Spreadsheet + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Title + $sheet->mergeCells('A1:D1'); + $sheet->setCellValue('A1', "Broker Policies Details for $month"); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + // Headers + $sheet->fromArray($header, NULL, 'A2'); + + // Data + $sheet->fromArray($data, NULL, 'A3'); + + // File Name + $fileName = $brokerName . '_Policies_Details_' . $monthName . '.xlsx'; + + // 1. Define the target row number (Must be the first step!) + $totalRowNumber = count($data) + 2; + + // 2. Set the 'TOTAL:' label in Column C + $sheet->setCellValue('C' . $totalRowNumber, 'TOTAL:'); + + // 3. Apply bold formatting to the label and the sum (Columns C and D) + $sheet->getStyle('C' . $totalRowNumber . ':D' . $totalRowNumber)->getFont()->setBold(true); + + // 4. Align the label to the right for a clean look next to the sum + $sheet->getStyle('C' . $totalRowNumber)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT); + + // HTTP Headers + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header("Cache-Control: max-age=0"); + + // Output File + $writer = new Xlsx($spreadsheet); + $writer->save('php://output'); + + 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); + } + } + + /** + * 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 --- + $db = \Config\Database::connect(); + $data = []; + + try { + $builder = $db->table('partner_policy pp'); + // Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details + $builder->select('pb.name AS broker_name, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.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'); + + // --- 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; + } + + // Function to 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'); + + // --- ADDED VALIDATION (Simplified logic for clarity) --- + if (empty($managerId) || empty($vehicleType) || empty($month)) { + $msg = "Missing: "; + $msg .= empty($managerId) ? "manager_id " : ""; + $msg .= empty($vehicleType) ? "vehicle_type " : ""; + $msg .= empty($month) ? "month " : ""; + $ref = ['debug_msg' => $msg]; + // $ref = ['message' => 'Missing required parameters: manager_id, vehicle_type, and month must be provided.']; + // 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->getProductPoliciesData($managerId, $vehicleType, $month); + // Define column headers + $header = ['Vehicle Type', 'Issue Date', 'Policy Number', 'Premium Amount']; + + // --- 1. MODIFIED LOGIC: Throw RuntimeException if no data --- + if (empty($data)) { + throw new \RuntimeException('No policies found for this vehicle type for the specified month.', 404); + } + + $grandTotal = 0; + foreach ($data as $row) { $grandTotal += (float)$row[3]; } + + // Create and append the "Total" row + $totalRow = ['','','Total:',$grandTotal]; + $data[] = $totalRow; + + // Determine file name and date string + $monthName = ($month === 'current') ? date('Ym') : date('Ym', strtotime('-1 month')); + $vehicleType = $data[0][0]; + + // 2. Prepare PhpSpreadsheet (assuming $spreadsheet, $writer, etc. are created here) + while (ob_get_level() > 0) { + ob_end_clean(); + } + + // Create Spreadsheet + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Title + $sheet->mergeCells('A1:D1'); + $sheet->setCellValue('A1', "Vehicle Type Policies Details for $month"); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + // Headers + $sheet->fromArray($header, NULL, 'A2'); + + // Data + $sheet->fromArray($data, NULL, 'A3'); + + // File Name + $fileName = $vehicleType . '_Policies_Details_' . $monthName . '.xlsx'; + + // 1. Define the target row number (Must be the first step!) + $totalRowNumber = count($data) + 2; + + // 2. Set the 'TOTAL:' label in Column C + $sheet->setCellValue('C' . $totalRowNumber, 'TOTAL:'); + + // 3. Apply bold formatting to the label and the sum (Columns C and D) + $sheet->getStyle('C' . $totalRowNumber . ':D' . $totalRowNumber)->getFont()->setBold(true); + + // 4. Align the label to the right for a clean look next to the sum + $sheet->getStyle('C' . $totalRowNumber)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT); + + // HTTP Headers + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header("Cache-Control: max-age=0"); + + // Output File + $writer = new Xlsx($spreadsheet); + $writer->save('php://output'); + + 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); + } + } + + /** + * 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 --- + $db = \Config\Database::connect(); + $data = []; + + try { + $builder = $db->table('partner_policy pp'); + // Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details + $builder->select('pp.vehicle_type, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.policy_number, pp.premium_amount'); + + + // --- 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; + } + + // Function to 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); + + // Define column headers + $header = ['Insurer Name', 'Insurer Short Name','Insured Name', 'Policy Issued Date','Policy Number', 'Premium Amount']; + + // --- 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); + } + + $grandTotal = 0; + foreach ($data as $row) { $grandTotal += (float)$row[5]; } + + // Create and append the "Total" row + $totalRow = ['','','','','Total:',$grandTotal]; + $data[] = $totalRow; + + // Determine file name and date string + $monthName = ($month === 'current') ? date('Ym') : date('Ym', strtotime('-1 month')); + $InsurerName = $data[0][0]; + + // 2. Prepare PhpSpreadsheet (assuming $spreadsheet, $writer, etc. are created here) + while (ob_get_level() > 0) { + ob_end_clean(); + } + + // Create Spreadsheet + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Title + $sheet->mergeCells('A1:G1'); + $sheet->setCellValue('A1', "Insurer Policies Details for $month"); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + // Headers + $sheet->fromArray($header, NULL, 'A2'); + + // Data + $sheet->fromArray($data, NULL, 'A3'); + + // 1. Define the target row number (Must be the first step!) + $totalRowNumber = count($data) + 2; + + // 2. Set the 'TOTAL:' label in Column F + $sheet->setCellValue('E' . $totalRowNumber, 'TOTAL:'); + + // 3. Apply bold formatting to the label and the sum (Columns C and D) + $sheet->getStyle('E' . $totalRowNumber . ':F' . $totalRowNumber)->getFont()->setBold(true); + + // 4. Align the label to the right for a clean look next to the sum + $sheet->getStyle('E' . $totalRowNumber)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT); + + // File Name + $fileName = $InsurerName . '_Policies_Details_' . $monthName . '.xlsx'; + + // HTTP Headers + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header("Cache-Control: max-age=0"); + + // Output File + $writer = new Xlsx($spreadsheet); + $writer->save('php://output'); + + 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); + } + } + + /** + * 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 --- + $db = \Config\Database::connect(); + $data = []; + + try { + $builder = $db->table('partner_policy pp'); + // Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details + $builder->select('i.name AS insurer_name,i.short_name,pp.insured_name, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.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'); + + + // --- 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'); + + $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; + } + + // Function to generate the Excel file + public function downloadStaffWiseProductPoliciesExcel() + { + try{ + $managerId = $this->request->getGet('manager_id'); + $brokerId = $this->request->getGet('broker_id'); + $month = $this->request->getGet('month'); + + // --- ADDED VALIDATION (Simplified logic for clarity) --- + if (empty($managerId) || empty($brokerId) || empty($month)) { + $ref = ['message' => 'Missing required parameters: manager_id, broker_id, and month must be provided.']; + // 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: manager_id, broker_id, and month must be provided.', + 'ref' => $ref + ])->setStatusCode(200); + } + + $data = $this->getBrokerPoliciesData($managerId, $brokerId, $month); + // Define column headers + $header = ['Broker Name', 'Issue Date', 'Policy Number', 'Premium Amount']; + + // --- 1. MODIFIED LOGIC: Throw RuntimeException if no data --- + if (empty($data)) { + throw new \RuntimeException('No policies found for this broker for the specified month.', 404); + } + + $grandTotal = 0; + foreach ($data as $row) { $grandTotal += (float)$row[3]; } + + // Create and append the "Total" row + $totalRow = ['','','Total:',$grandTotal]; + $data[] = $totalRow; + + // Determine file name and date string + $monthName = ($month === 'current') ? date('Ym') : date('Ym', strtotime('-1 month')); + $brokerName = $data[0][0]; + + // 2. Prepare PhpSpreadsheet (assuming $spreadsheet, $writer, etc. are created here) + while (ob_get_level() > 0) { + ob_end_clean(); + } + + // Create Spreadsheet + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Title + $sheet->mergeCells('A1:D1'); + $sheet->setCellValue('A1', "Broker Policies Details for $month"); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + // Headers + $sheet->fromArray($header, NULL, 'A2'); + + // Data + $sheet->fromArray($data, NULL, 'A3'); + + // File Name + $fileName = $brokerName . '_Policies_Details_' . $monthName . '.xlsx'; + + // HTTP Headers + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header("Cache-Control: max-age=0"); + + // Output File + $writer = new Xlsx($spreadsheet); + $writer->save('php://output'); + + 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 getStaffWiseProductPoliciesData($managerId, $brokerId, $month): array + { + // --- Correction 1: Initialize Database Connection --- + $db = \Config\Database::connect(); + $data = []; + + try { + $builder = $db->table('partner_policy pp'); + // Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details + $builder->select('pb.name AS broker_name, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.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'); + + // --- 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; + } + + // Function to generate the Excel file + public function downloadAgentMonthlyPoliciesExcel() + { + try{ + $managerId = $this->request->getGet('manager_id'); + $brokerId = $this->request->getGet('broker_id'); + $month = $this->request->getGet('month'); + + // --- ADDED VALIDATION (Simplified logic for clarity) --- + if (empty($managerId) || empty($brokerId) || empty($month)) { + $ref = ['message' => 'Missing required parameters: manager_id, broker_id, and month must be provided.']; + // Status code remains 200, but JSON code is 400 as per your preference + return $this->response->setJSON([ + 'status' => 'error', + 'code' => 400, + 'data' => [], + 'ref' => $ref + ])->setStatusCode(200); + } + + $data = $this->getAgentMonthlyPoliciesExcel($managerId, $brokerId, $month); + // Define column headers + $header = ['Partner Name','Partner Code' ,'Issue Date', 'Policy Number', 'Premium Amount']; + + + // --- 1. MODIFIED LOGIC: Throw RuntimeException if no data --- + if (empty($data)) { + throw new \RuntimeException('No policies found for this broker for the specified month.', 404); + } + + $grandTotal = 0; + foreach ($data as $row) { $grandTotal += (float)$row[3]; } + + // Create and append the "Total" row + $totalRow = ['','','Total:',$grandTotal]; + $data[] = $totalRow; + + // Determine file name and date string + $monthName = ($month === 'current') ? date('Ym') : date('Ym', strtotime('-1 month')); + $PartnerName = $data[0][0]; + + // 2. Prepare PhpSpreadsheet (assuming $spreadsheet, $writer, etc. are created here) + while (ob_get_level() > 0) { + ob_end_clean(); + } + + // Create Spreadsheet + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Title + $sheet->mergeCells('A1:F1'); + $sheet->setCellValue('A1', "Partner Policies Details for $month"); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + // Headers + $sheet->fromArray($header, NULL, 'A2'); + + // Data + $sheet->fromArray($data, NULL, 'A3'); + + // File Name + $fileName = $PartnerName . '_Policies_Details_' . $monthName . '.xlsx'; + + // HTTP Headers + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header("Cache-Control: max-age=0"); + + // Output File + $writer = new Xlsx($spreadsheet); + $writer->save('php://output'); + + 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' => [], + '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); + } + } + + /** + * 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 getAgentMonthlyPoliciesExcel($managerId, $AgentId, $month): array + { + // --- Correction 1: Initialize Database Connection --- + $db = \Config\Database::connect(); + $data = []; + + try { + $builder = $db->table('partner_policy pp'); + // Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details + $builder->select('pa.name AS agent_name,pa.agent_code, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.policy_number, pp.premium_amount'); + $builder->join('partner_agent pa', 'pp.agent_id = pa.id', 'inner'); + $builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', '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.agent_id', $AgentId); + $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; + } + + // Function to generate the Excel file + public function downloadAgentNoPolicyTimeRange() + { + try{ + $managerId = $this->request->getGet('manager_id'); + $brokerId = $this->request->getGet('broker_id'); + $month = $this->request->getGet('month'); + + // --- ADDED VALIDATION (Simplified logic for clarity) --- + if (empty($managerId) || empty($brokerId) || empty($month)) { + $ref = ['message' => 'Missing required parameters: manager_id, broker_id, and month must be provided.']; + // Status code remains 200, but JSON code is 400 as per your preference + return $this->response->setJSON([ + 'status' => 'error', + 'code' => 400, + 'data' => [], + 'ref' => $ref + ])->setStatusCode(200); + } + + $data = $this->getBrokerPoliciesData($managerId, $brokerId, $month); + // Define column headers + $header = ['Broker Name', 'Issue Date', 'Policy Number', 'Premium Amount']; + + // --- 1. MODIFIED LOGIC: Throw RuntimeException if no data --- + if (empty($data)) { + throw new \RuntimeException('No policies found for this broker for the specified month.', 404); + } + + $grandTotal = 0; + foreach ($data as $row) { $grandTotal += (float)$row[3]; } + + // Create and append the "Total" row + $totalRow = ['','','Total:',$grandTotal]; + $data[] = $totalRow; + + // Determine file name and date string + $monthName = ($month === 'current') ? date('Ym') : date('Ym', strtotime('-1 month')); + $brokerName = $data[0][0]; + + // 2. Prepare PhpSpreadsheet (assuming $spreadsheet, $writer, etc. are created here) + while (ob_get_level() > 0) { + ob_end_clean(); + } + + // Create Spreadsheet + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Title + $sheet->mergeCells('A1:D1'); + $sheet->setCellValue('A1', "Broker Policies Details for $month"); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + // Headers + $sheet->fromArray($header, NULL, 'A2'); + + // Data + $sheet->fromArray($data, NULL, 'A3'); + + // File Name + $fileName = $brokerName . '_Policies_Details_' . $monthName . '.xlsx'; + + // HTTP Headers + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header("Cache-Control: max-age=0"); + + // Output File + $writer = new Xlsx($spreadsheet); + $writer->save('php://output'); + + 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' => [], + '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); + } + } + + /** + * 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 getAgentNoPolicyTimeRange($managerId, $brokerId, $month): array + { + // --- Correction 1: Initialize Database Connection --- + $db = \Config\Database::connect(); + $data = []; + + try { + $builder = $db->table('partner_policy pp'); + // Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details + $builder->select('pb.name AS broker_name, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.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'); + + // --- 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; + } + + // Function to generate the Excel file + public function downloadBrokerPoliciesExcel_agentBelow50tPremiumTimeRange() + { + try{ + $managerId = $this->request->getGet('manager_id'); + $brokerId = $this->request->getGet('broker_id'); + $month = $this->request->getGet('month'); + + // --- ADDED VALIDATION (Simplified logic for clarity) --- + if (empty($managerId) || empty($brokerId) || empty($month)) { + $ref = ['message' => 'Missing required parameters: manager_id, broker_id, and month must be provided.']; + // Status code remains 200, but JSON code is 400 as per your preference + return $this->response->setJSON([ + 'status' => 'error', + 'code' => 400, + 'data' => [], + 'ref' => $ref + ])->setStatusCode(200); + } + + $data = $this->getBrokerPoliciesData($managerId, $brokerId, $month); + // Define column headers + $header = ['Broker Name', 'Issue Date', 'Policy Number', 'Premium Amount']; + + $grandTotal = 0; + foreach ($data as $row) { $grandTotal += (float)$row[3]; } + + // Create and append the "Total" row + $totalRow = ['','','Total:',$grandTotal]; + $data[] = $totalRow; + + // --- 1. MODIFIED LOGIC: Throw RuntimeException if no data --- + if (empty($data)) { + throw new \RuntimeException('No policies found for this broker for the specified month.', 404); + } + + // Determine file name and date string + $monthName = ($month === 'current') ? date('Ym') : date('Ym', strtotime('-1 month')); + $brokerName = $data[0][0]; + + // 2. Prepare PhpSpreadsheet (assuming $spreadsheet, $writer, etc. are created here) + while (ob_get_level() > 0) { + ob_end_clean(); + } + + // Create Spreadsheet + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + + // Title + $sheet->mergeCells('A1:D1'); + $sheet->setCellValue('A1', "Broker Policies Details for $month"); + $sheet->getStyle('A1')->getAlignment()->setHorizontal('center'); + + // Headers + $sheet->fromArray($header, NULL, 'A2'); + + // Data + $sheet->fromArray($data, NULL, 'A3'); + + // File Name + $fileName = $brokerName . '_Policies_Details_' . $monthName . '.xlsx'; + + // HTTP Headers + header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + header("Content-Disposition: attachment; filename=\"{$fileName}\""); + header("Cache-Control: max-age=0"); + + // Output File + $writer = new Xlsx($spreadsheet); + $writer->save('php://output'); + + 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' => [], + '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); + } + } + + /** + * 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_agentBelow50tPremiumTimeRange($managerId, $brokerId, $month): array + { + // --- Correction 1: Initialize Database Connection --- + $db = \Config\Database::connect(); + $data = []; + + try { + $builder = $db->table('partner_policy pp'); + // Note: I removed 'broker_id' from SELECT as it's redundant in the Excel sheet details + $builder->select('pb.name AS broker_name, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date,pp.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'); + + // --- 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; + } }