get(); } /** * Summary cards (dynamic) */ public function summaryCards($dateFrom, $dateTo) { $programs = $this->getPrograms(); $results = []; $days = Carbon::parse($dateFrom)->diffInDays($dateTo); foreach ($programs as $program) { $current = SurveillanceCase::where('surveillance_id', $program->id) ->whereBetween('case_date', [$dateFrom, $dateTo]) ->count(); $previousFrom = Carbon::parse($dateFrom)->subDays($days + 1); $previousTo = Carbon::parse($dateFrom)->subDay(); $previous = SurveillanceCase::where('surveillance_id', $program->id) ->whereBetween('case_date', [$previousFrom, $previousTo]) ->count(); $percentChange = $previous > 0 ? round((($current - $previous) / $previous) * 100, 1) : 0; $last24h = SurveillanceCase::where('surveillance_id', $program->id) ->where('case_date', '>=', Carbon::now()->subDay()) ->count(); $results[] = [ 'surveillance_id' => $program->id, 'code' => $program->code, 'name_en' => $program->name_en, 'name_kh' => $program->name_kh, 'current_total' => $current, 'percent_change' => $percentChange, 'last_24h' => $last24h, ]; } return $results; } /** * Aggregate cases by period * periodType: week | month | year */ public function aggregateAllPrograms($periodType, $dateFrom, $dateTo) { $programs = Surveillance::all(); $results = []; foreach ($programs as $program) { $query = SurveillanceCase::where('surveillance_id', $program->id) ->whereBetween('case_date', [$dateFrom, $dateTo]); switch ($periodType) { case 'week': $query->selectRaw(" YEAR(case_date) as year, WEEK(case_date, 3) as period, COUNT(*) as total ") ->groupByRaw("YEAR(case_date), WEEK(case_date, 3)") ->orderByRaw("YEAR(case_date), WEEK(case_date, 3)"); break; case 'month': $query->selectRaw(" YEAR(case_date) as year, MONTH(case_date) as period, COUNT(*) as total ") ->groupByRaw("YEAR(case_date), MONTH(case_date)") ->orderByRaw("YEAR(case_date), MONTH(case_date)"); break; case 'year': $query->selectRaw(" YEAR(case_date) as period, COUNT(*) as total ") ->groupByRaw("YEAR(case_date)") ->orderByRaw("YEAR(case_date)"); break; } $results[$program->code] = $query->get(); } return $results; } public function aggregateCases($surveillanceId, $periodType, $dateFrom, $dateTo) { $query = SurveillanceCase::where('surveillance_id', $surveillanceId) ->whereBetween('case_date', [$dateFrom, $dateTo]); switch ($periodType) { case 'week': $query->selectRaw(" YEAR(case_date) as year, WEEK(case_date, 3) as period, COUNT(*) as total ") ->groupByRaw("YEAR(case_date), WEEK(case_date, 3)") ->orderByRaw("YEAR(case_date), WEEK(case_date, 3)"); break; case 'month': $query->selectRaw(" YEAR(case_date) as year, MONTH(case_date) as period, COUNT(*) as total ") ->groupByRaw("YEAR(case_date), MONTH(case_date)") ->orderByRaw("YEAR(case_date), MONTH(case_date)"); break; case 'year': $query->selectRaw(" YEAR(case_date) as period, COUNT(*) as total ") ->groupByRaw("YEAR(case_date)") ->orderByRaw("YEAR(case_date)"); break; } return $query->get(); } /** * Province distribution */ public function provinceDistribution($dateFrom, $dateTo) { return SurveillanceCase::selectRaw(" site_province_name, COUNT(*) as total ") ->join('case_lab_results', 'surveillance_cases.lab_code', '=', 'case_lab_results.lab_code') ->whereIn('surveillance_cases.surveillance_id', [1, 2, 3]) // SARI ILI LBM ->where('case_lab_results.is_positive', 1) ->whereBetween('surveillance_cases.case_date', [$dateFrom, $dateTo]) ->groupBy('site_province_name') ->orderByDesc('total') ->get(); } public function sentinelMap($dateFrom, $dateTo) { return SurveillanceCase::selectRaw(" sentinel_site_id, sentinel_site_name, site_province_name, surveillance_id, COUNT(*) as total ") ->join('case_lab_results', 'surveillance_cases.lab_code', '=', 'case_lab_results.lab_code') ->whereIn('surveillance_cases.surveillance_id', [1, 2, 3]) ->where('case_lab_results.is_positive', 1) ->whereBetween('surveillance_cases.case_date', [$dateFrom, $dateTo]) ->groupBy( 'sentinel_site_id', 'sentinel_site_name', 'site_province_name', 'surveillance_id' ) ->get(); } public function provinceCircles($dateFrom, $dateTo) { return SurveillanceCase::selectRaw(" surveillance_cases.site_province_name, surveillance_cases.surveillance_id, COUNT(*) as total ") ->join( 'case_lab_results', 'surveillance_cases.lab_code', '=', 'case_lab_results.lab_code' ) ->whereIn('surveillance_cases.surveillance_id', [1, 2, 3]) ->where('case_lab_results.is_positive', 1) ->whereBetween('surveillance_cases.case_date', [$dateFrom, $dateTo]) ->groupBy( 'surveillance_cases.site_province_name', 'surveillance_cases.surveillance_id' ) ->get(); } /** * Pathogen distribution (positive only) */ public function pathogenDistribution($surveillanceId, $dateFrom, $dateTo) { return CaseLabResult::selectRaw(" case_lab_results.pathogen_name, COUNT(*) as total ") ->join('surveillance_cases', 'case_lab_results.lab_code', '=', 'surveillance_cases.lab_code') ->where('surveillance_cases.surveillance_id', $surveillanceId) ->whereBetween('surveillance_cases.case_date', [$dateFrom, $dateTo]) ->where('case_lab_results.is_positive', 1) ->groupBy('case_lab_results.pathogen_name') ->orderByDesc('total') ->get(); } /** * Positivity rate */ public function positivityRate($surveillanceId, $dateFrom, $dateTo) { $total = CaseLabResult::join('surveillance_cases', 'case_lab_results.lab_code', '=', 'surveillance_cases.lab_code') ->where('surveillance_cases.surveillance_id', $surveillanceId) ->whereBetween('surveillance_cases.case_date', [$dateFrom, $dateTo]) ->count(); $positive = CaseLabResult::join('surveillance_cases', 'case_lab_results.lab_code', '=', 'surveillance_cases.lab_code') ->where('surveillance_cases.surveillance_id', $surveillanceId) ->whereBetween('surveillance_cases.case_date', [$dateFrom, $dateTo]) ->where('case_lab_results.is_positive', 1) ->count(); return $total > 0 ? round(($positive / $total) * 100, 1) : 0; } /** * Age distribution (grouped) */ public function ageDistribution($surveillanceId, $dateFrom, $dateTo) { return SurveillanceCase::selectRaw(" CASE WHEN patient_age_inday < 365 THEN '0-1y' WHEN patient_age_inday < 1825 THEN '1-5y' WHEN patient_age_inday < 6570 THEN '5-18y' WHEN patient_age_inday < 21900 THEN '18-60y' ELSE '60+y' END as age_group, COUNT(*) as total ") ->where('surveillance_id', $surveillanceId) ->whereBetween('case_date', [$dateFrom, $dateTo]) ->groupBy('age_group') ->get(); } /** * Sex distribution */ public function sexDistribution($surveillanceId, $dateFrom, $dateTo) { return SurveillanceCase::selectRaw(" patient_sex, COUNT(*) as total ") ->where('surveillance_id', $surveillanceId) ->whereBetween('case_date', [$dateFrom, $dateTo]) ->groupBy('patient_sex') ->get(); } }