Fix code style issues across 32 files (Pint)

This commit is contained in:
myrmidex 2026-03-19 01:09:47 +01:00
parent 54de5b6cc2
commit 67ab1f5f41
32 changed files with 119 additions and 131 deletions

View file

@ -33,7 +33,7 @@ public function execute(
} else {
// Validate priority is positive
if ($priority < 1) {
throw new InvalidArgumentException("Priority must be at least 1");
throw new InvalidArgumentException('Priority must be at least 1');
}
// Check if priority already exists and shift others if needed
@ -57,7 +57,6 @@ public function execute(
});
}
/**
* Validate allocation value based on allocation type.
*/
@ -95,7 +94,7 @@ private function validateAllocationValue(BucketAllocationTypeEnum $allocationTyp
public function createDefaultBuckets(Scenario $scenario): array
{
$buckets = [];
// Monthly Expenses - Fixed limit, priority 1
$buckets[] = $this->execute(
$scenario,
@ -104,16 +103,16 @@ public function createDefaultBuckets(Scenario $scenario): array
0,
1
);
// Emergency Fund - Fixed limit, priority 2
$buckets[] = $this->execute(
$scenario,
'Emergency Fund',
'Emergency Fund',
BucketAllocationTypeEnum::FIXED_LIMIT,
0,
2
);
// Investments - Unlimited, priority 3
$buckets[] = $this->execute(
$scenario,
@ -122,7 +121,7 @@ public function createDefaultBuckets(Scenario $scenario): array
null,
3
);
return $buckets;
}
}
}

View file

@ -10,4 +10,4 @@ public function execute(Scenario $scenario): void
{
$scenario->delete();
}
}
}

View file

@ -10,7 +10,7 @@ enum BucketAllocationTypeEnum: string
public function getLabel(): string
{
return match($this) {
return match ($this) {
self::FIXED_LIMIT => 'Fixed Limit',
self::PERCENTAGE => 'Percentage',
self::UNLIMITED => 'Unlimited',
@ -24,7 +24,7 @@ public static function values(): array
public function getAllocationValueRules(): array
{
return match($this) {
return match ($this) {
self::FIXED_LIMIT => ['required', 'numeric', 'min:0'],
self::PERCENTAGE => ['required', 'numeric', 'min:0.01', 'max:100'],
self::UNLIMITED => ['nullable'],
@ -33,9 +33,9 @@ public function getAllocationValueRules(): array
public function formatValue(?float $value): string
{
return match($this) {
self::FIXED_LIMIT => '$' . number_format($value ?? 0, 2),
self::PERCENTAGE => number_format($value ?? 0, 2) . '%',
return match ($this) {
self::FIXED_LIMIT => '$'.number_format($value ?? 0, 2),
self::PERCENTAGE => number_format($value ?? 0, 2).'%',
self::UNLIMITED => 'All remaining',
};
}

View file

@ -36,6 +36,7 @@ public static function labels(): array
foreach (self::cases() as $case) {
$labels[$case->value] = $case->label();
}
return $labels;
}
@ -51,4 +52,4 @@ public function getMonthlyEquivalentMultiplier(): float
self::ONCE => 0.0,
};
}
}
}

View file

@ -34,7 +34,7 @@ public function index(Scenario $scenario): JsonResponse
});
return response()->json([
'buckets' => $buckets
'buckets' => $buckets,
]);
}
@ -42,7 +42,7 @@ public function store(Request $request, Scenario $scenario): JsonResponse
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'allocation_type' => 'required|in:' . implode(',', [
'allocation_type' => 'required|in:'.implode(',', [
Bucket::TYPE_FIXED_LIMIT,
Bucket::TYPE_PERCENTAGE,
Bucket::TYPE_UNLIMITED,
@ -52,7 +52,7 @@ public function store(Request $request, Scenario $scenario): JsonResponse
]);
try {
$createBucketAction = new CreateBucketAction();
$createBucketAction = new CreateBucketAction;
$bucket = $createBucketAction->execute(
$scenario,
$validated['name'],
@ -63,12 +63,12 @@ public function store(Request $request, Scenario $scenario): JsonResponse
return response()->json([
'bucket' => $this->formatBucketResponse($bucket),
'message' => 'Bucket created successfully.'
'message' => 'Bucket created successfully.',
], 201);
} catch (InvalidArgumentException $e) {
return response()->json([
'message' => 'Validation failed.',
'errors' => ['allocation_value' => [$e->getMessage()]]
'errors' => ['allocation_value' => [$e->getMessage()]],
], 422);
}
}
@ -77,7 +77,7 @@ public function update(Request $request, Bucket $bucket): JsonResponse
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'allocation_type' => 'required|in:' . implode(',', [
'allocation_type' => 'required|in:'.implode(',', [
Bucket::TYPE_FIXED_LIMIT,
Bucket::TYPE_PERCENTAGE,
Bucket::TYPE_UNLIMITED,
@ -107,7 +107,7 @@ public function update(Request $request, Bucket $bucket): JsonResponse
return response()->json([
'bucket' => $this->formatBucketResponse($bucket),
'message' => 'Bucket updated successfully.'
'message' => 'Bucket updated successfully.',
]);
}
@ -125,7 +125,7 @@ public function destroy(Bucket $bucket): JsonResponse
$this->shiftPrioritiesDown($scenarioId, $deletedPriority);
return response()->json([
'message' => 'Bucket deleted successfully.'
'message' => 'Bucket deleted successfully.',
]);
}
@ -151,7 +151,7 @@ public function updatePriorities(Request $request, Scenario $scenario): JsonResp
}
return response()->json([
'message' => 'Bucket priorities updated successfully.'
'message' => 'Bucket priorities updated successfully.',
]);
}
@ -175,7 +175,6 @@ private function formatBucketResponse(Bucket $bucket): array
];
}
/**
* Shift priorities down to fill gap after deletion.
*/

View file

@ -3,16 +3,16 @@
namespace App\Http\Controllers;
use App\Actions\CreateScenarioAction;
use App\Actions\UpdateScenarioAction;
use App\Actions\DeleteScenarioAction;
use App\Http\Resources\BucketResource;
use App\Http\Resources\StreamResource;
use App\Http\Resources\ScenarioResource;
use App\Actions\UpdateScenarioAction;
use App\Http\Requests\StoreScenarioRequest;
use App\Http\Requests\UpdateScenarioRequest;
use App\Http\Resources\BucketResource;
use App\Http\Resources\ScenarioResource;
use App\Http\Resources\StreamResource;
use App\Models\Scenario;
use App\Repositories\StreamRepository;
use App\Repositories\ScenarioRepository;
use App\Repositories\StreamRepository;
use App\Services\Streams\StatsService;
use Illuminate\Http\RedirectResponse;
use Inertia\Inertia;
@ -32,7 +32,7 @@ public function __construct(
public function index(): Response
{
return Inertia::render('Scenarios/Index', [
'scenarios' => ScenarioResource::collection($this->scenarioRepository->getAll())
'scenarios' => ScenarioResource::collection($this->scenarioRepository->getAll()),
]);
}
@ -46,7 +46,7 @@ public function show(Scenario $scenario): Response
'scenario' => new ScenarioResource($scenario),
'buckets' => BucketResource::collection($scenario->buckets),
'streams' => StreamResource::collection($this->streamRepository->getForScenario($scenario)),
'streamStats' => $this->statsService->getSummaryStats($scenario)
'streamStats' => $this->statsService->getSummaryStats($scenario),
]);
}
@ -65,7 +65,7 @@ public function store(StoreScenarioRequest $request): RedirectResponse
public function edit(Scenario $scenario): Response
{
return Inertia::render('Scenarios/Edit', [
'scenario' => new ScenarioResource($scenario)
'scenario' => new ScenarioResource($scenario),
]);
}

View file

@ -4,11 +4,11 @@
use App\Http\Requests\StoreStreamRequest;
use App\Http\Requests\UpdateStreamRequest;
use App\Models\Stream;
use App\Http\Resources\StreamResource;
use App\Models\Scenario;
use App\Models\Stream;
use App\Repositories\StreamRepository;
use App\Services\Streams\StatsService;
use App\Http\Resources\StreamResource;
use Illuminate\Http\JsonResponse;
class StreamController extends Controller
@ -24,7 +24,7 @@ public function index(Scenario $scenario): JsonResponse
return response()->json([
'streams' => StreamResource::collection($streams),
'stats' => $this->statsService->getSummaryStats($scenario)
'stats' => $this->statsService->getSummaryStats($scenario),
]);
}
@ -34,7 +34,7 @@ public function store(StoreStreamRequest $request, Scenario $scenario): JsonResp
return response()->json([
'stream' => new StreamResource($stream),
'message' => 'Stream created successfully.'
'message' => 'Stream created successfully.',
], 201);
}
@ -44,7 +44,7 @@ public function update(UpdateStreamRequest $request, Stream $stream): JsonRespon
return response()->json([
'stream' => new StreamResource($stream),
'message' => 'Stream updated successfully.'
'message' => 'Stream updated successfully.',
]);
}
@ -53,7 +53,7 @@ public function destroy(Stream $stream): JsonResponse
$this->streamRepository->delete($stream);
return response()->json([
'message' => 'Stream deleted successfully.'
'message' => 'Stream deleted successfully.',
]);
}
@ -63,7 +63,7 @@ public function toggle(Stream $stream): JsonResponse
return response()->json([
'stream' => new StreamResource($stream),
'message' => $stream->is_active ? 'Stream activated.' : 'Stream deactivated.'
'message' => $stream->is_active ? 'Stream activated.' : 'Stream deactivated.',
]);
}
}

View file

@ -26,4 +26,4 @@ public function messages(): array
'end_date.after_or_equal' => 'End date must be after or equal to start date.',
];
}
}
}

View file

@ -2,8 +2,8 @@
namespace App\Http\Requests;
use App\Models\Stream;
use App\Models\Scenario;
use App\Models\Stream;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
@ -37,7 +37,7 @@ public function rules(): array
Stream::FREQUENCY_MONTHLY,
Stream::FREQUENCY_QUARTERLY,
Stream::FREQUENCY_YEARLY,
])
]),
],
'start_date' => ['required', 'date', 'date_format:Y-m-d'],
'end_date' => ['nullable', 'date', 'date_format:Y-m-d', 'after_or_equal:start_date'],
@ -70,13 +70,13 @@ public function withValidator($validator): void
->where('id', $this->bucket_id)
->exists();
if (!$bucketBelongsToScenario) {
if (! $bucketBelongsToScenario) {
$validator->errors()->add('bucket_id', 'The selected bucket does not belong to this scenario.');
}
}
// For expense streams, bucket is required
if ($this->type === Stream::TYPE_EXPENSE && !$this->bucket_id) {
if ($this->type === Stream::TYPE_EXPENSE && ! $this->bucket_id) {
$validator->errors()->add('bucket_id', 'A bucket must be selected for expense streams.');
}
});
@ -85,13 +85,13 @@ public function withValidator($validator): void
protected function prepareForValidation(): void
{
// Ensure dates are in the correct format
if ($this->has('start_date') && !empty($this->start_date)) {
if ($this->has('start_date') && ! empty($this->start_date)) {
$this->merge([
'start_date' => date('Y-m-d', strtotime($this->start_date)),
]);
}
if ($this->has('end_date') && !empty($this->end_date)) {
if ($this->has('end_date') && ! empty($this->end_date)) {
$this->merge([
'end_date' => date('Y-m-d', strtotime($this->end_date)),
]);

View file

@ -3,7 +3,6 @@
namespace App\Http\Requests;
use App\Models\Stream;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
@ -31,7 +30,7 @@ public function rules(): array
Stream::FREQUENCY_MONTHLY,
Stream::FREQUENCY_QUARTERLY,
Stream::FREQUENCY_YEARLY,
])
]),
],
'start_date' => ['required', 'date', 'date_format:Y-m-d'],
'end_date' => ['nullable', 'date', 'date_format:Y-m-d', 'after_or_equal:start_date'],
@ -65,13 +64,13 @@ public function withValidator($validator): void
->where('id', $this->bucket_id)
->exists();
if (!$bucketBelongsToScenario) {
if (! $bucketBelongsToScenario) {
$validator->errors()->add('bucket_id', 'The selected bucket does not belong to this scenario.');
}
}
// For expense streams, bucket is required
if ($this->type === Stream::TYPE_EXPENSE && !$this->bucket_id) {
if ($this->type === Stream::TYPE_EXPENSE && ! $this->bucket_id) {
$validator->errors()->add('bucket_id', 'A bucket must be selected for expense streams.');
}
});
@ -80,13 +79,13 @@ public function withValidator($validator): void
protected function prepareForValidation(): void
{
// Ensure dates are in the correct format
if ($this->has('start_date') && !empty($this->start_date)) {
if ($this->has('start_date') && ! empty($this->start_date)) {
$this->merge([
'start_date' => date('Y-m-d', strtotime($this->start_date)),
]);
}
if ($this->has('end_date') && !empty($this->end_date)) {
if ($this->has('end_date') && ! empty($this->end_date)) {
$this->merge([
'end_date' => date('Y-m-d', strtotime($this->end_date)),
]);
@ -100,7 +99,7 @@ protected function prepareForValidation(): void
}
// Default is_active to current value if not provided
if (!$this->has('is_active')) {
if (! $this->has('is_active')) {
/** @var Stream $stream */
$stream = $this->route('stream');
$this->merge([

View file

@ -21,4 +21,4 @@ public function toArray(Request $request): array
],
];
}
}
}

View file

@ -140,13 +140,13 @@ public static function validationRules($scenarioId = null): array
{
$rules = [
'name' => 'required|string|max:255',
'allocation_type' => 'required|in:' . implode(',', BucketAllocationTypeEnum::values()),
'allocation_type' => 'required|in:'.implode(',', BucketAllocationTypeEnum::values()),
'priority' => 'required|integer|min:1',
];
// Add scenario-specific priority uniqueness if scenario ID provided
if ($scenarioId) {
$rules['priority'] .= '|unique:buckets,priority,NULL,id,scenario_id,' . $scenarioId;
$rules['priority'] .= '|unique:buckets,priority,NULL,id,scenario_id,'.$scenarioId;
}
return $rules;

View file

@ -17,14 +17,16 @@
* @property Carbon $date
* @property string $description
* @property bool $is_projected
*
* @method static create(array $array)
*/
class Draw extends Model
{
use HasAmount;
/** @use HasFactory<DrawFactory> */
use HasFactory;
use HasProjectionStatus;
use HasAmount;
protected $fillable = [
'bucket_id',

View file

@ -19,8 +19,8 @@
*/
class Inflow extends Model
{
use HasProjectionStatus;
use HasAmount;
use HasProjectionStatus;
protected $fillable = [
'stream_id',

View file

@ -18,14 +18,16 @@
* @property Carbon $date
* @property string $description
* @property bool $is_projected
*
* @method static create(array $array)
*/
class Outflow extends Model
{
use HasAmount;
/** @use HasFactory<OutflowFactory> */
use HasFactory;
use HasProjectionStatus;
use HasAmount;
protected $fillable = [
'stream_id',

View file

@ -11,6 +11,7 @@
/**
* @property int $id
* @property Collection<Bucket> $buckets
*
* @method static create(array $data)
*/
class Scenario extends Model

View file

@ -17,7 +17,7 @@
*/
class Stream extends Model
{
use HasFactory, HasAmount;
use HasAmount, HasFactory;
protected $fillable = [
'scenario_id',
@ -73,9 +73,10 @@ public function getFrequencyLabel(): string
public function getMonthlyEquivalent(): float
{
if (!$this->frequency) {
if (! $this->frequency) {
return 0;
}
return $this->amount * $this->frequency->getMonthlyEquivalentMultiplier();
}

View file

@ -28,4 +28,4 @@ public function getFormattedAmountAttribute(): string
{
return number_format($this->amount / 100, 2);
}
}
}

View file

@ -13,4 +13,4 @@ public function getAll(): Collection
->orderBy('created_at', 'desc')
->get();
}
}
}

View file

@ -2,8 +2,8 @@
namespace App\Repositories;
use App\Models\Stream;
use App\Models\Scenario;
use App\Models\Stream;
use Illuminate\Support\Collection;
class StreamRepository
@ -37,7 +37,7 @@ public function delete(Stream $stream): bool
public function toggleActive(Stream $stream): Stream
{
$stream->update([
'is_active' => !$stream->is_active
'is_active' => ! $stream->is_active,
]);
return $stream->fresh('bucket');
@ -57,8 +57,6 @@ public function bucketBelongsToScenario(Scenario $scenario, ?int $bucketId): boo
->exists();
}
/**
* Get streams grouped by type
*/

View file

@ -14,10 +14,6 @@
/**
* Allocate an inflow amount across scenario buckets according to priority rules.
*
* @param Scenario $scenario
* @param int $amount
* @param Carbon|null $date
* @param string|null $description
* @return Collection<Draw> Collection of Draw models
*/
public function allocateInflow(Scenario $scenario, int $amount, ?Carbon $date = null, ?string $description = null): Collection
@ -54,7 +50,7 @@ public function allocateInflow(Scenario $scenario, int $amount, ?Carbon $date =
'bucket_id' => $bucket->id,
'amount' => $allocation,
'date' => $allocationDate,
'description' => $description ?? "Allocation from inflow",
'description' => $description ?? 'Allocation from inflow',
'is_projected' => true,
]);
@ -69,10 +65,6 @@ public function allocateInflow(Scenario $scenario, int $amount, ?Carbon $date =
/**
* Calculate how much should be allocated to a specific bucket.
*
* @param Bucket $bucket
* @param int $remainingAmount
* @return int
*/
private function calculateBucketAllocation(Bucket $bucket, int $remainingAmount): int
{
@ -86,14 +78,10 @@ private function calculateBucketAllocation(Bucket $bucket, int $remainingAmount)
/**
* Calculate allocation for fixed limit buckets.
*
* @param Bucket $bucket
* @param int $remainingAmount
* @return int
*/
private function calculateFixedAllocation(Bucket $bucket, int $remainingAmount): int
{
$bucketCapacity = (int)($bucket->allocation_value ?? 0);
$bucketCapacity = (int) ($bucket->allocation_value ?? 0);
$currentBalance = $bucket->getCurrentBalance();
$availableSpace = max(0, $bucketCapacity - $currentBalance);
@ -102,14 +90,11 @@ private function calculateFixedAllocation(Bucket $bucket, int $remainingAmount):
/**
* Calculate allocation for percentage buckets.
*
* @param Bucket $bucket
* @param int $remainingAmount
* @return int
*/
private function calculatePercentageAllocation(Bucket $bucket, int $remainingAmount): int
{
$percentage = $bucket->allocation_value ?? 0;
return (int)round($remainingAmount * ($percentage / 100));
return (int) round($remainingAmount * ($percentage / 100));
}
}

View file

@ -15,11 +15,11 @@ public function getSummaryStats(Scenario $scenario): array
$totalMonthlyIncome = $streams
->where('type', StreamTypeEnum::INCOME)
->sum(fn($stream) => $stream->getMonthlyEquivalent());
->sum(fn ($stream) => $stream->getMonthlyEquivalent());
$totalMonthlyExpenses = $streams
->where('type', StreamTypeEnum::EXPENSE)
->sum(fn($stream) => $stream->getMonthlyEquivalent());
->sum(fn ($stream) => $stream->getMonthlyEquivalent());
return [
'total_streams' => $streams->count(),

View file

@ -50,7 +50,7 @@ public function definition(): array
public function fixedLimit($amount = null): Factory
{
$amount = $amount ?? $this->faker->numberBetween(500, 5000);
return $this->state([
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => $amount,
@ -63,7 +63,7 @@ public function fixedLimit($amount = null): Factory
public function percentage($percentage = null): Factory
{
$percentage = $percentage ?? $this->faker->numberBetween(10, 50);
return $this->state([
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
'allocation_value' => $percentage,
@ -119,10 +119,10 @@ public function defaultSet(): array
*/
private function getAllocationValueForType(BucketAllocationTypeEnum $type): ?float
{
return match($type) {
return match ($type) {
BucketAllocationTypeEnum::FIXED_LIMIT => $this->faker->numberBetween(100, 10000),
BucketAllocationTypeEnum::PERCENTAGE => $this->faker->numberBetween(5, 50),
BucketAllocationTypeEnum::UNLIMITED => null,
};
}
}
}

View file

@ -13,7 +13,7 @@ class ScenarioFactory extends Factory
public function definition(): array
{
return [
'name' => $this->faker->words(2, true) . ' Budget',
'name' => $this->faker->words(2, true).' Budget',
'description' => $this->faker->text,
];
}

View file

@ -6,7 +6,6 @@
use App\Http\Controllers\StreamController;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use Laravel\Fortify\Features;
// Scenario routes (no auth required for MVP)
Route::get('/', [ScenarioController::class, 'index'])->name('scenarios.index');

View file

@ -26,7 +26,7 @@ public function test_two_factor_challenge_redirects_to_login_when_not_authentica
public function test_two_factor_challenge_can_be_rendered(): void
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
if (! Features::canManageTwoFactorAuthentication()) {
$this->markTestSkipped('Two-factor authentication is not enabled.');
}

View file

@ -15,7 +15,7 @@ class VerificationNotificationTest extends TestCase
public function test_sends_verification_notification(): void
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
Notification::fake();
$user = User::factory()->create([
@ -32,7 +32,7 @@ public function test_sends_verification_notification(): void
public function test_does_not_send_verification_notification_if_email_is_verified(): void
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
Notification::fake();
$user = User::factory()->create([

View file

@ -25,7 +25,7 @@ public function test_password_update_page_is_displayed()
public function test_password_can_be_updated()
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
$user = User::factory()->create();
$response = $this
@ -47,7 +47,7 @@ public function test_password_can_be_updated()
public function test_correct_password_must_be_provided_to_update_password()
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
$user = User::factory()->create();
$response = $this

View file

@ -24,7 +24,7 @@ public function test_profile_page_is_displayed()
public function test_profile_information_can_be_updated()
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
$user = User::factory()->create();
$response = $this
@ -48,7 +48,7 @@ public function test_profile_information_can_be_updated()
public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged()
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
$user = User::factory()->create();
$response = $this
@ -68,7 +68,7 @@ public function test_email_verification_status_is_unchanged_when_the_email_addre
public function test_user_can_delete_their_account()
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
$user = User::factory()->create();
$response = $this
@ -88,7 +88,7 @@ public function test_user_can_delete_their_account()
public function test_correct_password_must_be_provided_to_delete_account()
{
$this->markTestSkipped('Auth routes not integrated with scenario pages');
$user = User::factory()->create();
$response = $this

View file

@ -15,12 +15,13 @@ class CreateBucketActionTest extends TestCase
use RefreshDatabase;
private CreateBucketAction $action;
private Scenario $scenario;
protected function setUp(): void
{
parent::setUp();
$this->action = new CreateBucketAction();
$this->action = new CreateBucketAction;
$this->scenario = Scenario::factory()->create();
}
@ -135,7 +136,6 @@ public function test_existing_priorities_are_shifted_when_inserting(): void
$this->assertEquals(4, $bucket3->priority); // Shifted from 3 to 4
}
public function test_throws_exception_for_fixed_limit_without_allocation_value(): void
{
$this->expectException(InvalidArgumentException::class);
@ -255,4 +255,4 @@ public function test_creates_buckets_in_database_transaction(): void
$this->assertEquals('Bucket 2', $buckets[0]->name); // New bucket at priority 1
$this->assertEquals('Bucket 1', $buckets[1]->name); // Original bucket shifted to priority 2
}
}
}

View file

@ -14,12 +14,13 @@ class PipelineAllocationServiceTest extends TestCase
use RefreshDatabase;
private PipelineAllocationService $service;
private Scenario $scenario;
protected function setUp(): void
{
parent::setUp();
$this->service = new PipelineAllocationService();
$this->service = new PipelineAllocationService;
$this->scenario = Scenario::factory()->create();
}
@ -32,7 +33,7 @@ public function test_allocates_to_single_fixed_bucket()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 50000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
// Act: Allocate $300
@ -52,21 +53,21 @@ public function test_allocates_across_multiple_fixed_buckets_by_priority()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 20000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
$bucket2 = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 30000,
'starting_amount' => 0,
'priority' => 2
'priority' => 2,
]);
$bucket3 = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 15000,
'starting_amount' => 0,
'priority' => 3
'priority' => 3,
]);
// Act: Allocate $550 (should fill bucket1 + bucket2 + partial bucket3)
@ -96,14 +97,14 @@ public function test_percentage_bucket_gets_percentage_of_remaining_amount()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 30000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
$percentageBucket = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
'allocation_value' => 20.00, // 20%
'starting_amount' => 0,
'priority' => 2
'priority' => 2,
]);
// Act: Allocate $1000
@ -123,14 +124,14 @@ public function test_unlimited_bucket_gets_all_remaining_amount()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 50000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
$unlimitedBucket = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::UNLIMITED,
'allocation_value' => null,
'starting_amount' => 0,
'priority' => 2
'priority' => 2,
]);
// Act: Allocate $1500
@ -150,14 +151,14 @@ public function test_skips_buckets_with_zero_allocation()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 0, // No capacity
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
$normalBucket = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 30000,
'starting_amount' => 0,
'priority' => 2
'priority' => 2,
]);
// Act: Allocate $200
@ -177,35 +178,35 @@ public function test_handles_complex_mixed_bucket_scenario()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 100000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
$percentage1 = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
'allocation_value' => 15.00, // 15%
'starting_amount' => 0,
'priority' => 2
'priority' => 2,
]);
$fixed2 = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 50000,
'starting_amount' => 0,
'priority' => 3
'priority' => 3,
]);
$percentage2 = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
'allocation_value' => 25.00, // 25%
'starting_amount' => 0,
'priority' => 4
'priority' => 4,
]);
$unlimited = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::UNLIMITED,
'allocation_value' => null,
'starting_amount' => 0,
'priority' => 5
'priority' => 5,
]);
// Act: Allocate $5000
@ -248,7 +249,7 @@ public function test_returns_empty_array_when_amount_is_zero()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 50000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
// Act: Allocate $0
@ -266,7 +267,7 @@ public function test_handles_negative_amount_gracefully()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 50000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
// Act: Allocate negative amount
@ -284,21 +285,21 @@ public function test_respects_bucket_priority_order()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 10000,
'starting_amount' => 0,
'priority' => 10 // Higher number
'priority' => 10, // Higher number
]);
$bucket1 = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 20000,
'starting_amount' => 0,
'priority' => 1 // Lower number (higher priority)
'priority' => 1, // Lower number (higher priority)
]);
$bucket2 = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 15000,
'starting_amount' => 0,
'priority' => 5 // Middle
'priority' => 5, // Middle
]);
// Act: Allocate $250
@ -320,14 +321,14 @@ public function test_percentage_allocation_with_insufficient_remaining_amount()
'allocation_type' => BucketAllocationTypeEnum::FIXED_LIMIT,
'allocation_value' => 95000,
'starting_amount' => 0,
'priority' => 1
'priority' => 1,
]);
$percentageBucket = Bucket::factory()->create([
'scenario_id' => $this->scenario->id,
'allocation_type' => BucketAllocationTypeEnum::PERCENTAGE,
'allocation_value' => 20.00, // 20%
'starting_amount' => 0,
'priority' => 2
'priority' => 2,
]);
// Act: Allocate $1000 (only $50 left after fixed)

View file

@ -19,12 +19,13 @@ class ProjectionGeneratorServiceTest extends TestCase
use RefreshDatabase;
private ProjectionGeneratorService $service;
private Scenario $scenario;
protected function setUp(): void
{
parent::setUp();
$this->service = new ProjectionGeneratorService(new PipelineAllocationService());
$this->service = new ProjectionGeneratorService(new PipelineAllocationService);
$this->scenario = Scenario::factory()->create();
// Set a fixed "now" for consistent testing