Files
econom/app/Services/Reports/ServiceAllocationService.php
brusnitsyn fb2e6c58e3
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
first commit
2026-04-06 00:06:00 +09:00

94 lines
3.6 KiB
PHP

<?php
namespace App\Services\Reports;
use App\Models\Department;
use App\Models\ReportPeriod;
use App\Models\ServiceCatalog;
use App\Models\ServiceEntry;
use Illuminate\Support\Collection;
class ServiceAllocationService
{
/**
* Build a provider sheet for the given period and service.
*
* @param Collection<int, Department> $recipientDepartments
* @return array<int, array<string, float>>
*/
public function entriesForProviderPeriodService(
ReportPeriod $period,
Department $providerDepartment,
ServiceCatalog $serviceCatalog,
Collection $recipientDepartments,
): array {
$entries = ServiceEntry::query()
->whereBelongsTo($period)
->whereBelongsTo($serviceCatalog)
->where('provider_department_id', $providerDepartment->id)
->whereIn('recipient_department_id', $recipientDepartments->pluck('id'))
->get()
->keyBy('recipient_department_id');
return $recipientDepartments->mapWithKeys(function (Department $recipientDepartment) use ($entries, $serviceCatalog): array {
/** @var ServiceEntry|null $entry */
$entry = $entries->get($recipientDepartment->id);
$quantity = (float) ($entry?->quantity ?? 0);
$unitPrice = (float) ($entry?->unit_price ?? $serviceCatalog->default_price);
return [$recipientDepartment->id => [
'quantity' => $quantity,
'unitPrice' => $unitPrice,
'totalAmount' => round($quantity * $unitPrice, 2),
]];
})->all();
}
/**
* Aggregate incoming services by recipient department.
*
* @param Collection<int, Department> $departments
* @param Collection<int, ServiceCatalog> $serviceCatalogs
* @return array<int, array<string, mixed>>
*/
public function incomingAllocationsForPeriod(
ReportPeriod $period,
Collection $departments,
Collection $serviceCatalogs,
): array {
$entries = ServiceEntry::query()
->with('serviceCatalog:id,code')
->whereBelongsTo($period)
->whereIn('recipient_department_id', $departments->pluck('id'))
->whereIn('service_catalog_id', $serviceCatalogs->pluck('id'))
->get()
->groupBy('recipient_department_id');
return $departments->mapWithKeys(function (Department $department) use ($entries, $serviceCatalogs): array {
/** @var Collection<int, ServiceEntry> $recipientEntries */
$recipientEntries = $entries->get($department->id, collect());
$services = $serviceCatalogs->mapWithKeys(function (ServiceCatalog $serviceCatalog) use ($recipientEntries): array {
$matchingEntries = $recipientEntries->filter(
fn (ServiceEntry $entry) => $entry->service_catalog_id === $serviceCatalog->id
);
$quantity = round((float) $matchingEntries->sum(fn (ServiceEntry $entry) => (float) $entry->quantity), 2);
$amount = round((float) $matchingEntries->sum(fn (ServiceEntry $entry) => $entry->totalAmount()), 2);
return [$serviceCatalog->code => [
'quantity' => $quantity,
'amount' => $amount,
]];
})->all();
return [$department->id => [
'services' => $services,
'totalQuantity' => round((float) collect($services)->sum('quantity'), 2),
'totalAmount' => round((float) collect($services)->sum('amount'), 2),
]];
})->all();
}
}