db = \Config\Database::connect(); } public function managerDashboard() { $manager_id = $this->request->getGet('manager_id'); $staff_id = $this->request->getGet('staff_id') ?? ''; $today = date('Y-m-d'); $month = date('m'); $year = date('Y'); // --- Policies Issued --- $policiesToday = $this->db->table('partner_policy') ->where('created_on >=', $today.' 00:00:00') ->where('created_on <=', $today.' 23:59:59') ->where('manager_id',$manager_id) ->countAllResults(); $policiesMonth = $this->db->table('partner_policy') ->where('MONTH(created_on)', $month) ->where('YEAR(created_on)', $year) ->where('manager_id',$manager_id) ->countAllResults(); $policiesYear = $this->db->table('partner_policy') ->where('YEAR(created_on)', $year) ->where('manager_id',$manager_id) ->countAllResults(); // --- Premium Value --- $premiumToday = (float) ($this->db->table('partner_policy') ->selectSum('premium_amount', 'total') ->where('created_on >=', $today.' 00:00:00') ->where('created_on <=', $today.' 23:59:59') ->where('manager_id',$manager_id) ->get()->getRow()->total ?? 0); $premiumMonth = (float) ($this->db->table('partner_policy') ->selectSum('premium_amount', 'total') ->where('MONTH(created_on)', $month) ->where('YEAR(created_on)', $year) ->where('manager_id',$manager_id) ->get()->getRow()->total ?? 0); $premiumYear = (float) ($this->db->table('partner_policy') ->selectSum('premium_amount', 'total') ->where('YEAR(created_on)', $year) ->where('manager_id',$manager_id) ->get()->getRow()->total ?? 0); // --- Earnings (same as premium for now) --- $earningsToday = $premiumToday; $earningsMonth = $premiumMonth; $earningsYear = $premiumYear; $last30 = date('Y-m-d H:i:s', strtotime('-30 days')); // --- Performance Agents (last 30 days) --- $performanceAgents = $this->db->table('partner_agent pa') ->select('pa.id AS agent_id, pa.name AS agent_name, COUNT(pp.id) AS total_policy_issued, COALESCE(SUM(pp.premium_amount),0) AS total_premium_value, IF(COUNT(pp.id)>0,"Active","Inactive") AS status') ->join('partner_policy pp', 'pp.agent_id = pa.id', 'inner') ->where('pp.created_on >=', $last30) ->where('pa.manager_id',$manager_id) ->get() ->getResultArray(); if(count($performanceAgents) == 1 && $performanceAgents[0]['agent_name'] == null){ $performanceAgents = []; } // --- Un assigned enquiry --- $unassignedEnquiry = $this->db->table('partner_enquiry pe') ->select('pe.* , pe.name as insured_name , pa.name as agent_name, pa.agent_code') ->join('partner_agent pa', 'pa.id = pe.agent_id', 'left') ->where('pe.assigned_to', 0) ->where('pe.manager_id', $manager_id) ->get() ->getResultArray(); // // --- Staff level Quotations Pending --- // $quotationsPending = $this->db->table('partner_staff ps') // ->select('ps.name as staff_name, COUNT(pe.id) as total_quotation_pending') // ->join('partner_enquiry pe', "pe.assigned_to = ps.id AND pe.status = 'Awaiting Proposal'", 'left') // ->where('ps.role_id', 2) // ->where('ps.manager_id',$manager_id) // ->groupBy('ps.id, ps.name') // ->get()->getResultArray(); // // --- Staff level Quotations Approva Pending --- // $quotationsApprovalPending = $this->db->table('partner_staff ps') // ->select('ps.name as staff_name, COUNT(pe.id) as total_approval_pending') // ->join('partner_enquiry pe', "pe.assigned_to = ps.id AND pe.status = 'Proposal Created'", 'left') // ->where('ps.role_id', 2) // ->where('ps.manager_id',$manager_id) // ->groupBy('ps.id, ps.name') // ->get()->getResultArray(); // // --- Staff level Policies Pending --- // $policiesPending = $this->db->table('partner_staff ps') // ->select('ps.name as staff_name, COUNT(pe.id) as total_policis_pending, SUM(pq.premium_amount) as total_premium_value') // ->join('partner_enquiry pe', "pe.assigned_to = ps.id AND pe.status = 'Proposal Accepted'", 'left') // ->join('partner_quotation pq', "pq.enquiry_id = pe.id AND pq.status = 'Accepted'", 'left') // ->where('ps.role_id', 2) // ->where('ps.manager_id',$manager_id) // ->groupBy('ps.id, ps.name') // ->get()->getResultArray(); $builder = $this->db->table('partner_enquiry pe') ->select(" ps.name AS staff_name, ps.id AS staff_id, ps.handler_id, COUNT(pe.id) AS total_assigned, SUM(CASE WHEN pe.enquiry_status != 'Completed' THEN 1 ELSE 0 END) AS total_pending, SUM(CASE WHEN DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_assigned, SUM(CASE WHEN pe.enquiry_status = 'Assigned' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_pending, SUM(CASE WHEN pe.enquiry_status = 'In progress' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_in_progress, SUM(CASE WHEN pe.enquiry_status = 'Completed' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_completed, ") ->join('partner_staff ps', 'ps.id = pe.assigned_to AND ps.is_active = 1', 'left') ->where('pe.manager_id', $manager_id) ->where('pe.is_active', 1) ->where('pe.assigned_to IS NOT NULL') ->where('ps.name IS NOT NULL') ->where('pe.assigned_to !=', 0); if (!empty($staff_id)) { $builder->where('ps.id', $staff_id); } $staffLevelPendingSummary = $builder ->groupBy('pe.assigned_to') ->orderBy('ps.name', 'ASC') ->get() ->getResultArray(); foreach ($staffLevelPendingSummary as &$row) { $handlerIds = json_decode($row['handler_id'] ?? '[]', true); if (!empty($handlerIds)) { $handlers = $this->db->table('partner_staff') ->select('name') ->whereIn('id', $handlerIds) ->get() ->getResultArray(); $row['handlers'] = array_column($handlers, 'name'); } else { $row['handlers'] = []; } } $result = [ 'policies_issued' => [ 'today' => $policiesToday, 'month' => $policiesMonth, 'year' => $policiesYear, ], 'premium_value' => [ 'today' => $premiumToday, 'month' => $premiumMonth, 'year' => $premiumYear, ], 'earnings' => [ 'today' => $earningsToday, 'month' => $earningsMonth, 'year' => $earningsYear, ], 'agents_performance' => $performanceAgents, 'unassigned_enquiry' => $unassignedEnquiry, // 'quotations_pending' => $quotationsPending, // 'quotations_approval_pending' => $quotationsApprovalPending, // 'policies_pending' => $policiesPending, 'staff_level_pending_summary' => $staffLevelPendingSummary ]; return $this->respond(['status' => 'success', 'code' => 200, 'data' => $result], 200); } public function handlerDashboard() { $handler_id = $this->request->getGet('handler_id'); $manager_id = $this->request->getGet('manager_id'); if (empty($handler_id)) { return $this->response->setJSON([ 'status' => false, 'message' => 'Handler ID is required.' ]); } $staffLevelPendingSummary = $this->db->table('partner_enquiry pe') ->select(" ps.name AS staff_name, ps.id AS staff_id, COUNT(pe.id) AS total_assigned, SUM(CASE WHEN pe.enquiry_status != 'Completed' THEN 1 ELSE 0 END) AS total_pending, SUM(CASE WHEN DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_assigned, SUM(CASE WHEN pe.enquiry_status = 'Assigned' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_pending, SUM(CASE WHEN pe.enquiry_status = 'In progress' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_in_progress, SUM(CASE WHEN pe.enquiry_status = 'Completed' AND DATE(pe.created_on) = CURDATE() THEN 1 ELSE 0 END) AS today_completed, ") ->join('partner_staff ps', 'ps.id = pe.assigned_to', 'left') ->groupStart() ->where("JSON_CONTAINS(ps.handler_id, '\"$handler_id\"')") ->orWhere('ps.id', $handler_id) ->groupEnd() // ->where('ps.handler_id', $handler_id) ->where('pe.is_active', 1) ->where('pe.assigned_to IS NOT NULL') ->where('pe.assigned_to !=', 0) ->groupBy('pe.assigned_to') ->orderBy('ps.name', 'ASC') ->get() ->getResultArray(); $last30 = date('Y-m-d H:i:s', strtotime('-30 days')); // --- Performance Agents (last 30 days) --- $performanceAgents = $this->db->table('partner_agent pa') ->select('pa.id AS agent_id, pa.name AS agent_name, COUNT(pp.id) AS total_policy_issued, COALESCE(SUM(pp.premium_amount),0) AS total_premium_value, IF(COUNT(pp.id)>0,"Active","Inactive") AS status') ->join('partner_policy pp', 'pp.agent_id = pa.id', 'inner') ->where('pp.created_on >=', $last30) ->where('pa.manager_id',$manager_id) ->get() ->getResultArray(); if(count($performanceAgents) == 1 && $performanceAgents[0]['agent_name'] == null) { $performanceAgents = []; } // --- Un assigned enquiry --- $unassignedEnquiry = $this->db->table('partner_enquiry pe') ->select('pe.* , pe.name as insured_name , pa.name as agent_name, pa.agent_code') ->join('partner_agent pa', 'pa.id = pe.agent_id', 'left') ->where('pe.assigned_to', 0) ->where('pe.manager_id', $manager_id) ->get() ->getResultArray(); $result = [ 'staff_level_pending_summary' => $staffLevelPendingSummary, 'agents_performance' => $performanceAgents, 'unassigned_enquiry' => $unassignedEnquiry, ]; return $this->respond(['status' => 'success', 'code' => 200, 'data' => $result], 200); } public function staffDashboard() { $staff_id = $this->request->getGet('staff_id'); // --- Proposal pending for staff (last 30 days) --- $quotationsPending = $this->db->table('partner_enquiry pe') ->select('pe.* ') ->where('pe.assigned_to',$staff_id) ->whereIn('pe.status',["Awaiting Proposal","Proposal Rejected"]) ->orderBy('pe.created_on', 'DESC') ->get() ->getResultArray(); // --- Proposal Approval pending for staff (last 30 days) --- $quotationsApprovalPending = $this->db->table('partner_enquiry pe') ->select('pe.* ') ->where('pe.assigned_to',$staff_id) ->whereIn('pe.status',["Proposal Created"]) ->orderBy('pe.created_on', 'DESC') ->get() ->getResultArray(); // --- Policy pending for staff (last 30 days) --- $policiesPending = $this->db->table('partner_enquiry pe') ->select('pe.* , I.name as insurer_name, I.short_name as insurer_short_name') ->join('partner_quotation Q', 'Q.enquiry_id = pe.id AND Q.status = "Accepted"', 'left') ->join('insurers I', 'I.id = Q.insurer_id', 'left') ->where('pe.assigned_to',$staff_id) ->whereIn('pe.status',["Proposal Accepted"]) ->orderBy('pe.created_on', 'DESC') ->get() ->getResultArray(); $result = [ 'quotations_pending' => $quotationsPending, 'quotations_approval_pending' => $quotationsApprovalPending, 'quotations_rejected' => $quotationsApprovalPending, 'policies_pending' => $policiesPending, ]; return $this->respond(['status' => 'success', 'code' => 200, 'data' => $result], 200); } public function agentDashboard() { $agent_id = $this->request->getGet('agent_id'); $today = date('Y-m-d'); $month = date('m'); $year = date('Y'); // --- Policies Issued --- $policiesToday = $this->db->table('partner_policy') ->where('created_on >=', $today.' 00:00:00') ->where('created_on <=', $today.' 23:59:59') ->where('agent_id',$agent_id) ->countAllResults(); $policiesMonth = $this->db->table('partner_policy') ->where('MONTH(created_on)', $month) ->where('YEAR(created_on)', $year) ->where('agent_id',$agent_id) ->countAllResults(); $policiesYear = $this->db->table('partner_policy') ->where('YEAR(created_on)', $year) ->where('agent_id',$agent_id) ->countAllResults(); // --- Premium Value --- $premiumToday = (float) ($this->db->table('partner_policy') ->selectSum('premium_amount', 'total') ->where('created_on >=', $today.' 00:00:00') ->where('created_on <=', $today.' 23:59:59') ->where('agent_id',$agent_id) ->get()->getRow()->total ?? 0); $premiumMonth = (float) ($this->db->table('partner_policy') ->selectSum('premium_amount', 'total') ->where('MONTH(created_on)', $month) ->where('YEAR(created_on)', $year) ->where('agent_id',$agent_id) ->get()->getRow()->total ?? 0); $premiumYear = (float) ($this->db->table('partner_policy') ->selectSum('premium_amount', 'total') ->where('YEAR(created_on)', $year) ->where('agent_id',$agent_id) ->get()->getRow()->total ?? 0); // --- Earnings (same as premium for now) --- $earningsToday = $premiumToday; $earningsMonth = $premiumMonth; $earningsYear = $premiumYear; $last30 = date('Y-m-d H:i:s', strtotime('-30 days')); // --- Proposal pending for agent (last 30 days) --- $quotationsPending = $this->db->table('partner_enquiry pe') ->select('pe.* ') ->where('pe.created_on >=', $last30) ->where('pe.agent_id',$agent_id) ->whereIn('pe.status',["Awaiting Proposal","Proposal Rejected"]) ->orderBy('pe.created_on', 'DESC') ->get() ->getResultArray(); // --- Proposal approval pending for agent (last 30 days) --- $quotationsApprovalPending = $this->db->table('partner_enquiry pe') ->select('pe.* ') ->where('pe.created_on >=', $last30) ->where('pe.agent_id',$agent_id) ->whereIn('pe.status',["Awaiting Created"]) ->orderBy('pe.created_on', 'DESC') ->get() ->getResultArray(); // --- Policy pending for agent (last 30 days) --- $policiesPending = $this->db->table('partner_enquiry pe') ->select('pe.* , I.name as insurer_name , I.short_name as insurer_short_name') ->join('partner_quotation Q', 'Q.enquiry_id = pe.id AND Q.status = "Accepted"', 'left') ->join('insurers I', 'I.id = Q.insurer_id', 'left') ->where('pe.created_on >=', $last30) ->where('pe.agent_id',$agent_id) ->where('pe.status','Proposal Accepted') ->orderBy('pe.created_on', 'DESC') ->get() ->getResultArray(); $result = [ 'policies_issued' => [ 'today' => $policiesToday, 'month' => $policiesMonth, 'year' => $policiesYear, ], 'premium_value' => [ 'today' => $premiumToday, 'month' => $premiumMonth, 'year' => $premiumYear, ], 'earnings' => [ 'today' => $earningsToday, 'month' => $earningsMonth, 'year' => $earningsYear, ], 'quotations_pending' => $quotationsPending, 'quotations_approval_pending' => $quotationsApprovalPending, 'policies_pending' => $policiesPending, ]; return $this->respond(['status' => 'success', 'code' => 200, 'data' => $result], 200); } //business dashboard = month-wise insurer,broker and product (PolicyCount , Premium) public function businessDashboard() { $raw = false;$ref = []; $manager_id = $this->request->getGet('manager_id'); $raw_param = strtolower(trim($this->request->getGet('raw') ?? '')); $raw = in_array($raw_param, ['true', '1'], true); // Initialize the details array to ensure the final output is always structured. $details = [ 'brokerWise' => [], 'productWise' => [], 'insurerWise' => []]; $message = "Business Dashboard Data Retrieved Successfully"; try { // 1. Fetch all data concurrently (or sequentially, as shown) $details['brokerWise'] = $this->brokerWise($manager_id,$raw); $details['productWise'] = $this->productWise($manager_id,$raw); $details['insurerWise'] = $this->insurerWise($manager_id,$raw); $ref['message'] = $message; $ref['brokerWise_total_records'] = is_array($details['brokerWise']) ? count($details['brokerWise']) : 0; $ref['productWise_total_records'] = is_array($details['productWise']) ? count($details['productWise']) : 0 ; $ref['insurerWise_total_records'] = is_array($details['insurerWise']) ? count($details['insurerWise']) : 0; // 2. Check for overall emptiness (optional, but good practice) $is_empty = array_reduce($details, function ($carry, $item) { return $carry && empty($item); }, true); if ($is_empty) { // Throw a 404 if ALL data sections are empty throw new \RuntimeException('No Data Found', 404); } // 3. Return a successful, combined JSON response return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $details, 'ref' => $ref ], 200); } catch (\Throwable $e) { if ($e instanceof \RuntimeException && $e->getCode() === 404) { $ref['message'] = 'No Data Found'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'ref' => $ref], 200); } $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { $ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine(); $ref['message'] = 'Database Error Occurred.'; } else { $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } return $this->respond([ 'status' => 'error', 'code' => $e->getCode(), 'data' => [], 'ref' => $ref], 200); } } //partner dashboard = month-wise PolicyCount , month-wise Premium, No Agent For Last 10 Days and below 50thouands Premium agentwise public function partnerDashboard() { $raw = false;$ref = []; $manager_id = $this->request->getGet('manager_id'); $raw_param = strtolower(trim($this->request->getGet('raw') ?? '')); $raw = in_array($raw_param, ['true', '1'], true); // Initialize the details array to ensure the final output is always structured. $message = "Partner Dashboard Data Retrieved Successfully"; $details = [ 'agentsPerformanceList' => [],'nonAgentsPerformanceList' => [],'nonAgentsPerformanceListPremium' => []]; // 'agentNoPolicyLast10Days' => [],// 'agentBelow50tPremiumLast10Days' => [], try { // 1. Fetch all data concurrently (or sequentially, as shown) $from_date = $this->request->getGet('from_date'); $to_date = $this->request->getGet('to_date'); if (empty($from_date) || empty($to_date)) { // Default last 10 days $fromDate = date('Y-m-d', strtotime('-10 days')); $toDate = date('Y-m-d'); } else { // Convert d-m-Y → Y-m-d $fromDate = DateTime::createFromFormat('d-m-Y', $from_date)->format('Y-m-d 00:00:00'); $toDate = DateTime::createFromFormat('d-m-Y', $to_date)->format('Y-m-d 23:59:59'); } $data1 = $this->getDataPerformingAgents($fromDate, $toDate, $manager_id, false); if (!empty($data1)) { $lastIndex1 = count(reset($data1)) - 1; usort($data1, function($a, $b) use ($lastIndex1) { $rowA = array_values($a); $rowB = array_values($b); return (float)$rowB[$lastIndex1] <=> (float)$rowA[$lastIndex1]; }); } $details['agentsPerformanceList'] = $data1; $details['nonAgentsPerformanceList'] = $this->getDataNonAgentsPerformanceList($fromDate, $toDate,$manager_id,$raw); $data2 = $this->getDataLowPremiumAgent($fromDate, $toDate,$manager_id,$raw); if (!empty($data2)) { $lastIndex2 = count(reset($data2)) - 1; usort($data2, function($a, $b) use ($lastIndex2) { $rowC = array_values($a); $rowD = array_values($b); return (float)$rowD[$lastIndex2] <=> (float)$rowC[$lastIndex2]; }); } $details['nonAgentsPerformanceListPremium'] = $data2; // $details['agentsPerformanceListPremium'] = $this->agentMonthlyPremiumAmount($date,$manager_id,$raw); $ref['agentsPerformanceList_monthlyPolicyCountAndPremiumAmount_totalRecords'] = is_array($details['agentsPerformanceList']) ? count($details['agentsPerformanceList']) : 0; $ref['nonAgentsPerformanceList_noPolicyTimeRange_totalRecords'] = is_array($details['nonAgentsPerformanceList']) ? count($details['nonAgentsPerformanceList']) : 0; $ref['nonAgentsPerformanceListPremium_below50tPremiumTimeRange_totalRecords'] = is_array($details['nonAgentsPerformanceListPremium']) ? count($details['nonAgentsPerformanceListPremium']) : 0; // 2. Check for overall emptiness (optional, but good practice) $is_empty = array_reduce($details, function ($carry, $item) { return $carry && empty($item); }, true); if ($is_empty) { throw new \RuntimeException('No Data Found', 404); } // 3. Return a successful, combined JSON response return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $details, 'ref' => $ref ], 200); } catch (\Throwable $e) { if ($e instanceof \RuntimeException && $e->getCode() === 404) { $ref['message'] = 'No Data Found'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'ref' => $ref], 200); } $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { $ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine(); $ref['message'] = 'Database Error Occurred.'; } else { $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } return $this->respond([ 'status' => 'error', 'code' => $e->getCode(), 'data' => [], 'ref' => $ref], 200); } } public function productivityDashboard(){ $raw = false;$ref = []; $manager_id = $this->request->getGet('manager_id'); $raw_param = strtolower(trim($this->request->getGet('raw') ?? '')); $raw = in_array($raw_param, ['true', '1'], true); // Initialize the details array to ensure the final output is always structured. $details = [ 'StaffWise' => []]; $message = "Productivity Dashboard Data Retrieved Successfully"; try { // 1. Fetch all data concurrently (or sequentially, as shown) $details['StaffWise'] = $this->staffWiseProductList($manager_id,$raw); $ref['StaffWise_total_records'] = is_array($details['StaffWise']) ? count($details['StaffWise']) : 0; // 2. Check for overall emptiness (optional, but good practice) $is_empty = array_reduce($details, function ($carry, $item) { return $carry && empty($item); }, true); if ($is_empty) { // Throw a 404 if ALL data sections are empty throw new \RuntimeException('No Data Found', 404); } // 3. Return a successful, combined JSON response return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $details, 'ref' => $ref ], 200); } catch (\Throwable $e) { if ($e instanceof \RuntimeException && $e->getCode() === 404) { $ref['message'] = 'No Data Found'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'ref' => $ref], 200); } $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { $ref['debug_info'] = $e->getFile() . " / LN : " . $e->getLine(); $ref['message'] = 'Database Error Occurred.'; } else { $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } return $this->respond([ 'status' => 'error', 'code' => $e->getCode(), 'data' => [], 'ref' => $ref], 200); } } //Step 1.1 public function insurerWise($manager_id, $raw){ $builder = $this->db->table('partner_policy pp'); $builder->select(" i.name, i.short_name, i.id AS insurer_id, pp.insured_name, COUNT( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.policy_number ELSE NULL END ) AS total_policies_current_month, SUM( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.premium_amount ELSE 0 END ) AS total_premium_current_month, COUNT( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.policy_number ELSE NULL END ) AS total_policies_pre_month, SUM( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.premium_amount ELSE 0 END ) AS total_premium_pre_month "); $builder->join('partner_quotation pq', 'pq.id = pp.quotation_id', 'left'); $builder->join('insurers i', 'i.id = pq.insurer_id', 'left'); $builder->where(" pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') ", null, false); $builder->where('pp.manager_id',$manager_id); $builder->where('i.is_active',1); $builder->where("pq.insurer_id != 0"); $builder->groupBy('pq.insurer_id'); $builder->orderBy('pq.insurer_id'); if ($raw === true) { return $builder->getCompiledSelect(); } $query = $builder->get(); $result = $query->getResultArray(); return $result; } //Step 1.2 public function brokerWise($manager_id, $raw){ $builder = $this->db->table('partner_policy pp'); $builder->select(" pb.name AS broker_name, pb.short_name AS broker_short_name, pb.id AS broker_id, COUNT( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.policy_number ELSE NULL END ) AS total_policies_current_month, SUM( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.premium_amount ELSE 0 END ) AS total_premium_current_month, COUNT( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.policy_number ELSE NULL END ) AS total_policies_pre_month, SUM( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.premium_amount ELSE 0 END ) AS total_premium_pre_month "); $builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left'); $builder->join('partner_brokers pb', 'pb.id = pe.broker_id', 'left'); $builder->where(" pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') ", null, false); $builder->where('pp.manager_id',$manager_id); $builder->groupBy('pb.id'); $builder->orderBy('pb.id'); if ($raw === true) { return $builder->getCompiledSelect(); } $query = $builder->get(); $result = $query->getResultArray(); return $result; } //Step 1.3 public function productWise($manager_id , $raw){ $builder = $this->db->table('partner_policy pp'); $builder->select(" pp.vehicle_type, COUNT( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.policy_number ELSE NULL END ) AS total_policies_current_month, SUM( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.premium_amount ELSE 0 END ) AS total_premium_current_month, COUNT( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.policy_number ELSE NULL END ) AS total_policies_pre_month, SUM( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.premium_amount ELSE 0 END ) AS total_premium_pre_month "); $builder->where(" pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') ", null, false); $builder->where('pp.manager_id',$manager_id); $builder->groupBy('pp.vehicle_type'); if ($raw === true) { return $builder->getCompiledSelect(); } $query = $builder->get(); $result = $query->getResultArray(); return $result; } //Step 2 public function getDataPerformingAgents($fromDate, $toDate, $manager_id, $raw){ $builder = $this->db->table('partner_policy pp'); $builder->select(" pa.id AS agent_id, pa.name AS agent_name, pa.agent_code, COUNT(pp.policy_number) AS policy_count, SUM(pp.premium_amount) AS total_premium_amount "); $builder->join('partner_agent pa', 'pp.agent_id = pa.id', 'inner'); $builder->join('partner_enquiry pe', 'pe.id = pp.enquiry_id', 'left'); $builder->where('pp.issued_date >=', $fromDate); $builder->where('pp.issued_date <=', $toDate); // $builder->where('pp.manager_id',$manager_id); $builder->groupBy(['pa.id']); $builder->orderBy('policy_count', 'DESC'); $builder->limit(50); if ($raw === true) { return $builder->getCompiledSelect(); } $result = $builder->get()->getResultArray(); // echo $this->db->getLastQuery()->getQuery();die; return $result; } // public function agentMonthlyPremiumAmount($customDate,$manager_id, $raw){ // $builder = $this->db->table('partner_policy pp'); // $builder->select(" // pa.id AS agent_id, // pa.name AS agent_name, // pa.agent_code, // SUM(pp.premium_amount) AS total_premium_amount // "); // $builder->join('partner_agent pa', 'pp.agent_id = pa.id', 'inner'); // $builder->where("MONTH(pp.issued_date) = MONTH('$customDate')", null, false); // $builder->where("YEAR(pp.issued_date) = YEAR('$customDate')", null, false); // $builder->where('pp.manager_id',$manager_id); // $builder->groupBy(['pa.id','pa.name','pa.agent_code']); // $builder->orderBy('total_premium_amount', 'DESC'); // $builder->limit(50); // if ($raw === true) { // return $builder->getCompiledSelect(); // } // $result = $builder->get()->getResultArray(); // return $result; // } //Step 3 no buiness // public function getDataNonAgentsPerformanceList($managerId, $raw){ // // $builder = $this->db->table('partner_agent pa'); // // $builder->select(' // // pa.id AS agent_id, // // pa.name AS agent_name, // // pa.email, // // pa.mobile, // // pa.agent_code, // // pa.is_active // // '); // // $builder->join( // // 'partner_policy pp', // // "pa.id = pp.agent_id AND pp.issued_date >= $interval AND pp.manager_id = $manager_id", // // 'left', // // false // IMPORTANT → allows raw SQL // // ); // // $builder->where('pa.manager_id',$manager_id); // // $builder->where('pp.id', null); // // $builder->orderBy('pa.name'); // // 1. Select the required columns // $builder = $this->db->table('partner_agent pa'); // $builder->select(' // pa.id AS agent_id, // pa.agent_code, // pa.name AS agent_name, // pa.email, // pa.mobile, // pa.is_active, // MAX(hist.issued_date) AS last_issued_date // '); // // 2. INNER JOIN ensures they have at least one policy in history (skips new/empty agents) // $builder->join('partner_policy hist', 'pa.id = hist.agent_id', 'inner'); // // 3. LEFT JOIN checks for policies in the last 10 days // $builder->join('partner_policy recent', // "pa.id = recent.agent_id AND recent.issued_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 10 DAY)", // 'left' // ); // // 4. Filters // $builder->where('pa.manager_id', $managerId); // $builder->where('pa.is_active', 1); // $builder->where('recent.id', NULL); // Keeps only those with NO activity in the 10-day window // // 5. Grouping and Ordering // $builder->groupBy('pa.id'); // $builder->orderBy('pa.name', 'ASC'); // // 6. Get Raw Query // if ($raw === true) { // return $builder->getCompiledSelect(); // } // // 7. Execute // $query = $builder->get(); // $result = $query->getResult(); // // 8. To verify the exact SQL for debugging: // // echo (string) $db->getLastQuery(); // // echo $this->db->getLastQuery()->getQuery();die; // return $result; // } public function getDataNonAgentsPerformanceList($fromDate, $toDate, $managerId, $raw) { $builder = $this->db->table('partner_agent pa'); $builder->select(' pa.id AS agent_id, pa.agent_code, pa.name AS agent_name, pa.email, pa.mobile, pa.is_active, MAX(hist.issued_date) AS last_issued_date '); // Must have at least one policy ever $builder->join( 'partner_policy hist', 'pa.id = hist.agent_id', 'inner' ); // Check activity inside the date range $builder->join( 'partner_policy recent', "pa.id = recent.agent_id AND recent.issued_date >= '{$fromDate}' AND recent.issued_date <= '{$toDate}'", 'left' ); // Filters $builder->where('pa.manager_id', $managerId); $builder->where('pa.is_active', 1); // Key condition → NO activity in date range $builder->where('recent.agent_id IS NULL', null, false); // Group & Order $builder->groupBy('pa.id'); $builder->orderBy('pa.name', 'ASC'); if ($raw === true) { return $builder->getCompiledSelect(); } return $builder->get()->getResult(); } //Step 4 //any changed in this query also change in do the same in ExcelExportController - getDataLowPremiumAgent public function getDataLowPremiumAgent($fromDate, $toDate,$manager_id, $raw){ $builder = $this->db->table('partner_policy pp'); $builder->select(" pa.id AS agent_id, pa.name AS agent_name, pa.agent_code, CASE WHEN pa.is_active = 1 THEN 'Active' ELSE 'Inactive' END AS agent_status, MAX(pp.issued_date) AS last_business_date, CONCAT('₹ ', FORMAT(SUM(pp.premium_amount), 2, 'en_IN')) AS display_premium, SUM(pp.premium_amount) AS total_premium_amount "); $builder->join('partner_agent pa', 'pa.id = pp.agent_id', 'inner'); $builder->where('pp.manager_id', $manager_id); $builder->having('total_premium_amount <', 50000); $builder->where('pp.issued_date >=', $fromDate); $builder->where('pp.issued_date <=', $toDate); // groupBy must be array of separate fields $builder->groupBy([ 'pa.id', 'pa.name', 'pa.agent_code', 'pa.is_active' ]); // orderBy must not contain semicolon + must be separated $builder->orderBy('total_premium_amount', 'DESC'); $builder->orderBy('last_business_date', 'ASC'); if ($raw === true) { return $builder->getCompiledSelect(); } return $builder->get()->getResultArray(); } // Step 5 public function staffWiseProductList($manager_id, $raw){ $builder = $this->db->table('partner_policy pp'); $builder->select(" pa.sales_executive_id, pse.name as sales_executive_name, pp.vehicle_type AS vechile_type, COUNT( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.policy_number END ) AS total_policies_current_month, SUM( CASE WHEN MONTH(pp.issued_date) = MONTH(CURRENT_DATE()) AND YEAR(pp.issued_date) = YEAR(CURRENT_DATE()) THEN pp.premium_amount ELSE 0 END ) AS total_premium_current_month, COUNT( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.policy_number END ) AS total_policies_pre_month, SUM( CASE WHEN pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(CURRENT_DATE(), '%Y-%m-01') THEN pp.premium_amount ELSE 0 END ) AS total_premium_pre_month "); $builder->join('partner_agent pa', 'pa.id = pp.agent_id', 'left'); $builder->join('partner_sales_executive pse', 'pse.id = pa.sales_executive_id', 'left'); // Date filters $builder->where(" pp.issued_date >= DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') AND pp.issued_date < DATE_FORMAT(DATE_ADD(CURRENT_DATE(), INTERVAL 1 MONTH), '%Y-%m-01') ", null, false); $builder->where('pp.manager_id', $manager_id); $builder->where('pa.sales_executive_id IS NOT NULL', null, false); $builder->where('pse.is_active', 1); // Group by sales exec + vehicle type $builder->groupBy("pa.sales_executive_id, pp.vehicle_type"); $builder->orderBy("pa.sales_executive_id"); if ($raw === true) { return $builder->getCompiledSelect(); } $rows = $builder->get()->getResultArray(); // Final compilation $final = []; foreach ($rows as $row) { $se_id = $row['sales_executive_id']; if (!isset($final[$se_id])) { $final[$se_id] = [ "sales_executive_id" => $row["sales_executive_id"], "sales_executive_name" => $row["sales_executive_name"], "products_list" => [], ]; } // Add each product entry $final[$se_id]["products_list"][] = [ "vechile_type" => $row["vechile_type"], "total_policies_current_month" => $row["total_policies_current_month"], "total_premium_current_month" => $row["total_premium_current_month"], "total_policies_pre_month" => $row["total_policies_pre_month"], "total_premium_pre_month" => $row["total_premium_pre_month"] ]; } // Add total_products count // foreach ($final as $key => $value) { // $final[$key]["total_products"] = count($value["products_list"]); // } return array_values($final); } // ───────────────────────────────────────────────────────────────────────────── // DashboardController.php — Partner Portal API methods // Routes: // GET partner/(:num)/details → partnerDetails($id) // GET partner/(:num)/policies → partnerPolicies($id) // GET partner/(:num)/renewals → partnerRenewals($id) ?days=20 // GET partner/(:num)/earnings → partnerEarnings($id) // ───────────────────────────────────────────────────────────────────────────── // ══════════════════════════════════════════════════════════════════════════════ // GET partner/{id}/details // agent_id = partner_agent.id // Joins: partner_policy (agent_id), partner_enquiry (agent_id), // partner_endorsement_request (agent_id) // ══════════════════════════════════════════════════════════════════════════════ public function partnerDetails($id) { $ref = []; try { if (empty($id)) { return $this->respond([ 'status' => 'error', 'code' => 400, 'data' => [], 'message' => 'Missing required parameter: id', ], 200); } // ── 1. Agent profile (partner_agent.id = $id) $agent = $this->db->table('partner_agent pa') ->select(' pa.id, pa.name AS agent_name, pa.agent_code, pa.mobile, pa.email, pa.is_active, ps.name AS manager_name, ps.mobile AS manager_mobile, ps.email AS manager_email ') ->join('partner_staff ps', 'ps.id = pa.manager_id', 'left') ->where('pa.id', $id) ->get()->getRowArray(); if (empty($agent)) { throw new \RuntimeException('Partner not found.', 404); } // -- 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(" 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(); $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, SUM(CASE WHEN pe.enquiry_status = "Completed" THEN 1 ELSE 0 END) AS enquiry_completed, SUM(CASE WHEN pe.enquiry_status != "Completed" THEN 1 ELSE 0 END) AS enquiry_pending ') ->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 (created in current FY) $endorseStats = $this->db->table('partner_endorsement_request per') ->select(' COUNT(per.id) AS endorsement_total, SUM(CASE WHEN per.status = "Completed" THEN 1 ELSE 0 END) AS endorsement_done, SUM(CASE WHEN per.status != "Completed" THEN 1 ELSE 0 END) AS endorsement_pending ') ->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', 'overview_financial_year' => $overviewFy, ], $policyStats ?? [], $enquiryStats ?? [], $endorseStats ?? [], ); $ref['message'] = 'Partner details retrieved successfully.'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $data, 'ref' => $ref, ], 200); } catch (\Throwable $e) { if ($e instanceof \RuntimeException && $e->getCode() === 404) { $ref['message'] = 'No Data Found'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'message' => 'No Data Found', 'ref' => $ref, ], 200); } $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { $ref['debug_info'] = $e->getFile() . ' / LN : ' . $e->getLine(); $ref['message'] = 'Database Error Occurred.'; } else { $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } return $this->respond([ 'status' => 'error', 'code' => 500, 'data' => [], 'ref' => $ref, ], 200); } } // ══════════════════════════════════════════════════════════════════════════════ // GET partner/{id}/policies // partner_policy.agent_id = $id // holder_name → pp.insured_name (the actual insured person, NOT agent) // product → pp.product (varchar 50), falls back to pp.vehicle_type // policy_no → pp.policy_number // ══════════════════════════════════════════════════════════════════════════════ public function partnerPolicies($id) { $ref = []; try { if (empty($id)) { return $this->respond([ 'status' => 'error', 'code' => 400, 'data' => [], 'message' => 'Missing required parameter: id', ], 200); } $results = $this->db->table('partner_policy pp') ->select(' pp.policy_number AS policy_no, pp.insured_name AS holder_name, COALESCE(NULLIF(pp.product, ""), pp.vehicle_type) AS product, pp.premium_amount AS premium, DATE_FORMAT(pp.issued_date, "%d-%m-%Y") AS issued_date, DATE_FORMAT(pp.end_date, "%d-%m-%Y") AS expiry_date ') ->where('pp.agent_id', $id) ->where('pp.policy_number IS NOT NULL') ->where('pp.premium_amount IS NOT NULL') ->where('pp.is_active', 1) ->orderBy('pp.issued_date', 'DESC') ->get()->getResultArray(); $ref['total_records'] = count($results); if (empty($results)) { throw new \RuntimeException('No policies found for this partner.', 404); } return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $results, 'ref' => $ref, ], 200); } catch (\Throwable $e) { if ($e instanceof \RuntimeException && $e->getCode() === 404) { $ref['message'] = 'No Data Found'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'message' => 'No Data Found', 'ref' => $ref, ], 200); } $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { $ref['debug_info'] = $e->getFile() . ' / LN : ' . $e->getLine(); $ref['message'] = 'Database Error Occurred.'; } else { $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } return $this->respond([ 'status' => 'error', 'code' => 500, 'data' => [], 'ref' => $ref, ], 200); } } // ══════════════════════════════════════════════════════════════════════════════ // GET partner/{id}/renewals?days=20 // partner_policy.agent_id = $id // holder_name → pp.insured_name // premium → pp.premium_amount // ══════════════════════════════════════════════════════════════════════════════ public function partnerRenewals($id) { $ref = []; $days = (int) ($this->request->getGet('days') ?? 20); // Calculate range boundaries // 10 => 0–10 | 20 => 11–20 | 30 => 21–30 | 40 => 31–40 | 50 => 41–50 $endDay = $days; $startDay = ($days <= 10) ? 0 : ($days - 9); try { if (empty($id)) { return $this->respond([ 'status' => 'error', 'code' => 400, 'data' => [], 'message' => 'Missing required parameter: id', ], 200); } $results = $this->db->table('partner_policy pp') ->select(' pp.policy_number AS policy_no, pp.insured_name AS holder_name, pp.premium_amount AS premium, pp.vehicle_type AS vehicle_type, DATE_FORMAT(pp.end_date, "%d-%m-%Y") AS end_date, DATEDIFF(pp.end_date, CURDATE()) AS days_left ') ->where('pp.agent_id', $id) ->where('pp.is_active', 1) ->where('pp.policy_number IS NOT NULL') ->where('pp.premium_amount IS NOT NULL') ->where("pp.end_date >= DATE_ADD(CURDATE(), INTERVAL {$startDay} DAY)", null, false) ->where("pp.end_date <= DATE_ADD(CURDATE(), INTERVAL {$endDay} DAY)", null, false) ->orderBy('pp.end_date', 'ASC') ->get()->getResultArray(); $ref['days_filter'] = $days; $ref['range'] = "day {$startDay} to day {$endDay}"; $ref['total_records'] = count($results); if (empty($results)) { throw new \RuntimeException('No renewals due within this range.', 404); } return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => $results, 'ref' => $ref, ], 200); } catch (\Throwable $e) { if ($e instanceof \RuntimeException && $e->getCode() === 404) { $ref['message'] = 'No Data Found'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'message' => 'No Data Found', 'ref' => $ref, ], 200); } $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { $ref['debug_info'] = $e->getFile() . ' / LN : ' . $e->getLine(); $ref['message'] = 'Database Error Occurred.'; } else { $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } return $this->respond([ 'status' => 'error', 'code' => 500, 'data' => [], 'ref' => $ref, ], 200); } } // ══════════════════════════════════════════════════════════════════════════════ // GET partner/{id}/earnings // partner_policy.agent_id = $id // Groups by issued_date month → month_key (YYYY-MM), month_label (Month YYYY) // 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)) { return $this->respond([ 'status' => 'error', 'code' => 400, 'data' => [], 'message' => 'Missing required parameter: id', ], 200); } $agentId = (int) $id; $fyBounds = null; if (!empty($fyParam)) { $fyBounds = $this->indianFinancialYearBounds($fyParam); } $builder = $this->db->table('partner_policy pp'); $builder->select(" DATE_FORMAT(pp.issued_date, '%Y-%m') AS month_key, 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(COALESCE(pp.commission_amount, 0)), 0) AS payout "); $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); } $builder->groupBy("DATE_FORMAT(pp.issued_date, '%Y-%m')"); $builder->orderBy('month_key', 'ASC'); $results = $builder->get()->getResultArray(); // 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 ($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, 'data' => $results, 'ref' => $ref, ], 200); } catch (\Throwable $e) { if ($e instanceof \RuntimeException && $e->getCode() === 404) { $ref['message'] = 'No Data Found'; return $this->respond([ 'status' => 'success', 'code' => 200, 'data' => [], 'message' => 'No Data Found', 'ref' => $ref, ], 200); } $isDbError = $e instanceof \CodeIgniter\Database\Exceptions\DatabaseException || $e instanceof \mysqli_sql_exception || $e instanceof \PDOException; if ($isDbError) { $ref['debug_info'] = $e->getFile() . ' / LN : ' . $e->getLine(); $ref['message'] = 'Database Error Occurred.'; } else { $ref['message'] = 'An unexpected error occurred: ' . $e->getMessage(); } return $this->respond([ 'status' => 'error', 'code' => 500, 'data' => [], 'ref' => $ref, ], 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, ]; } }