Files
nrml_dashboard/dashboard/app/Services/DashboardService.php
2026-04-08 14:48:42 +07:00

1033 lines
36 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Services;
use App\Models\Surveillance;
use App\Models\SurveillanceCase;
use App\Models\CaseLabResult;
class DashboardService
{
private function totalTested($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::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]);
})
->distinct('lab_code')
->count('lab_code');
}
/*
|--------------------------------------------------------------------------
| Overview Summary Cards
|--------------------------------------------------------------------------
*/
public function summaryCards()
{
$programs = Surveillance::orderBy('id')->get();
$results = [];
$today = date('Y-m-d');
$currentFrom = date('Y-m-d', strtotime('-6 days'));
$currentTo = $today;
$prevFrom = date('Y-m-d', strtotime('-13 days'));
$prevTo = date('Y-m-d', strtotime('-7 days'));
foreach ($programs as $program) {
$current = SurveillanceCase::where('surveillance_id', $program->id)
->whereBetween('case_date', [$currentFrom, $currentTo])
->count();
$previous = SurveillanceCase::where('surveillance_id', $program->id)
->whereBetween('case_date', [$prevFrom, $prevTo])
->count();
$percentChange = $previous > 0
? round((($current - $previous) / $previous) * 100, 1)
: ($current > 0 ? 100 : 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 programSummaryFast($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.is_positive = 1
AND (
LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
OR LOWER(case_lab_results.pathogen_name) LIKE '%influzena%'
)
THEN surveillance_cases.lab_code
END) as influenza_positive,
COUNT(DISTINCT CASE
WHEN case_lab_results.is_positive = 1
AND (
LOWER(case_lab_results.pathogen_name) LIKE '%covid%'
OR LOWER(case_lab_results.pathogen_name) LIKE '%sars%'
)
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 afiTrend($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
return CaseLabResult::join(
'surveillance_cases',
'case_lab_results.lab_code',
'=',
'surveillance_cases.lab_code'
)
->where('surveillance_cases.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]);
})
->where('case_lab_results.is_positive', 1)
->whereNotNull('case_lab_results.pathogen_name')
->where('case_lab_results.pathogen_name', '!=', '')
->where('case_lab_results.pathogen_name', '!=', 'Positive')
->selectRaw("
surveillance_cases.year_data as year,
surveillance_cases.week_data as period,
CASE
WHEN LOWER(case_lab_results.pathogen_name) LIKE '%influenza%' THEN 'Influenza'
ELSE case_lab_results.pathogen_name
END as pathogen,
COUNT(DISTINCT surveillance_cases.lab_code) as total
")
->groupBy(
'surveillance_cases.year_data',
'surveillance_cases.week_data',
'pathogen'
)
->orderBy('surveillance_cases.year_data')
->orderBy('surveillance_cases.week_data')
->get();
}
public function programSummary($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
$prevWeek = $endWeek - 1;
$prevYear = $endYear;
if ($prevWeek <= 0) {
$prevWeek = 52;
$prevYear--;
}
$latest = SurveillanceCase::where('surveillance_id', $surveillanceId)
->selectRaw("year_data, week_data")
->orderByDesc('year_data')
->orderByDesc('week_data')
->first();
$year = $latest->year_data;
$week = $latest->week_data;
$current = $this->programSummaryFast($surveillanceId, $year, $week);
$previous = $this->programSummaryFast($surveillanceId, $prevYear, $prevWeek);
$prevWeek = $week - 1;
$prevYear = $year;
if ($prevWeek <= 0) {
$prevWeek = 52;
$prevYear--;
}
$previous = $this->programSummaryFast($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($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
),
'afi_trend' => $this->afiTrend(
$surveillanceId,
$startYear,
$startWeek,
$endYear,
$endWeek
),
'province_distribution' => $this->provinceProgram(
$surveillanceId,
$startYear,
$startWeek,
$endYear,
$endWeek
),
'virus_trend' => $this->virusTrend(
$surveillanceId,
$startYear,
$startWeek,
$endYear,
$endWeek
),
'subtype_distribution' => $this->subtypeDistribution(
$surveillanceId,
$startYear,
$startWeek,
$endYear,
$endWeek
),
'sentinel_sites' => $this->sentinelSites(
$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,
-- Overall positivity rate
ROUND(
COUNT(DISTINCT CASE
WHEN case_lab_results.is_positive = 1
THEN surveillance_cases.lab_code
END)
/ NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
,1) as positivity_rate,
-- Influenza positivity rate
ROUND(
COUNT(DISTINCT CASE
WHEN case_lab_results.is_positive = 1
AND (
LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
OR LOWER(case_lab_results.pathogen_name) LIKE '%influzena%'
)
THEN surveillance_cases.lab_code
END)
/ NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
,1) as influenza_rate,
-- COVID positivity rate
ROUND(
COUNT(DISTINCT CASE
WHEN case_lab_results.is_positive = 1
AND (
case_lab_results.pathogen_name = 'Positive'
OR case_lab_results.pathogen_name = 'SARS-CoV-2'
)
AND case_lab_results.indicator LIKE '%Covid%'
THEN surveillance_cases.lab_code
END)
/ NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
,1) as covid_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;
}
public function virusTrend($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
return CaseLabResult::join(
'surveillance_cases',
'case_lab_results.lab_code',
'=',
'surveillance_cases.lab_code'
)
->where('surveillance_cases.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]);
})
->selectRaw("
surveillance_cases.week_data as period,
COUNT(DISTINCT CASE
WHEN case_lab_results.is_positive = 1
AND (
LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
OR LOWER(case_lab_results.pathogen_name) LIKE '%influzena%'
)
THEN surveillance_cases.lab_code
END) as influenza,
COUNT(DISTINCT CASE
WHEN case_lab_results.is_positive = 1
AND (
case_lab_results.pathogen_name = 'Positive'
OR case_lab_results.pathogen_name = 'SARS-CoV-2'
)
AND case_lab_results.indicator LIKE '%Covid%'
THEN surveillance_cases.lab_code
END) as covid
")
->groupBy('surveillance_cases.week_data')
->orderBy('surveillance_cases.week_data')
->get();
}
/*
|--------------------------------------------------------------------------
| Province Distribution (Program)
|--------------------------------------------------------------------------
*/
public function provinceCircles($startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::join('case_lab_results', function ($join) {
$join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
})
->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
$q->whereRaw(
"(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
[
$startYear * 100 + $startWeek,
$endYear * 100 + $endWeek
]
);
})
->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Influenza"')
->selectRaw("
surveillance_cases.patient_province,
case_lab_results.subtype as pathogen_name,
COUNT(DISTINCT surveillance_cases.lab_code) as total
")
->groupBy(
'surveillance_cases.patient_province',
'case_lab_results.subtype'
)
->get();
return SurveillanceCase::leftJoin(
'case_lab_results',
'surveillance_cases.lab_code',
'=',
'case_lab_results.lab_code'
)
->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]
)
->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6)');
})
->selectRaw("
surveillance_cases.patient_province,
case_lab_results.pathogen_name,
COUNT(DISTINCT surveillance_cases.lab_code) as total
")
->groupBy(
'surveillance_cases.patient_province',
'case_lab_results.pathogen_name'
)
->get();
}
/* Start Overview Section */
public function influenzaSubtypeDetected($startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::join('case_lab_results', function ($join) {
$join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
})
->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
$q->whereRaw(
"(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
[
$startYear * 100 + $startWeek,
$endYear * 100 + $endWeek
]
);
})
->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Influenza"')
->selectRaw("
case_lab_results.subtype,
COUNT(DISTINCT surveillance_cases.lab_code) as total
")
->groupBy(
'case_lab_results.subtype'
)
->get();
}
public function covidDistributedByAgeGroup($startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::join('case_lab_results', function ($join) {
$join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
})
->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
$q->whereRaw(
"(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
[
$startYear * 100 + $startWeek,
$endYear * 100 + $endWeek
]
);
})
->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Covid-19"')
->selectRaw("
CASE
WHEN patient_age_inday <= 28 THEN '028 days'
WHEN patient_age_inday <= 364 THEN '29 days11 months'
WHEN patient_age_inday <= 1460 THEN '14 years'
WHEN patient_age_inday <= 5110 THEN '514 years'
WHEN patient_age_inday <= 8765 THEN '1524 years'
WHEN patient_age_inday <= 18250 THEN '2549 years'
WHEN patient_age_inday <= 23725 THEN '5064 years'
ELSE '65+ years'
END as age_group,
CASE
WHEN patient_age_inday <= 28 THEN 1
WHEN patient_age_inday <= 364 THEN 2
WHEN patient_age_inday <= 1460 THEN 3
WHEN patient_age_inday <= 5110 THEN 4
WHEN patient_age_inday <= 8765 THEN 5
WHEN patient_age_inday <= 18250 THEN 6
WHEN patient_age_inday <= 23725 THEN 7
ELSE 8
END as age_order,
COUNT(*) as total
")
->groupBy('age_group', 'age_order')
->orderBy('age_order')
->get();
}
public function covidLineageRelativeOverTime($startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::join('case_lab_results', function ($join) {
$join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
})
->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
$q->whereRaw(
"(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
[
$startYear * 100 + $startWeek,
$endYear * 100 + $endWeek
]
);
})
->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id=6 and case_lab_results.indicator="Covid-19" and case_lab_results.pathogen_name not in("","unable to align","N/A","NA")')
->selectRaw("
case_lab_results.pathogen_name as lineage,
concat(surveillance_cases.year_data,'-',surveillance_cases.week_data) as week,
COUNT(DISTINCT surveillance_cases.lab_code) as total
")
->groupBy(
'case_lab_results.pathogen_name',
'week'
)
->get();
}
public function influenzaRelativeOverTime($startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::join('case_lab_results', function ($join) {
$join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
})
->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
$q->whereRaw(
"(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
[
$startYear * 100 + $startWeek,
$endYear * 100 + $endWeek
]
);
})
->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Influenza"')
->selectRaw("
case_lab_results.subtype as lineage,
concat(surveillance_cases.year_data,'-',surveillance_cases.week_data) as week,
COUNT(DISTINCT surveillance_cases.lab_code) as total
")
->groupBy(
'case_lab_results.subtype',
'week'
)
->get();
}
/* End Overview Section */
public function provinceProgram($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::selectRaw("
surveillance_cases.patient_province,
COUNT(DISTINCT surveillance_cases.lab_code) as total,
COUNT(DISTINCT CASE
WHEN case_lab_results.is_positive = 1
THEN surveillance_cases.lab_code
END) as positive
")
->join(
'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]
);
})
->groupBy('surveillance_cases.patient_province')
->get();
}
/*
|--------------------------------------------------------------------------
| sentinel sites
|--------------------------------------------------------------------------
*/
public function sentinelSites($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::selectRaw("
sentinel_site_name as name,
COUNT(DISTINCT lab_code) 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('sentinel_site_name')
->orderByDesc('total')
->get();
}
/*
|--------------------------------------------------------------------------
| Pathogen Distribution
|--------------------------------------------------------------------------
*/
public function pathogenDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
$total = $this->totalTested($surveillanceId, $startYear, $startWeek, $endYear, $endWeek);
$rows = CaseLabResult::where('case_lab_results.surveillance_id', $surveillanceId)
->whereIn('lab_code', function ($q) use ($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) {
$q->select('lab_code')
->from('surveillance_cases')
->where('surveillance_id', $surveillanceId)
->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
})
->where('case_lab_results.is_positive', 1)
->selectRaw("
CASE
WHEN LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
THEN 'Influenza'
ELSE case_lab_results.pathogen_name
END as pathogen,
COUNT(DISTINCT case_lab_results.lab_code) as total
")
->groupBy('pathogen')
->havingRaw("pathogen IS NOT NULL AND pathogen != ''")
->orderByDesc('total')
->get();
return $rows->map(function ($r) use ($total) {
$r->rate = $total > 0 ? round(($r->total / $total) * 100, 1) : 0;
return $r;
});
}
public function subtypeDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
$total = $this->totalTested($surveillanceId, $startYear, $startWeek, $endYear, $endWeek);
$rows = CaseLabResult::where('case_lab_results.surveillance_id', $surveillanceId)
->whereIn('case_lab_results.lab_code', function ($q) use ($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) {
$q->select('lab_code')
->from('surveillance_cases')
->where('surveillance_id', $surveillanceId)
->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
})
->where('case_lab_results.is_positive', 1)
->selectRaw("
COALESCE(NULLIF(case_lab_results.subtype, ''), 'Unsubtyped') as subtype,
COUNT(DISTINCT case_lab_results.lab_code) as total
")
->where('case_lab_results.subtype', '!=', 'Positive')
->groupBy('subtype')
->orderByDesc('total')
->get();
return $rows->map(function ($r) use ($total) {
$r->rate = $total > 0 ? round(($r->total / $total) * 100, 1) : 0;
return $r;
});
}
/*
|--------------------------------------------------------------------------
| Age Distribution
|--------------------------------------------------------------------------
*/
public function ageDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
return SurveillanceCase::selectRaw("
CASE
WHEN patient_age_inday <= 28 THEN '028 days'
WHEN patient_age_inday <= 364 THEN '29 days11 months'
WHEN patient_age_inday <= 1460 THEN '14 years'
WHEN patient_age_inday <= 5110 THEN '514 years'
WHEN patient_age_inday <= 8765 THEN '1524 years'
WHEN patient_age_inday <= 18250 THEN '2549 years'
WHEN patient_age_inday <= 23725 THEN '5064 years'
ELSE '65+ years'
END as age_group,
CASE
WHEN patient_age_inday <= 28 THEN 1
WHEN patient_age_inday <= 364 THEN 2
WHEN patient_age_inday <= 1460 THEN 3
WHEN patient_age_inday <= 5110 THEN 4
WHEN patient_age_inday <= 8765 THEN 5
WHEN patient_age_inday <= 18250 THEN 6
WHEN patient_age_inday <= 23725 THEN 7
ELSE 8
END as age_order,
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', 'age_order')
->orderBy('age_order')
->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();
}
/*
|--------------------------------------------------------------------------
| sequencing trend
|--------------------------------------------------------------------------
*/
public function sequencingTrend($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
{
return CaseLabResult::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)
->whereNotNull('subtype')
->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]);
})
->selectRaw("
surveillance_cases.week_data as period,
subtype,
COUNT(DISTINCT surveillance_cases.lab_code) as total
")
->groupBy('period', 'subtype')
->orderBy('period')
->get();
}
}