diff --git a/app/Config/Routes.php b/app/Config/Routes.php index f2b1d15..2ddf684 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -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'); diff --git a/app/Controllers/AgentIncentiveController.php b/app/Controllers/AgentIncentiveController.php index f987e98..90697df 100644 --- a/app/Controllers/AgentIncentiveController.php +++ b/app/Controllers/AgentIncentiveController.php @@ -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); - } - } - } diff --git a/app/Controllers/EndorsementController.php b/app/Controllers/EndorsementController.php index a3d16de..a788f7d 100644 --- a/app/Controllers/EndorsementController.php +++ b/app/Controllers/EndorsementController.php @@ -405,6 +405,7 @@ class EndorsementController extends ResourceController if (!empty($staff) && $staff['role_id'] == 4) { $updateData['is_data_accuracy_checked'] = 1; + $updateData['status'] = "Closed" ; } } diff --git a/app/Models/AgentIncentiveFileModel.php b/app/Models/AgentIncentiveFileModel.php index 0d56149..9a86903 100644 --- a/app/Models/AgentIncentiveFileModel.php +++ b/app/Models/AgentIncentiveFileModel.php @@ -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]' ]; } diff --git a/app/Models/PartnerInsurancePayoutGridModel.php b/app/Models/PartnerInsurancePayoutGridModel.php index 983635b..bd7598c 100644 --- a/app/Models/PartnerInsurancePayoutGridModel.php +++ b/app/Models/PartnerInsurancePayoutGridModel.php @@ -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); - } }