Collection of Draw models */ public function allocateInflow(Scenario $scenario, int $amount, ?Carbon $date = null, ?string $description = null): Collection { $draws = collect(); // Guard clauses if ($amount <= 0) { return $draws; } // Get buckets ordered by priority $buckets = $scenario->buckets() ->orderBy('priority') ->get(); if ($buckets->isEmpty()) { return $draws; } $priorityOrder = 1; $remainingAmount = $amount; $allocationDate = $date ?? now(); foreach ($buckets as $bucket) { if ($remainingAmount <= 0) { break; } $allocation = $this->calculateBucketAllocation($bucket, $remainingAmount); if ($allocation > 0) { $draw = new Draw([ 'bucket_id' => $bucket->id, 'amount' => $allocation, 'date' => $allocationDate, 'description' => $description ?? 'Allocation from inflow', 'is_projected' => true, ]); $draws->push($draw); $remainingAmount -= $allocation; $priorityOrder++; } } return $draws; } /** * Calculate how much should be allocated to a specific bucket. */ private function calculateBucketAllocation(Bucket $bucket, int $remainingAmount): int { return match ($bucket->allocation_type) { BucketAllocationTypeEnum::FIXED_LIMIT => $this->calculateFixedAllocation($bucket, $remainingAmount), BucketAllocationTypeEnum::PERCENTAGE => $this->calculatePercentageAllocation($bucket, $remainingAmount), BucketAllocationTypeEnum::UNLIMITED => $remainingAmount, // Takes all remaining default => 0, }; } /** * Calculate allocation for fixed limit buckets. */ private function calculateFixedAllocation(Bucket $bucket, int $remainingAmount): int { $bucketCapacity = (int) ($bucket->allocation_value ?? 0); $currentBalance = $bucket->getCurrentBalance(); $availableSpace = max(0, $bucketCapacity - $currentBalance); return min($availableSpace, $remainingAmount); } /** * Calculate allocation for percentage buckets. */ private function calculatePercentageAllocation(Bucket $bucket, int $remainingAmount): int { $percentage = $bucket->allocation_value ?? 0; return (int) round($remainingAmount * ($percentage / 100)); } }