2025-12-31 02:34:30 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
|
|
use App\Http\Requests\CalculateProjectionRequest;
|
2026-03-21 11:05:50 +01:00
|
|
|
use App\Http\Requests\PreviewAllocationRequest;
|
2025-12-31 02:34:30 +01:00
|
|
|
use App\Http\Resources\ProjectionResource;
|
2026-03-21 11:05:50 +01:00
|
|
|
use App\Models\Bucket;
|
2025-12-31 02:34:30 +01:00
|
|
|
use App\Models\Scenario;
|
2026-03-21 11:05:50 +01:00
|
|
|
use App\Services\Projection\PipelineAllocationService;
|
2025-12-31 02:34:30 +01:00
|
|
|
use App\Services\Projection\ProjectionGeneratorService;
|
|
|
|
|
use Carbon\Carbon;
|
2026-03-21 11:05:50 +01:00
|
|
|
use Illuminate\Http\JsonResponse;
|
2025-12-31 02:34:30 +01:00
|
|
|
|
|
|
|
|
class ProjectionController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function __construct(
|
2026-03-21 11:05:50 +01:00
|
|
|
private readonly ProjectionGeneratorService $projectionGeneratorService,
|
|
|
|
|
private readonly PipelineAllocationService $pipelineAllocationService,
|
2025-12-31 02:34:30 +01:00
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
public function calculate(CalculateProjectionRequest $request, Scenario $scenario): ProjectionResource
|
|
|
|
|
{
|
|
|
|
|
$startDate = Carbon::parse($request->input('start_date'));
|
|
|
|
|
$endDate = Carbon::parse($request->input('end_date'));
|
|
|
|
|
|
|
|
|
|
$projections = $this->projectionGeneratorService->generateProjections(
|
|
|
|
|
$scenario,
|
|
|
|
|
$startDate,
|
|
|
|
|
$endDate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return new ProjectionResource($projections);
|
|
|
|
|
}
|
2026-03-21 11:05:50 +01:00
|
|
|
|
2026-03-21 17:26:45 +01:00
|
|
|
/**
|
|
|
|
|
* All amounts in cents. Frontend handles conversion to display units.
|
|
|
|
|
*/
|
2026-03-21 11:05:50 +01:00
|
|
|
public function preview(PreviewAllocationRequest $request, Scenario $scenario): JsonResponse
|
|
|
|
|
{
|
2026-03-21 17:26:45 +01:00
|
|
|
$amountInCents = (int) $request->input('amount');
|
2026-03-21 11:05:50 +01:00
|
|
|
|
|
|
|
|
$draws = $this->pipelineAllocationService->allocateInflow($scenario, $amountInCents);
|
|
|
|
|
|
|
|
|
|
/** @var array<int, Bucket> $bucketLookup */
|
|
|
|
|
$bucketLookup = $scenario->buckets->keyBy('id')->all();
|
|
|
|
|
|
|
|
|
|
$allocations = $draws->map(function ($draw) use ($bucketLookup) {
|
|
|
|
|
$bucket = $bucketLookup[$draw->bucket_id];
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'bucket_id' => $bucket->uuid,
|
|
|
|
|
'bucket_name' => $bucket->name,
|
|
|
|
|
'bucket_type' => $bucket->type->value,
|
2026-03-21 17:26:45 +01:00
|
|
|
'allocated_amount' => $draw->amount,
|
|
|
|
|
'remaining_capacity' => $bucket->hasFiniteCapacity()
|
|
|
|
|
? max(0, $bucket->getEffectiveCapacity() - $draw->amount)
|
|
|
|
|
: null,
|
2026-03-21 11:05:50 +01:00
|
|
|
];
|
|
|
|
|
})->values();
|
|
|
|
|
|
2026-03-21 17:26:45 +01:00
|
|
|
$totalAllocated = $draws->sum('amount');
|
2026-03-21 11:05:50 +01:00
|
|
|
|
|
|
|
|
return response()->json([
|
|
|
|
|
'allocations' => $allocations,
|
2026-03-21 17:26:45 +01:00
|
|
|
'total_allocated' => $totalAllocated,
|
|
|
|
|
'unallocated' => $amountInCents - $totalAllocated,
|
2026-03-21 11:05:50 +01:00
|
|
|
]);
|
|
|
|
|
}
|
2025-12-31 02:34:30 +01:00
|
|
|
}
|