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' => $draw->amount_currency, 'remaining_capacity' => $this->remainingCapacity($bucket, $draw->amount_currency), ]; })->values(); $totalAllocatedCents = $draws->sum('amount'); return response()->json([ 'allocations' => $allocations, 'total_allocated' => round($totalAllocatedCents / 100, 2), 'unallocated' => round(($amountInCents - $totalAllocatedCents) / 100, 2), ]); } private function remainingCapacity(Bucket $bucket, float $allocatedDollars): ?float { $effectiveCapacity = $bucket->getEffectiveCapacity(); if ($effectiveCapacity === PHP_FLOAT_MAX) { return null; } return round(max(0, $effectiveCapacity - $allocatedDollars), 2); } }