input('start_date')); $endDate = Carbon::parse($request->input('end_date')); $projections = $this->projectionGeneratorService->generateProjections( $scenario, $startDate, $endDate ); return new ProjectionResource($projections); } public function preview(PreviewAllocationRequest $request, Scenario $scenario): JsonResponse { $amountInCents = (int) round($request->input('amount') * 100); $draws = $this->pipelineAllocationService->allocateInflow($scenario, $amountInCents); /** @var array $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' => (float) $draw->amount_currency, 'remaining_capacity' => $this->remainingCapacity($bucket, $draw->amount), ]; })->values(); $totalAllocatedCents = $draws->sum('amount'); return response()->json([ 'allocations' => $allocations, 'total_allocated' => (float) round($totalAllocatedCents / 100, 2), 'unallocated' => (float) round(($amountInCents - $totalAllocatedCents) / 100, 2), ]); } private function remainingCapacity(Bucket $bucket, int $allocatedCents): ?float { $capacityCents = $bucket->getEffectiveCapacity(); if ($capacityCents === PHP_INT_MAX) { return null; } $remainingCents = max(0, $capacityCents - $allocatedCents); return round($remainingCents / 100, 2); } }