buckets/app/Http/Controllers/ProjectionController.php

88 lines
2.9 KiB
PHP
Raw Normal View History

2025-12-31 02:34:30 +01:00
<?php
namespace App\Http\Controllers;
use App\Actions\ApplyDistributionAction;
2025-12-31 02:34:30 +01:00
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,
private readonly ApplyDistributionAction $applyDistributionAction,
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
/**
* 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
{
$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,
'allocated_amount' => $draw->amount,
'remaining_capacity' => $bucket->hasFiniteCapacity()
? max(0, $bucket->getEffectiveCapacity() - $draw->amount)
: null,
2026-03-21 11:05:50 +01:00
];
})->values();
$totalAllocated = $draws->sum('amount');
2026-03-21 11:05:50 +01:00
return response()->json([
'allocations' => $allocations,
'total_allocated' => $totalAllocated,
'unallocated' => $amountInCents - $totalAllocated,
2026-03-21 11:05:50 +01:00
]);
}
/**
* Apply an income distribution to bucket balances.
*
* Re-runs the allocation server-side and updates starting_amount for each bucket.
* All amounts in cents.
*/
public function apply(PreviewAllocationRequest $request, Scenario $scenario): JsonResponse
{
$amountInCents = (int) $request->input('amount');
$result = $this->applyDistributionAction->execute($scenario, $amountInCents);
return response()->json($result);
}
2025-12-31 02:34:30 +01:00
}