From 5e17a4c2e48be3a97ecd5a3d21015f781f829bec Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Sat, 18 Apr 2026 17:32:59 +0530 Subject: [PATCH] GWM : commissionPayoutReportExport API --- app/Config/Routes.php | 2 +- app/Controllers/PolicyController.php | 328 +++++++++++++++++++++++++++ 2 files changed, 329 insertions(+), 1 deletion(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 0f1a706..dd64744 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -144,7 +144,7 @@ $routes->group('api', ['filter' => ["jwtAuth:1,2,3,4,agent","appSignature"] ], f $routes->post('policy/uploadCommissionExcel', 'PolicyController::uploadCommissionExcel'); $routes->post('policy/payoutInilneEditUpdate', 'PolicyController::payoutInilneEditUpdate'); $routes->get('policy/commissionPayoutReport', 'PolicyController::commissionPayoutReport'); - + $routes->get('policy/commissionPayoutReportExport', 'PolicyController::commissionPayoutReportExport'); //claims $routes->get('claim/ClaimList', 'ClaimController::ClaimList'); $routes->post('claim/createClaim', 'ClaimController::createClaim'); diff --git a/app/Controllers/PolicyController.php b/app/Controllers/PolicyController.php index 1afe3b6..358ddea 100644 --- a/app/Controllers/PolicyController.php +++ b/app/Controllers/PolicyController.php @@ -1754,6 +1754,334 @@ class PolicyController extends ResourceController } } + + public function commissionPayoutReportExport() + { + try { + // ── 1. Collect & validate filters (same logic as commissionPayoutReport) ── + $fromDate = $this->request->getGet('from_date'); + $toDate = $this->request->getGet('to_date'); + $agentIdRaw = $this->request->getGet('agent_id'); + $payoutRaised = $this->request->getGet('payout_raised'); + + $fromDate = ($fromDate !== null && $fromDate !== '') ? trim((string) $fromDate) : null; + $toDate = ($toDate !== null && $toDate !== '') ? trim((string) $toDate) : null; + + $agentId = null; + if ($agentIdRaw !== null && $agentIdRaw !== '') { + $agentId = (int) $agentIdRaw; + } + + if ($payoutRaised !== null && $payoutRaised !== '') { + $payoutRaised = strtolower(trim((string) $payoutRaised)); + if (! in_array($payoutRaised, ['yes', 'no', 'all'], true)) { + return $this->respond([ + 'status' => 'failed', + 'code' => 400, + 'data' => 'payout_raised must be yes, no, or all', + ], 400); + } + } else { + $payoutRaised = null; + } + + $hasDateFilter = $fromDate !== null || $toDate !== null; + $hasPayoutFilter = $payoutRaised !== null; + if (! $hasDateFilter && $agentId === null && ! $hasPayoutFilter) { + return $this->respond([ + 'status' => 'failed', + 'code' => 400, + 'data' => 'Provide at least one filter: from_date, to_date, agent_id, or payout_raised', + ], 400); + } + + // ── 2. Build query (identical to the report API) ────────────────────── + $db = \Config\Database::connect(); + $builder = $db->table('partner_policy pp'); + $builder->select( + 'pa.agent_code, pa.name AS agent_name, ' + . 'pp.policy_number AS policy_no, pp.premium_amount AS premium, ' + . 'pp.commission_amount, pe.reg_no, pp.weight, pp.fuel_type, ' + . 'pp.vehicle_type, pp.issued_date' + ); + $builder->select( + 'COALESCE((SELECT GROUP_CONCAT(piu.utr_no ORDER BY piu.id SEPARATOR ", ") ' + . 'FROM partner_invoice_items pii_utr ' + . 'INNER JOIN partner_invoice pi_u ON pi_u.id = pii_utr.invoice_id AND pi_u.is_active = 1 ' + . 'INNER JOIN partner_invoice_utr piu ON piu.invoice_id = pii_utr.invoice_id AND piu.is_active = 1 ' + . 'WHERE pii_utr.policy_id = pp.id AND pii_utr.is_active = 1), "") AS utr_no', + false + ); + $builder->select( + "(CASE WHEN EXISTS (SELECT 1 FROM partner_invoice_items pii " + . "INNER JOIN partner_invoice pi ON pi.id = pii.invoice_id AND pi.is_active = 1 " + . "WHERE pii.policy_id = pp.id AND pii.is_active = 1) THEN 'yes' ELSE 'no' END) AS received_or_not", + false + ); + $builder->join('partner_agent pa', 'pa.id = pp.agent_id', 'left'); + $builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left'); + $builder->where('pp.is_active', 1); + + if ($fromDate !== null) { + $builder->where('pp.issued_date >=', date('Y-m-d', strtotime($fromDate))); + } + if ($toDate !== null) { + $builder->where('pp.issued_date <=', date('Y-m-d', strtotime($toDate))); + } + if ($agentId !== null) { + $builder->where('pp.agent_id', $agentId); + } + if ($payoutRaised === 'yes') { + $builder->where( + 'EXISTS (SELECT 1 FROM partner_invoice_items pii2 ' + . 'INNER JOIN partner_invoice pi2 ON pi2.id = pii2.invoice_id AND pi2.is_active = 1 ' + . 'WHERE pii2.policy_id = pp.id AND pii2.is_active = 1)', + null, false + ); + } elseif ($payoutRaised === 'no') { + $builder->where( + 'NOT EXISTS (SELECT 1 FROM partner_invoice_items pii2 ' + . 'INNER JOIN partner_invoice pi2 ON pi2.id = pii2.invoice_id AND pi2.is_active = 1 ' + . 'WHERE pii2.policy_id = pp.id AND pii2.is_active = 1)', + null, false + ); + } + + $builder->orderBy('pa.agent_code', 'ASC'); + $builder->orderBy('pp.policy_number', 'ASC'); + + $rows = $builder->get()->getResultArray(); + + // ── 3. Compute summary totals ───────────────────────────────────────── + $sumTotal = $sumRaised = $sumPending = 0.0; + foreach ($rows as $row) { + $amt = (float) ($row['commission_amount'] ?? 0); + $sumTotal += $amt; + if (($row['received_or_not'] ?? '') === 'yes') { + $sumRaised += $amt; + } else { + $sumPending += $amt; + } + } + + // ── 4. Build spreadsheet ────────────────────────────────────────────── + $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setTitle('Payout Report'); + + // ── Shared style helpers ────────────────────────────────────────────── + $headerFill = [ + 'fill' => [ + 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, + 'startColor' => ['argb' => 'FFB8CCE4'], // light-blue like the screenshot + ], + ]; + $redBoldCenter = [ + 'font' => ['bold' => true, 'color' => ['argb' => 'FFFF0000'], 'name' => 'Arial', 'size' => 11], + 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER], + ]; + $labelBold = [ + 'font' => ['bold' => true, 'name' => 'Arial', 'size' => 10], + 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT], + ]; + $dateHighlight = [ + 'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['argb' => 'FFFFFF00']], + 'font' => ['bold' => true, 'name' => 'Arial', 'size' => 10], + ]; + $colHeaderStyle = [ + 'font' => ['bold' => true, 'name' => 'Arial', 'size' => 10], + 'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['argb' => 'FFB8CCE4']], + 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'wrapText' => true], + 'borders' => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN]], + ]; + $cellStyle = [ + 'font' => ['name' => 'Arial', 'size' => 9], + 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER], + 'borders' => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN]], + ]; + $summaryLabelStyle = [ + 'font' => ['bold' => true, 'name' => 'Arial', 'size' => 10], + 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT], + ]; + $summaryValueStyle = [ + 'font' => ['bold' => true, 'name' => 'Arial', 'size' => 10, 'color' => ['argb' => 'FF0070C0']], + 'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT], + ]; + + // Total columns used: A–T (20 columns) + $lastCol = 'T'; + $lastColNo = 20; + + // ── Row 1: Title ────────────────────────────────────────────────────── + $sheet->mergeCells("A1:{$lastCol}1"); + $sheet->setCellValue('A1', 'WE NEED THIS TYPE FORMENT IN PATNER LOGIN (PAYOUT REPORT)'); + $sheet->getStyle('A1')->applyFromArray($redBoldCenter); + $sheet->getRowDimension(1)->setRowHeight(20); + + // ── Row 2: Partner name + Date range ───────────────────────────────── + $sheet->setCellValue('A2', 'PARTNER NAME'); + $sheet->getStyle('A2')->applyFromArray($labelBold); + + // Agent name: use first row's agent_name or fall back to id + $partnerLabel = ! empty($rows) ? ($rows[0]['agent_name'] ?? ('Agent #' . $agentId)) : 'ALL AGENTS'; + $sheet->mergeCells('B2:D2'); + $sheet->setCellValue('B2', strtoupper($partnerLabel)); + $sheet->getStyle('B2')->applyFromArray($labelBold); + + $sheet->setCellValue('F2', 'DATE RANG'); + $sheet->getStyle('F2')->applyFromArray($dateHighlight); + + $dateRangeFrom = $fromDate ? date('d-m-Y', strtotime($fromDate)) : 'N/A'; + $dateRangeTo = $toDate ? date('d-m-Y', strtotime($toDate)) : 'N/A'; + $sheet->setCellValue('G2', $dateRangeFrom); + $sheet->getStyle('G2')->applyFromArray($dateHighlight); + $sheet->setCellValue('H2', 'TO'); + $sheet->setCellValue('I2', $dateRangeTo); + $sheet->getStyle('I2')->applyFromArray($dateHighlight); + $sheet->getRowDimension(2)->setRowHeight(18); + + // ── Row 3: Column headers ───────────────────────────────────────────── + $headers = [ + 'A3' => 'REF NO', + 'B3' => 'INSURER', + 'C3' => 'PLAN TYPE', + 'D3' => 'POLICY NO', + 'E3' => "INSURED\nNAME", + 'F3' => 'REG NO', + 'G3' => 'PRODUCT', + 'H3' => 'FUEL TYPE', + 'I3' => 'GVW', + 'J3' => 'MFG', + 'K3' => 'RTO LOC', + 'L3' => "DATE OF\nREG.", + 'M3' => 'COMPANY', + 'N3' => "MAKE &\nVARIANT", + 'O3' => 'A (OD)', + 'P3' => 'B (TP)', + 'Q3' => 'A+B (NET)', + 'R3' => 'S.TAX', + 'S3' => 'TOTAL', + 'T3' => "PAYMENT\nPO MODE", // UTR / UTR DATE placed here for simplicity + ]; + + foreach ($headers as $cell => $label) { + $sheet->setCellValue($cell, $label); + $sheet->getStyle($cell)->applyFromArray($colHeaderStyle); + } + $sheet->getRowDimension(3)->setRowHeight(30); + + // ── Rows 4+: Data ───────────────────────────────────────────────────── + $dataStartRow = 4; + $rowNum = $dataStartRow; + + foreach ($rows as $index => $row) { + $refNo = $index + 1; + $policyNo = $row['policy_no'] ?? ''; + $regNo = $row['reg_no'] ?? ''; + $fuelType = $row['fuel_type'] ?? ''; + $vehicleType = $row['vehicle_type'] ?? ''; + $weight = $row['weight'] ?? ''; + $commissionAmt = (float) ($row['commission_amount'] ?? 0); + $premium = (float) ($row['premium'] ?? 0); + $utrNo = $row['utr_no'] ?? ''; + $payoutStatus = ($row['received_or_not'] ?? '') === 'yes' ? 'LINK' : 'PENDING'; + + $rowData = [ + 'A' => $refNo, + 'B' => $row['agent_code'] ?? '', // Insurer / agent code + 'C' => $vehicleType, // Plan type + 'D' => $policyNo, + 'E' => '', // Insured name – not in current query; extend if needed + 'F' => $regNo, + 'G' => $vehicleType, // Product (two-wheeler, etc.) + 'H' => $fuelType, + 'I' => $weight, // GVW / weight + 'J' => '', // MFG – add to query if available + 'K' => '', // RTO LOC – add to query if available + 'L' => isset($row['issued_date']) ? date('d-m-Y', strtotime($row['issued_date'])) : '', + 'M' => '', // Company / insurer – add to query if available + 'N' => '', // Make & Variant – add if available + 'O' => 0, // A (OD) – extend query if split premium available + 'P' => $premium, // B (TP) – using full premium; adjust if split + 'Q' => $premium, // A+B Net + 'R' => 0, // S.TAX – add if available + 'S' => $commissionAmt, // Commission as TOTAL + 'T' => $payoutStatus . ($utrNo ? ' | ' . $utrNo : ''), + ]; + + foreach ($rowData as $col => $value) { + $sheet->setCellValue("{$col}{$rowNum}", $value); + $sheet->getStyle("{$col}{$rowNum}")->applyFromArray($cellStyle); + } + + $sheet->getRowDimension($rowNum)->setRowHeight(18); + $rowNum++; + } + + // ── Summary row ─────────────────────────────────────────────────────── + $summaryRow = $rowNum + 1; + $sheet->mergeCells("A{$summaryRow}:R{$summaryRow}"); + $sheet->setCellValue("A{$summaryRow}", 'TOTAL COMMISSION SUMMARY'); + $sheet->getStyle("A{$summaryRow}")->applyFromArray($summaryLabelStyle); + + $summaryRow++; + $sheet->setCellValue("A{$summaryRow}", 'Total Commission:'); + $sheet->setCellValue("B{$summaryRow}", round($sumTotal, 2)); + $sheet->getStyle("A{$summaryRow}")->applyFromArray($summaryLabelStyle); + $sheet->getStyle("B{$summaryRow}")->applyFromArray($summaryValueStyle); + + $summaryRow++; + $sheet->setCellValue("A{$summaryRow}", 'Raised (Invoiced):'); + $sheet->setCellValue("B{$summaryRow}", round($sumRaised, 2)); + $sheet->getStyle("A{$summaryRow}")->applyFromArray($summaryLabelStyle); + $sheet->getStyle("B{$summaryRow}")->applyFromArray($summaryValueStyle); + + $summaryRow++; + $sheet->setCellValue("A{$summaryRow}", 'Pending:'); + $sheet->setCellValue("B{$summaryRow}", round($sumPending, 2)); + $sheet->getStyle("A{$summaryRow}")->applyFromArray($summaryLabelStyle); + $sheet->getStyle("B{$summaryRow}")->applyFromArray($summaryValueStyle); + + // ── Column widths ───────────────────────────────────────────────────── + $colWidths = [ + 'A' => 8, 'B' => 16, 'C' => 13, 'D' => 14, 'E' => 16, + 'F' => 13, 'G' => 13, 'H' => 10, 'I' => 8, 'J' => 8, + 'K' => 10, 'L' => 13, 'M' => 16, 'N' => 16, 'O' => 8, + 'P' => 8, 'Q' => 10, 'R' => 8, 'S' => 10, 'T' => 18, + ]; + foreach ($colWidths as $col => $width) { + $sheet->getColumnDimension($col)->setWidth($width); + } + + // ── Freeze panes below header ───────────────────────────────────────── + $sheet->freezePane('A4'); + + // ── 5. Stream the file to the browser ───────────────────────────────── + $filename = 'commission_payout_report_' . date('Ymd_His') . '.xlsx'; + + $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); + + // Prevent any prior output from corrupting the binary stream + if (ob_get_length()) { + ob_end_clean(); + } + + header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + header('Cache-Control: max-age=0'); + + $writer->save('php://output'); + exit; + + } catch (\Throwable $e) { + return $this->respond([ + 'status' => 'failed', + 'code' => 500, + 'message' => $e->getMessage(), + ], 500); + } + } + /** * POST multipart field: commission_excel (xlsx). Updates partner_policy.commission_amount by policy number. */