From 80afc350ebe7d8937098b95af9686f36ab3b6d71 Mon Sep 17 00:00:00 2001 From: "sanjeev.p" Date: Fri, 3 Apr 2026 18:57:36 +0530 Subject: [PATCH] FIX_dashboard api --- app/Controllers/DashboardController.php | 198 ++++++++++++++++++++---- 1 file changed, 169 insertions(+), 29 deletions(-) diff --git a/app/Controllers/DashboardController.php b/app/Controllers/DashboardController.php index e4a42a9..2bc7a8c 100644 --- a/app/Controllers/DashboardController.php +++ b/app/Controllers/DashboardController.php @@ -1221,24 +1221,57 @@ public function partnerDetails($id) throw new \RuntimeException('Partner not found.', 404); } - // -- 2. Policy counts + premium + commission - // mapped_policies = ALL policies under this agent (226) - // issued_policies = policy_number IS NOT NULL AND is_active = 1 (217) - // pending_policies = policy_number IS NULL (9 — raised but not yet issued) - // total_premium / commission = from issued policies only + // -- 2. Overview = current Indian financial year (Apr–Mar, Asia/Kolkata) + $fy = $this->indianFinancialYearBounds(null); + $fyStart = $fy['start']; + $fyEnd = $fy['end']; + $overviewFy = $fy['label']; + $policyStats = $this->db->table('partner_policy pp') - ->select(' - COUNT(pp.id) AS mapped_policies, - SUM(CASE WHEN pp.policy_number IS NOT NULL AND pp.is_active = 1 AND pp.premium_amount IS NOT NULL THEN 1 ELSE 0 END) AS issued_policies, - SUM(CASE WHEN pp.policy_number IS NULL THEN 1 ELSE 0 END) AS pending_policies, - COALESCE(SUM(CASE WHEN pp.policy_number IS NOT NULL THEN pp.premium_amount ELSE 0 END), 0) AS total_premium, - COALESCE(SUM(CASE WHEN pp.policy_number IS NOT NULL THEN pp.premium_amount * 0.15 ELSE 0 END), 0) AS commission_earned - ') + ->select(" + SUM(CASE WHEN pp.policy_number IS NOT NULL AND pp.issued_date >= '{$fyStart}' AND pp.issued_date <= '{$fyEnd}' THEN 1 ELSE 0 END) AS issued_policies, + SUM(CASE WHEN pp.policy_number IS NULL AND DATE(pp.created_on) >= '{$fyStart}' AND DATE(pp.created_on) <= '{$fyEnd}' THEN 1 ELSE 0 END) AS pending_policies, + COALESCE(SUM(CASE WHEN pp.policy_number IS NOT NULL AND pp.issued_date >= '{$fyStart}' AND pp.issued_date <= '{$fyEnd}' THEN pp.premium_amount ELSE 0 END), 0) AS total_premium, + COALESCE(SUM(CASE WHEN pp.policy_number IS NOT NULL AND pp.issued_date >= '{$fyStart}' AND pp.issued_date <= '{$fyEnd}' THEN COALESCE(pp.commission_amount, 0) ELSE 0 END), 0) AS commission_earned + ", false) ->where('pp.agent_id', $id) ->get()->getRowArray(); - // ── 3. Enquiry counts - // enquiry_status enum: To be assigned | Assigned | In progress | Completed + $policyStats['mapped_policies'] = (int) ($policyStats['issued_policies'] ?? 0) + (int) ($policyStats['pending_policies'] ?? 0); + + $agentId = (int) $id; + + $paidRow = $this->db->table('partner_invoice_items pii') + ->select('COALESCE(SUM(COALESCE(pii.commission_amount, 0)), 0) AS commission_paid', false) + ->join('partner_policy pp', 'pp.id = pii.policy_id', 'inner') + ->join('partner_invoice pi', 'pi.id = pii.invoice_id AND pi.is_active = 1', 'inner') + ->where('pp.agent_id', $agentId) + ->where('pii.is_active', 1) + ->where('pp.is_active', 1) + ->where('pp.policy_number IS NOT NULL') + ->where('pp.issued_date >=', $fyStart) + ->where('pp.issued_date <=', $fyEnd) + ->where( + 'JSON_SEARCH(pi.agent_id, \'one\', CAST(' . $agentId . ' AS CHAR)) IS NOT NULL', + null, + false + ) + ->where( + 'EXISTS (SELECT 1 FROM partner_invoice_utr piu WHERE piu.invoice_id = pi.id AND piu.is_active = 1 AND piu.amount > 0)', + null, + false + ) + ->get()->getRowArray(); + + $commissionEarned = (float) ($policyStats['commission_earned'] ?? 0); + $commissionPaidRaw = (float) ($paidRow['commission_paid'] ?? 0); + $commissionPaid = min($commissionPaidRaw, $commissionEarned); + $commissionUnpaid = max(0, $commissionEarned - $commissionPaid); + + $policyStats['commission_paid'] = $commissionPaid; + $policyStats['commission_unpaid'] = $commissionUnpaid; + + // ── 3. Enquiry counts (created in current FY) $enquiryStats = $this->db->table('partner_enquiry pe') ->select(' COUNT(pe.id) AS enquiry_total, @@ -1247,10 +1280,11 @@ public function partnerDetails($id) ') ->where('pe.agent_id', $id) ->where('pe.is_active', 1) + ->where('pe.created_on >=', $fyStart . ' 00:00:00') + ->where('pe.created_on <=', $fyEnd . ' 23:59:59') ->get()->getRowArray(); - // ── 4. Endorsement counts - // status is varchar(20) — adjust "Completed" to match your actual values + // ── 4. Endorsement counts (created in current FY) $endorseStats = $this->db->table('partner_endorsement_request per') ->select(' COUNT(per.id) AS endorsement_total, @@ -1259,14 +1293,16 @@ public function partnerDetails($id) ') ->where('per.agent_id', $id) ->where('per.is_active', 1) + ->where('per.created_at >=', $fyStart . ' 00:00:00') + ->where('per.created_at <=', $fyEnd . ' 23:59:59') ->get()->getRowArray(); // ── Merge everything $data = array_merge( $agent, [ - 'status' => $agent['is_active'] ? 'Active' : 'Inactive', - 'commission_rate' => 15, + 'status' => $agent['is_active'] ? 'Active' : 'Inactive', + 'overview_financial_year' => $overviewFy, ], $policyStats ?? [], $enquiryStats ?? [], @@ -1490,13 +1526,17 @@ public function partnerRenewals($id) // GET partner/{id}/earnings // partner_policy.agent_id = $id // Groups by issued_date month → month_key (YYYY-MM), month_label (Month YYYY) -// paid = MAX(is_data_accuracy_checked) — 1 if all policies in month are checked -// No month_key param → returns ALL months (FY filtering done client-side in Dart) +// payout = SUM(partner_policy.commission_amount) — total commission for the month +// payout_paid = SUM(partner_invoice_items.commission_amount) where policy belongs to agent, +// invoice lists this agent in agent_id JSON, and invoice has UTR payment (amount > 0) +// payout_unpaid = payout − payout_paid (floored at 0) +// FY filter is client-side // ══════════════════════════════════════════════════════════════════════════════ public function partnerEarnings($id) { $ref = []; $monthKey = $this->request->getGet('month_key') ?? null; + $fyParam = $this->request->getGet('financial_year') ?? null; try { if (empty($id)) { @@ -1508,6 +1548,13 @@ public function partnerEarnings($id) ], 200); } + $agentId = (int) $id; + + $fyBounds = null; + if (!empty($fyParam)) { + $fyBounds = $this->indianFinancialYearBounds($fyParam); + } + $builder = $this->db->table('partner_policy pp'); $builder->select(" @@ -1515,17 +1562,19 @@ public function partnerEarnings($id) DATE_FORMAT(pp.issued_date, '%M %Y') AS month_label, COUNT(pp.id) AS policies, COALESCE(SUM(pp.premium_amount), 0) AS premium, - COALESCE(SUM(pp.premium_amount * 0.15), 0) AS commission, - COALESCE(SUM(pp.premium_amount * 0.15 * 0.10), 0) AS tds, - COALESCE(SUM(pp.premium_amount * 0.15 * 0.90), 0) AS net_payout, - MAX(pp.is_data_accuracy_checked) AS paid + COALESCE(SUM(COALESCE(pp.commission_amount, 0)), 0) AS payout "); - $builder->where('pp.agent_id', $id); + $builder->where('pp.agent_id', $agentId); $builder->where('pp.is_active', 1); $builder->where('pp.policy_number IS NOT NULL'); $builder->where('pp.premium_amount IS NOT NULL'); + if ($fyBounds !== null) { + $builder->where('pp.issued_date >=', $fyBounds['start']); + $builder->where('pp.issued_date <=', $fyBounds['end']); + } + if (!empty($monthKey)) { $builder->where("DATE_FORMAT(pp.issued_date, '%Y-%m')", $monthKey); } @@ -1535,13 +1584,63 @@ public function partnerEarnings($id) $results = $builder->get()->getResultArray(); - $ref['month_filter'] = $monthKey ?? 'all'; - $ref['total_records'] = count($results); + // Paid commission: invoice line items tied to this agent’s policies, invoice includes agent, UTR settled + $paidBuilder = $this->db->table('partner_invoice_items pii'); + $paidBuilder->select(" + DATE_FORMAT(pp.issued_date, '%Y-%m') AS month_key, + COALESCE(SUM(COALESCE(pii.commission_amount, 0)), 0) AS payout_paid + ", false); + $paidBuilder->join('partner_policy pp', 'pp.id = pii.policy_id', 'inner'); + $paidBuilder->join('partner_invoice pi', 'pi.id = pii.invoice_id AND pi.is_active = 1', 'inner'); + $paidBuilder->where('pp.agent_id', $agentId); + $paidBuilder->where('pii.is_active', 1); + $paidBuilder->where('pp.is_active', 1); + $paidBuilder->where('pp.policy_number IS NOT NULL'); + $paidBuilder->where('pp.premium_amount IS NOT NULL'); + $paidBuilder->where( + 'JSON_SEARCH(pi.agent_id, \'one\', CAST(' . $agentId . ' AS CHAR)) IS NOT NULL', + null, + false + ); + $paidBuilder->where( + 'EXISTS (SELECT 1 FROM partner_invoice_utr piu WHERE piu.invoice_id = pi.id AND piu.is_active = 1 AND piu.amount > 0)', + null, + false + ); - if (empty($results)) { - throw new \RuntimeException('No earning data found for this partner.', 404); + if ($fyBounds !== null) { + $paidBuilder->where('pp.issued_date >=', $fyBounds['start']); + $paidBuilder->where('pp.issued_date <=', $fyBounds['end']); } + if (!empty($monthKey)) { + $paidBuilder->where("DATE_FORMAT(pp.issued_date, '%Y-%m')", $monthKey); + } + + $paidBuilder->groupBy("DATE_FORMAT(pp.issued_date, '%Y-%m')"); + $paidRows = $paidBuilder->get()->getResultArray(); + + $paidMap = []; + foreach ($paidRows as $pr) { + $paidMap[$pr['month_key']] = (float) $pr['payout_paid']; + } + + foreach ($results as &$row) { + $mk = $row['month_key']; + $payout = (float) $row['payout']; + $payoutPaid = min((float) ($paidMap[$mk] ?? 0), $payout); + $row['payout'] = $payout; + $row['payout_paid'] = $payoutPaid; + $row['payout_unpaid'] = max(0, $payout - $payoutPaid); + $row['premium'] = (float) $row['premium']; + $row['policies'] = (int) $row['policies']; + } + unset($row); + + $ref['month_filter'] = $monthKey ?? 'all'; + $ref['financial_year'] = ($fyBounds !== null) ? $fyBounds['label'] : 'all'; + $ref['total_records'] = count($results); + return $this->respond([ 'status' => 'success', 'code' => 200, @@ -1581,4 +1680,45 @@ public function partnerEarnings($id) ], 200); } } + + /** + * Indian financial year Apr 1 (Y) → Mar 31 (Y+1). + * + * @param string|null $fyStr e.g. "2025-2026" (first year is the April year) + * @return array{start: string, end: string, label: string} Y-m-d bounds + label "2025-2026" + */ + private function indianFinancialYearBounds(?string $fyStr = null): array + { + if ($fyStr !== null && preg_match('/^(\d{4})-(\d{4})$/', trim($fyStr), $m)) { + $y1 = (int) $m[1]; + $y2 = (int) $m[2]; + if ($y2 !== $y1 + 1) { + $y1 = $y1 - 1; + $y2 = $y1 + 1; + } + $start = sprintf('%04d-04-01', $y1); + $end = sprintf('%04d-03-31', $y2); + + return [ + 'start' => $start, + 'end' => $end, + 'label' => $y1 . '-' . $y2, + ]; + } + + $tz = new \DateTimeZone('Asia/Kolkata'); + $now = new \DateTime('now', $tz); + $y = (int) $now->format('Y'); + $mo = (int) $now->format('n'); + $y1 = $mo >= 4 ? $y : $y - 1; + $y2 = $y1 + 1; + $start = sprintf('%04d-04-01', $y1); + $end = sprintf('%04d-03-31', $y2); + + return [ + 'start' => $start, + 'end' => $end, + 'label' => $y1 . '-' . $y2, + ]; + } } \ No newline at end of file