diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 2ddf684..2e68cac 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -126,6 +126,7 @@ $routes->group('api', ['filter' => ["jwtAuth:1,2,3,4,agent","appSignature"] ], f $routes->get('policy/findPolicy', 'PolicyController::findPolicy'); $routes->post('policy/createPolicy', 'PolicyController::createPolicy'); $routes->post('policy/updatePolicy', 'PolicyController::updatePolicy'); + $routes->post('policy/updatePolicyCommission', 'PolicyController::updatePolicyCommission'); $routes->get('policy/downloadPolicyFile', 'PolicyController::downloadPolicyFile'); $routes->post('policy/uploadPolicyFile', 'PolicyController::uploadPolicyFile'); $routes->get("policy/searchThePolicies", "PolicyController::searchThePolicies"); @@ -196,8 +197,8 @@ $routes->group('api', ['filter' => ["jwtAuth:1,2,3,4,agent","appSignature"] ], f // GET /partner/{id}/earnings $routes->get('partner/(:num)/earnings', 'DashboardController::partnerEarnings/$1'); - - + // DASHBOARD Season 7 — Partner Portal + $routes->get('grid/download', 'ExcelExportController::downloadExcelGrid'); //invoice @@ -210,8 +211,6 @@ $routes->group('api', ['filter' => ["jwtAuth:1,2,3,4,agent","appSignature"] ], f $routes->get('invoice/getAgentUnusedCommissionList', 'InvoiceController::getAgentUnusedCommissionList'); $routes->post('invoice/bulk-upload-commission', 'InvoiceController::bulkUploadCommission'); $routes->post('invoice/bulk-upload-commission/proceed', 'InvoiceController::bulkUploadCommissionProceed'); - $routes->post('invoice/bulk-upload-commission', 'InvoiceController::bulkUploadCommission'); - $routes->post('invoice/bulk-upload-commission/proceed', 'InvoiceController::bulkUploadCommissionProceed'); // SALES EXECUTIVE diff --git a/app/Controllers/EndorsementController.php b/app/Controllers/EndorsementController.php index a788f7d..5a36221 100644 --- a/app/Controllers/EndorsementController.php +++ b/app/Controllers/EndorsementController.php @@ -316,11 +316,30 @@ class EndorsementController extends ResourceController $uploadRevisedFile->move($uploadRevisedPath, $uploadedRevisedCompletionFile); } - //COMMON UPDATE FIELDS + /* + * COMMON UPDATE FIELDS + * Keep update mapping explicit so fields sent by frontend are not silently ignored. + */ $updateData = []; // Update only if provided (avoid null overwrite) + if (isset($reqData['policy_from'])) { + $updateData['policy_from'] = $reqData['policy_from']; + } + + if (isset($reqData['policy_number'])) { + $updateData['policy_number'] = $reqData['policy_number']; + } + + if (isset($reqData['manager_id'])) { + $updateData['manager_id'] = $reqData['manager_id']; + } + + if (isset($reqData['agent_id'])) { + $updateData['agent_id'] = $reqData['agent_id']; + } + if (isset($reqData['endorsement_type'])) { $updateData['endorsement_type'] = $reqData['endorsement_type']; } @@ -349,6 +368,10 @@ class EndorsementController extends ResourceController $updateData['endorsement_premium'] = $reqData['endorsement_premium']; } + if (isset($reqData['commission_amount'])) { + $updateData['commission_amount'] = $reqData['commission_amount']; + } + if (isset($reqData['pending_days'])) { $updateData['pending_days'] = $reqData['pending_days']; } @@ -358,8 +381,13 @@ class EndorsementController extends ResourceController $updateData['endorsement_file_name'] = $uploadedOriginalCompletionFile; $updateData['endorsement_completion_file'] = $uploadedRevisedCompletionFile; // ✅ fixed variable - // External Policy Editable Fields - if ($endorsement['policy_from'] === 'External') { + /* + * External Policy Editable Fields + * Use incoming policy_from first (if provided), fallback to stored value. + * This prevents missing updates when stored value casing differs (external/External). + */ + $effectivePolicyFrom = $reqData['policy_from'] ?? $endorsement['policy_from'] ?? ''; + if (strcasecmp(trim((string)$effectivePolicyFrom), 'External') === 0) { if (isset($reqData['insurer_id'])) { $updateData['insurer_id'] = $reqData['insurer_id'] ?? null; diff --git a/app/Controllers/ExcelExportController.php b/app/Controllers/ExcelExportController.php index fe3b438..f8b3860 100644 --- a/app/Controllers/ExcelExportController.php +++ b/app/Controllers/ExcelExportController.php @@ -2550,4 +2550,179 @@ class ExcelExportController extends ResourceController } } + // grid/download?role=Manager means all list + // grid/download?role=Manager&insurer=HDFC&vehicle_type=TWO%20WHEELER&plan_type=comp + // grid/download?role=Manager&insurer=HDFC&rto=TN&segment=BIKE&plan_type=comp + // grid/download?role=Manager&insurer=HDFC&segment=BIKE&vehicle_type=TWO%20WHEELER&plan_type=comp + public function downloadExcelGrid() + { + try { + $request = $this->request; + + // ✅ Inputs + $role = trim((string) ($request->getGet('role') ?? '')); + $fileId = trim((string) ($request->getGet('file_id') ?? '')); + $insurer = trim((string) ($request->getGet('insurer') ?? '')); + $rto = trim((string) ($request->getGet('rto') ?? '')); + $segment = trim((string) ($request->getGet('segment') ?? '')); + $vehicleType = trim((string) ($request->getGet('vehicle_type') ?? '')); + $planType = strtolower(trim((string) ($request->getGet('plan_type') ?? ''))); + $search = trim((string) ($request->getGet('search') ?? '')); + $loggedId = trim((string) ($request->getGet('logged_id') ?? '')); + + if ($role === '') { + return $this->response->setJSON([ + 'status' => 'failed', + 'code' => 400, + 'data' => 'Role is required to export payout grid.', + ]); + } + + $isAgent = strtolower($role) === 'agent'; + + // ✅ Get retention rate (only for Agent) + $retentionRate = 0; + if ($isAgent && $loggedId !== '') { + $agent = $this->db->table('partner_agent') + ->select('retention_rate') + ->where('id', $loggedId) + ->get() + ->getRowArray(); + + $retentionRate = isset($agent['retention_rate']) ? (float)$agent['retention_rate'] : 0; + } + + // ✅ Main query + $builder = $this->db->table('partner_insurance_payout_grid'); + + if ($fileId !== '') { + $builder->where('partner_agent_incentive_file_id', $fileId); + } else { + $maxFileId = $this->db->table('partner_insurance_payout_grid') + ->selectMax('partner_agent_incentive_file_id') + ->get() + ->getRow() + ->partner_agent_incentive_file_id ?? null; + + if (!empty($maxFileId)) { + $builder->where('partner_agent_incentive_file_id', $maxFileId); + } + } + + // ✅ Filters + if ($insurer !== '') $builder->where('insurer', $insurer); + if ($rto !== '') $builder->where('rto', $rto); + if ($segment !== '') $builder->where('segment', $segment); + if ($vehicleType !== '') $builder->where('vehicle_type', $vehicleType); + + if (in_array($planType, ['comp', 'tp', 'od'])) { + $builder->where("$planType IS NOT NULL", null, false) + ->where("$planType !=", '') + ->where("$planType !=", '0'); + } + + // ✅ Search + if ($search !== '') { + $builder->groupStart() + ->like('insurer', $search) + ->orLike('vehicle_type', $search) + ->orLike('segment', $search) + ->orLike('rto', $search) + ->orLike('remarks', $search) + ->groupEnd(); + } + + // ✅ Fetch rows + $rows = $builder + ->select('id, insurer, vehicle_type, segment, rto, comp, tp, od, remarks') + ->orderBy('id', 'DESC') + ->get() + ->getResultArray(); + + // ========================= + // ✅ HEADERS + // ========================= + $headers = ['S.No', 'Insurer', 'Vehicle Type', 'Segment', 'RTO']; + + if ($isAgent) { + if ($planType === 'comp') { + $headers[] = 'Comp'; + } elseif ($planType === 'tp') { + $headers[] = 'TP'; + } elseif ($planType === 'od') { + $headers[] = 'OD'; + } + } else { + // ✅ Manager / Accounts + $headers[] = 'Comp'; + $headers[] = 'TP'; + $headers[] = 'OD'; + } + + $headers[] = 'Remarks'; + + // ========================= + // ✅ DATA + // ========================= + $data = []; + $sNo = 1; + + foreach ($rows as $row) { + + $comp = isset($row['comp']) ? (float)$row['comp'] : 0; + $tp = isset($row['tp']) ? (float)$row['tp'] : 0; + $od = isset($row['od']) ? (float)$row['od'] : 0; + + // ✅ Apply retention only for Agent + if ($isAgent) { + $comp -= $retentionRate; + $tp -= $retentionRate; + $od -= $retentionRate; + } + + $line = [ + $sNo++, + $row['insurer'] ?? '-', + $row['vehicle_type'] ?? '-', + $row['segment'] ?? '-', + $row['rto'] ?? '-', + ]; + + // ✅ Dynamic columns (Agent only) + if ($isAgent) { + if ($planType === 'comp') { + $line[] = $comp; + } elseif ($planType === 'tp') { + $line[] = $tp; + } elseif ($planType === 'od') { + $line[] = $od; + } + } else { + // ✅ Manager / Accounts → always all + $line[] = $comp; + $line[] = $tp; + $line[] = $od; + } + + $line[] = $row['remarks'] ?? '-'; + + $data[] = $line; + } + + // ✅ Export + $fileName = "grid_" . date('Ymd_His') . ".xlsx"; + + return $this->streamExcelFile($headers, $data, 'Payout Grid', $fileName, false); + + } catch (\Throwable $e) { + return $this->response->setJSON([ + 'status' => 'failed', + 'code' => 500, + 'data' => $e->getMessage(), + ]); + } + } + + + } diff --git a/app/Controllers/InvoiceController.php b/app/Controllers/InvoiceController.php index c275563..beb89d6 100644 --- a/app/Controllers/InvoiceController.php +++ b/app/Controllers/InvoiceController.php @@ -9,7 +9,9 @@ use App\Models\InvoiceModel; use App\Models\InvoiceItemModel; use App\Models\InvoiceUtrModel; use App\Models\PartnerAccountHistoryModel; +// use App\Models\AgentIncentiveFileModel; use CodeIgniter\Database\Exceptions\DataException; +// use PhpOffice\PhpSpreadsheet\IOFactory; class InvoiceController extends ResourceController { @@ -20,6 +22,7 @@ class InvoiceController extends ResourceController protected $InvoiceItemModel; protected $InvoiceUtrModel; protected $PartnerAccountHistoryModel; + // protected $AgentIncentiveFileModel; protected $db; public function __construct() @@ -31,6 +34,7 @@ class InvoiceController extends ResourceController $this->InvoiceItemModel = new InvoiceItemModel(); $this->InvoiceUtrModel = new InvoiceUtrModel(); $this->PartnerAccountHistoryModel = new PartnerAccountHistoryModel(); + // $this->AgentIncentiveFileModel = new AgentIncentiveFileModel(); $this->db = \Config\Database::connect(); } @@ -193,7 +197,7 @@ class InvoiceController extends ResourceController if (!$invoiceId) { // Generate invoice number only for CREATE - $invoiceData['invoice_no'] = $this->generateInvoiceNo($input['pos_id']); + $invoiceData['invoice_no'] = $this->generateInvoiceNo($input['pos_id'] ?? 0); $invoiceData['created_at'] = date('Y-m-d H:i:s'); $invoiceData['created_by'] = $input['created_by'] ?? 0; @@ -266,9 +270,8 @@ class InvoiceController extends ResourceController private function generateInvoiceNo($pos_id) { - $pos_id = !empty($pos_id) ? $pos_id : 0; $year = date('Y'); - $prefix = "NIIB/$pos_id/$year/"; + $prefix = !empty($pos_id) & $pos_id != 0 ? "NIIB/$pos_id/$year/" : "MIG/$year/"; // Get last invoice of current year $lastInvoice = $this->InvoiceModel @@ -592,6 +595,109 @@ class InvoiceController extends ResourceController } } + // public function bulkUploadCommission() + // { + // $this->db->transBegin(); + // try { + // $input = $this->request->getJSON(true); + // if (!is_array($input)) { + // $input = []; + // } + + // $post = $this->request->getPost(); + // if (!is_array($post)) { + // $post = []; + // } + + // $rows = $input['rows'] ?? []; + // $updatedBy = (int)($input['updated_by'] ?? ($post['created_by'] ?? 0)); + + // // Multipart flow: read excel on backend and store upload metadata. + // $file = $this->request->getFile('file_name'); + // if ($file && $file->isValid()) { + // $month = date('Y-m-d'); + // $uploadPath = WRITEPATH . 'uploads/agent/incentive_file/'; + // if (!is_dir($uploadPath)) { + // mkdir($uploadPath, 0777, true); + // } + + // $storedFileName = time() . '_' . $file->getRandomName(); + // $file->move($uploadPath, $storedFileName); + + // $this->AgentIncentiveFileModel->insert([ + // 'incentive_month' => $month, + // 'incentive_file_name' => $storedFileName, + // 'file_type' => 'invoice', + // 'is_active' => 1, + // 'created_by' => $updatedBy > 0 ? $updatedBy : null, + // ], true); + + // $spreadsheet = IOFactory::load($uploadPath . $storedFileName); + // $excelRows = $spreadsheet->getActiveSheet()->toArray(null, true, true, false); + + // if (empty($excelRows)) { + // return $this->respond([ + // 'status' => 'failed', + // 'code' => 400, + // 'message' => 'Uploaded file is empty', + // ], 400); + // } + + // $headerRow = $excelRows[0] ?? []; + // $headerIndex = []; + // foreach ($headerRow as $idx => $headerValue) { + // $normalized = preg_replace('/[^a-z0-9]/', '', strtolower(trim((string)$headerValue))); + // if (!empty($normalized)) { + // $headerIndex[$normalized] = (int)$idx; + // } + // } + + // $policyIdx = $headerIndex['policynumber'] ?? null; + // $invoiceIdx = $headerIndex['invoicenumber'] ?? null; + // $commissionIdx = $headerIndex['commission'] ?? ($headerIndex['commissionamount'] ?? null); + + // if ($policyIdx === null || $commissionIdx === null) { + // return $this->respond([ + // 'status' => 'failed', + // 'code' => 400, + // 'message' => 'Expected columns: Policy Number, Invoice Number, Commission or Commission Amount', + // ], 400); + // } + + // $fallbackInvoiceNo = trim((string)($post['invoice_number'] ?? '')); + // $rows = []; + // foreach ($excelRows as $index => $row) { + // if ($index === 0) { + // continue; + // } + + // $policyNo = trim((string)($row[$policyIdx] ?? '')); + // $invoiceNoFromFile = $invoiceIdx !== null ? trim((string)($row[$invoiceIdx] ?? '')) : ''; + // $invoiceNo = $invoiceNoFromFile !== '' ? $invoiceNoFromFile : $fallbackInvoiceNo; + // $commissionRaw = trim((string)($row[$commissionIdx] ?? '')); + + // if ($policyNo === '' && $invoiceNo === '' && $commissionRaw === '') { + // continue; + // } + + // $commission = (float)str_replace(',', '', $commissionRaw); + // if ($policyNo === '' || $invoiceNo === '' || !is_numeric(str_replace(',', '', $commissionRaw))) { + // return $this->respond([ + // 'status' => 'failed', + // 'code' => 400, + // 'message' => 'Invalid data at line ' . ($index + 1), + // ], 400); + // } + + // $rows[] = [ + // 'line_no' => $index + 1, + // 'policy_number' => $policyNo, + // 'invoice_no' => $invoiceNo, + // 'commission_amount' => $commission, + // ]; + // } + // } + public function bulkUploadCommission() { $this->db->transBegin(); diff --git a/app/Controllers/PolicyController.php b/app/Controllers/PolicyController.php index 855ade8..ee4cac3 100644 --- a/app/Controllers/PolicyController.php +++ b/app/Controllers/PolicyController.php @@ -411,6 +411,82 @@ class PolicyController extends ResourceController } } + public function updatePolicyCommission() + { + try { + $data = $this->request->getJSON(true); + + if (empty($data['id'])) { + return $this->respond([ + 'status' => 'failed', + 'code' => 422, + 'data' => 'Policy id is required', + ], 422); + } + + if (!isset($data['commission_amount']) || $data['commission_amount'] === '') { + return $this->respond([ + 'status' => 'failed', + 'code' => 422, + 'data' => 'commission_amount is required', + ], 422); + } + + $policyId = (int) $data['id']; + $policy = $this->PolicyModel->find($policyId); + if (!$policy) { + return $this->respond([ + 'status' => 'failed', + 'code' => 404, + 'data' => 'Policy not found', + ], 404); + } + + $commission = (float) $data['commission_amount']; + if ($commission < 0) { + return $this->respond([ + 'status' => 'failed', + 'code' => 422, + 'data' => 'commission_amount must be positive', + ], 422); + } + + /* + * Commission-only update endpoint. + * Keeps the existing policy workflow unchanged and updates only required fields. + */ + $updateData = [ + 'commission_amount' => number_format($commission, 2, '.', ''), + 'updated_by' => $data['updated_by'] ?? null, + 'updated_on' => date('Y-m-d H:i:s'), + ]; + + if (!$this->PolicyModel->update($policyId, $updateData)) { + return $this->respond([ + 'status' => 'failed', + 'code' => 422, + 'data' => $this->PolicyModel->errors(), + ], 422); + } + + return $this->respond([ + 'status' => 'success', + 'code' => 200, + 'data' => [ + 'policy_id' => (string) $policyId, + 'commission_amount' => $updateData['commission_amount'], + 'message' => 'Commission updated successfully', + ], + ], 200); + } catch (\Exception $e) { + return $this->respond([ + 'status' => 'failed', + 'code' => 500, + 'data' => $e->getMessage(), + ], 500); + } + } + public function uploadPolicyFile() { try { diff --git a/app/Models/PolicyModel.php b/app/Models/PolicyModel.php index b53c047..7dc61e5 100644 --- a/app/Models/PolicyModel.php +++ b/app/Models/PolicyModel.php @@ -30,6 +30,7 @@ class PolicyModel extends Model 'pt_oc_share_details_id', 'created_by', 'updated_by', + 'updated_on', // newly added 'tp',