94 lines
3.6 KiB
PHP
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();
|
|
}
|
|
}
|