Extract allocation type to enum
This commit is contained in:
parent
e23ee84ce8
commit
a07461e5a3
5 changed files with 135 additions and 94 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Actions;
|
namespace App\Actions;
|
||||||
|
|
||||||
|
use App\Enums\BucketAllocationType;
|
||||||
use App\Models\Bucket;
|
use App\Models\Bucket;
|
||||||
use App\Models\Scenario;
|
use App\Models\Scenario;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
@ -12,21 +13,15 @@ class CreateBucketAction
|
||||||
public function execute(
|
public function execute(
|
||||||
Scenario $scenario,
|
Scenario $scenario,
|
||||||
string $name,
|
string $name,
|
||||||
string $allocationType,
|
BucketAllocationType $allocationType,
|
||||||
?float $allocationValue = null,
|
?float $allocationValue = null,
|
||||||
?int $priority = null
|
?int $priority = null
|
||||||
): Bucket {
|
): Bucket {
|
||||||
// Validate allocation type
|
|
||||||
$validTypes = [Bucket::TYPE_FIXED_LIMIT, Bucket::TYPE_PERCENTAGE, Bucket::TYPE_UNLIMITED];
|
|
||||||
if (!in_array($allocationType, $validTypes)) {
|
|
||||||
throw new InvalidArgumentException("Invalid allocation type: {$allocationType}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate allocation value based on type
|
// Validate allocation value based on type
|
||||||
$this->validateAllocationValue($allocationType, $allocationValue);
|
$this->validateAllocationValue($allocationType, $allocationValue);
|
||||||
|
|
||||||
// Set allocation_value to null for unlimited buckets
|
// Set allocation_value to null for unlimited buckets
|
||||||
if ($allocationType === Bucket::TYPE_UNLIMITED) {
|
if ($allocationType === BucketAllocationType::UNLIMITED) {
|
||||||
$allocationValue = null;
|
$allocationValue = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,10 +61,10 @@ public function execute(
|
||||||
/**
|
/**
|
||||||
* Validate allocation value based on allocation type.
|
* Validate allocation value based on allocation type.
|
||||||
*/
|
*/
|
||||||
private function validateAllocationValue(string $allocationType, ?float $allocationValue): void
|
private function validateAllocationValue(BucketAllocationType $allocationType, ?float $allocationValue): void
|
||||||
{
|
{
|
||||||
switch ($allocationType) {
|
switch ($allocationType) {
|
||||||
case Bucket::TYPE_FIXED_LIMIT:
|
case BucketAllocationType::FIXED_LIMIT:
|
||||||
if ($allocationValue === null) {
|
if ($allocationValue === null) {
|
||||||
throw new InvalidArgumentException('Fixed limit buckets require an allocation value');
|
throw new InvalidArgumentException('Fixed limit buckets require an allocation value');
|
||||||
}
|
}
|
||||||
|
|
@ -78,7 +73,7 @@ private function validateAllocationValue(string $allocationType, ?float $allocat
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Bucket::TYPE_PERCENTAGE:
|
case BucketAllocationType::PERCENTAGE:
|
||||||
if ($allocationValue === null) {
|
if ($allocationValue === null) {
|
||||||
throw new InvalidArgumentException('Percentage buckets require an allocation value');
|
throw new InvalidArgumentException('Percentage buckets require an allocation value');
|
||||||
}
|
}
|
||||||
|
|
@ -87,10 +82,47 @@ private function validateAllocationValue(string $allocationType, ?float $allocat
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Bucket::TYPE_UNLIMITED:
|
case BucketAllocationType::UNLIMITED:
|
||||||
// Unlimited buckets should not have an allocation value
|
// Unlimited buckets should not have an allocation value
|
||||||
// We'll set it to null in the main method regardless
|
// We'll set it to null in the main method regardless
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create default buckets for a scenario.
|
||||||
|
*/
|
||||||
|
public function createDefaultBuckets(Scenario $scenario): array
|
||||||
|
{
|
||||||
|
$buckets = [];
|
||||||
|
|
||||||
|
// Monthly Expenses - Fixed limit, priority 1
|
||||||
|
$buckets[] = $this->execute(
|
||||||
|
$scenario,
|
||||||
|
'Monthly Expenses',
|
||||||
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
// Emergency Fund - Fixed limit, priority 2
|
||||||
|
$buckets[] = $this->execute(
|
||||||
|
$scenario,
|
||||||
|
'Emergency Fund',
|
||||||
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
|
// Investments - Unlimited, priority 3
|
||||||
|
$buckets[] = $this->execute(
|
||||||
|
$scenario,
|
||||||
|
'Investments',
|
||||||
|
BucketAllocationType::UNLIMITED,
|
||||||
|
null,
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
return $buckets;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
42
app/Enums/BucketAllocationType.php
Normal file
42
app/Enums/BucketAllocationType.php
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum BucketAllocationType: string
|
||||||
|
{
|
||||||
|
case FIXED_LIMIT = 'fixed_limit';
|
||||||
|
case PERCENTAGE = 'percentage';
|
||||||
|
case UNLIMITED = 'unlimited';
|
||||||
|
|
||||||
|
public function getLabel(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::FIXED_LIMIT => 'Fixed Limit',
|
||||||
|
self::PERCENTAGE => 'Percentage',
|
||||||
|
self::UNLIMITED => 'Unlimited',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function values(): array
|
||||||
|
{
|
||||||
|
return array_column(self::cases(), 'value');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllocationValueRules(): array
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::FIXED_LIMIT => ['required', 'numeric', 'min:0'],
|
||||||
|
self::PERCENTAGE => ['required', 'numeric', 'min:0.01', 'max:100'],
|
||||||
|
self::UNLIMITED => ['nullable'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function formatValue(?float $value): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::FIXED_LIMIT => '$' . number_format($value ?? 0, 2),
|
||||||
|
self::PERCENTAGE => number_format($value ?? 0, 2) . '%',
|
||||||
|
self::UNLIMITED => 'All remaining',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\BucketAllocationType;
|
||||||
use Database\Factories\BucketFactory;
|
use Database\Factories\BucketFactory;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
@ -34,11 +35,6 @@ class Bucket extends Model
|
||||||
'allocation_value' => 'decimal:2',
|
'allocation_value' => 'decimal:2',
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO Extract to Enum
|
|
||||||
const string TYPE_FIXED_LIMIT = 'fixed_limit';
|
|
||||||
const string TYPE_PERCENTAGE = 'percentage';
|
|
||||||
const string TYPE_UNLIMITED = 'unlimited';
|
|
||||||
|
|
||||||
public function scenario(): BelongsTo
|
public function scenario(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Scenario::class);
|
return $this->belongsTo(Scenario::class);
|
||||||
|
|
@ -95,7 +91,7 @@ public function getCurrentBalance(): float
|
||||||
*/
|
*/
|
||||||
public function hasAvailableSpace(): bool
|
public function hasAvailableSpace(): bool
|
||||||
{
|
{
|
||||||
if ($this->allocation_type !== self::TYPE_FIXED_LIMIT) {
|
if ($this->allocation_type !== BucketAllocationType::FIXED_LIMIT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +103,7 @@ public function hasAvailableSpace(): bool
|
||||||
*/
|
*/
|
||||||
public function getAvailableSpace(): float
|
public function getAvailableSpace(): float
|
||||||
{
|
{
|
||||||
if ($this->allocation_type !== self::TYPE_FIXED_LIMIT) {
|
if ($this->allocation_type !== BucketAllocationType::FIXED_LIMIT) {
|
||||||
return PHP_FLOAT_MAX;
|
return PHP_FLOAT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,12 +115,7 @@ public function getAvailableSpace(): float
|
||||||
*/
|
*/
|
||||||
public function getAllocationTypeLabel(): string
|
public function getAllocationTypeLabel(): string
|
||||||
{
|
{
|
||||||
return match($this->allocation_type) {
|
return $this->allocation_type->getLabel();
|
||||||
self::TYPE_FIXED_LIMIT => 'Fixed Limit',
|
|
||||||
self::TYPE_PERCENTAGE => 'Percentage',
|
|
||||||
self::TYPE_UNLIMITED => 'Unlimited',
|
|
||||||
default => 'Unknown',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -132,12 +123,7 @@ public function getAllocationTypeLabel(): string
|
||||||
*/
|
*/
|
||||||
public function getFormattedAllocationValue(): string
|
public function getFormattedAllocationValue(): string
|
||||||
{
|
{
|
||||||
return match($this->allocation_type) {
|
return $this->allocation_type->formatValue($this->allocation_value);
|
||||||
self::TYPE_FIXED_LIMIT => '$' . number_format($this->allocation_value, 2),
|
|
||||||
self::TYPE_PERCENTAGE => number_format($this->allocation_value, 2) . '%',
|
|
||||||
self::TYPE_UNLIMITED => 'All remaining',
|
|
||||||
default => '-',
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,11 +133,7 @@ public static function validationRules($scenarioId = null): array
|
||||||
{
|
{
|
||||||
$rules = [
|
$rules = [
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'allocation_type' => 'required|in:' . implode(',', [
|
'allocation_type' => 'required|in:' . implode(',', BucketAllocationType::values()),
|
||||||
self::TYPE_FIXED_LIMIT,
|
|
||||||
self::TYPE_PERCENTAGE,
|
|
||||||
self::TYPE_UNLIMITED,
|
|
||||||
]),
|
|
||||||
'priority' => 'required|integer|min:1',
|
'priority' => 'required|integer|min:1',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -166,13 +148,8 @@ public static function validationRules($scenarioId = null): array
|
||||||
/**
|
/**
|
||||||
* Get allocation value validation rules based on type.
|
* Get allocation value validation rules based on type.
|
||||||
*/
|
*/
|
||||||
public static function allocationValueRules($allocationType): array
|
public static function allocationValueRules(BucketAllocationType $allocationType): array
|
||||||
{
|
{
|
||||||
return match($allocationType) {
|
return $allocationType->getAllocationValueRules();
|
||||||
self::TYPE_FIXED_LIMIT => ['required', 'numeric', 'min:0'],
|
|
||||||
self::TYPE_PERCENTAGE => ['required', 'numeric', 'min:0.01', 'max:100'],
|
|
||||||
self::TYPE_UNLIMITED => ['nullable'],
|
|
||||||
default => ['nullable'],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Enums\BucketAllocationType;
|
||||||
use App\Models\Bucket;
|
use App\Models\Bucket;
|
||||||
use App\Models\Scenario;
|
use App\Models\Scenario;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
@ -14,9 +15,9 @@ class BucketFactory extends Factory
|
||||||
public function definition(): array
|
public function definition(): array
|
||||||
{
|
{
|
||||||
$allocationType = $this->faker->randomElement([
|
$allocationType = $this->faker->randomElement([
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
Bucket::TYPE_PERCENTAGE,
|
BucketAllocationType::PERCENTAGE,
|
||||||
Bucket::TYPE_UNLIMITED,
|
BucketAllocationType::UNLIMITED,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
@ -50,7 +51,7 @@ public function fixedLimit($amount = null): Factory
|
||||||
$amount = $amount ?? $this->faker->numberBetween(500, 5000);
|
$amount = $amount ?? $this->faker->numberBetween(500, 5000);
|
||||||
|
|
||||||
return $this->state([
|
return $this->state([
|
||||||
'allocation_type' => Bucket::TYPE_FIXED_LIMIT,
|
'allocation_type' => BucketAllocationType::FIXED_LIMIT,
|
||||||
'allocation_value' => $amount,
|
'allocation_value' => $amount,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +64,7 @@ public function percentage($percentage = null): Factory
|
||||||
$percentage = $percentage ?? $this->faker->numberBetween(10, 50);
|
$percentage = $percentage ?? $this->faker->numberBetween(10, 50);
|
||||||
|
|
||||||
return $this->state([
|
return $this->state([
|
||||||
'allocation_type' => Bucket::TYPE_PERCENTAGE,
|
'allocation_type' => BucketAllocationType::PERCENTAGE,
|
||||||
'allocation_value' => $percentage,
|
'allocation_value' => $percentage,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +75,7 @@ public function percentage($percentage = null): Factory
|
||||||
public function unlimited(): Factory
|
public function unlimited(): Factory
|
||||||
{
|
{
|
||||||
return $this->state([
|
return $this->state([
|
||||||
'allocation_type' => Bucket::TYPE_UNLIMITED,
|
'allocation_type' => BucketAllocationType::UNLIMITED,
|
||||||
'allocation_value' => null,
|
'allocation_value' => null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
@ -89,21 +90,21 @@ public function defaultSet(): array
|
||||||
'name' => 'Monthly Expenses',
|
'name' => 'Monthly Expenses',
|
||||||
'priority' => 1,
|
'priority' => 1,
|
||||||
'sort_order' => 1,
|
'sort_order' => 1,
|
||||||
'allocation_type' => Bucket::TYPE_FIXED_LIMIT,
|
'allocation_type' => BucketAllocationType::FIXED_LIMIT,
|
||||||
'allocation_value' => 0,
|
'allocation_value' => 0,
|
||||||
]),
|
]),
|
||||||
$this->state([
|
$this->state([
|
||||||
'name' => 'Emergency Fund',
|
'name' => 'Emergency Fund',
|
||||||
'priority' => 2,
|
'priority' => 2,
|
||||||
'sort_order' => 2,
|
'sort_order' => 2,
|
||||||
'allocation_type' => Bucket::TYPE_FIXED_LIMIT,
|
'allocation_type' => BucketAllocationType::FIXED_LIMIT,
|
||||||
'allocation_value' => 0,
|
'allocation_value' => 0,
|
||||||
]),
|
]),
|
||||||
$this->state([
|
$this->state([
|
||||||
'name' => 'Investments',
|
'name' => 'Investments',
|
||||||
'priority' => 3,
|
'priority' => 3,
|
||||||
'sort_order' => 3,
|
'sort_order' => 3,
|
||||||
'allocation_type' => Bucket::TYPE_UNLIMITED,
|
'allocation_type' => BucketAllocationType::UNLIMITED,
|
||||||
'allocation_value' => null,
|
'allocation_value' => null,
|
||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
|
|
@ -112,12 +113,12 @@ public function defaultSet(): array
|
||||||
/**
|
/**
|
||||||
* Get allocation value based on type.
|
* Get allocation value based on type.
|
||||||
*/
|
*/
|
||||||
private function getAllocationValueForType(string $type): ?float
|
private function getAllocationValueForType(BucketAllocationType $type): ?float
|
||||||
{
|
{
|
||||||
return match($type) {
|
return match($type) {
|
||||||
Bucket::TYPE_FIXED_LIMIT => $this->faker->numberBetween(100, 10000),
|
BucketAllocationType::FIXED_LIMIT => $this->faker->numberBetween(100, 10000),
|
||||||
Bucket::TYPE_PERCENTAGE => $this->faker->numberBetween(5, 50),
|
BucketAllocationType::PERCENTAGE => $this->faker->numberBetween(5, 50),
|
||||||
Bucket::TYPE_UNLIMITED => null,
|
BucketAllocationType::UNLIMITED => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Tests\Unit\Actions;
|
namespace Tests\Unit\Actions;
|
||||||
|
|
||||||
use App\Actions\CreateBucketAction;
|
use App\Actions\CreateBucketAction;
|
||||||
|
use App\Enums\BucketAllocationType;
|
||||||
use App\Models\Bucket;
|
use App\Models\Bucket;
|
||||||
use App\Models\Scenario;
|
use App\Models\Scenario;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
|
@ -28,13 +29,13 @@ public function test_can_create_fixed_limit_bucket(): void
|
||||||
$bucket = $this->action->execute(
|
$bucket = $this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Test Bucket',
|
'Test Bucket',
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
1000.00
|
1000.00
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertInstanceOf(Bucket::class, $bucket);
|
$this->assertInstanceOf(Bucket::class, $bucket);
|
||||||
$this->assertEquals('Test Bucket', $bucket->name);
|
$this->assertEquals('Test Bucket', $bucket->name);
|
||||||
$this->assertEquals(Bucket::TYPE_FIXED_LIMIT, $bucket->allocation_type);
|
$this->assertEquals(BucketAllocationType::FIXED_LIMIT, $bucket->allocation_type);
|
||||||
$this->assertEquals(1000.00, $bucket->allocation_value);
|
$this->assertEquals(1000.00, $bucket->allocation_value);
|
||||||
$this->assertEquals(1, $bucket->priority);
|
$this->assertEquals(1, $bucket->priority);
|
||||||
$this->assertEquals(1, $bucket->sort_order);
|
$this->assertEquals(1, $bucket->sort_order);
|
||||||
|
|
@ -46,11 +47,11 @@ public function test_can_create_percentage_bucket(): void
|
||||||
$bucket = $this->action->execute(
|
$bucket = $this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Percentage Bucket',
|
'Percentage Bucket',
|
||||||
Bucket::TYPE_PERCENTAGE,
|
BucketAllocationType::PERCENTAGE,
|
||||||
25.5
|
25.5
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(Bucket::TYPE_PERCENTAGE, $bucket->allocation_type);
|
$this->assertEquals(BucketAllocationType::PERCENTAGE, $bucket->allocation_type);
|
||||||
$this->assertEquals(25.5, $bucket->allocation_value);
|
$this->assertEquals(25.5, $bucket->allocation_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,10 +60,10 @@ public function test_can_create_unlimited_bucket(): void
|
||||||
$bucket = $this->action->execute(
|
$bucket = $this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Unlimited Bucket',
|
'Unlimited Bucket',
|
||||||
Bucket::TYPE_UNLIMITED
|
BucketAllocationType::UNLIMITED
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(Bucket::TYPE_UNLIMITED, $bucket->allocation_type);
|
$this->assertEquals(BucketAllocationType::UNLIMITED, $bucket->allocation_type);
|
||||||
$this->assertNull($bucket->allocation_value);
|
$this->assertNull($bucket->allocation_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,11 +72,11 @@ public function test_unlimited_bucket_ignores_allocation_value(): void
|
||||||
$bucket = $this->action->execute(
|
$bucket = $this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Unlimited Bucket',
|
'Unlimited Bucket',
|
||||||
Bucket::TYPE_UNLIMITED,
|
BucketAllocationType::UNLIMITED,
|
||||||
999.99 // This should be ignored and set to null
|
999.99 // This should be ignored and set to null
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(Bucket::TYPE_UNLIMITED, $bucket->allocation_type);
|
$this->assertEquals(BucketAllocationType::UNLIMITED, $bucket->allocation_type);
|
||||||
$this->assertNull($bucket->allocation_value);
|
$this->assertNull($bucket->allocation_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,14 +85,14 @@ public function test_priority_auto_increments_when_not_specified(): void
|
||||||
$bucket1 = $this->action->execute(
|
$bucket1 = $this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'First Bucket',
|
'First Bucket',
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
100
|
100
|
||||||
);
|
);
|
||||||
|
|
||||||
$bucket2 = $this->action->execute(
|
$bucket2 = $this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Second Bucket',
|
'Second Bucket',
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
200
|
200
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -104,7 +105,7 @@ public function test_can_specify_custom_priority(): void
|
||||||
$bucket = $this->action->execute(
|
$bucket = $this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Priority Bucket',
|
'Priority Bucket',
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
100,
|
100,
|
||||||
5
|
5
|
||||||
);
|
);
|
||||||
|
|
@ -115,12 +116,12 @@ public function test_can_specify_custom_priority(): void
|
||||||
public function test_existing_priorities_are_shifted_when_inserting(): void
|
public function test_existing_priorities_are_shifted_when_inserting(): void
|
||||||
{
|
{
|
||||||
// Create initial buckets
|
// Create initial buckets
|
||||||
$bucket1 = $this->action->execute($this->scenario, 'Bucket 1', Bucket::TYPE_FIXED_LIMIT, 100, 1);
|
$bucket1 = $this->action->execute($this->scenario, 'Bucket 1', BucketAllocationType::FIXED_LIMIT, 100, 1);
|
||||||
$bucket2 = $this->action->execute($this->scenario, 'Bucket 2', Bucket::TYPE_FIXED_LIMIT, 200, 2);
|
$bucket2 = $this->action->execute($this->scenario, 'Bucket 2', BucketAllocationType::FIXED_LIMIT, 200, 2);
|
||||||
$bucket3 = $this->action->execute($this->scenario, 'Bucket 3', Bucket::TYPE_FIXED_LIMIT, 300, 3);
|
$bucket3 = $this->action->execute($this->scenario, 'Bucket 3', BucketAllocationType::FIXED_LIMIT, 300, 3);
|
||||||
|
|
||||||
// Insert a bucket at priority 2
|
// Insert a bucket at priority 2
|
||||||
$newBucket = $this->action->execute($this->scenario, 'New Bucket', Bucket::TYPE_FIXED_LIMIT, 150, 2);
|
$newBucket = $this->action->execute($this->scenario, 'New Bucket', BucketAllocationType::FIXED_LIMIT, 150, 2);
|
||||||
|
|
||||||
// Refresh models from database
|
// Refresh models from database
|
||||||
$bucket1->refresh();
|
$bucket1->refresh();
|
||||||
|
|
@ -134,18 +135,6 @@ public function test_existing_priorities_are_shifted_when_inserting(): void
|
||||||
$this->assertEquals(4, $bucket3->priority); // Shifted from 3 to 4
|
$this->assertEquals(4, $bucket3->priority); // Shifted from 3 to 4
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_throws_exception_for_invalid_allocation_type(): void
|
|
||||||
{
|
|
||||||
$this->expectException(InvalidArgumentException::class);
|
|
||||||
$this->expectExceptionMessage('Invalid allocation type: invalid_type');
|
|
||||||
|
|
||||||
$this->action->execute(
|
|
||||||
$this->scenario,
|
|
||||||
'Test Bucket',
|
|
||||||
'invalid_type',
|
|
||||||
100
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function test_throws_exception_for_fixed_limit_without_allocation_value(): void
|
public function test_throws_exception_for_fixed_limit_without_allocation_value(): void
|
||||||
{
|
{
|
||||||
|
|
@ -155,7 +144,7 @@ public function test_throws_exception_for_fixed_limit_without_allocation_value()
|
||||||
$this->action->execute(
|
$this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Test Bucket',
|
'Test Bucket',
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +157,7 @@ public function test_throws_exception_for_negative_fixed_limit_value(): void
|
||||||
$this->action->execute(
|
$this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Test Bucket',
|
'Test Bucket',
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
-100
|
-100
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +170,7 @@ public function test_throws_exception_for_percentage_without_allocation_value():
|
||||||
$this->action->execute(
|
$this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Test Bucket',
|
'Test Bucket',
|
||||||
Bucket::TYPE_PERCENTAGE,
|
BucketAllocationType::PERCENTAGE,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +183,7 @@ public function test_throws_exception_for_percentage_below_minimum(): void
|
||||||
$this->action->execute(
|
$this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Test Bucket',
|
'Test Bucket',
|
||||||
Bucket::TYPE_PERCENTAGE,
|
BucketAllocationType::PERCENTAGE,
|
||||||
0.005
|
0.005
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +196,7 @@ public function test_throws_exception_for_percentage_above_maximum(): void
|
||||||
$this->action->execute(
|
$this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Test Bucket',
|
'Test Bucket',
|
||||||
Bucket::TYPE_PERCENTAGE,
|
BucketAllocationType::PERCENTAGE,
|
||||||
101
|
101
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +209,7 @@ public function test_throws_exception_for_negative_priority(): void
|
||||||
$this->action->execute(
|
$this->action->execute(
|
||||||
$this->scenario,
|
$this->scenario,
|
||||||
'Test Bucket',
|
'Test Bucket',
|
||||||
Bucket::TYPE_FIXED_LIMIT,
|
BucketAllocationType::FIXED_LIMIT,
|
||||||
100,
|
100,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
@ -237,19 +226,19 @@ public function test_create_default_buckets(): void
|
||||||
// Monthly Expenses
|
// Monthly Expenses
|
||||||
$this->assertEquals('Monthly Expenses', $buckets[0]->name);
|
$this->assertEquals('Monthly Expenses', $buckets[0]->name);
|
||||||
$this->assertEquals(1, $buckets[0]->priority);
|
$this->assertEquals(1, $buckets[0]->priority);
|
||||||
$this->assertEquals(Bucket::TYPE_FIXED_LIMIT, $buckets[0]->allocation_type);
|
$this->assertEquals(BucketAllocationType::FIXED_LIMIT, $buckets[0]->allocation_type);
|
||||||
$this->assertEquals(0, $buckets[0]->allocation_value);
|
$this->assertEquals(0, $buckets[0]->allocation_value);
|
||||||
|
|
||||||
// Emergency Fund
|
// Emergency Fund
|
||||||
$this->assertEquals('Emergency Fund', $buckets[1]->name);
|
$this->assertEquals('Emergency Fund', $buckets[1]->name);
|
||||||
$this->assertEquals(2, $buckets[1]->priority);
|
$this->assertEquals(2, $buckets[1]->priority);
|
||||||
$this->assertEquals(Bucket::TYPE_FIXED_LIMIT, $buckets[1]->allocation_type);
|
$this->assertEquals(BucketAllocationType::FIXED_LIMIT, $buckets[1]->allocation_type);
|
||||||
$this->assertEquals(0, $buckets[1]->allocation_value);
|
$this->assertEquals(0, $buckets[1]->allocation_value);
|
||||||
|
|
||||||
// Investments
|
// Investments
|
||||||
$this->assertEquals('Investments', $buckets[2]->name);
|
$this->assertEquals('Investments', $buckets[2]->name);
|
||||||
$this->assertEquals(3, $buckets[2]->priority);
|
$this->assertEquals(3, $buckets[2]->priority);
|
||||||
$this->assertEquals(Bucket::TYPE_UNLIMITED, $buckets[2]->allocation_type);
|
$this->assertEquals(BucketAllocationType::UNLIMITED, $buckets[2]->allocation_type);
|
||||||
$this->assertNull($buckets[2]->allocation_value);
|
$this->assertNull($buckets[2]->allocation_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,8 +246,8 @@ public function test_creates_buckets_in_database_transaction(): void
|
||||||
{
|
{
|
||||||
// This test ensures database consistency by creating multiple buckets
|
// This test ensures database consistency by creating multiple buckets
|
||||||
// and verifying they all exist with correct priorities
|
// and verifying they all exist with correct priorities
|
||||||
$this->action->execute($this->scenario, 'Bucket 1', Bucket::TYPE_FIXED_LIMIT, 100, 1);
|
$this->action->execute($this->scenario, 'Bucket 1', BucketAllocationType::FIXED_LIMIT, 100, 1);
|
||||||
$this->action->execute($this->scenario, 'Bucket 2', Bucket::TYPE_FIXED_LIMIT, 200, 1); // Insert at priority 1
|
$this->action->execute($this->scenario, 'Bucket 2', BucketAllocationType::FIXED_LIMIT, 200, 1); // Insert at priority 1
|
||||||
|
|
||||||
// Both buckets should exist with correct priorities
|
// Both buckets should exist with correct priorities
|
||||||
$buckets = $this->scenario->buckets()->orderBy('priority')->get();
|
$buckets = $this->scenario->buckets()->orderBy('priority')->get();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue