169 lines
6.1 KiB
PHP
169 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace App\Infrastructure\Reports\Services;
|
|
|
|
use App\Domain\Reports\ValueObjects\MetrikaConfig;
|
|
use App\Models\Department;
|
|
use App\Models\MisLpuDoctor;
|
|
use App\Models\Report;
|
|
use App\Models\UnwantedEvent;
|
|
use App\Models\User;
|
|
use App\Services\DateRange;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Collection;
|
|
|
|
/**
|
|
* Read-side сервис для metadata отчёта: текущий отчёт, события, планы и периоды.
|
|
*/
|
|
class ReportMetadataReadService
|
|
{
|
|
public function __construct(
|
|
private readonly ReportReadContextResolver $contextResolver,
|
|
) {}
|
|
|
|
public function getCurrentReportInfo(Department $department, User $user, DateRange $dateRange): array
|
|
{
|
|
$reportToday = $this->contextResolver->resolveReportForPeriod($department->department_id, $dateRange);
|
|
|
|
$isHeadOrAdmin = $user->isHeadOfDepartment() || $user->isAdmin();
|
|
$useSnapshots = $isHeadOrAdmin || ! $dateRange->isEndDateToday() || $reportToday;
|
|
|
|
if ($useSnapshots && $isHeadOrAdmin && $reportToday) {
|
|
$fillableUserId = $reportToday->rf_lpudoctor_id ?? null;
|
|
} else {
|
|
$fillableUserId = request()->query('userId', $user->rf_lpudoctor_id);
|
|
}
|
|
|
|
$unwantedEvents = $this->getUnwantedEvents($department, $dateRange);
|
|
$isActiveSendButton = $this->isSendButtonActive($user, $dateRange, $reportToday);
|
|
|
|
$message = null;
|
|
if ($reportToday) {
|
|
$reportDoctor = $reportToday->lpuDoctor;
|
|
$message = "Отчет создан пользователем: $reportDoctor->FAM_V $reportDoctor->IM_V $reportDoctor->OT_V";
|
|
}
|
|
|
|
$statusMessage = $reportToday
|
|
? ($reportToday->status === 'submitted'
|
|
? 'Этот отчет в статусе: опубликован'
|
|
: 'Этот отчет в статусе: черновик')
|
|
: null;
|
|
|
|
$lpuDoctor = $this->getDoctorInfo($fillableUserId, $dateRange);
|
|
$date = $isHeadOrAdmin ? [
|
|
$dateRange->startDate->getTimestampMs(),
|
|
$dateRange->endDate->getTimestampMs(),
|
|
] : $dateRange->endDate->getTimestampMs();
|
|
|
|
return [
|
|
'report_id' => $reportToday?->report_id,
|
|
'unwantedEvents' => $unwantedEvents,
|
|
'isActiveSendButton' => $isActiveSendButton,
|
|
'message' => $dateRange->isOneDay ? $message : null,
|
|
'status' => $reportToday?->status ?? 'draft',
|
|
'statusMessage' => $dateRange->isOneDay ? $statusMessage : null,
|
|
'canPublish' => (bool) $reportToday && ($reportToday->status === 'draft') && $isActiveSendButton,
|
|
'isOneDay' => $dateRange->isOneDay,
|
|
'isHeadOrAdmin' => $isHeadOrAdmin,
|
|
'dates' => $date,
|
|
'userId' => $fillableUserId,
|
|
'userName' => $lpuDoctor ? "$lpuDoctor->FAM_V $lpuDoctor->IM_V $lpuDoctor->OT_V" : null,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, array<string, mixed>>
|
|
*/
|
|
public function getUnwantedEvents(Department $department, DateRange $dateRange): Collection
|
|
{
|
|
return UnwantedEvent::query()
|
|
->whereHas('report', function ($query) use ($department, $dateRange) {
|
|
$query->where('rf_department_id', $department->department_id);
|
|
|
|
if ($dateRange->isOneDay) {
|
|
$query->exactPeriod($dateRange->startSql(), $dateRange->endSql());
|
|
} else {
|
|
$query->withinPeriod($dateRange->startSql(), $dateRange->endSql());
|
|
}
|
|
})
|
|
->get()
|
|
->map(function (UnwantedEvent $item) {
|
|
return [
|
|
...$item->toArray(),
|
|
'created_at' => Carbon::parse($item->created_at)->format('Создано d.m.Y в H:i'),
|
|
];
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, Report>
|
|
*/
|
|
public function getReportsForDateRange(int $departmentId, DateRange $dateRange): Collection
|
|
{
|
|
return $this->contextResolver->getReportsForDateRange($departmentId, $dateRange);
|
|
}
|
|
|
|
public function getRecipientPlanOfYear(Department $department, DateRange $dateRange): array
|
|
{
|
|
$periodPlanModel = $department->recipientPlanOfYear();
|
|
$monthsInPeriod = ceil($dateRange->startDate->diffInMonths($dateRange->endDate));
|
|
$annualPlan = $periodPlanModel ? (int) $periodPlanModel->value : 0;
|
|
$oneMonthPlan = ceil($annualPlan / 12);
|
|
$periodPlan = round($oneMonthPlan * $monthsInPeriod);
|
|
|
|
$query = $department->reports()
|
|
->with('metrikaResults')
|
|
->where('period_start', '>', $dateRange->startSql())
|
|
->where('period_end', '<=', $dateRange->endSql());
|
|
|
|
if ($dateRange->isOneDay) {
|
|
$query->where('period_start', '>=', $dateRange->startFirstOfMonth())
|
|
->where('period_end', '<=', $dateRange->endSql());
|
|
} else {
|
|
$query->where('period_start', '>', $dateRange->startSql())
|
|
->where('period_end', '<=', $dateRange->endSql());
|
|
}
|
|
|
|
$progress = 0;
|
|
|
|
foreach ($query->get() as $report) {
|
|
$outcome = $report->metrikaResults()
|
|
->where('rf_metrika_item_id', MetrikaConfig::OUTCOME)
|
|
->first();
|
|
|
|
if ($outcome) {
|
|
$progress += (int) $outcome->value;
|
|
}
|
|
}
|
|
|
|
return [
|
|
'plan' => $periodPlan,
|
|
'progress' => $progress,
|
|
];
|
|
}
|
|
|
|
private function isSendButtonActive(User $user, DateRange $dateRange, ?Report $reportToday): bool
|
|
{
|
|
if (! $user->isHeadOfDepartment() && ! $user->isAdmin()) {
|
|
if ($reportToday && $reportToday->status === 'submitted') {
|
|
return false;
|
|
}
|
|
|
|
return $dateRange->isEndDateToday();
|
|
}
|
|
|
|
return (bool) $reportToday && $dateRange->isOneDay;
|
|
}
|
|
|
|
private function getDoctorInfo(?int $doctorId, DateRange $dateRange): ?MisLpuDoctor
|
|
{
|
|
if (! $doctorId || ! $dateRange->isOneDay) {
|
|
return null;
|
|
}
|
|
|
|
return MisLpuDoctor::query()
|
|
->where('LPUDoctorID', $doctorId)
|
|
->first();
|
|
}
|
|
}
|