|
@@ -43,11 +43,30 @@ class BudgetResource extends Resource
|
43
|
43
|
Forms\Components\DatePicker::make('end_date')
|
44
|
44
|
->required()
|
45
|
45
|
->default(now()->endOfYear())
|
46
|
|
- ->live(),
|
47
|
|
- Forms\Components\Textarea::make('notes')->columnSpanFull(),
|
|
46
|
+ ->live()
|
|
47
|
+ ->disabled(static fn (Forms\Get $get) => blank($get('start_date')))
|
|
48
|
+ ->minDate(fn (Forms\Get $get) => match (BudgetIntervalType::parse($get('interval_type'))) {
|
|
49
|
+ BudgetIntervalType::Week => Carbon::parse($get('start_date'))->addWeek(),
|
|
50
|
+ BudgetIntervalType::Month => Carbon::parse($get('start_date'))->addMonth(),
|
|
51
|
+ BudgetIntervalType::Quarter => Carbon::parse($get('start_date'))->addQuarter(),
|
|
52
|
+ BudgetIntervalType::Year => Carbon::parse($get('start_date'))->addYear(),
|
|
53
|
+ default => Carbon::parse($get('start_date'))->addDay(),
|
|
54
|
+ })
|
|
55
|
+ ->maxDate(fn (Forms\Get $get) => Carbon::parse($get('start_date'))->endOfYear()),
|
|
56
|
+ Forms\Components\Textarea::make('notes')
|
|
57
|
+ ->columnSpanFull(),
|
48
|
58
|
]),
|
49
|
59
|
|
50
|
60
|
Forms\Components\Section::make('Budget Items')
|
|
61
|
+ ->headerActions([
|
|
62
|
+ Forms\Components\Actions\Action::make('addAllAccounts')
|
|
63
|
+ ->label('Add All Accounts')
|
|
64
|
+ ->icon('heroicon-m-plus')
|
|
65
|
+ ->outlined()
|
|
66
|
+ ->color('primary')
|
|
67
|
+ ->action(static fn (Forms\Set $set, Forms\Get $get) => self::addAllAccounts($set, $get))
|
|
68
|
+ ->hidden(static fn (Forms\Get $get) => filled($get('budgetItems'))),
|
|
69
|
+ ])
|
51
|
70
|
->schema([
|
52
|
71
|
Forms\Components\Repeater::make('budgetItems')
|
53
|
72
|
->columns(4)
|
|
@@ -57,13 +76,13 @@ class BudgetResource extends Resource
|
57
|
76
|
->label('Account')
|
58
|
77
|
->options(Account::query()->pluck('name', 'id'))
|
59
|
78
|
->searchable()
|
|
79
|
+ ->disableOptionsWhenSelectedInSiblingRepeaterItems()
|
60
|
80
|
->columnSpan(1)
|
61
|
81
|
->required(),
|
62
|
82
|
|
63
|
83
|
Forms\Components\TextInput::make('total_amount')
|
64
|
84
|
->label('Total Amount')
|
65
|
85
|
->numeric()
|
66
|
|
- ->required()
|
67
|
86
|
->columnSpan(1)
|
68
|
87
|
->suffixAction(
|
69
|
88
|
Forms\Components\Actions\Action::make('disperse')
|
|
@@ -78,7 +97,7 @@ class BudgetResource extends Resource
|
78
|
97
|
->columns(4)
|
79
|
98
|
->schema(static fn (Forms\Get $get) => self::getAllocationFields($get('../../start_date'), $get('../../end_date'), $get('../../interval_type'))),
|
80
|
99
|
])
|
81
|
|
- ->defaultItems(1)
|
|
100
|
+ ->defaultItems(0)
|
82
|
101
|
->addActionLabel('Add Budget Item'),
|
83
|
102
|
]),
|
84
|
103
|
]);
|
|
@@ -130,9 +149,31 @@ class BudgetResource extends Resource
|
130
|
149
|
]);
|
131
|
150
|
}
|
132
|
151
|
|
133
|
|
- /**
|
134
|
|
- * Disperses the total amount across the budget items based on the selected interval.
|
135
|
|
- */
|
|
152
|
+ private static function addAllAccounts(Forms\Set $set, Forms\Get $get): void
|
|
153
|
+ {
|
|
154
|
+ $accounts = Account::query()
|
|
155
|
+ ->pluck('id');
|
|
156
|
+
|
|
157
|
+ $budgetItems = $accounts->map(static fn ($accountId) => [
|
|
158
|
+ 'account_id' => $accountId,
|
|
159
|
+ 'total_amount' => 0, // Default to 0 until the user inputs amounts
|
|
160
|
+ 'amounts' => self::generateDefaultAllocations($get('start_date'), $get('end_date'), $get('interval_type')),
|
|
161
|
+ ])->toArray();
|
|
162
|
+
|
|
163
|
+ $set('budgetItems', $budgetItems);
|
|
164
|
+ }
|
|
165
|
+
|
|
166
|
+ private static function generateDefaultAllocations(?string $startDate, ?string $endDate, ?string $intervalType): array
|
|
167
|
+ {
|
|
168
|
+ if (! $startDate || ! $endDate || ! $intervalType) {
|
|
169
|
+ return [];
|
|
170
|
+ }
|
|
171
|
+
|
|
172
|
+ $labels = self::generateFormattedLabels($startDate, $endDate, $intervalType);
|
|
173
|
+
|
|
174
|
+ return collect($labels)->mapWithKeys(static fn ($label) => [$label => 0])->toArray();
|
|
175
|
+ }
|
|
176
|
+
|
136
|
177
|
private static function disperseTotalAmount(Forms\Set $set, Forms\Get $get, float $totalAmount): void
|
137
|
178
|
{
|
138
|
179
|
$startDate = $get('../../start_date');
|
|
@@ -143,7 +184,6 @@ class BudgetResource extends Resource
|
143
|
184
|
return;
|
144
|
185
|
}
|
145
|
186
|
|
146
|
|
- // Generate labels based on interval type (must match `getAllocationFields()`)
|
147
|
187
|
$labels = self::generateFormattedLabels($startDate, $endDate, $intervalType);
|
148
|
188
|
$numPeriods = count($labels);
|
149
|
189
|
|
|
@@ -151,20 +191,15 @@ class BudgetResource extends Resource
|
151
|
191
|
return;
|
152
|
192
|
}
|
153
|
193
|
|
154
|
|
- // Calculate base allocation and handle rounding
|
155
|
194
|
$baseAmount = floor($totalAmount / $numPeriods);
|
156
|
195
|
$remainder = $totalAmount - ($baseAmount * $numPeriods);
|
157
|
196
|
|
158
|
|
- // Assign amounts to the correct fields using labels
|
159
|
197
|
foreach ($labels as $index => $label) {
|
160
|
198
|
$amount = $baseAmount + ($index === 0 ? $remainder : 0);
|
161
|
|
- $set("amounts.{$label}", $amount); // Now correctly assigns to the right field
|
|
199
|
+ $set("amounts.{$label}", $amount);
|
162
|
200
|
}
|
163
|
201
|
}
|
164
|
202
|
|
165
|
|
- /**
|
166
|
|
- * Generates formatted labels for the budget allocation fields based on the selected interval type.
|
167
|
|
- */
|
168
|
203
|
private static function generateFormattedLabels(string $startDate, string $endDate, string $intervalType): array
|
169
|
204
|
{
|
170
|
205
|
$start = Carbon::parse($startDate);
|
|
@@ -218,7 +253,6 @@ class BudgetResource extends Resource
|
218
|
253
|
->numeric()
|
219
|
254
|
->required();
|
220
|
255
|
|
221
|
|
- // Move to the next period
|
222
|
256
|
match ($intervalTypeEnum) {
|
223
|
257
|
BudgetIntervalType::Week => $start->addWeek(),
|
224
|
258
|
BudgetIntervalType::Month => $start->addMonth(),
|