nhance_partner_be/app/Controllers/AgentIncentiveController.php

844 lines
39 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
use App\Controllers\BaseController;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use App\Models\AgentIncentiveFileModel;
use App\Models\PartnerInsurancePayoutGridModel;
use App\Models\AgentModel;
class AgentIncentiveController extends ResourceController
{
protected $AgentIncentiveFileModel;
protected $PayoutGridModel;
protected $PartnerAgentModel;
public function __construct()
{
$this->AgentIncentiveFileModel = new AgentIncentiveFileModel();
$this->PayoutGridModel = new PartnerInsurancePayoutGridModel();
$this->PartnerAgentModel = new AgentModel();
}
// -------------------------------------------------------------------------
// Upload Grid File (file_type = 'grid')
// Parses Excel and UPSERTs rows into partner_insurance_payout_grid
// -------------------------------------------------------------------------
public function uploadPayoutGridFile()
{
try {
/* ====================================================================
* STEP 1 — Validate POST input
* ==================================================================== */
$data = $this->request->getPost();
$agentId = $data['agent_id'] ?? null;
$month = $data['incentive_month'] ?? null;
$createdBy = $data['created_by'] ?? null;
if (empty($agentId) || empty($month)) {
return $this->respond([
'status' => 'failed',
'code' => 400,
'data' => 'agent_id and incentive_month are required.',
], 200);
}
/* ====================================================================
* STEP 2 — Duplicate check on partner_agent_incentive_file
* ==================================================================== */
$duplicate = $this->AgentIncentiveFileModel
->where('agent_id', $agentId)
->where('incentive_month', $month)
->where('file_type', 'grid')
->first();
if (!empty($duplicate)) {
return $this->respond([
'status' => 'failed',
'code' => 200,
'data' => 'Duplicate Entry.',
], 200);
}
/* ====================================================================
* STEP 3 — Fetch retention_rate from partner_agent using agent_id
*
* retention_rate is stored as decimal(4,2) e.g. 2.50
* Used later to calculate partner_comp / partner_tp / partner_od
* by subtracting from broker_excel values.
* If agent not found or retention_rate is NULL → partner fields = null
* ==================================================================== */
$agent = $this->PartnerAgentModel->find($agentId);
$retentionRate = (!empty($agent) && $agent['retention_rate'] !== null)
? (float) $agent['retention_rate']
: null;
/* ====================================================================
* STEP 4 — Validate uploaded file (extension check)
* ==================================================================== */
$gridFile = $this->request->getFile('incentive_file_name');
if (!$gridFile || !$gridFile->isValid()) {
return $this->respond([
'status' => 'failed',
'code' => 400,
'data' => 'No valid file uploaded.',
], 200);
}
$extension = strtolower($gridFile->getClientExtension());
if (!in_array($extension, ['xlsx', 'xls', 'csv'], true)) {
return $this->respond([
'status' => 'failed',
'code' => 400,
'data' => 'Only xlsx, xls, csv grid files are allowed.',
], 200);
}
/* ====================================================================
* STEP 5 — Move file to upload directory
* ==================================================================== */
$uploadPath = WRITEPATH . 'uploads/agent/incentive_file/';
if (!is_dir($uploadPath)) {
mkdir($uploadPath, 0777, true);
}
$gridFileName = time() . '_' . $gridFile->getRandomName();
$gridFile->move($uploadPath, $gridFileName);
/* ====================================================================
* STEP 6 — Insert record into partner_agent_incentive_file
* (same as uploadAgentIncentiveFile but file_type = 'grid')
* ==================================================================== */
$this->AgentIncentiveFileModel->insert([
'agent_id' => $agentId,
'incentive_month' => $month,
'incentive_file_name' => $gridFileName,
'file_type' => 'grid',
'is_active' => 1,
'created_by' => $createdBy,
]);
/* ====================================================================
* STEP 7 — Parse Excel sheet into a flat array of rows
* ==================================================================== */
$spreadsheet = IOFactory::load($uploadPath . $gridFileName);
$rows = $spreadsheet->getActiveSheet()
->toArray(null, true, true, false);
if (empty($rows)) {
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [
'inserted' => 0,
'updated' => 0,
'message' => 'File saved but grid sheet is empty — no rows processed.',
],
], 200);
}
/* ====================================================================
* STEP 8 — Helper: normalise a cell value
* Strips spaces & non-alphanumeric chars, returns lowercase.
* Used to safely compare header/section values.
* ==================================================================== */
$normalize = static function ($value): string {
$value = strtolower(trim((string) $value));
return preg_replace('/[^a-z0-9]+/', '', $value) ?? '';
};
/* ====================================================================
* STEP 9 — Helper: extract numeric value from broker_excel cell
*
* Broker excel cells come in mixed formats:
* "22" → 22.0 (plain number)
* "4.8" → 4.8
* "5.5X" → 5.5 (strip trailing X)
* "NET 1.9X" → 1.9 (strip prefix text + X)
* "OD 1.5X" → 1.5 (strip OD prefix + X)
* "1.5 X" → 1.5 (space before X)
* "OD25+TP10" → 35.0 (compound format, splits and sums up)
* "OD 20+TP 15"→ 35.0 (compound format, splits and sums up)
* "" / null → null
*
* Returns float|null
* ==================================================================== */
$extractNumeric = static function ($value): ?float {
$str = strtolower(trim((string) $value));
// Blank or nan → null
if ($str === '' || $str === 'nan') {
return null;
}
// Compound values like "OD25+TP10" or "OD 20+TP 15"
if (str_contains($str, '+')) {
$sum = 0.0;
$hasValid = false;
foreach (explode('+', $str) as $part) {
$cleanPart = preg_replace('/^(net|od|tp)\s*/i', '', trim($part));
$cleanPart = rtrim(trim($cleanPart), 'xX ');
if (is_numeric($cleanPart)) {
$sum += (float) $cleanPart;
$hasValid = true;
}
}
return $hasValid ? $sum : null;
}
// Strip known text prefixes: "net", "od", "tp", spaces
$str = preg_replace('/^(net|od|tp)\s*/i', '', $str);
// Strip trailing "x" or "X" and any surrounding spaces
$str = rtrim(trim($str), 'xX ');
// Now try to parse as float
if (is_numeric($str)) {
return (float) $str;
}
return null;
};
/* ====================================================================
* STEP 10 — Helper: calculate partner rate
*
* Formula: partner_value = broker_excel_value - retention_rate
*
* Rules:
* - If broker_excel_value is null → return null
* - If retention_rate is null → return null
* - Result rounded to 2 decimal places
* - Stored as string to match varchar column type
* ==================================================================== */
$calcPartnerRate = static function (
?string $brokerExcelRaw,
?float $retentionRate,
callable $extractNumeric
): ?string {
// Either side missing → cannot compute partner rate
if ($brokerExcelRaw === null || $retentionRate === null) {
return null;
}
$brokerValue = $extractNumeric($brokerExcelRaw);
// Could not parse a clean number from the broker value
if ($brokerValue === null) {
return null;
}
// partner rate = broker excel value retention rate
$partnerValue = round($brokerValue - $retentionRate, 2);
return (string) $partnerValue;
};
/* ====================================================================
* STEP 11 — Walk rows: detect section headers → column headers → data
*
* Excel has two column layouts depending on section:
*
* Layout A — TWO WHEELER / PCV / GCV / LCV / HCV / BUS / TAXI etc.
* [0] INSURER | [1] RTO | [2] SEGMENT | [3] COMP | [4] TP
* [5] REMARKS | [6] BROKER | [7] BROKER_EXCEL_COMP | [8] BROKER_EXCEL_TP
*
* Layout B — PRIVATE CAR-TP / fuel-separated sections
* [0] INSURER | [1] RTO | [2] SEGMENT | [3] TP | [4] FUEL
* [5] REMARKS | [6] BROKER | [7] BROKER_EXCEL_TP
* ==================================================================== */
$currentVehicleType = null;
$layoutHasComp = true; // true = Layout A, false = Layout B
$insertedCount = 0;
$updatedCount = 0;
foreach ($rows as $row) {
// Pad row to 9 columns so every index access is always safe
while (count($row) < 9) {
$row[] = null;
}
$col0 = trim((string) ($row[0] ?? ''));
$col1 = trim((string) ($row[1] ?? ''));
$col2 = trim((string) ($row[2] ?? ''));
$col3 = trim((string) ($row[3] ?? ''));
$col4 = trim((string) ($row[4] ?? ''));
// Consider col1 empty when it is blank or the string "nan"
$isCol1Empty = ($col1 === '' || strtolower($col1) === 'nan');
/* ------------------------------------------------------------------
* Row type A — Date row (very first row of the sheet) → skip
* ------------------------------------------------------------------ */
if ($col0 !== '' && $isCol1Empty && strtotime($col0) !== false) {
continue;
}
/* ------------------------------------------------------------------
* Row type B — Section-header row
* Condition: col0 has text, col1 is empty, col0 is NOT "INSURER"
* Action: set currentVehicleType, reset layout flag
* ------------------------------------------------------------------ */
if (
$col0 !== ''
&& $isCol1Empty
&& strtoupper($col0) !== 'INSURER'
&& $normalize($col0) !== 'nan'
) {
$currentVehicleType = strtoupper($col0);
$layoutHasComp = true; // will be re-detected from next header row
continue;
}
/* ------------------------------------------------------------------
* Row type C — Column-header row (col0 == "INSURER")
* Detect layout from col[4]:
* FUEL / PETROL / DIESEL / TP → Layout B (no comp column)
* anything else → Layout A (has comp column)
* ------------------------------------------------------------------ */
if (strtoupper($col0) === 'INSURER') {
$col4Upper = strtoupper($col4);
$layoutHasComp = !(
str_contains($col4Upper, 'FUEL')
|| str_contains($col4Upper, 'PETROL')
|| str_contains($col4Upper, 'DIESEL')
|| $col4Upper === 'TP'
);
continue;
}
/* ------------------------------------------------------------------
* Row type D — Completely blank row → skip
* ------------------------------------------------------------------ */
if ($col0 === '' && $col1 === '' && $col2 === '') {
continue;
}
/* ------------------------------------------------------------------
* Row type E — Data row before any section header was seen → skip
* ------------------------------------------------------------------ */
if ($currentVehicleType === null) {
continue;
}
/* ==================================================================
* MAP COLUMNS TO FIELDS based on detected layout
* ================================================================== */
if ($layoutHasComp) {
/* ----------------------------------------------------------------
* LAYOUT A (COMP + TP both present)
* col[3] = COMP (broker rate for comprehensive)
* col[4] = TP (broker rate for third-party)
* col[7] = BROKER_EXCEL_COMP
* col[8] = BROKER_EXCEL_TP
* ---------------------------------------------------------------- */
$insurer = $col0 !== '' ? strtoupper($col0) : null;
$rto = $col1 !== '' ? strtoupper($col1) : null;
$segment = $col2 !== '' ? strtoupper($col2) : null;
$comp = $col3 !== '' ? strtoupper($col3) : null;
$tp = $col4 !== '' ? strtoupper($col4) : null;
$fuel = null;
$remarks = trim((string) ($row[5] ?? '')) ?: null;
$brokerName = trim((string) ($row[6] ?? '')) ?: null;
$brokerExcelComp = trim((string) ($row[7] ?? '')) ?: null;
$brokerExcelTp = trim((string) ($row[8] ?? '')) ?: null;
$brokerExcelOd = null;
$od = null;
/* partner_comp = broker_excel_comp retention_rate
partner_tp = broker_excel_tp retention_rate
partner_od = null (no OD broker value in Layout A)
Any of these will be null if broker_excel or retention_rate is null */
$partnerComp = $calcPartnerRate($brokerExcelComp, $retentionRate, $extractNumeric);
$partnerTp = $calcPartnerRate($brokerExcelTp, $retentionRate, $extractNumeric);
$partnerOd = null;
} else {
/* ----------------------------------------------------------------
* LAYOUT B (TP only, with FUEL column)
* col[3] = TP (broker rate for third-party)
* col[4] = FUEL type
* col[7] = BROKER_EXCEL_TP
* No COMP or OD broker excel column in this layout
* ---------------------------------------------------------------- */
$insurer = $col0 !== '' ? strtoupper($col0) : null;
$rto = $col1 !== '' ? strtoupper($col1) : null;
$segment = $col2 !== '' ? strtoupper($col2) : null;
$comp = null;
$tp = $col3 !== '' ? strtoupper($col3) : null;
$fuel = $col4 !== '' ? strtoupper($col4) : null;
$remarks = trim((string) ($row[5] ?? '')) ?: null;
$brokerName = trim((string) ($row[6] ?? '')) ?: null;
$brokerExcelComp = null;
$brokerExcelTp = trim((string) ($row[7] ?? '')) ?: null;
$brokerExcelOd = null;
$od = null;
/* partner_comp = null (no comp in Layout B)
partner_tp = broker_excel_tp retention_rate
partner_od = null (no OD broker value in Layout B) */
$partnerComp = null;
$partnerTp = $calcPartnerRate($brokerExcelTp, $retentionRate, $extractNumeric);
$partnerOd = null;
}
// Skip rows that have no essential identifiers
if (empty($insurer) || empty($segment)) {
continue;
}
/* ------------------------------------------------------------------
* OD-only row detection
* Some rows encode OD rate inside the comp column (e.g. "OD 1.5X")
* when tp is empty. Promote comp → od and clear comp.
* Recalculate partner_od from broker_excel_comp in this case.
* ------------------------------------------------------------------ */
if ($comp !== null && stripos($comp, 'OD') === 0 && $tp === null) {
$od = $comp;
$comp = null;
$brokerExcelOd = $brokerExcelComp; // broker excel comp was OD value
$brokerExcelComp = null;
// partner_od = broker_excel_od retention_rate
$partnerOd = $calcPartnerRate($brokerExcelOd, $retentionRate, $extractNumeric);
$partnerComp = null;
}
/* ==================================================================
* UPSERT into partner_insurance_payout_grid
* Natural key: vehicle_type + insurer + rto + segment
* UPDATE if record exists, INSERT otherwise.
* ================================================================== */
$existing = $this->PayoutGridModel
->where('vehicle_type', $currentVehicleType)
->where('insurer', $insurer)
->where('rto', $rto ?? '')
->where('segment', $segment)
->first();
$gridRow = [
'vehicle_type' => $currentVehicleType,
'fuel' => $fuel,
'insurer' => $insurer,
'rto' => $rto,
'broker_name' => $brokerName,
'segment' => $segment,
'comp' => $comp,
'tp' => $tp,
'od' => $od,
'remarks' => $remarks,
'broker_excel_comp' => $brokerExcelComp,
'broker_excel_tp' => $brokerExcelTp,
'broker_excel_od' => $brokerExcelOd,
// partner_* = broker_excel_* retention_rate
// null when either broker value or retention_rate is missing
'partner_comp' => $partnerComp,
'partner_tp' => $partnerTp,
'partner_od' => $partnerOd,
];
if (!empty($existing)) {
// Record already exists → UPDATE, stamp updated_by
$gridRow['updated_by'] = $createdBy;
$this->PayoutGridModel->update($existing['id'], $gridRow);
$updatedCount++;
} else {
// New record → INSERT, stamp created_by
$gridRow['created_by'] = $createdBy;
$this->PayoutGridModel->insert($gridRow);
$insertedCount++;
}
}
/* ====================================================================
* STEP 12 — Return summary response
* ==================================================================== */
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => [
'file' => $gridFileName,
'inserted' => $insertedCount,
'updated' => $updatedCount,
'retention_rate' => $retentionRate,
'message' => "Grid processed: {$insertedCount} inserted, {$updatedCount} updated.",
],
], 200);
} catch (\Exception $e) {
return $this->respond([
'status' => 'failed',
'code' => 500,
'data' => $e->getMessage(),
], 500);
}
}
// -------------------------------------------------------------------------
// List all grid records (optional utility endpoint)
// -------------------------------------------------------------------------
// GET /agent/payoutGrid?role=Manager means all list
// GET /agent/payoutGrid?role=Manager&insurer=HDFC&vehicle_type=TWO%20WHEELER&plan_type=comp
// GET /agent/payoutGrid?role=Manager&insurer=HDFC&rto=TN&segment=BIKE&plan_type=comp
// GET /agent/payoutGrid?role=Manager&insurer=HDFC&segment=BIKE&vehicle_type=TWO%20WHEELER&plan_type=comp
public function getPayoutGrid()
{
try {
$request = $this->request;
$role = $request->getGet('role');
// 1. Check if Role is provided
if (!$role) {
return $this->respond([
'status' => 'failed',
'code' => 400,
'data' => 'Role is required to fetch payout data.'
], 400);
}
// 2. Extract Filters
$insurer = $request->getGet('insurer');
$rto = $request->getGet('rto');
$segment = $request->getGet('segment');
$vehicle_type = $request->getGet('vehicle_type');
$plan_type = $request->getGet('plan_type');
// 3. Build the Grid Query
$builder = $this->PayoutGridModel->builder();
$builder->orderBy('vehicle_type', 'ASC')->orderBy('insurer', 'ASC');
// Apply filters only for authorized roles
if (in_array($role, ['Manager', 'Accounts'])) {
if (!empty($insurer)) $builder->where('insurer', $insurer);
if (!empty($rto)) $builder->where('rto', $rto);
if (!empty($segment)) $builder->where('segment', $segment);
if (!empty($vehicle_type)) $builder->where('vehicle_type', $vehicle_type);
// Handle dynamic column selection (comp/tp/od)
if (!empty($plan_type) && in_array($plan_type, ['comp', 'tp', 'od'])) {
$builder->select("id, insurer, vehicle_type, segment, rto, $plan_type as payout,fuel,broker_name,comp,tp,od,remarks,broker_excel_comp,
broker_excel_tp,broker_excel_od,partner_comp,partner_tp,partner_od,created_by,created_at,updated_by,updated_at");
} else {
// Default selection if no plan_type or invalid plan_type
$builder->select('id, insurer, vehicle_type, segment, rto, comp, tp, od, fuel,broker_name,comp,tp,od,remarks,broker_excel_comp,
broker_excel_tp,broker_excel_od,partner_comp,partner_tp,partner_od,created_by,created_at,updated_by,updated_at');
}
}
$gridResults = $builder->get()->getResult();
// 4. Combine Grid Results with Dropdown Meta-data
$responseData = [
'grid' => $gridResults,
'rtos' => $this->getUniqueColumnValues('rto'),
'segments' => $this->getUniqueColumnValues('segment'),
'vehicle_types' => $this->getUniqueColumnValues('vehicle_type'),
'insurers' => $this->getUniqueColumnValues('insurer'),
'plan_types' => [
['value' => 'comp', 'label' => 'Comprehensive'],
['value' => 'tp', 'label' => 'Third Party'],
['value' => 'od', 'label' => 'Own Damage']
]
];
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => $responseData
], 200);
} catch (\Exception $e) {
return $this->respond([
'status' => 'failed',
'code' => 500,
'data' => $e->getMessage()
], 500);
}
}
/**
* Helper function to fetch unique non-empty values for a column
*/
private function getUniqueColumnValues($column)
{
$results = $this->PayoutGridModel->select($column)
->distinct()
->where("$column IS NOT NULL")
->where("$column !=", '')
->orderBy($column, 'ASC')
->findAll();
return array_column($results, $column);
}
// -------------------------------------------------------------------------
// Update grid row by id
// Route: POST /agent/updateGrid
// -------------------------------------------------------------------------
public function updateGrid()
{
try {
$jsonData = (array) ($this->request->getJSON(true) ?? []);
$postData = $this->request->getPost() ?? [];
$data = !empty($jsonData) ? $jsonData : $postData;
$id = isset($data['id']) ? (int) $data['id'] : 0;
if ($id <= 0) {
return $this->respond([
'status' => 'failed',
'code' => 400,
'data' => 'id is required.',
], 200);
}
$existing = $this->PayoutGridModel->find($id);
if (empty($existing)) {
return $this->respond([
'status' => 'failed',
'code' => 404,
'data' => 'Grid record not found.',
], 200);
}
$updateData = [
'vehicle_type' => array_key_exists('vehicle_type', $data) ? $data['vehicle_type'] : null,
'fuel' => array_key_exists('fuel', $data) ? $data['fuel'] : null,
'rto' => array_key_exists('rto', $data) ? $data['rto'] : null,
'segment' => array_key_exists('segment', $data) ? $data['segment'] : null,
'broker_name' => array_key_exists('broker_name', $data) ? $data['broker_name'] : null,
'comp' => array_key_exists('comp', $data) ? $data['comp'] : null,
'tp' => array_key_exists('tp', $data) ? $data['tp'] : null,
'od' => array_key_exists('od', $data) ? $data['od'] : null,
'broker_excel_comp' => array_key_exists('broker_excel_comp', $data) ? $data['broker_excel_comp'] : null,
'broker_excel_tp' => array_key_exists('broker_excel_tp', $data) ? $data['broker_excel_tp'] : null,
'broker_excel_od' => array_key_exists('broker_excel_od', $data) ? $data['broker_excel_od'] : null,
'partner_comp' => array_key_exists('partner_comp', $data) ? $data['partner_comp'] : null,
'partner_tp' => array_key_exists('partner_tp', $data) ? $data['partner_tp'] : null,
'partner_od' => array_key_exists('partner_od', $data) ? $data['partner_od'] : null,
'remarks' => array_key_exists('remarks', $data) ? $data['remarks'] : null,
];
$hasAnyField = false;
foreach (array_keys($updateData) as $field) {
if (array_key_exists($field, $data)) {
$hasAnyField = true;
break;
}
}
if (!$hasAnyField) {
return $this->respond([
'status' => 'failed',
'code' => 400,
'data' => 'No update fields provided.',
], 200);
}
if (array_key_exists('updated_by', $data)) {
$updateData['updated_by'] = $data['updated_by'];
}
$this->PayoutGridModel->updateGridById($id, $updateData);
$updated = $this->PayoutGridModel->find($id);
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => $updated,
], 200);
} catch (\Exception $e) {
return $this->respond([
'status' => 'failed',
'code' => 500,
'data' => $e->getMessage(),
], 500);
}
}
// -------------------------------------------------------------------------
// 2. Download Filtered Grid in Excel
// Route: $routes->get('agent/downloadGrid', 'AgentIncentiveController::downloadGridInExcel');
// Purpose: Applies the exact same filters as getPayoutGrid(), but instead
// of returning JSON, it generates and downloads an Excel file.
// -------------------------------------------------------------------------
public function downloadGridInExcel()
{
try {
$request = $this->request;
// Get GET parameters for filtering
$role = $request->getGet('role');
$insurer = $request->getGet('insurer');
$rto = $request->getGet('rto');
$segment = $request->getGet('segment');
$vehicle_type = $request->getGet('vehicle_type');
$plan_type = $request->getGet('plan_type'); // comp, tp, od
$builder = $this->PayoutGridModel->builder();
$builder->orderBy('vehicle_type', 'ASC')->orderBy('insurer', 'ASC');
// Apply filters if the user is a Manager or Accounts role
if (in_array($role, ['Manager', 'Accounts'])) {
if (!empty($insurer)) $builder->where('insurer', $insurer);
if (!empty($rto)) $builder->where('rto', $rto);
if (!empty($segment)) $builder->where('segment', $segment);
if (!empty($vehicle_type)) $builder->where('vehicle_type', $vehicle_type);
}
// Fetch the filtered records
$records = $builder->get()->getResultArray();
if (empty($records)) {
return $this->respond([
'status' => 'failed',
'code' => 404,
'data' => 'No records found to export based on your filters.'
], 404);
}
// --- Start Excel Generation ---
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// Setup Header Row
$sheet->setCellValue('A1', 'Vehicle Type');
$sheet->setCellValue('B1', 'Insurer');
$sheet->setCellValue('C1', 'RTO');
$sheet->setCellValue('D1', 'Segment');
$sheet->setCellValue('E1', 'Broker Name'); // Changed from 'ID' for clarity
// Set the dynamic column header based on the selected plan type
if ($plan_type === 'comp') {
$sheet->setCellValue('F1', 'Comp');
$sheet->setCellValue('G1', 'Comp');
} elseif ($plan_type === 'tp') {
$sheet->setCellValue('F1', 'TP');
$sheet->setCellValue('G1', 'TP');
} elseif ($plan_type === 'od') {
$sheet->setCellValue('F1', 'OD');
$sheet->setCellValue('G1', 'OD');
} else {
// If no specific plan type is selected, show all
$sheet->setCellValue('F1', 'Comp');
$sheet->setCellValue('G1', 'TP');
$sheet->setCellValue('H1', 'OD');
$sheet->setCellValue('I1', 'Comp');
$sheet->setCellValue('J1', 'TP');
$sheet->setCellValue('K1', 'OD');
}
// Populate Excel Rows
$rowNumber = 2; // Start on row 2 (row 1 is headers)
foreach ($records as $row) {
$sheet->setCellValue('A' . $rowNumber, $row['vehicle_type']);
$sheet->setCellValue('B' . $rowNumber, $row['insurer']);
$sheet->setCellValue('C' . $rowNumber, $row['rto']);
$sheet->setCellValue('D' . $rowNumber, $row['segment']);
$sheet->setCellValue('E' . $rowNumber, $row['broker_name']);
// Output dynamic columns based on selected plan type
if ($plan_type === 'comp') {
$sheet->setCellValue('F' . $rowNumber, $row['comp']);
$sheet->setCellValue('G' . $rowNumber, $row['partner_comp']);
} elseif ($plan_type === 'tp') {
$sheet->setCellValue('F' . $rowNumber, $row['tp']);
$sheet->setCellValue('G' . $rowNumber, $row['partner_tp']);
} elseif ($plan_type === 'od') {
$sheet->setCellValue('F' . $rowNumber, $row['od']);
$sheet->setCellValue('G' . $rowNumber, $row['partner_od']);
} else {
$sheet->setCellValue('F' . $rowNumber, $row['comp']);
$sheet->setCellValue('G' . $rowNumber, $row['tp']);
$sheet->setCellValue('H' . $rowNumber, $row['od']);
$sheet->setCellValue('I' . $rowNumber, $row['partner_comp']);
$sheet->setCellValue('J' . $rowNumber, $row['partner_tp']);
$sheet->setCellValue('K' . $rowNumber, $row['partner_od']);
}
$rowNumber++;
}
// Auto-size columns for better readability
foreach (range('A', $sheet->getHighestColumn()) as $columnID) {
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
// Write the file to a temporary location
$writer = new Xlsx($spreadsheet);
$fileName = 'Filtered_Payout_Grid_' . date('Y-m-d_H-i') . '.xlsx';
$tempFile = tempnam(sys_get_temp_dir(), 'grid_export');
$writer->save($tempFile);
// Return the file as a direct download response
return $this->response->download($tempFile, null)->setFileName($fileName);
} catch (\Exception $e) {
return $this->respond([
'status' => 'failed',
'code' => 500,
'data' => 'Failed to generate Excel file: ' . $e->getMessage()
], 500);
}
}
// -------------------------------------------------------------------------
// 3. Download the Originally Uploaded Reference Grid
// Route: $routes->get('agent/downloadExistGrid', 'AgentIncentiveController::downloadLastestGrid');
// Purpose: Finds the most recently uploaded physical Excel file (where file_type='grid')
// from the partner_agent_incentive_file table and initiates a download.
// -------------------------------------------------------------------------
public function downloadLastestGrid()
{
try {
// Find the latest file entry in the database where file_type is 'grid'
$latestFileRecord = $this->AgentIncentiveFileModel
->where('file_type', 'grid')
->orderBy('created_on', 'DESC')
->first();
if (empty($latestFileRecord)) {
return $this->respond([
'status' => 'failed',
'code' => 404,
'data' => 'No uploaded reference grid file found in the database.'
], 404);
}
// Construct the exact file path where it was saved during upload
$fileName = $latestFileRecord['incentive_file_name'];
$filePath = WRITEPATH . 'uploads/agent/incentive_file/' . $fileName;
// Check if the physical file actually exists on the server
if (!file_exists($filePath)) {
return $this->respond([
'status' => 'failed',
'code' => 404,
'data' => 'The file record exists, but the physical file is missing from the server.'
], 404);
}
// Initiate the download of the physical file
return $this->response->download($filePath, null)->setFileName('Reference_Grid_' . $fileName);
} catch (\Exception $e) {
return $this->respond([
'status' => 'failed',
'code' => 500,
'data' => 'Error attempting to download file: ' . $e->getMessage()
], 500);
}
}
}