PHP method name. */ public const KPI_MAP = [ 181 => 'policy_exposure_summary', 185 => 'premium_as_on_date', 186 => 'claims_experience_summary', 190 => 'claim_amount_by_gender', 191 => 'age_band', 194 => 'top_5_hospitals_by_incurred_amount', 197 => 'claims_incidence_rate', 198 => 'policy_start_date', 199 => 'policy_end_date', 200 => 'insurer', 201 => 'tpa', 203 => 'earned_premium', 204 => 'total_claims', 206 => 'incurred_amount', 207 => 'incurred_ratio', 208 => 'projected_claims', 209 => 'projected_ratio', 213 => 'total_reimbursement_amount', 214 => 'total_reimbursement_amt_pct', 215 => 'cashless_claim_amt', 216 => 'cashless_claim_amt_pct', 217 => 'total_incurred_by_city', 219 => 'claim_amount_by_claim_status', 220 => 'hospitals_in_detail', 221 => 'hospital_city_wise_si_limit_pregnancy', 224 => 's_pregnancy_normal_delivery_exceeded_amt', 225 => 's_pregnancy_c_sec_avg_exceeded_amt', 228 => 'cataract_exceeded_claim_amount', 229 => 'cataract_avg_exceeded_amount', 230 => 'hospital_city_wise_si_limit_cataract', 231 => 'total_incurred_by_cliam_status', 232 => 'inception_emp_lives', 233 => 'current_emp_lives', 234 => 'claim_value_by_month', 235 => 'claim_amount_by_relationship', 236 => 'top_10_ailments_by_claim_count', ]; /** * Human-readable KPI labels (Metabase name). */ public const KPI_LABELS = [ 'policy_exposure_summary' => 'POLICY & EXPOSURE SUMMARY', 'premium_as_on_date' => 'PREMIUM AS ON DATE', 'claims_experience_summary' => 'CLAIMS EXPERIENCE SUMMARY', 'claim_amount_by_gender' => 'Claim Amount by Gender', 'age_band' => 'Age Band', 'top_5_hospitals_by_incurred_amount' => 'Top 5 Hospitals by Incurred amount', 'claims_incidence_rate' => 'Claims Incidence Rate', 'policy_start_date' => 'Policy Start Date', 'policy_end_date' => 'Policy End Date', 'insurer' => 'Insurer', 'tpa' => 'TPA', 'earned_premium' => 'Earned Premium', 'total_claims' => 'Total Claims', 'incurred_amount' => 'Incurred Amount', 'incurred_ratio' => 'Incurred Ratio', 'projected_claims' => 'Projected Claims', 'projected_ratio' => 'Projected Ratio', 'total_reimbursement_amount' => 'Total Reimbursement Amount', 'total_reimbursement_amt_pct' => 'Total Reimbursement Amt %', 'cashless_claim_amt' => 'Cashless Claim Amt', 'cashless_claim_amt_pct' => 'Cashless Claim Amt %', 'total_incurred_by_city' => 'Total Incurred by city', 'claim_amount_by_claim_status' => 'Claim Amount by Claim Status', 'hospitals_in_detail' => 'Hospitals in detail', 'hospital_city_wise_si_limit_pregnancy' => 'Hospital city wise SI Limit - Pregnancy', 's_pregnancy_normal_delivery_exceeded_amt' => 'S-PREGNANCY - NORMAL DELIVERY Exceeded Amt', 's_pregnancy_c_sec_avg_exceeded_amt' => 'S-Pregnancy C-Sec avg exceeded amt', 'cataract_exceeded_claim_amount' => 'Cataract exceeded claim amount', 'cataract_avg_exceeded_amount' => 'Cataract avg exceeded amount', 'hospital_city_wise_si_limit_cataract' => 'Hospital city wise SI Limit - Cataract', 'total_incurred_by_cliam_status' => 'Total Incurred by Cliam Status ', 'inception_emp_lives' => 'Inception Employees & Lives', 'current_emp_lives' => 'Current Employees & Lives', 'claim_value_by_month' => 'Claim Value by Month', 'claim_amount_by_relationship' => 'Claim Amount by Relationship', 'top_10_ailments_by_claim_count' => 'Top 10 Ailments by Claim Count', ]; protected function runKpiQuery(string $sql, int $policyId): array { // Metabase export may contain literal \t / \n in CSV — normalize for MySQL. $sql = str_replace(['\\t', '\\n', '\\r'], ["\t", "\n", "\r"], $sql); $db = \Config\Database::connect($this->DBGroup); $query = $db->query($sql, ['policy_id' => $policyId]); return $query->getResultArray(); } public function getKpi(string $method, int $policyId): array { if (!method_exists($this, $method)) { return []; } return $this->{$method}($policyId); } public function getAllKpis(int $policyId): array { $out = []; foreach (self::KPI_MAP as $id => $method) { $out[$method] = [ 'id' => (int) $id, 'label' => self::KPI_LABELS[$method] ?? $method, 'rows' => $this->getKpi($method, $policyId), ]; } return $out; } /** Metabase #181: POLICY & EXPOSURE SUMMARY */ public function policy_exposure_summary(int $policyId): array { $sql = <<<'SQL' SELECT cp.policy_start_date, cp.policy_end_date, i.name AS insurer_name, t.name AS tpa_name FROM client_policy cp LEFT JOIN insurers i ON i.id = cp.insurer_id LEFT JOIN tpa t ON t.id = cp.tpa_id WHERE cp.id = :policy_id: SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #185: PREMIUM AS ON DATE (legacy — not in KPI_MAP; kept for reference) */ public function premium_as_on_date_legacy(int $policyId): array { $sql = <<<'SQL' SELECT CONCAT('💰 ', FORMAT( COALESCE(SUM( CASE WHEN LOWER(e.change_event) = '%inception%' THEN ep.rata_premimum WHEN LOWER(e.change_event) NOT LIKE '%inception%' AND (ep.date_of_exit IS NULL OR ep.date_of_exit = '') THEN ep.rata_premimum WHEN ep.date_of_exit IS NOT NULL AND ep.date_of_exit != '' AND ep.claim_status = 0 THEN -ep.rata_premimum ELSE 0 END ), 0) , 0)) AS premium_as_on_date FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = :policy_id: AND ep.is_active = 1; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #185: PREMIUM AS ON DATE */ public function premium_as_on_date(int $policyId): array { $sql = <<<'SQL' SELECT CONCAT('💰 ', FORMAT( COALESCE(SUM( CASE WHEN ep.date_of_exit IS NOT NULL AND ep.date_of_exit != '' AND (ep.claim_status = 0 OR ep.claim_status IS NULL) AND ep.date_coverage IS NOT NULL AND ep.date_coverage != '' AND ep.policy_end_date IS NOT NULL AND ep.policy_end_date != '' THEN (ep.rata_premimum + COALESCE(ep.gst, 0)) * ( (DATEDIFF(ep.policy_end_date, ep.date_coverage) + 1) - (DATEDIFF(ep.policy_end_date, ep.date_of_exit) - 1) ) / NULLIF(DATEDIFF(ep.policy_end_date, ep.date_coverage) + 1, 0) ELSE (ep.rata_premimum + COALESCE(ep.gst, 0)) END ), 0) , 0)) AS premium_as_on_date FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = :policy_id: AND ep.is_active = 1 AND ep.status = 'active' AND e.is_active = 1 AND e.emp_status = 'active'; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #186: CLAIMS EXPERIENCE SUMMARY */ public function claims_experience_summary(int $policyId): array { $sql = <<<'SQL' SELECT /* run days */ DATEDIFF( LEAST(CURDATE(), cp.policy_end_date), cp.policy_start_date ) + 1 AS run_days, /* earned premium */ FORMAT( (prem.premium_as_on_date / 365) * ( DATEDIFF( LEAST(CURDATE(), cp.policy_end_date), cp.policy_start_date ) + 1 ), 2 ) AS earned_premium, /* claims reported */ FORMAT(COUNT(tm.id), 0) AS claims_reported, \t\t/* incurred claims count */ \tFORMAT( \t SUM( \t CASE \t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1 \t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1 \t ELSE 0 \t END \t ) , 0) AS incurred_claims, /* incurred amount */ FORMAT( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) , 0) AS incurred_amount, /* incurred ratio */ CONCAT( ROUND( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( (prem.premium_as_on_date / 365) * DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) , 0) * 100 , 2) , '%') AS incurred_ratio, /* rejection rate */ CONCAT( ROUND( SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END) / NULLIF(COUNT(tm.id), 0) * 100 , 2) , '%') AS rejection_rate, /* projected claims */ FORMAT( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 , 0) AS projected_claims, /* projected ratio */ CONCAT( ROUND( ( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 ) / NULLIF(prem.premium_as_on_date, 0) * 100 , 2) , '%') AS projected_ratio FROM client_policy cp JOIN ( SELECT ep2.client_policy_id, COALESCE(SUM( CASE WHEN ep2.date_of_exit IS NOT NULL AND ep2.date_of_exit != '' AND (ep2.claim_status = 0 OR ep2.claim_status IS NULL) AND ep2.date_coverage IS NOT NULL AND ep2.date_coverage != '' AND ep2.policy_end_date IS NOT NULL AND ep2.policy_end_date != '' THEN (ep2.rata_premimum + COALESCE(ep2.gst, 0)) * ( (DATEDIFF(ep2.policy_end_date, ep2.date_coverage) + 1) - (DATEDIFF(ep2.policy_end_date, ep2.date_of_exit) - 1) ) / NULLIF(DATEDIFF(ep2.policy_end_date, ep2.date_coverage) + 1, 0) ELSE (ep2.rata_premimum + COALESCE(ep2.gst, 0)) END ), 0) AS premium_as_on_date FROM employee_polices ep2 JOIN employees e2 ON e2.id = ep2.employee_id WHERE ep2.client_policy_id = :policy_id: AND ep2.is_active = 1 AND ep2.status = 'active' AND e2.is_active = 1 AND e2.emp_status = 'active' GROUP BY ep2.client_policy_id ) prem ON prem.client_policy_id = cp.id LEFT JOIN ticket_master tm ON tm.client_policy_id = cp.id AND tm.is_active = 1 LEFT JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id WHERE cp.id = :policy_id: GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #190: Claim Amount by Gender */ public function claim_amount_by_gender(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(e.gender, 'Unknown') AS gender, COUNT(tm.id) AS claim_count, CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%') AS count_pct, COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, CONCAT(ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2), '%') AS value_pct FROM ticket_master tm JOIN employees e ON e.id = tm.emp_id JOIN ( SELECT COUNT(id) AS total_count, COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 GROUP BY e.gender, totals.total_count, totals.total_value ORDER BY claim_count DESC; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #191: Age Band */ public function age_band(int $policyId): array { $sql = <<<'SQL' WITH age_slabs AS ( SELECT '0-18' AS age_band, 0 AS min_age, 18 AS max_age UNION ALL SELECT '19-25', 19, 25 UNION ALL SELECT '26-35', 26, 35 UNION ALL SELECT '36-45', 36, 45 UNION ALL SELECT '46-55', 46, 55 UNION ALL SELECT '56-65', 56, 65 UNION ALL SELECT '66-75', 66, 75 UNION ALL SELECT '75+', 76, 200 ), base AS ( SELECT TIMESTAMPDIFF(YEAR, e.dob, cp.policy_end_date) AS age, tm.claim_amount FROM ticket_master tm JOIN employees e ON e.id = tm.insured_emp_id \tJOIN client_policy cp ON tm.client_policy_id = cp.id WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 ), totals AS ( SELECT COUNT(*) AS total_count, COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) SELECT s.age_band, COUNT(b.age) AS claim_count, ROUND(COUNT(b.age) / NULLIF(t.total_count, 0) * 100, 2) AS count_pct, COALESCE(SUM(CAST(NULLIF(b.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, ROUND( COALESCE(SUM(CAST(NULLIF(b.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(t.total_value, 0) * 100 , 2) AS value_pct FROM age_slabs s LEFT JOIN base b ON b.age BETWEEN s.min_age AND s.max_age CROSS JOIN totals t GROUP BY s.age_band, s.min_age, t.total_count, t.total_value ORDER BY s.min_age; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #194: Top 5 Hospitals by Incurred amount */ public function top_5_hospitals_by_incurred_amount(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(tm.hospital_name, 'Not Specified') AS hospital_name, COALESCE(tm.hospital_city, '-') AS hospital_city, COALESCE(tm.hospital_state, '-') AS hospital_state, COUNT(tm.id) AS claim_count, ROUND( COUNT(tm.id) / totals.total_count * 100, 2 ) AS count_pct, COALESCE( SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0 ) AS claim_value, ROUND( COALESCE( SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0 ) / NULLIF(totals.total_value, 0) * 100, 2 ) AS value_pct FROM ticket_master tm JOIN ( SELECT COUNT(id) AS total_count, COALESCE( SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0 ) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND tm.hospital_name IS NOT NULL GROUP BY tm.hospital_name, tm.hospital_city, tm.hospital_state, totals.total_count, totals.total_value ORDER BY claim_count DESC LIMIT 5; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #197: Claims Incidence Rate */ public function claims_incidence_rateOLD(int $policyId): array { $sql = <<<'SQL' SELECT CONCAT( ROUND( COUNT(tm.id) / NULLIF(lives.current_lives, 0) * 100 , 2) , '%') AS claims_incidence_rate, max(cdf.created_at) as created_at FROM ticket_master tm JOIN claim_dump_files cdf ON tm.client_policy_id = cdf.client_policy_id AND tm.tpa_id = cdf.tpa_id JOIN ( SELECT COUNT(DISTINCT ep.employee_id) AS current_lives FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = :policy_id: AND ep.status = 'active' AND ep.is_active = 1 AND e.emp_status = 'active' AND e.is_active = 1 ) lives ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1; SQL; return $this->runKpiQuery($sql, $policyId); } public function claims_incidence_rate(int $policyId): array { $sql = <<<'SQL' SELECT CONCAT( ROUND( (SELECT COUNT(tm.id) FROM ticket_master tm WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1) / NULLIF(lives.current_lives, 0) * 100 , 2) , '%') AS claims_incidence_rate, (SELECT MAX(cdf.created_at) FROM claim_dump_files cdf WHERE cdf.client_policy_id = :policy_id:) AS created_at FROM ( SELECT COUNT(DISTINCT ep.employee_id) AS current_lives FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = :policy_id: AND ep.status = 'active' AND ep.is_active = 1 AND e.emp_status = 'active' AND e.is_active = 1 ) lives; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #198: Policy Start Date */ public function policy_start_date(int $policyId): array { $sql = <<<'SQL' SELECT CONCAT(DATE_FORMAT(cp.policy_start_date, '%d %b, %Y'), ' 📅') AS policy_start_date, -- cp.policy_start_date, cp.policy_end_date, i.name AS insurer_name, t.name AS tpa_name FROM client_policy cp LEFT JOIN insurers i ON i.id = cp.insurer_id LEFT JOIN tpa t ON t.id = cp.tpa_id WHERE cp.id = :policy_id: SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #199: Policy End Date */ public function policy_end_date(int $policyId): array { $sql = <<<'SQL' SELECT cp.policy_start_date,CONCAT(DATE_FORMAT(cp.policy_end_date, '%d %b, %Y'), ' 📅') AS policy_end_date, -- cp.policy_end_date, i.name AS insurer_name, t.name AS tpa_name FROM client_policy cp LEFT JOIN insurers i ON i.id = cp.insurer_id LEFT JOIN tpa t ON t.id = cp.tpa_id WHERE cp.id = :policy_id: SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #200: Insurer */ public function insurer(int $policyId): array { $sql = <<<'SQL' SELECT cp.policy_start_date, cp.policy_end_date, i.name AS insurer_name, t.short_name AS tpa_name FROM client_policy cp LEFT JOIN insurers i ON i.id = cp.insurer_id LEFT JOIN tpa t ON t.id = cp.tpa_id WHERE cp.id = :policy_id: SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #201: TPA */ public function tpa(int $policyId): array { $sql = <<<'SQL' SELECT cp.policy_start_date, cp.policy_end_date, i.name AS insurer_name, t.name AS tpa_name FROM client_policy cp LEFT JOIN insurers i ON i.id = cp.insurer_id LEFT JOIN tpa t ON t.id = cp.tpa_id WHERE cp.id = :policy_id: SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #203: Earned Premium */ public function earned_premium(int $policyId): array { $sql = <<<'SQL' SELECT /* earned premium */ CONCAT('💵 ', FORMAT( (prem.premium_as_on_date / 365) * DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) ,0))AS earned_premium FROM client_policy cp JOIN ( SELECT ep2.client_policy_id, COALESCE(SUM( CASE WHEN e2.change_event = 'inception' THEN ep2.rata_premimum WHEN e2.change_event != 'inception' AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '') THEN ep2.rata_premimum WHEN ep2.date_of_exit IS NOT NULL AND ep2.date_of_exit != '' AND ep2.claim_status = 0 THEN -ep2.rata_premimum ELSE 0 END ), 0) AS premium_as_on_date FROM employee_polices ep2 JOIN employees e2 ON e2.id = ep2.employee_id WHERE ep2.client_policy_id = :policy_id: AND ep2.is_active = 1 GROUP BY ep2.client_policy_id ) prem ON prem.client_policy_id = cp.id JOIN ticket_master tm ON tm.client_policy_id = cp.id AND tm.is_active = 1 JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id WHERE cp.id = :policy_id: GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #204: Total Claims */ public function total_claims(int $policyId): array { $sql = <<<'SQL' SELECT /* run days */ DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1 AS run_days, /* earned premium */ FORMAT( (prem.premium_as_on_date / 365) * (DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1) , 0) AS earned_premium, /* claims reported */ FORMAT(COUNT(tm.id), 0) AS claims_reported, \t\t/* incurred claims count */ \tFORMAT( \t SUM( \t CASE \t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1 \t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1 \t ELSE 0 \t END \t ) , 0) AS incurred_claims, /* incurred amount */ FORMAT( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) , 0) AS incurred_amount, /* incurred ratio */ CONCAT( ROUND( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( (prem.premium_as_on_date / 365) * DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) , 0) * 100 , 2) , '%') AS incurred_ratio, /* rejection rate */ CONCAT( ROUND( SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END) / NULLIF(COUNT(tm.id), 0) * 100 , 2) , '%') AS rejection_rate, /* projected claims */ FORMAT( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 , 0) AS projected_claims, /* projected ratio */ CONCAT( ROUND( ( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 ) / NULLIF(prem.premium_as_on_date, 0) * 100 , 2) , '%') AS projected_ratio FROM client_policy cp JOIN ( SELECT ep2.client_policy_id, COALESCE(SUM( CASE WHEN e2.change_event = 'inception' THEN ep2.rata_premimum WHEN e2.change_event != 'inception' AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '') THEN ep2.rata_premimum WHEN ep2.date_of_exit IS NOT NULL AND ep2.date_of_exit != '' AND ep2.claim_status = 0 THEN -ep2.rata_premimum ELSE 0 END ), 0) AS premium_as_on_date FROM employee_polices ep2 JOIN employees e2 ON e2.id = ep2.employee_id WHERE ep2.client_policy_id = :policy_id: AND ep2.is_active = 1 GROUP BY ep2.client_policy_id ) prem ON prem.client_policy_id = cp.id JOIN ticket_master tm ON tm.client_policy_id = cp.id AND tm.is_active = 1 JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id WHERE cp.id = :policy_id: GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #206: Incurred Amount */ public function incurred_amount(int $policyId): array { $sql = <<<'SQL' SELECT /* run days */ DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1 AS run_days, /* earned premium */ FORMAT( (prem.premium_as_on_date / 365) * (DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1) , 0) AS earned_premium, /* claims reported */ FORMAT(COUNT(tm.id), 0) AS claims_reported, \t\t/* incurred claims count */ \tFORMAT( \t SUM( \t CASE \t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1 \t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1 \t ELSE 0 \t END \t ) , 0) AS incurred_claims, /* incurred amount */ FORMAT( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) , 0) AS incurred_amount, /* incurred ratio */ CONCAT( ROUND( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( (prem.premium_as_on_date / 365) * DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) , 0) * 100 , 2) , '%') AS incurred_ratio, /* rejection rate */ CONCAT( ROUND( SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END) / NULLIF(COUNT(tm.id), 0) * 100 , 2) , '%') AS rejection_rate, /* projected claims */ FORMAT( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 , 0) AS projected_claims, /* projected ratio */ CONCAT( ROUND( ( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 ) / NULLIF(prem.premium_as_on_date, 0) * 100 , 2) , '%') AS projected_ratio FROM client_policy cp JOIN ( SELECT ep2.client_policy_id, COALESCE(SUM( CASE WHEN e2.change_event = 'inception' THEN ep2.rata_premimum WHEN e2.change_event != 'inception' AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '') THEN ep2.rata_premimum WHEN ep2.date_of_exit IS NOT NULL AND ep2.date_of_exit != '' AND ep2.claim_status = 0 THEN -ep2.rata_premimum ELSE 0 END ), 0) AS premium_as_on_date FROM employee_polices ep2 JOIN employees e2 ON e2.id = ep2.employee_id WHERE ep2.client_policy_id = :policy_id: AND ep2.is_active = 1 GROUP BY ep2.client_policy_id ) prem ON prem.client_policy_id = cp.id JOIN ticket_master tm ON tm.client_policy_id = cp.id AND tm.is_active = 1 JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id WHERE cp.id = :policy_id: GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #207: Incurred Ratio */ public function incurred_ratio(int $policyId): array { $sql = <<<'SQL' SELECT /* run days */ DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1 AS run_days, /* earned premium */ FORMAT( (prem.premium_as_on_date / 365) * (DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1) , 0) AS earned_premium, /* claims reported */ FORMAT(COUNT(tm.id), 0) AS claims_reported, \t\t/* incurred claims count */ \tFORMAT( \t SUM( \t CASE \t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1 \t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1 \t ELSE 0 \t END \t ) , 0) AS incurred_claims, /* incurred amount */ FORMAT( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) , 0) AS incurred_amount, /* incurred ratio */ CONCAT('💹 ', ROUND( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( (prem.premium_as_on_date / 365) * DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) , 0) * 100 , 2) , '%') AS incurred_ratio, /* rejection rate */ CONCAT( ROUND( SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END) / NULLIF(COUNT(tm.id), 0) * 100 , 2) , '%') AS rejection_rate, /* projected claims */ FORMAT( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 , 0) AS projected_claims, /* projected ratio */ CONCAT( ROUND( ( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 ) / NULLIF(prem.premium_as_on_date, 0) * 100 , 2) , '%') AS projected_ratio FROM client_policy cp JOIN ( SELECT ep2.client_policy_id, COALESCE(SUM( CASE WHEN e2.change_event = 'inception' THEN ep2.rata_premimum WHEN e2.change_event != 'inception' AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '') THEN ep2.rata_premimum WHEN ep2.date_of_exit IS NOT NULL AND ep2.date_of_exit != '' AND ep2.claim_status = 0 THEN -ep2.rata_premimum ELSE 0 END ), 0) AS premium_as_on_date FROM employee_polices ep2 JOIN employees e2 ON e2.id = ep2.employee_id WHERE ep2.client_policy_id = :policy_id: AND ep2.is_active = 1 GROUP BY ep2.client_policy_id ) prem ON prem.client_policy_id = cp.id JOIN ticket_master tm ON tm.client_policy_id = cp.id AND tm.is_active = 1 JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id WHERE cp.id = :policy_id: GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #208: Projected Claims */ public function projected_claims(int $policyId): array { $sql = <<<'SQL' SELECT /* run days */ DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1 AS run_days, /* earned premium */ FORMAT( (prem.premium_as_on_date / 365) * (DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1) , 0) AS earned_premium, /* claims reported */ FORMAT(COUNT(tm.id), 0) AS claims_reported, \t\t/* incurred claims count */ \tFORMAT( \t SUM( \t CASE \t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1 \t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1 \t ELSE 0 \t END \t ) , 0) AS incurred_claims, /* incurred amount */ FORMAT( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) , 0) AS incurred_amount, /* incurred ratio */ CONCAT( ROUND( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( (prem.premium_as_on_date / 365) * DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) , 0) * 100 , 2) , '%') AS incurred_ratio, /* rejection rate */ CONCAT( ROUND( SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END) / NULLIF(COUNT(tm.id), 0) * 100 , 2) , '%') AS rejection_rate, /* projected claims */ CONCAT('🎯 ', FORMAT( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 , 0)) AS projected_claims, /* projected ratio */ CONCAT( ROUND( ( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 ) / NULLIF(prem.premium_as_on_date, 0) * 100 , 2) , '%') AS projected_ratio FROM client_policy cp JOIN ( SELECT ep2.client_policy_id, COALESCE(SUM( CASE WHEN e2.change_event = 'inception' THEN ep2.rata_premimum WHEN e2.change_event != 'inception' AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '') THEN ep2.rata_premimum WHEN ep2.date_of_exit IS NOT NULL AND ep2.date_of_exit != '' AND ep2.claim_status = 0 THEN -ep2.rata_premimum ELSE 0 END ), 0) AS premium_as_on_date FROM employee_polices ep2 JOIN employees e2 ON e2.id = ep2.employee_id WHERE ep2.client_policy_id = :policy_id: AND ep2.is_active = 1 GROUP BY ep2.client_policy_id ) prem ON prem.client_policy_id = cp.id JOIN ticket_master tm ON tm.client_policy_id = cp.id AND tm.is_active = 1 JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id WHERE cp.id = :policy_id: GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #209: Projected Ratio */ public function projected_ratio(int $policyId): array { $sql = <<<'SQL' SELECT /* run days */ DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1 AS run_days, /* earned premium */ FORMAT( (prem.premium_as_on_date / 365) * (DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) + 1) , 0) AS earned_premium, /* claims reported */ FORMAT(COUNT(tm.id), 0) AS claims_reported, \t\t/* incurred claims count */ \tFORMAT( \t SUM( \t CASE \t WHEN tcs.claim_status IN ('Settled', 'Paid') THEN 1 \t WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN 1 \t ELSE 0 \t END \t ) , 0) AS incurred_claims, /* incurred amount */ FORMAT( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) , 0) AS incurred_amount, /* incurred ratio */ CONCAT( ROUND( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( (prem.premium_as_on_date / 365) * DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ) , 0) * 100 , 2) , '%') AS incurred_ratio, /* rejection rate */ CONCAT( ROUND( SUM(CASE WHEN tcs.claim_status IN ('Rejected', 'Denied') THEN 1 ELSE 0 END) / NULLIF(COUNT(tm.id), 0) * 100 , 2) , '%') AS rejection_rate, /* projected claims */ FORMAT( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 , 0) AS projected_claims, /* projected ratio */ CONCAT('💹 ', ROUND( ( ( COALESCE(SUM( CASE WHEN tcs.claim_status IN ('Settled', 'Paid') THEN CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) WHEN tcs.claim_status NOT IN ('Settled', 'Paid', 'Rejected', 'Denied') THEN CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2)) ELSE 0 END ), 0) / NULLIF( DATEDIFF( MAX(COALESCE(tm.claim_dump_date, cp.policy_end_date)), cp.policy_start_date ), 0 ) * 365 ) * 1.10 ) / NULLIF(prem.premium_as_on_date, 0) * 100 , 2) , '%') AS projected_ratio FROM client_policy cp JOIN ( SELECT ep2.client_policy_id, COALESCE(SUM( CASE WHEN e2.change_event = 'inception' THEN ep2.rata_premimum WHEN e2.change_event != 'inception' AND (ep2.date_of_exit IS NULL OR ep2.date_of_exit = '') THEN ep2.rata_premimum WHEN ep2.date_of_exit IS NOT NULL AND ep2.date_of_exit != '' AND ep2.claim_status = 0 THEN -ep2.rata_premimum ELSE 0 END ), 0) AS premium_as_on_date FROM employee_polices ep2 JOIN employees e2 ON e2.id = ep2.employee_id WHERE ep2.client_policy_id = :policy_id: AND ep2.is_active = 1 GROUP BY ep2.client_policy_id ) prem ON prem.client_policy_id = cp.id JOIN ticket_master tm ON tm.client_policy_id = cp.id AND tm.is_active = 1 JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id WHERE cp.id = :policy_id: GROUP BY cp.id, cp.policy_start_date, prem.premium_as_on_date; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #213: Total Reimbursement Amount */ public function total_reimbursement_amount(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2) AS value_pct FROM ticket_master tm JOIN ( SELECT COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND ( tm.tpa_claim_type IS NULL OR TRIM(LOWER(tm.tpa_claim_type)) IN ('unknown', 'reimbursement', '') ); SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #214: Total Reimbursement Amt % */ public function total_reimbursement_amt_pct(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2) AS value_pct FROM ticket_master tm JOIN ( SELECT COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND ( tm.tpa_claim_type IS NULL OR TRIM(LOWER(tm.tpa_claim_type)) IN ('unknown', 'reimbursement', '') ); SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #215: Cashless Claim Amt */ public function cashless_claim_amt(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2) AS value_pct FROM ticket_master tm JOIN ( SELECT COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND TRIM(LOWER(tm.tpa_claim_type)) = 'cashless'; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #216: Cashless Claim Amt % */ public function cashless_claim_amt_pct(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2) AS value_pct FROM ticket_master tm JOIN ( SELECT COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND TRIM(LOWER(tm.tpa_claim_type)) = 'cashless'; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #217: Total Incurred by city */ public function total_incurred_by_city(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(tm.hospital_name, 'Not Specified') AS hospital_name, COALESCE(tm.hospital_city, '-') AS hospital_city, COALESCE(tm.hospital_state, '-') AS hospital_state, COUNT(tm.id) AS claim_count, ROUND( COUNT(tm.id) / totals.total_count * 100, 2 ) AS count_pct, COALESCE( SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0 ) AS claim_value, ROUND( COALESCE( SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0 ) / NULLIF(totals.total_value, 0) * 100, 2 ) AS value_pct FROM ticket_master tm JOIN ( SELECT COUNT(id) AS total_count, COALESCE( SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0 ) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND tm.hospital_name IS NOT NULL GROUP BY tm.hospital_name, tm.hospital_city, tm.hospital_state, totals.total_count, totals.total_value ORDER BY claim_count DESC LIMIT 5; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #219: Claim Amount by Claim Status */ public function claim_amount_by_claim_status(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(tcs.display_name, 'Unknown') AS claim_status, COUNT(tm.id) AS claim_count, CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%') AS count_pct, COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, CONCAT(ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2), '%') AS value_pct FROM ticket_master tm JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id JOIN ( SELECT COUNT(id) AS total_count, COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 GROUP BY tcs.display_name, totals.total_count, totals.total_value ORDER BY claim_count DESC; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #220: Hospitals in detail */ public function hospitals_in_detail(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(NULLIF(TRIM(tm.hospital_name), ''), 'Not Specified') AS hospital_name, COALESCE(NULLIF(TRIM(tm.hospital_city), ''), '-') AS hospital_city, COALESCE(NULLIF(TRIM(tm.hospital_state), ''), '-') AS hospital_state, COUNT(tm.id) AS claim_count, CAST( GREATEST( ROUND( ( COUNT(tm.id) / NULLIF(totals.total_count, 0) ) * 100, 2 ), 0.01 ) AS DECIMAL(10,2) ) AS count_pct, CAST( COALESCE( SUM( CASE WHEN TRIM(tm.claim_amount) REGEXP '^[0-9]+(\\\\.[0-9]+)?$' THEN CAST(TRIM(tm.claim_amount) AS DECIMAL(15,2)) ELSE 0 END ), 0 ) AS DECIMAL(15,2) ) AS claim_value, CAST( GREATEST( ROUND( ( COALESCE( SUM( CASE WHEN TRIM(tm.claim_amount) REGEXP '^[0-9]+(\\\\.[0-9]+)?$' THEN CAST(TRIM(tm.claim_amount) AS DECIMAL(15,2)) ELSE 0 END ), 0 ) / NULLIF(totals.total_value, 0) ) * 100, 2 ), 0.01 ) AS DECIMAL(10,2) ) AS value_pct FROM ticket_master tm JOIN ( SELECT COUNT(id) AS total_count, CAST( COALESCE( SUM( CASE WHEN TRIM(claim_amount) REGEXP '^[0-9]+(\\\\.[0-9]+)?$' THEN CAST(TRIM(claim_amount) AS DECIMAL(15,2)) ELSE 0 END ), 0 ) AS DECIMAL(15,2) ) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1 = 1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND NULLIF(TRIM(tm.hospital_name), '') IS NOT NULL GROUP BY tm.hospital_name, tm.hospital_city, tm.hospital_state ORDER BY claim_count DESC; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #221: Hospital city wise SI Limit - Pregnancy */ public function hospital_city_wise_si_limit_pregnancy(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(tm.hospital_city, 'Not Specified') AS hospital_city, \tCOALESCE(tm.hospital_name, 'Not Specified') AS hospital_name, COUNT(tm.id) AS `Claim Count`, FORMAT( COALESCE( SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ), 0), 0) AS `SUM OF CLAIMED AMOUNT`, CASE WHEN COALESCE( SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ), 0) > COALESCE( SUM( CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2)) ), 0) THEN 'Exceeded' ELSE 'Within Limit' END AS `CLAIM STATUS LIMIT` FROM ticket_master tm INNER JOIN employee_polices ep ON ep.employee_id = tm.emp_id AND ep.client_policy_id = tm.client_policy_id AND ep.is_active = 1 AND ep.status = 'active' WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND tm.hospital_name IS NOT NULL /* Pregnancy Related Conditions */ AND ( LOWER(tm.tpa_ailments) LIKE '%pregnancy%' OR LOWER(tm.tpa_ailments) LIKE '%maternal%' OR LOWER(tm.tpa_ailments) LIKE '%gestational%' OR LOWER(tm.tpa_ailments) LIKE '%delivery%' OR LOWER(tm.tpa_ailments) LIKE '%cesarean%' OR LOWER(tm.tpa_ailments) LIKE '%caesarean%' OR LOWER(tm.tpa_ailments) LIKE '%c-section%' OR LOWER(tm.tpa_ailments) LIKE '%spontaneous delivery%' OR LOWER(tm.tpa_ailments) LIKE '%normal delivery%' OR LOWER(tm.tpa_ailments) LIKE '%forceps%' OR LOWER(tm.tpa_ailments) LIKE '%vaccum extractor%' ) GROUP BY tm.hospital_city,tm.hospital_name ORDER BY SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ) DESC; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #224: S-PREGNANCY - NORMAL DELIVERY Exceeded Amt */ public function s_pregnancy_normal_delivery_exceeded_amt(int $policyId): array { $sql = <<<'SQL' SELECT 'SINGLE PREGNANCY - NORMAL DELIVERY' AS diagnosis, COALESCE( SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ),0) AS exceeded_claim_amount FROM ticket_master tm INNER JOIN employee_polices ep ON ep.employee_id = tm.emp_id AND ep.client_policy_id = tm.client_policy_id AND ep.is_active = 1 AND ep.status = 'active' WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND ( LOWER(tm.tpa_ailments) LIKE '%spontaneous delivery%' OR LOWER(tm.tpa_ailments) LIKE '%normal delivery%' OR LOWER(tm.tpa_ailments) LIKE '%forceps%' OR LOWER(tm.tpa_ailments) LIKE '%vaccum extractor%' ) AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) > CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2)); SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #225: S-Pregnancy C-Sec avg exceeded amt */ public function s_pregnancy_c_sec_avg_exceeded_amt(int $policyId): array { $sql = <<<'SQL' SELECT 'SINGLE PREGNANCY - CAESAREAN DELIVERY' AS diagnosis, COALESCE( AVG( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ), 2) AS avg_exceeded_amount FROM ticket_master tm INNER JOIN employee_polices ep ON ep.employee_id = tm.emp_id AND ep.client_policy_id = tm.client_policy_id AND ep.is_active = 1 AND ep.status = 'active' WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND ( LOWER(tm.tpa_ailments) LIKE '%cesarean%' OR LOWER(tm.tpa_ailments) LIKE '%caesarean%' OR LOWER(tm.tpa_ailments) LIKE '%c-section%' ) AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) > CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2)); SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #228: Cataract exceeded claim amount */ public function cataract_exceeded_claim_amount(int $policyId): array { $sql = <<<'SQL' SELECT 'CATARACT' AS diagnosis, COALESCE( SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ), 0) AS exceeded_claim_amount FROM ticket_master tm INNER JOIN employee_polices ep ON ep.employee_id = tm.emp_id AND ep.client_policy_id = tm.client_policy_id AND ep.is_active = 1 AND ep.status = 'active' WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND LOWER(tm.tpa_ailments) LIKE '%cataract%' AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) > CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2)); SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #229: Cataract avg exceeded amount */ public function cataract_avg_exceeded_amount(int $policyId): array { $sql = <<<'SQL' SELECT 'CATARACT' AS diagnosis, FORMAT( COALESCE( AVG( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ), 0), 2) AS avg_exceeded_claim_amount FROM ticket_master tm INNER JOIN employee_polices ep ON ep.employee_id = tm.emp_id AND ep.client_policy_id = tm.client_policy_id AND ep.is_active = 1 AND ep.status = 'active' WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND LOWER(tm.tpa_ailments) LIKE '%cataract%' AND CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) > CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2)); SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #230: Hospital city wise SI Limit - Cataract */ public function hospital_city_wise_si_limit_cataract(int $policyId): array { $sql = <<<'SQL' SELECT \tCOALESCE(tm.hospital_city, 'Not Specified') AS hospital_city, COALESCE(tm.hospital_name, 'Not Specified') AS hospital_name, COUNT(tm.id) AS claim_count, FORMAT( COALESCE( SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ), 0), 0) AS `SUM OF CLAIMED AMOUNT`, CASE WHEN COALESCE( SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ), 0) > COALESCE( SUM( CAST(NULLIF(ep.basic_cover_si, '') AS DECIMAL(15,2)) ), 0) THEN 'Exceeded' ELSE 'Within Limit' END AS `CLAIM STATUS LIMIT` FROM ticket_master tm INNER JOIN employee_polices ep ON ep.employee_id = tm.emp_id AND ep.client_policy_id = tm.client_policy_id AND ep.is_active = 1 AND ep.status = 'active' WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND tm.hospital_name IS NOT NULL /* Cataract Related */ AND LOWER(tm.tpa_ailments) LIKE '%cataract%' GROUP BY tm.hospital_city,tm.hospital_name ORDER BY SUM( CAST(NULLIF(tm.approved_amount, '') AS DECIMAL(15,2)) ) DESC; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #231: Total Incurred by Cliam Status */ public function total_incurred_by_cliam_status(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(tcs.display_name, 'Unknown') AS `Claim Status`, -- COUNT(tm.id) AS claim_count, -- CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%') -- AS count_pct, COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS `Total Incurred Amount`, CONCAT(ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2), '%') AS `Value PCT` FROM ticket_master tm JOIN ticket_claim_status tcs ON tcs.id = tm.claim_status_id JOIN ( SELECT COUNT(id) AS total_count, COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 GROUP BY tcs.display_name, totals.total_count, totals.total_value -- ORDER BY claim_count DESC; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #232: Inception Employees & Lives */ public function inception_emp_lives(int $policyId): array { $sql = <<<'SQL' SELECT COUNT(DISTINCT CASE WHEN e.relationship = 'Self' THEN e.id END) AS inception_emp, COUNT(DISTINCT e.id) AS inception_lives FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = :policy_id: AND LOWER(e.change_event) LIKE '%inception%' AND ep.is_active = 1 AND e.is_active = 1; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #233: Current Employees & Lives */ public function current_emp_lives(int $policyId): array { $sql = <<<'SQL' SELECT COUNT(DISTINCT CASE WHEN e.relationship = 'Self' THEN e.id END) AS current_emp, COUNT(DISTINCT e.id) AS current_lives, ROUND( COUNT(DISTINCT e.id) / NULLIF(COUNT(DISTINCT CASE WHEN e.relationship = 'Self' THEN e.id END), 0) , 2) AS avg_family_size FROM employee_polices ep JOIN employees e ON e.id = ep.employee_id WHERE ep.client_policy_id = :policy_id: AND ep.status = 'active' AND ep.is_active = 1 AND e.emp_status = 'active' AND e.is_active = 1; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #234: Claim Value by Month */ public function claim_value_by_month(int $policyId): array { $sql = <<<'SQL' SELECT DATE_FORMAT(tm.created_at, '%b %Y') AS claim_month, DATE_FORMAT(tm.created_at, '%Y-%m') AS month_sort, -- COUNT(tm.id) AS claim_count, -- CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%') AS count_pct, COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value -- CONCAT(ROUND( -- COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) -- / NULLIF(totals.total_value, 0) * 100 -- , 2), '%') AS value_pct FROM ticket_master tm JOIN ( SELECT COUNT(id) AS total_count, COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 GROUP BY DATE_FORMAT(tm.created_at, '%b %Y'), DATE_FORMAT(tm.created_at, '%Y-%m'), totals.total_count, totals.total_value ORDER BY month_sort; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #235: Claim Amount by Relationship */ public function claim_amount_by_relationship(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(tm.relationship, 'Unknown') AS relationship, COUNT(tm.id) AS claim_count, ROUND(COUNT(tm.id) / NULLIF(totals.total_count, 0) * 100, 2) AS count_pct, COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100, 2) AS value_pct FROM ticket_master tm JOIN ( SELECT COUNT(id) AS total_count, COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 GROUP BY tm.relationship ORDER BY claim_count DESC; -- SELECT -- COALESCE( -- CONCAT(UPPER(SUBSTRING(tm.relationship, 1, 1)), LOWER(SUBSTRING(tm.relationship, 2))), -- 'Unknown' -- ) AS relationship, -- COUNT(tm.id) AS claim_count, -- ROUND(COUNT(tm.id) / NULLIF(totals.total_count, 0) * 100, 2) AS count_pct, -- COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) AS claim_value, -- ROUND( -- COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) -- / NULLIF(totals.total_value, 0) * 100, -- 2) AS value_pct -- FROM ticket_master tm -- JOIN ( -- SELECT -- COUNT(id) AS total_count, -- COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value -- FROM ticket_master -- WHERE client_policy_id = :policy_id: AND is_active = 1 -- ) totals ON 1=1 -- WHERE tm.client_policy_id = :policy_id: -- AND tm.is_active = 1 -- GROUP BY tm.relationship -- ORDER BY -- CASE LOWER(tm.relationship) -- WHEN 'self' THEN 1 -- WHEN 'spouse' THEN 2 -- WHEN 'son' THEN 3 -- WHEN 'daughter' THEN 4 -- WHEN 'father' THEN 5 -- WHEN 'mother' THEN 6 -- WHEN 'father-in-law' THEN 7 -- WHEN 'mother-in-law' THEN 8 -- WHEN 'unknown' THEN 9 -- ELSE 10 -- END; SQL; return $this->runKpiQuery($sql, $policyId); } /** Metabase #236: Top 10 Ailments by Claim Count */ public function top_10_ailments_by_claim_count(int $policyId): array { $sql = <<<'SQL' SELECT COALESCE(tm.tpa_ailments, 'Not Specified') AS ailment, COUNT(tm.id) AS claim_count, CONCAT(ROUND(COUNT(tm.id) / totals.total_count * 100, 2), '%') AS count_pct, FORMAT( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) , 0) AS claim_value, CONCAT(ROUND( COALESCE(SUM(CAST(NULLIF(tm.claim_amount, '') AS DECIMAL(15,2))), 0) / NULLIF(totals.total_value, 0) * 100 , 2), '%') AS value_pct FROM ticket_master tm JOIN ( SELECT COUNT(id) AS total_count, COALESCE(SUM(CAST(NULLIF(claim_amount, '') AS DECIMAL(15,2))), 0) AS total_value FROM ticket_master WHERE client_policy_id = :policy_id: AND is_active = 1 ) totals ON 1=1 WHERE tm.client_policy_id = :policy_id: AND tm.is_active = 1 AND tm.tpa_ailments IS NOT NULL GROUP BY tm.tpa_ailments, totals.total_count, totals.total_value ORDER BY claim_count DESC LIMIT 10; SQL; return $this->runKpiQuery($sql, $policyId); } }