> */ public function valueMatrixForRow(?MedicationExpenseRow $row): array { $matrix = []; foreach (FundingSource::cases() as $fundingSource) { foreach (ExpenseCategory::cases() as $expenseCategory) { $matrix[$fundingSource->value][$expenseCategory->value] = 0.0; } } if ($row === null) { return $matrix; } $row->loadMissing('values'); foreach ($row->values as $value) { $matrix[$value->funding_source->value][$value->expense_category->value] = (float) $value->amount; } return $matrix; } /** * Calculate medication expense totals for the given matrix. * * @param array> $matrix * @return array */ public function calculateFromMatrix(array $matrix): array { $byFundingSource = []; $totalWithoutDressing = 0.0; $totalDressing = 0.0; foreach (FundingSource::cases() as $fundingSource) { $withoutDressing = 0.0; $dressing = 0.0; foreach (ExpenseCategory::cases() as $expenseCategory) { $amount = (float) ($matrix[$fundingSource->value][$expenseCategory->value] ?? 0); if ($expenseCategory->countsTowardsWithoutDressing()) { $withoutDressing += $amount; } else { $dressing += $amount; } } $byFundingSource[$fundingSource->value] = [ 'label' => $fundingSource->label(), 'without_dressing' => round($withoutDressing, 2), 'dressing' => round($dressing, 2), 'total' => round($withoutDressing + $dressing, 2), ]; $totalWithoutDressing += $withoutDressing; $totalDressing += $dressing; } $budgetWithoutDressing = $byFundingSource[FundingSource::Budget->value]['without_dressing']; $budgetDressing = $byFundingSource[FundingSource::Budget->value]['dressing']; return [ 'byFundingSource' => $byFundingSource, 'total_without_dressing' => round($totalWithoutDressing, 2), 'total_dressing' => round($totalDressing, 2), 'total_expense' => round($totalWithoutDressing + $totalDressing, 2), 'without_budget_no_dressing' => round($totalWithoutDressing - $budgetWithoutDressing, 2), 'without_budget_dressing' => round($totalDressing - $budgetDressing, 2), 'without_budget_total' => round(($totalWithoutDressing - $budgetWithoutDressing) + ($totalDressing - $budgetDressing), 2), ]; } /** * Calculate medication expense totals for a department in the given period. * * @return array */ public function calculateForDepartmentPeriod(ReportPeriod $period, Department $department): array { $row = MedicationExpenseRow::query() ->with('values') ->whereBelongsTo($period) ->whereBelongsTo($department) ->first(); $matrix = $this->valueMatrixForRow($row); return [ 'rowId' => $row?->id, 'matrix' => $matrix, 'totals' => $this->calculateFromMatrix($matrix), ]; } /** * Build totals for many departments in the period. * * @param Collection $departments * @return array> */ public function calculateForDepartments(ReportPeriod $period, Collection $departments): array { $rows = MedicationExpenseRow::query() ->with('values') ->whereBelongsTo($period) ->whereIn('department_id', $departments->pluck('id')) ->get() ->keyBy('department_id'); return $departments->mapWithKeys(function (Department $department) use ($rows): array { /** @var MedicationExpenseRow|null $row */ $row = $rows->get($department->id); $matrix = $this->valueMatrixForRow($row); return [$department->id => [ 'rowId' => $row?->id, 'matrix' => $matrix, 'totals' => $this->calculateFromMatrix($matrix), ]]; })->all(); } }