Перевод на доменную архитектуру

This commit is contained in:
brusnitsyn
2026-04-26 23:37:50 +09:00
parent 75ca01ffd8
commit f107ebd167
70 changed files with 4656 additions and 2070 deletions

View File

@@ -0,0 +1,116 @@
<?php
namespace App\Infrastructure\Reports\Services;
use App\Models\Department;
use App\Models\MisStationarBranch;
use App\Models\Report;
use App\Models\User;
use App\Services\DateRange;
use Illuminate\Support\Collection;
/**
* Разрешает контекст отчётного периода, необходимый для read-side сервисов.
*
* Класс хранит в одном месте правила поиска отчётов по периоду и решения
* snapshot-vs-replica, чтобы не дублировать их по контроллерам и сервисам.
*/
class ReportReadContextResolver
{
/**
* Определить MIS branch id для отчётного отделения.
*/
public function resolveBranchId(Department $department): ?int
{
return MisStationarBranch::query()
->where('rf_DepartmentID', $department->rf_mis_department_id)
->value('StationarBranchID');
}
/**
* Определить, нужно ли читать submitted-снапшоты вместо live-данных.
*/
public function shouldUseSnapshots(
Department $department,
DateRange $dateRange,
bool $beforeCreate = false
): bool {
if ($beforeCreate) {
return false;
}
$report = $this->getReportForPeriod($department->department_id, $dateRange);
return $report?->status === 'submitted';
}
/**
* Для самых изменчивых статусов врачи должны продолжать видеть live-данные за текущие сутки.
*/
public function shouldUseReplicaForLiveStatus(User $user, string $status, DateRange $dateRange): bool
{
if ($user->isHeadOfDepartment() || $user->isAdmin()) {
return false;
}
return in_array($status, ['plan', 'emergency', 'recipient', 'current', 'reanimation'], true)
&& $dateRange->isOneDay
&& $dateRange->isEndDateToday();
}
/**
* Вернуть submitted-отчёты, относящиеся к выбранному отчётному окну.
*
* @return Collection<int, Report>
*/
public function getReportsForDateRange(int $departmentId, DateRange $dateRange): Collection
{
if ($dateRange->isOneDay) {
return Report::query()
->where('rf_department_id', $departmentId)
->exactPeriod($dateRange->startSql(), $dateRange->endSql())
->onlySubmitted()
->orderBy('period_end', 'DESC')
->get();
}
return Report::query()
->where('rf_department_id', $departmentId)
->withinPeriod($dateRange->startSql(), $dateRange->endSql())
->onlySubmitted()
->orderBy('period_end', 'DESC')
->get();
}
/**
* Recipient-снапшоты читаются из последнего отчёта в выбранном окне.
*
* @param array<int, int> $reportIds
* @return array<int, int>
*/
public function getRecipientReportIds(array $reportIds): array
{
if (empty($reportIds)) {
return [];
}
return [reset($reportIds)];
}
/**
* Найти отчёт, который определяет видимость снапшотов для запрошенного периода.
*/
private function getReportForPeriod(int $departmentId, DateRange $dateRange): ?Report
{
$query = Report::query()
->where('rf_department_id', $departmentId)
->exactPeriod($dateRange->startSql(), $dateRange->endSql())
->orderByDesc('report_id');
if ($dateRange->isOneDay) {
return $query->first();
}
return $query->onlySubmitted()->first();
}
}