FIX_Endorsement file
This commit is contained in:
parent
b792d4c058
commit
a5a9004a5d
@ -74,13 +74,9 @@ $routes->group('api', ['filter' => ["jwtAuth:1,2,3,4,agent","appSignature"] ], f
|
||||
$routes->get('agent/deleteAgentIncentiveFile', 'AgentController::deleteAgentIncentiveFile');
|
||||
$routes->get('agent/downloadAgentIncentiveFile', 'AgentController::downloadAgentIncentiveFile');
|
||||
|
||||
$routes->post('agent/uploadGrid', 'AgentIncentiveController::uploadPayoutGridFile');
|
||||
$routes->post('agent/updateGrid', 'AgentIncentiveController::updateGrid');
|
||||
$routes->get('agent/payoutGrid', 'AgentIncentiveController::getPayoutGrid');
|
||||
$routes->get('agent/downloadGrid', 'AgentIncentiveController::downloadGridInExcel');
|
||||
$routes->get('agent/loadGrid', 'AgentIncentiveController::loadGrid');
|
||||
$routes->get('agent/downloadExistGrid', 'AgentIncentiveController::downloadLastestGrid');
|
||||
|
||||
$routes->get('grid', 'AgentIncentiveController::getGridData');
|
||||
$routes->post('grid/upload', 'AgentIncentiveController::uploadGridFile');
|
||||
$routes->get('grid/fileList', 'AgentIncentiveController::gridFileList');
|
||||
|
||||
//Staff
|
||||
$routes->get('staff/staffList', 'StaffController::staffList');
|
||||
|
||||
@ -27,65 +27,87 @@ class AgentIncentiveController extends ResourceController
|
||||
$this->PartnerAgentModel = new AgentModel();
|
||||
}
|
||||
|
||||
// GET /agent/gridFileList
|
||||
public function gridFileList()
|
||||
{
|
||||
try {
|
||||
$builder = $this->AgentIncentiveFileModel->builder();
|
||||
|
||||
// 1. Explicitly select and format dates in the SQL layer (Faster + Indian Format)
|
||||
$builder->select("
|
||||
paif.id,
|
||||
paif.agent_id,
|
||||
paif.incentive_month,
|
||||
DATE_FORMAT(paif.incentive_month, '%d-%m-%Y') as vaild_from,
|
||||
paif.incentive_file_name,
|
||||
ps.name as created_by_name,
|
||||
paif.created_on,
|
||||
DATE_FORMAT(paif.created_on, '%d-%m-%Y %h:%i %p') as created_date
|
||||
");
|
||||
|
||||
$builder->from('partner_agent_incentive_file paif');
|
||||
|
||||
// 2. The Join
|
||||
$builder->join('partner_staff ps', 'ps.id = paif.created_by', 'left');
|
||||
|
||||
// 3. Filters
|
||||
$builder->where('paif.is_active', 1);
|
||||
$builder->where('paif.file_type', 'grid');
|
||||
|
||||
// 4. THE FIX: Group by the primary ID to stop the "5 rows" duplication
|
||||
$builder->groupBy('paif.id');
|
||||
|
||||
// 5. Order
|
||||
$builder->orderBy('paif.id', 'DESC');
|
||||
|
||||
$query = $builder->get();
|
||||
$result = $query->getResult();
|
||||
|
||||
// Use $this->respond to maintain consistency with your other API methods
|
||||
return $this->respond([
|
||||
'status' => 'success', // Changed to 'success' to match your other methods
|
||||
'code' => 200,
|
||||
'data' => $result
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return $this->respond([
|
||||
'status' => 'failed',
|
||||
'code' => 500,
|
||||
'data' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Upload Grid File (file_type = 'grid')
|
||||
// Parses Excel and UPSERTs rows into partner_insurance_payout_grid
|
||||
// -------------------------------------------------------------------------
|
||||
public function uploadPayoutGridFile()
|
||||
public function uploadGridFile()
|
||||
{
|
||||
try {
|
||||
/* ====================================================================
|
||||
* STEP 1 — Validate POST input
|
||||
* STEP 1 — Validate POST input (Agent ID removed)
|
||||
* ==================================================================== */
|
||||
$data = $this->request->getPost();
|
||||
$agentId = $data['agent_id'] ?? null;
|
||||
$month = $data['incentive_month'] ?? null;
|
||||
$createdBy = $data['created_by'] ?? null;
|
||||
$month = $data['incentive_month'] ?? null;
|
||||
$createdBy = $data['created_by'] ?? null;
|
||||
|
||||
if (empty($agentId) || empty($month)) {
|
||||
/* ====================================================================
|
||||
* STEP 2 — Validation now only checks for month
|
||||
* ==================================================================== */
|
||||
if (empty($month)) {
|
||||
return $this->respond([
|
||||
'status' => 'failed',
|
||||
'code' => 400,
|
||||
'data' => 'agent_id and incentive_month are required.',
|
||||
'data' => 'Incentive month is 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)
|
||||
* STEP 3 — Validate uploaded file
|
||||
* ==================================================================== */
|
||||
$gridFile = $this->request->getFile('incentive_file_name');
|
||||
|
||||
if (!$gridFile || !$gridFile->isValid()) {
|
||||
return $this->respond([
|
||||
'status' => 'failed',
|
||||
@ -94,339 +116,132 @@ class AgentIncentiveController extends ResourceController
|
||||
], 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
|
||||
* STEP 4 — Move file
|
||||
* ==================================================================== */
|
||||
$uploadPath = WRITEPATH . 'uploads/agent/incentive_file/';
|
||||
if (!is_dir($uploadPath)) {
|
||||
mkdir($uploadPath, 0777, true);
|
||||
}
|
||||
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')
|
||||
* STEP 5 — Save File record & GET THE ID
|
||||
* ==================================================================== */
|
||||
$this->AgentIncentiveFileModel->insert([
|
||||
'agent_id' => $agentId,
|
||||
$fileData = [
|
||||
'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)) {
|
||||
];
|
||||
|
||||
// insert() with returnID enabled returns the inserted primary key in CI4.
|
||||
$fileId = $this->AgentIncentiveFileModel->insert($fileData, true);
|
||||
if (empty($fileId) || (int)$fileId <= 0) {
|
||||
$modelErrors = $this->AgentIncentiveFileModel->errors();
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'code' => 200,
|
||||
'data' => [
|
||||
'inserted' => 0,
|
||||
'updated' => 0,
|
||||
'message' => 'File saved but grid sheet is empty — no rows processed.',
|
||||
],
|
||||
'status' => 'failed',
|
||||
'code' => 400,
|
||||
'data' => !empty($modelErrors) ? $modelErrors : 'Unable to create incentive file record.',
|
||||
], 200);
|
||||
}
|
||||
|
||||
/* ====================================================================
|
||||
* STEP 8 — Helper: normalise a cell value
|
||||
* Strips spaces & non-alphanumeric chars, returns lowercase.
|
||||
* Used to safely compare header/section values.
|
||||
* STEP 6 — Parse Excel
|
||||
* ==================================================================== */
|
||||
$normalize = static function ($value): string {
|
||||
$value = strtolower(trim((string) $value));
|
||||
return preg_replace('/[^a-z0-9]+/', '', $value) ?? '';
|
||||
};
|
||||
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($uploadPath . $gridFileName);
|
||||
$rows = $spreadsheet->getActiveSheet()->toArray(null, true, true, false);
|
||||
|
||||
if (empty($rows)) {
|
||||
return $this->respond(['status' => 'success', 'code' => 200, 'data' => 'File empty.'], 200);
|
||||
}
|
||||
|
||||
/* ====================================================================
|
||||
* 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
|
||||
* STEP 7 — Clean Numeric Helper (Modified to store only numbers)
|
||||
* ==================================================================== */
|
||||
$extractNumeric = static function ($value): ?float {
|
||||
$str = strtolower(trim((string) $value));
|
||||
if ($str === '' || $str === 'nan') return null;
|
||||
|
||||
// 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;
|
||||
$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;
|
||||
}
|
||||
$cleanPart = preg_replace('/[^0-9.]/', '', $part);
|
||||
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;
|
||||
// Strip everything except numbers and decimals
|
||||
$str = preg_replace('/[^0-9.]/', '', $str);
|
||||
return is_numeric($str) ? (float) $str : 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
|
||||
* STEP 8 — Process Rows
|
||||
* ==================================================================== */
|
||||
$currentVehicleType = null;
|
||||
$layoutHasComp = true; // true = Layout A, false = Layout B
|
||||
$layoutHasComp = true;
|
||||
$insertedCount = 0;
|
||||
$updatedCount = 0;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
while (count($row) < 9) $row[] = null;
|
||||
|
||||
// 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]);
|
||||
|
||||
$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'
|
||||
) {
|
||||
// Section Header Detection
|
||||
if ($col0 !== '' && ($col1 === '' || strtolower($col1) === 'nan') && strtoupper($col0) !== 'INSURER') {
|
||||
$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)
|
||||
* ------------------------------------------------------------------ */
|
||||
// Column Header Detection (Layout A vs B)
|
||||
if (strtoupper($col0) === 'INSURER') {
|
||||
$col4Upper = strtoupper($col4);
|
||||
$layoutHasComp = !(
|
||||
str_contains($col4Upper, 'FUEL')
|
||||
|| str_contains($col4Upper, 'PETROL')
|
||||
|| str_contains($col4Upper, 'DIESEL')
|
||||
|| $col4Upper === 'TP'
|
||||
);
|
||||
$col4Upper = strtoupper((string)$row[4]);
|
||||
$layoutHasComp = !preg_match('/(FUEL|PETROL|DIESEL|TP)/', $col4Upper);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Row type D — Completely blank row → skip
|
||||
* ------------------------------------------------------------------ */
|
||||
if ($col0 === '' && $col1 === '' && $col2 === '') {
|
||||
continue;
|
||||
}
|
||||
if (empty($col0) || $currentVehicleType === null) 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
|
||||
* ================================================================== */
|
||||
// Mapping with Clean Numbers
|
||||
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;
|
||||
$insurer = strtoupper($col0);
|
||||
$rto = strtoupper((string)$row[1]);
|
||||
$segment = strtoupper((string)$row[2]);
|
||||
// We extract numeric values only for the storage
|
||||
$comp = $extractNumeric($row[3]);
|
||||
$tp = $extractNumeric($row[4]);
|
||||
$od = 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;
|
||||
$brokerName = trim((string)$row[6]);
|
||||
$brokerExcelComp = $extractNumeric($row[7]);
|
||||
$brokerExcelTp = $extractNumeric($row[8]);
|
||||
$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;
|
||||
$insurer = strtoupper($col0);
|
||||
$rto = strtoupper((string)$row[1]);
|
||||
$segment = strtoupper((string)$row[2]);
|
||||
$comp = $extractNumeric($row[3]);
|
||||
$tp = 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
|
||||
$fuel = strtoupper((string)$row[4]);
|
||||
$brokerName = trim((string)$row[6]);
|
||||
$brokerExcelComp = null;
|
||||
|
||||
// partner_od = broker_excel_od − retention_rate
|
||||
$partnerOd = $calcPartnerRate($brokerExcelOd, $retentionRate, $extractNumeric);
|
||||
$partnerComp = null;
|
||||
$brokerExcelTp = $extractNumeric($row[7]);
|
||||
$brokerExcelOd = 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();
|
||||
// OD logic (if COMP contains an OD value)
|
||||
if ($comp !== null && stripos((string)$row[3], 'OD') !== false && $tp === null) {
|
||||
$od = $comp; $comp = null;
|
||||
$brokerExcelOd = $brokerExcelComp; $brokerExcelComp = null;
|
||||
}
|
||||
|
||||
$gridRow = [
|
||||
'partner_agent_incentive_file_id' => $fileId, // STORE THE FILE ID HERE
|
||||
'vehicle_type' => $currentVehicleType,
|
||||
'fuel' => $fuel,
|
||||
'insurer' => $insurer,
|
||||
@ -436,51 +251,31 @@ class AgentIncentiveController extends ResourceController
|
||||
'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,
|
||||
'remarks' => trim((string)($row[5] ?? '')),
|
||||
'broker_comp' => $brokerExcelComp,
|
||||
'broker_tp' => $brokerExcelTp,
|
||||
'broker_od' => $brokerExcelOd,
|
||||
];
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
$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.",
|
||||
'file_id' => $fileId,
|
||||
'inserted' => $insertedCount,
|
||||
'message' => "Processed: {$insertedCount} new",
|
||||
],
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return $this->respond([
|
||||
'status' => 'failed',
|
||||
'code' => 500,
|
||||
'data' => $e->getMessage(),
|
||||
], 500);
|
||||
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,11 +286,12 @@ class AgentIncentiveController extends ResourceController
|
||||
// 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()
|
||||
public function getGridData()
|
||||
{
|
||||
try {
|
||||
$request = $this->request;
|
||||
$role = $request->getGet('role');
|
||||
$file_id = $request->getGet('file_id');
|
||||
|
||||
// 1. Check if Role is provided
|
||||
if (!$role) {
|
||||
@ -526,12 +322,39 @@ class AgentIncentiveController extends ResourceController
|
||||
|
||||
// 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");
|
||||
$builder->select("id, insurer, vehicle_type, segment, rto, $plan_type as payout,fuel,broker_name,comp,tp,od,remarks,broker_comp,
|
||||
broker_tp,broker_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');
|
||||
$builder->select('id, insurer, vehicle_type, segment, rto, comp, tp, od, fuel,broker_name,comp,tp,od,remarks,broker_comp,
|
||||
broker_tp,broker_od,created_by,created_at,updated_by,updated_at');
|
||||
}
|
||||
}
|
||||
|
||||
if ($file_id) {
|
||||
$builder->where('partner_agent_incentive_file_id', $file_id);
|
||||
} else {
|
||||
$maxRow = $this->PayoutGridModel
|
||||
->selectMax('partner_agent_incentive_file_id')
|
||||
->first();
|
||||
|
||||
// Model may return array or object based on global returnType.
|
||||
$maxFileId = null;
|
||||
if (is_array($maxRow)) {
|
||||
$maxFileId = $maxRow['partner_agent_incentive_file_id'] ?? null;
|
||||
} elseif (is_object($maxRow)) {
|
||||
$maxFileId = $maxRow->partner_agent_incentive_file_id ?? null;
|
||||
}
|
||||
|
||||
if (!empty($maxFileId)) {
|
||||
$builder->where('partner_agent_incentive_file_id', $maxFileId);
|
||||
} else {
|
||||
// No data case
|
||||
return $this->respond([
|
||||
'status' => 'failed',
|
||||
'code' => 404,
|
||||
'data' => 'No data found'
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
|
||||
@ -619,12 +442,10 @@ class AgentIncentiveController extends ResourceController
|
||||
'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,
|
||||
'broker_comp' => array_key_exists('broker_comp', $data) ? $data['broker_comp'] : null,
|
||||
'broker_tp' => array_key_exists('broker_tp', $data) ? $data['broker_tp'] : null,
|
||||
'broker_od' => array_key_exists('broker_od', $data) ? $data['broker_od'] : null,
|
||||
|
||||
'remarks' => array_key_exists('remarks', $data) ? $data['remarks'] : null,
|
||||
];
|
||||
|
||||
@ -669,7 +490,7 @@ class AgentIncentiveController extends ResourceController
|
||||
// -------------------------------------------------------------------------
|
||||
// 2. Download Filtered Grid in Excel
|
||||
// Route: $routes->get('agent/downloadGrid', 'AgentIncentiveController::downloadGridInExcel');
|
||||
// Purpose: Applies the exact same filters as getPayoutGrid(), but instead
|
||||
// Purpose: Applies the exact same filters as getGridData/(:num)(), but instead
|
||||
// of returning JSON, it generates and downloads an Excel file.
|
||||
// -------------------------------------------------------------------------
|
||||
public function downloadGridInExcel()
|
||||
@ -751,20 +572,18 @@ class AgentIncentiveController extends ResourceController
|
||||
// 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++;
|
||||
}
|
||||
@ -792,52 +611,4 @@ class AgentIncentiveController extends ResourceController
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -405,6 +405,7 @@ class EndorsementController extends ResourceController
|
||||
|
||||
if (!empty($staff) && $staff['role_id'] == 4) {
|
||||
$updateData['is_data_accuracy_checked'] = 1;
|
||||
$updateData['status'] = "Closed" ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,9 +33,9 @@ class AgentIncentiveFileModel extends Model
|
||||
|
||||
// Validation rules (optional, add as per your need)
|
||||
protected $validationRules = [
|
||||
'agent_id' => 'required|integer',
|
||||
'incentive_month' => 'required|valid_date',
|
||||
'incentive_file_name'=> 'required|string|max_length[150]',
|
||||
'file_type' => 'permit_empty|max_length[50]'
|
||||
'agent_id' => 'permit_empty|integer',
|
||||
'incentive_month' => 'required|valid_date',
|
||||
'incentive_file_name' => 'required|string|max_length[150]',
|
||||
'file_type' => 'permit_empty|max_length[50]'
|
||||
];
|
||||
}
|
||||
|
||||
@ -24,12 +24,10 @@ class PartnerInsurancePayoutGridModel extends Model
|
||||
'tp',
|
||||
'od',
|
||||
'remarks',
|
||||
'broker_excel_comp',
|
||||
'broker_excel_tp',
|
||||
'broker_excel_od',
|
||||
'partner_comp',
|
||||
'partner_tp',
|
||||
'partner_od',
|
||||
'broker_comp',
|
||||
'broker_tp',
|
||||
'broker_od',
|
||||
'partner_agent_incentive_file_id',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
];
|
||||
@ -54,56 +52,6 @@ class PartnerInsurancePayoutGridModel extends Model
|
||||
|
||||
protected $skipValidation = false;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Find by the natural UPSERT key
|
||||
// -------------------------------------------------------------------------
|
||||
public function findByUpsertKey(
|
||||
string $vehicleType,
|
||||
string $insurer,
|
||||
?string $rto,
|
||||
string $segment
|
||||
): ?array {
|
||||
return $this
|
||||
->where('vehicle_type', $vehicleType)
|
||||
->where('insurer', $insurer)
|
||||
->where('rto', $rto ?? '')
|
||||
->where('segment', $segment)
|
||||
->first();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Bulk UPSERT helper
|
||||
// Accepts an array of grid rows and inserts or updates each one.
|
||||
// Returns ['inserted' => int, 'updated' => int]
|
||||
// -------------------------------------------------------------------------
|
||||
public function bulkUpsert(array $gridRows, ?int $userId = null): array
|
||||
{
|
||||
$inserted = 0;
|
||||
$updated = 0;
|
||||
|
||||
foreach ($gridRows as $row) {
|
||||
$existing = $this->findByUpsertKey(
|
||||
$row['vehicle_type'],
|
||||
$row['insurer'],
|
||||
$row['rto'] ?? null,
|
||||
$row['segment']
|
||||
);
|
||||
|
||||
$row['updated_by'] = $userId;
|
||||
|
||||
if (!empty($existing)) {
|
||||
$this->update($existing['id'], $row);
|
||||
$updated++;
|
||||
} else {
|
||||
$row['created_by'] = $userId;
|
||||
$this->insert($row);
|
||||
$inserted++;
|
||||
}
|
||||
}
|
||||
|
||||
return ['inserted' => $inserted, 'updated' => $updated];
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Fetch grid filtered by vehicle_type
|
||||
// -------------------------------------------------------------------------
|
||||
@ -127,11 +75,4 @@ class PartnerInsurancePayoutGridModel extends Model
|
||||
->findAll();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Update a grid row by id
|
||||
// -------------------------------------------------------------------------
|
||||
public function updateGridById(int $id, array $data): bool
|
||||
{
|
||||
return $this->update($id, $data);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user