get(); $results = []; foreach ($programs as $program) { $current = SurveillanceCase::where('surveillance_id', $program->id) ->whereBetween('case_date', [$dateFrom, $dateTo]) ->count(); $previous = SurveillanceCase::where('surveillance_id', $program->id) ->whereBetween('case_date', [ date('Y-m-d', strtotime($dateFrom . ' -7 days')), date('Y-m-d', strtotime($dateFrom . ' -1 day')) ]) ->count(); $percentChange = $previous > 0 ? round((($current - $previous) / $previous) * 100, 1) : 0; $results[] = [ 'surveillance_id' => $program->id, 'code' => $program->code, 'current_total' => $current, 'previous_total' => $previous, 'percent_change' => $percentChange ]; } return $results; } /* |-------------------------------------------------------------------------- | Fast SARI Summary (single query) |-------------------------------------------------------------------------- */ public function sariSummaryFast($surveillanceId, $year, $week) { $row = SurveillanceCase::leftJoin( 'case_lab_results', 'surveillance_cases.lab_code', '=', 'case_lab_results.lab_code' ) ->where('surveillance_cases.surveillance_id', $surveillanceId) ->where('surveillance_cases.year_data', $year) ->where('surveillance_cases.week_data', $week) ->selectRaw(" COUNT(DISTINCT surveillance_cases.lab_code) as total_cases, COUNT(DISTINCT CASE WHEN case_lab_results.is_positive = 1 THEN surveillance_cases.lab_code END) as overall_positive, COUNT(DISTINCT CASE WHEN case_lab_results.indicator = 'SARI Influenza Test' AND case_lab_results.is_positive = 1 THEN surveillance_cases.lab_code END) as influenza_positive, COUNT(DISTINCT CASE WHEN case_lab_results.indicator = 'SARI Covid Test' AND case_lab_results.is_positive = 1 THEN surveillance_cases.lab_code END) as covid_positive ") ->first(); if (!$row || $row->total_cases == 0) { return [ 'cases' => 0, 'overall_rate' => 0, 'influenza_rate' => 0, 'covid_rate' => 0 ]; } return [ 'cases' => $row->total_cases, 'overall_rate' => round( ($row->overall_positive / $row->total_cases) * 100 , 1 ), 'influenza_rate' => round( ($row->influenza_positive / $row->total_cases) * 100 , 1 ), 'covid_rate' => round( ($row->covid_positive / $row->total_cases) * 100 , 1 ), ]; } /* |-------------------------------------------------------------------------- | Program Summary |-------------------------------------------------------------------------- */ public function programSummary($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) { $prevWeek = $endWeek - 1; $prevYear = $endYear; if ($prevWeek <= 0) { $prevWeek = 52; $prevYear--; } $current = $this->sariSummaryFast($surveillanceId, $endYear, $endWeek); $previous = $this->sariSummaryFast($surveillanceId, $prevYear, $prevWeek); return [ 'cases' => [ 'current' => $current['cases'], 'previous' => $previous['cases'] ], 'hospital_rate' => [ 'current' => 0, 'previous' => 0 ], 'icu_rate' => [ 'current' => 0, 'previous' => 0 ], 'positivity_rate' => [ 'current' => $current['overall_rate'], 'previous' => $previous['overall_rate'] ], 'influenza_rate' => [ 'current' => $current['influenza_rate'], 'previous' => $previous['influenza_rate'] ], 'covid_rate' => [ 'current' => $current['covid_rate'], 'previous' => $previous['covid_rate'] ], ]; } /* |-------------------------------------------------------------------------- | Overview Trend |-------------------------------------------------------------------------- */ public function aggregateAllPrograms($periodType, $startYear, $startWeek, $endYear, $endWeek) { $data = SurveillanceCase::selectRaw(" surveillance_id, year_data as year, week_data as period, COUNT(*) as total ") ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) { $q->whereRaw( "(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek] ) ->whereRaw( "(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek] ); }) ->groupBy('surveillance_id', 'year_data', 'week_data') ->orderBy('year_data') ->orderBy('week_data') ->get(); $programs = Surveillance::pluck('code', 'id'); $results = []; foreach ($data as $row) { $code = $programs[$row->surveillance_id]; $results[$code][] = $row; } return $results; } /* |-------------------------------------------------------------------------- | Program Dashboard |-------------------------------------------------------------------------- */ public function programDashboardData($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) { return [ 'summary' => $this->programSummary( $surveillanceId, $startYear, $startWeek, $endYear, $endWeek ), 'trend' => $this->trendSingleProgram( $surveillanceId, $startYear, $startWeek, $endYear, $endWeek ), 'pathogen_distribution' => $this->pathogenDistribution( $surveillanceId, $startYear, $startWeek, $endYear, $endWeek ), 'age_distribution' => $this->ageDistribution( $surveillanceId, $startYear, $startWeek, $endYear, $endWeek ), 'sex_distribution' => $this->sexDistribution( $surveillanceId, $startYear, $startWeek, $endYear, $endWeek ), 'province_distribution' => $this->provinceCirclesProgram( $surveillanceId, $startYear, $startWeek, $endYear, $endWeek ) ]; } /* |-------------------------------------------------------------------------- | Trend Single Program |-------------------------------------------------------------------------- */ public function trendSingleProgram($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) { $rows = SurveillanceCase::leftJoin( 'case_lab_results', 'surveillance_cases.lab_code', '=', 'case_lab_results.lab_code' ) ->where('surveillance_cases.surveillance_id', $surveillanceId) ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) { $q->whereRaw( "(surveillance_cases.year_data > ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data >= ?))", [$startYear, $startYear, $startWeek] ) ->whereRaw( "(surveillance_cases.year_data < ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data <= ?))", [$endYear, $endYear, $endWeek] ); }) ->selectRaw(" surveillance_cases.year_data as year, surveillance_cases.week_data as period, COUNT(DISTINCT surveillance_cases.lab_code) as total_samples, ROUND( SUM(CASE WHEN case_lab_results.is_positive = 1 THEN 1 ELSE 0 END) / NULLIF(COUNT(*),0) * 100,1 ) as positivity_rate ") ->groupBy( 'surveillance_cases.year_data', 'surveillance_cases.week_data' ) ->get() ->keyBy(fn($r) => $r->year . '-' . $r->period); $results = []; $year = $startYear; $week = $startWeek; while (true) { $key = $year . '-' . $week; if (isset($rows[$key])) { $results[] = $rows[$key]; } else { $results[] = [ 'year' => $year, 'period' => $week, 'total_samples' => 0, 'positivity_rate' => 0 ]; } if ($year == $endYear && $week == $endWeek) break; $week++; if ($week > 52) { $week = 1; $year++; } } return $results; } /* |-------------------------------------------------------------------------- | Province Distribution (Program) |-------------------------------------------------------------------------- */ public function provinceCirclesProgram($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) { return SurveillanceCase::selectRaw(" surveillance_cases.site_province_name, COUNT(DISTINCT surveillance_cases.lab_code) as total ") ->join( 'case_lab_results', 'surveillance_cases.lab_code', '=', 'case_lab_results.lab_code' ) ->where('surveillance_cases.surveillance_id', $surveillanceId) ->where('case_lab_results.is_positive', 1) ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) { $q->whereRaw( "(surveillance_cases.year_data > ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data >= ?))", [$startYear, $startYear, $startWeek] ) ->whereRaw( "(surveillance_cases.year_data < ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data <= ?))", [$endYear, $endYear, $endWeek] ); }) ->groupBy('surveillance_cases.site_province_name') ->get(); } /* |-------------------------------------------------------------------------- | Pathogen Distribution |-------------------------------------------------------------------------- */ public function pathogenDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) { return CaseLabResult::selectRaw(" pathogen_name, COUNT(*) as total ") ->join( 'surveillance_cases', 'case_lab_results.lab_code', '=', 'surveillance_cases.lab_code' ) ->where('surveillance_cases.surveillance_id', $surveillanceId) ->where('case_lab_results.is_positive', 1) ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) { $q->whereRaw( "(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek] ) ->whereRaw( "(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek] ); }) ->groupBy('pathogen_name') ->orderByDesc('total') ->get(); } /* |-------------------------------------------------------------------------- | Age Distribution |-------------------------------------------------------------------------- */ public function ageDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) { 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) ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) { $q->whereRaw( "(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek] ) ->whereRaw( "(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek] ); }) ->groupBy('age_group') ->get(); } /* |-------------------------------------------------------------------------- | Sex Distribution |-------------------------------------------------------------------------- */ public function sexDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) { return SurveillanceCase::selectRaw(" patient_sex, COUNT(*) as total ") ->where('surveillance_id', $surveillanceId) ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) { $q->whereRaw( "(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek] ) ->whereRaw( "(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek] ); }) ->groupBy('patient_sex') ->get(); } }