Andrew Wallo 6ヶ月前
コミット
01ea270c67

+ 4
- 29
app/Filament/Company/Pages/Accounting/Transactions.php ファイルの表示

@@ -36,7 +36,6 @@ use Filament\Forms\Get;
36 36
 use Filament\Forms\Set;
37 37
 use Filament\Pages\Page;
38 38
 use Filament\Support\Colors\Color;
39
-use Filament\Support\Enums\Alignment;
40 39
 use Filament\Support\Enums\FontWeight;
41 40
 use Filament\Support\Enums\IconPosition;
42 41
 use Filament\Support\Enums\IconSize;
@@ -111,6 +110,9 @@ class Transactions extends Page implements HasTable
111 110
                     ->label('Add journal transaction')
112 111
                     ->fillForm(fn (): array => $this->getFormDefaultsForType(TransactionType::Journal))
113 112
                     ->modalWidth(MaxWidth::Screen)
113
+                    ->extraModalWindowAttributes([
114
+                        'class' => 'journal-transaction-modal',
115
+                    ])
114 116
                     ->model(static::getModel())
115 117
                     ->form(fn (Form $form) => $this->journalTransactionForm($form))
116 118
                     ->modalSubmitAction(fn (Actions\StaticAction $action) => $action->disabled(! $this->isJournalEntryBalanced()))
@@ -343,34 +345,7 @@ class Transactions extends Page implements HasTable
343 345
                 $filters['posted_at'],
344 346
                 $filters['updated_at'],
345 347
             ])
346
-            ->deferFilters()
347
-            ->deferLoading()
348 348
             ->filtersFormWidth(MaxWidth::ThreeExtraLarge)
349
-            ->filtersTriggerAction(
350
-                fn (Tables\Actions\Action $action) => $action
351
-                    ->slideOver()
352
-                    ->modalFooterActionsAlignment(Alignment::End)
353
-                    ->modalCancelAction(false)
354
-                    ->extraModalFooterActions(function (Table $table) use ($action) {
355
-                        return [
356
-                            $table->getFiltersApplyAction()
357
-                                ->close(),
358
-                            Actions\StaticAction::make('cancel')
359
-                                ->label($action->getModalCancelActionLabel())
360
-                                ->button()
361
-                                ->close()
362
-                                ->color('gray'),
363
-                            Tables\Actions\Action::make('resetFilters')
364
-                                ->label(__('Clear all'))
365
-                                ->color('primary')
366
-                                ->link()
367
-                                ->extraAttributes([
368
-                                    'class' => 'me-auto',
369
-                                ])
370
-                                ->action('resetTableFiltersForm'),
371
-                        ];
372
-                    })
373
-            )
374 349
             ->actions([
375 350
                 Tables\Actions\Action::make('markAsReviewed')
376 351
                     ->label('Mark as reviewed')
@@ -623,7 +598,7 @@ class Transactions extends Page implements HasTable
623 598
                 ->label('Type')
624 599
                 ->options(JournalEntryType::class)
625 600
                 ->live()
626
-                ->afterStateUpdated(function (Get $get, Set $set, ?string $state, ?string $old) {
601
+                ->afterStateUpdated(function (Get $get, Set $set, $state, $old) {
627 602
                     $this->adjustJournalEntryAmountsForTypeChange(JournalEntryType::parse($state), JournalEntryType::parse($old), $get('amount'));
628 603
                 })
629 604
                 ->softRequired(),

+ 64
- 0
app/Filament/Company/Resources/Accounting/BudgetResource.php ファイルの表示

@@ -5,11 +5,17 @@ namespace App\Filament\Company\Resources\Accounting;
5 5
 use App\Enums\Accounting\BudgetIntervalType;
6 6
 use App\Filament\Company\Resources\Accounting\BudgetResource\Pages;
7 7
 use App\Filament\Forms\Components\CustomSection;
8
+use App\Filament\Forms\Components\CustomTableRepeater;
8 9
 use App\Models\Accounting\Account;
9 10
 use App\Models\Accounting\Budget;
11
+use App\Models\Accounting\BudgetItem;
12
+use Awcodes\TableRepeater\Header;
10 13
 use Filament\Forms;
11 14
 use Filament\Forms\Form;
12 15
 use Filament\Resources\Resource;
16
+use Filament\Support\Enums\Alignment;
17
+use Filament\Support\Enums\MaxWidth;
18
+use Filament\Support\RawJs;
13 19
 use Filament\Tables;
14 20
 use Filament\Tables\Table;
15 21
 use Illuminate\Support\Carbon;
@@ -232,6 +238,64 @@ class BudgetResource extends Resource
232 238
                 Tables\Actions\ActionGroup::make([
233 239
                     Tables\Actions\ViewAction::make(),
234 240
                     Tables\Actions\EditAction::make(),
241
+                    Tables\Actions\EditAction::make('editAllocations')
242
+                        ->name('editAllocations')
243
+                        ->url(null)
244
+                        ->label('Edit Allocations')
245
+                        ->icon('heroicon-o-table-cells')
246
+                        ->modalWidth(MaxWidth::Screen)
247
+                        ->modalHeading('Edit Budget Allocations')
248
+                        ->modalDescription('Update the allocations for this budget')
249
+                        ->slideOver()
250
+                        ->form(function (Budget $record) {
251
+                            $periods = $record->getPeriods();
252
+
253
+                            $headers = [
254
+                                Header::make('Account')
255
+                                    ->label('Account')
256
+                                    ->width('200px'),
257
+                            ];
258
+
259
+                            foreach ($periods as $period) {
260
+                                $headers[] = Header::make($period)
261
+                                    ->label($period)
262
+                                    ->width('120px')
263
+                                    ->align(Alignment::Right);
264
+                            }
265
+
266
+                            return [
267
+                                CustomTableRepeater::make('budgetItems')
268
+                                    ->relationship()
269
+                                    ->hiddenLabel()
270
+                                    ->headers($headers)
271
+                                    ->schema([
272
+                                        Forms\Components\Placeholder::make('account')
273
+                                            ->hiddenLabel()
274
+                                            ->content(fn (BudgetItem $record) => $record->account->name ?? ''),
275
+
276
+                                        // Create a field for each period
277
+                                        ...collect($periods)->map(function ($period) {
278
+                                            return Forms\Components\TextInput::make("allocations.{$period}")
279
+                                                ->mask(RawJs::make('$money($input)'))
280
+                                                ->stripCharacters(',')
281
+                                                ->numeric()
282
+                                                ->extraInputAttributes(['class' => 'text-right'])
283
+                                                ->afterStateHydrated(function ($component, $state, BudgetItem $record) use ($period) {
284
+                                                    // Find the allocation for this period
285
+                                                    $allocation = $record->allocations->firstWhere('period', $period);
286
+                                                    $component->state($allocation ? $allocation->amount : 0);
287
+                                                })
288
+                                                ->dehydrated(false); // We'll handle saving manually
289
+                                        })->toArray(),
290
+                                    ])
291
+                                    ->spreadsheet()
292
+                                    ->itemLabel(fn (BudgetItem $record) => $record->account->name ?? 'Budget Item')
293
+                                    ->deletable(false)
294
+                                    ->reorderable(false)
295
+                                    ->addable(false) // Don't allow adding new budget items
296
+                                    ->columnSpanFull(),
297
+                            ];
298
+                        }),
235 299
                 ]),
236 300
             ])
237 301
             ->bulkActions([

+ 199
- 8
app/Filament/Company/Resources/Accounting/BudgetResource/Pages/CreateBudget.php ファイルの表示

@@ -327,6 +327,7 @@ class CreateBudget extends CreateRecord
327 327
             ]);
328 328
 
329 329
             $allocationStart = Carbon::parse($data['start_date']);
330
+            $budgetEndDate = Carbon::parse($data['end_date']);
330 331
 
331 332
             // Determine amounts based on the prefill method
332 333
             $amounts = match ($data['prefill_method'] ?? null) {
@@ -335,9 +336,25 @@ class CreateBudget extends CreateRecord
335 336
                 default => $this->generateZeroAmounts($data['start_date'], $data['end_date'], BudgetIntervalType::parse($data['interval_type'])),
336 337
             };
337 338
 
339
+            if (empty($amounts)) {
340
+                $amounts = $this->generateZeroAmounts(
341
+                    $data['start_date'],
342
+                    $data['end_date'],
343
+                    BudgetIntervalType::parse($data['interval_type'])
344
+                );
345
+            }
346
+
338 347
             foreach ($amounts as $periodLabel => $amount) {
348
+                if ($allocationStart->gt($budgetEndDate)) {
349
+                    break;
350
+                }
351
+
339 352
                 $allocationEnd = self::calculateEndDate($allocationStart, BudgetIntervalType::parse($data['interval_type']));
340 353
 
354
+                if ($allocationEnd->gt($budgetEndDate)) {
355
+                    $allocationEnd = $budgetEndDate->copy();
356
+                }
357
+
341 358
                 $budgetItem->allocations()->create([
342 359
                     'period' => $periodLabel,
343 360
                     'interval_type' => $data['interval_type'],
@@ -355,13 +372,78 @@ class CreateBudget extends CreateRecord
355 372
 
356 373
     private function getAmountsFromActuals(Account $account, int $fiscalYear, BudgetIntervalType $intervalType): array
357 374
     {
358
-        // Determine the fiscal year start and end dates
359
-        $fiscalYearStart = Carbon::create($fiscalYear, 1, 1)->startOfYear();
360
-        $fiscalYearEnd = $fiscalYearStart->copy()->endOfYear();
375
+        $amounts = [];
376
+
377
+        // Get the start and end date of the budget being created
378
+        $budgetStartDate = Carbon::parse($this->data['start_date']);
379
+        $budgetEndDate = Carbon::parse($this->data['end_date']);
380
+
381
+        // Map to equivalent dates in the reference fiscal year
382
+        $referenceStartDate = Carbon::create($fiscalYear, $budgetStartDate->month, $budgetStartDate->day);
383
+        $referenceEndDate = Carbon::create($fiscalYear, $budgetEndDate->month, $budgetEndDate->day);
384
+
385
+        // Handle year boundary case (if budget crosses year boundary)
386
+        if ($budgetStartDate->month > $budgetEndDate->month ||
387
+            ($budgetStartDate->month === $budgetEndDate->month && $budgetStartDate->day > $budgetEndDate->day)) {
388
+            $referenceEndDate->year++;
389
+        }
390
+
391
+        if ($intervalType->isMonth()) {
392
+            // Process month by month within the reference period
393
+            $currentDate = $referenceStartDate->copy()->startOfMonth();
394
+            $lastMonth = $referenceEndDate->copy()->startOfMonth();
361 395
 
362
-        $netMovement = Accounting::getNetMovement($account, $fiscalYearStart->toDateString(), $fiscalYearEnd->toDateString());
396
+            while ($currentDate->lte($lastMonth)) {
397
+                $periodStart = $currentDate->copy()->startOfMonth();
398
+                $periodEnd = $currentDate->copy()->endOfMonth();
399
+                $periodLabel = $this->determinePeriod($periodStart, $intervalType);
400
+
401
+                $netMovement = Accounting::getNetMovement(
402
+                    $account,
403
+                    $periodStart->toDateString(),
404
+                    $periodEnd->toDateString()
405
+                );
406
+
407
+                $amounts[$periodLabel] = $netMovement->getAmount();
408
+
409
+                $currentDate->addMonth();
410
+            }
411
+        } elseif ($intervalType->isQuarter()) {
412
+            // Process quarter by quarter within the reference period
413
+            $currentDate = $referenceStartDate->copy()->startOfQuarter();
414
+            $lastQuarter = $referenceEndDate->copy()->startOfQuarter();
415
+
416
+            while ($currentDate->lte($lastQuarter)) {
417
+                $periodStart = $currentDate->copy()->startOfQuarter();
418
+                $periodEnd = $currentDate->copy()->endOfQuarter();
419
+                $periodLabel = $this->determinePeriod($periodStart, $intervalType);
420
+
421
+                $netMovement = Accounting::getNetMovement(
422
+                    $account,
423
+                    $periodStart->toDateString(),
424
+                    $periodEnd->toDateString()
425
+                );
426
+
427
+                $amounts[$periodLabel] = $netMovement->getAmount();
428
+
429
+                $currentDate->addQuarter();
430
+            }
431
+        } else {
432
+            // For yearly intervals
433
+            $periodStart = $referenceStartDate->copy()->startOfYear();
434
+            $periodEnd = $referenceEndDate->copy()->endOfYear();
435
+            $periodLabel = $this->determinePeriod($periodStart, $intervalType);
436
+
437
+            $netMovement = Accounting::getNetMovement(
438
+                $account,
439
+                $periodStart->toDateString(),
440
+                $periodEnd->toDateString()
441
+            );
442
+
443
+            $amounts[$periodLabel] = $netMovement->getAmount();
444
+        }
363 445
 
364
-        return $this->distributeAmountAcrossPeriods($netMovement->getAmount(), $fiscalYearStart, $fiscalYearEnd, $intervalType);
446
+        return $amounts;
365 447
     }
366 448
 
367 449
     private function distributeAmountAcrossPeriods(int $totalAmountInCents, Carbon $startDate, Carbon $endDate, BudgetIntervalType $intervalType): array
@@ -397,12 +479,121 @@ class CreateBudget extends CreateRecord
397 479
     {
398 480
         $amounts = [];
399 481
 
482
+        // Get the budget being created start and end dates
483
+        $newBudgetStartDate = Carbon::parse($this->data['start_date']);
484
+        $newBudgetEndDate = Carbon::parse($this->data['end_date']);
485
+
486
+        // Get source budget's date information
487
+        $sourceBudget = Budget::findOrFail($sourceBudgetId);
488
+        $sourceBudgetType = $sourceBudget->interval_type;
489
+
490
+        // Retrieve all previous allocations for this account
400 491
         $previousAllocations = BudgetAllocation::query()
401
-            ->whereHas('budgetItem', fn ($query) => $query->where('account_id', $account->id)->where('budget_id', $sourceBudgetId))
492
+            ->whereHas(
493
+                'budgetItem',
494
+                fn ($query) => $query->where('account_id', $account->id)
495
+                    ->where('budget_id', $sourceBudgetId)
496
+            )
497
+            ->orderBy('start_date')
402 498
             ->get();
403 499
 
404
-        foreach ($previousAllocations as $allocation) {
405
-            $amounts[$allocation->period] = $allocation->getRawOriginal('amount');
500
+        if ($previousAllocations->isEmpty()) {
501
+            return $this->generateZeroAmounts(
502
+                $this->data['start_date'],
503
+                $this->data['end_date'],
504
+                $intervalType
505
+            );
506
+        }
507
+
508
+        // Map previous budget periods to current budget periods
509
+        if ($intervalType === $sourceBudgetType) {
510
+            // Same interval type: direct mapping of equivalent periods
511
+            foreach ($previousAllocations as $allocation) {
512
+                $allocationDate = Carbon::parse($allocation->start_date);
513
+
514
+                // Create an equivalent date in the new budget's time range
515
+                $equivalentMonth = $allocationDate->month;
516
+                $equivalentDay = $allocationDate->day;
517
+                $equivalentYear = $newBudgetStartDate->year;
518
+
519
+                // Adjust year if the budget spans multiple years
520
+                if ($newBudgetStartDate->month > $newBudgetEndDate->month &&
521
+                    $equivalentMonth < $newBudgetStartDate->month) {
522
+                    $equivalentYear++;
523
+                }
524
+
525
+                $equivalentDate = Carbon::create($equivalentYear, $equivalentMonth, $equivalentDay);
526
+
527
+                // Only include if the date falls within our new budget period
528
+                if ($equivalentDate->between($newBudgetStartDate, $newBudgetEndDate)) {
529
+                    $periodLabel = $this->determinePeriod($equivalentDate, $intervalType);
530
+                    $amounts[$periodLabel] = $allocation->getRawOriginal('amount');
531
+                }
532
+            }
533
+        } else {
534
+            // Handle conversion between different interval types
535
+            $newBudgetPeriods = $this->generateZeroAmounts(
536
+                $this->data['start_date'],
537
+                $this->data['end_date'],
538
+                $intervalType
539
+            );
540
+
541
+            // Fill with zeros initially
542
+            $amounts = array_fill_keys(array_keys($newBudgetPeriods), 0);
543
+
544
+            // Group previous allocations by their date range
545
+            $allocationsByRange = [];
546
+            foreach ($previousAllocations as $allocation) {
547
+                $allocationsByRange[] = [
548
+                    'start' => Carbon::parse($allocation->start_date),
549
+                    'end' => Carbon::parse($allocation->end_date),
550
+                    'amount' => $allocation->getRawOriginal('amount'),
551
+                ];
552
+            }
553
+
554
+            // Create new allocations based on interval type
555
+            $currentDate = Carbon::parse($this->data['start_date']);
556
+            $endDate = Carbon::parse($this->data['end_date']);
557
+
558
+            while ($currentDate->lte($endDate)) {
559
+                $periodStart = $currentDate->copy();
560
+                $periodEnd = self::calculateEndDate($currentDate, $intervalType);
561
+
562
+                if ($periodEnd->gt($endDate)) {
563
+                    $periodEnd = $endDate->copy();
564
+                }
565
+
566
+                $periodLabel = $this->determinePeriod($periodStart, $intervalType);
567
+
568
+                // Calculate the proportional amount from the source budget
569
+                $weightedAmount = 0;
570
+
571
+                foreach ($allocationsByRange as $allocation) {
572
+                    // Find overlapping days between new period and source allocation
573
+                    $overlapStart = max($periodStart, $allocation['start']);
574
+                    $overlapEnd = min($periodEnd, $allocation['end']);
575
+
576
+                    if ($overlapStart <= $overlapEnd) {
577
+                        // Calculate overlapping days
578
+                        $overlapDays = $overlapStart->diffInDays($overlapEnd) + 1;
579
+                        $allocationTotalDays = $allocation['start']->diffInDays($allocation['end']) + 1;
580
+
581
+                        // Calculate proportional amount based on days
582
+                        $proportion = $overlapDays / $allocationTotalDays;
583
+                        $proportionalAmount = (int) ($allocation['amount'] * $proportion);
584
+
585
+                        $weightedAmount += $proportionalAmount;
586
+                    }
587
+                }
588
+
589
+                // Assign the calculated amount to the period
590
+                if (array_key_exists($periodLabel, $amounts)) {
591
+                    $amounts[$periodLabel] = $weightedAmount;
592
+                }
593
+
594
+                // Move to the next period
595
+                $currentDate = $periodEnd->copy()->addDay();
596
+            }
406 597
         }
407 598
 
408 599
         return $amounts;

+ 92
- 13
app/Filament/Company/Resources/Accounting/BudgetResource/Pages/EditBudget.php ファイルの表示

@@ -4,11 +4,18 @@ namespace App\Filament\Company\Resources\Accounting\BudgetResource\Pages;
4 4
 
5 5
 use App\Enums\Accounting\BudgetIntervalType;
6 6
 use App\Filament\Company\Resources\Accounting\BudgetResource;
7
+use App\Filament\Forms\Components\CustomTableRepeater;
7 8
 use App\Models\Accounting\Budget;
8 9
 use App\Models\Accounting\BudgetAllocation;
9 10
 use App\Models\Accounting\BudgetItem;
11
+use Awcodes\TableRepeater\Header;
10 12
 use Filament\Actions;
13
+use Filament\Forms;
14
+use Filament\Forms\Form;
11 15
 use Filament\Resources\Pages\EditRecord;
16
+use Filament\Support\Enums\Alignment;
17
+use Filament\Support\Enums\MaxWidth;
18
+use Filament\Support\RawJs;
12 19
 use Illuminate\Database\Eloquent\Model;
13 20
 use Illuminate\Support\Carbon;
14 21
 
@@ -24,25 +31,97 @@ class EditBudget extends EditRecord
24 31
         ];
25 32
     }
26 33
 
27
-    protected function mutateFormDataBeforeFill(array $data): array
34
+    public function getMaxContentWidth(): MaxWidth | string | null
35
+    {
36
+        return 'max-w-8xl';
37
+    }
38
+
39
+    public function form(Form $form): Form
28 40
     {
29 41
         /** @var Budget $budget */
30 42
         $budget = $this->record;
43
+        $periods = $budget->getPeriods();
44
+
45
+        $headers = [
46
+            Header::make('Account')
47
+                ->label('Account')
48
+                ->width('200px'),
49
+        ];
31 50
 
32
-        $data['budgetItems'] = $budget->budgetItems->map(function (BudgetItem $budgetItem) {
33
-            return [
34
-                'id' => $budgetItem->id,
35
-                'account_id' => $budgetItem->account_id,
36
-                'total_amount' => $budgetItem->allocations->sum('amount'), // Calculate total dynamically
37
-                'amounts' => $budgetItem->allocations->mapWithKeys(static function (BudgetAllocation $allocation) {
38
-                    return [$allocation->period => $allocation->amount]; // Use the correct period label
39
-                })->toArray(),
40
-            ];
41
-        })->toArray();
42
-
43
-        return $data;
51
+        foreach ($periods as $period) {
52
+            $headers[] = Header::make($period)
53
+                ->label($period)
54
+                ->width('120px')
55
+                ->align(Alignment::Center);
56
+        }
57
+
58
+        return $form->schema([
59
+            Forms\Components\Section::make('Budget Details')
60
+                ->schema([
61
+                    Forms\Components\TextInput::make('name')
62
+                        ->required(),
63
+                    Forms\Components\Select::make('interval_type')
64
+                        ->disabled(), // Can't change interval type after creation
65
+                    Forms\Components\DatePicker::make('start_date')
66
+                        ->disabled(),
67
+                    Forms\Components\DatePicker::make('end_date')
68
+                        ->disabled(),
69
+                    Forms\Components\Textarea::make('notes'),
70
+                ]),
71
+
72
+            Forms\Components\Section::make('Budget Allocations')
73
+                ->schema([
74
+                    CustomTableRepeater::make('budgetItems')
75
+                        ->relationship()
76
+                        ->headers($headers)
77
+                        ->schema([
78
+                            Forms\Components\Placeholder::make('account')
79
+                                ->hiddenLabel()
80
+                                ->content(fn ($record) => $record->account->name ?? ''),
81
+
82
+                            // Create a field for each period
83
+                            ...collect($periods)->map(function ($period) {
84
+                                return Forms\Components\TextInput::make("allocations.{$period}")
85
+                                    ->mask(RawJs::make('$money($input)'))
86
+                                    ->stripCharacters(',')
87
+                                    ->numeric()
88
+                                    ->afterStateHydrated(function ($component, $state, $record) use ($period) {
89
+                                        // Find the allocation for this period
90
+                                        $allocation = $record->allocations->firstWhere('period', $period);
91
+                                        $component->state($allocation ? $allocation->amount : 0);
92
+                                    })
93
+                                    ->dehydrated(false); // We'll handle saving manually
94
+                            })->toArray(),
95
+                        ])
96
+                        ->spreadsheet()
97
+                        ->itemLabel(fn ($record) => $record->account->name ?? 'Budget Item')
98
+                        ->deletable(false)
99
+                        ->reorderable(false)
100
+                        ->addable(false) // Don't allow adding new budget items
101
+                        ->columnSpanFull(),
102
+                ]),
103
+        ]);
44 104
     }
45 105
 
106
+    //    protected function mutateFormDataBeforeFill(array $data): array
107
+    //    {
108
+    //        /** @var Budget $budget */
109
+    //        $budget = $this->record;
110
+    //
111
+    //        $data['budgetItems'] = $budget->budgetItems->map(function (BudgetItem $budgetItem) {
112
+    //            return [
113
+    //                'id' => $budgetItem->id,
114
+    //                'account_id' => $budgetItem->account_id,
115
+    //                'total_amount' => $budgetItem->allocations->sum('amount'), // Calculate total dynamically
116
+    //                'amounts' => $budgetItem->allocations->mapWithKeys(static function (BudgetAllocation $allocation) {
117
+    //                    return [$allocation->period => $allocation->amount]; // Use the correct period label
118
+    //                })->toArray(),
119
+    //            ];
120
+    //        })->toArray();
121
+    //
122
+    //        return $data;
123
+    //    }
124
+
46 125
     protected function handleRecordUpdate(Model $record, array $data): Model
47 126
     {
48 127
         /** @var Budget $budget */

+ 42
- 2
app/Filament/Company/Resources/Accounting/BudgetResource/RelationManagers/BudgetItemsRelationManager.php ファイルの表示

@@ -2,6 +2,9 @@
2 2
 
3 3
 namespace App\Filament\Company\Resources\Accounting\BudgetResource\RelationManagers;
4 4
 
5
+use App\Models\Accounting\BudgetAllocation;
6
+use Filament\Forms\Components\Grid;
7
+use Filament\Forms\Components\TextInput;
5 8
 use Filament\Resources\RelationManagers\RelationManager;
6 9
 use Filament\Tables;
7 10
 use Filament\Tables\Table;
@@ -36,8 +39,45 @@ class BudgetItemsRelationManager extends RelationManager
36 39
                 // Tables\Actions\CreateAction::make(),
37 40
             ])
38 41
             ->actions([
39
-                // Tables\Actions\EditAction::make(),
40
-                // Tables\Actions\DeleteAction::make(),
42
+                Tables\Actions\Action::make('editAllocations')
43
+                    ->label('Edit Allocations')
44
+                    ->icon('heroicon-o-pencil')
45
+                    ->modalHeading(fn ($record) => "Edit Allocations for {$record->account->name}")
46
+                    ->modalWidth('xl')
47
+                    ->form(function ($record) {
48
+                        $fields = [];
49
+
50
+                        // Get allocations ordered by date
51
+                        $allocations = $record->allocations()->orderBy('start_date')->get();
52
+
53
+                        foreach ($allocations as $allocation) {
54
+                            $fields[] = TextInput::make("allocations.{$allocation->id}")
55
+                                ->label($allocation->period)
56
+                                ->numeric()
57
+                                ->default(function () use ($allocation) {
58
+                                    return $allocation->amount;
59
+                                })
60
+                                ->prefix('$')
61
+                                ->live(debounce: 500)
62
+                                ->afterStateUpdated(function (TextInput $component, $state) {
63
+                                    // Format the value as needed
64
+                                    $component->state(number_format($state, 2, '.', ''));
65
+                                });
66
+                        }
67
+
68
+                        return [
69
+                            Grid::make()
70
+                                ->schema($fields)
71
+                                ->columns(3),
72
+                        ];
73
+                    })
74
+                    ->action(function (array $data, $record) {
75
+                        foreach ($data['allocations'] as $allocationId => $amount) {
76
+                            BudgetAllocation::find($allocationId)->update([
77
+                                'amount' => $amount,
78
+                            ]);
79
+                        }
80
+                    }),
41 81
             ])
42 82
             ->bulkActions([
43 83
                 //                Tables\Actions\BulkActionGroup::make([

+ 38
- 0
app/Filament/Forms/Components/CustomTableRepeater.php ファイルの表示

@@ -0,0 +1,38 @@
1
+<?php
2
+
3
+namespace App\Filament\Forms\Components;
4
+
5
+use Awcodes\TableRepeater\Components\TableRepeater;
6
+use Closure;
7
+
8
+class CustomTableRepeater extends TableRepeater
9
+{
10
+    protected bool | Closure | null $spreadsheet = null;
11
+
12
+    public function spreadsheet(bool | Closure $condition = true): static
13
+    {
14
+        $this->spreadsheet = $condition;
15
+
16
+        return $this;
17
+    }
18
+
19
+    public function isSpreadsheet(): bool
20
+    {
21
+        return $this->evaluate($this->spreadsheet) ?? false;
22
+    }
23
+
24
+    protected function setUp(): void
25
+    {
26
+        parent::setUp();
27
+
28
+        $this->extraAttributes(function (): array {
29
+            $attributes = [];
30
+
31
+            if ($this->isSpreadsheet()) {
32
+                $attributes['class'] = 'is-spreadsheet';
33
+            }
34
+
35
+            return $attributes;
36
+        });
37
+    }
38
+}

+ 19
- 0
app/Models/Accounting/Budget.php ファイルの表示

@@ -57,6 +57,25 @@ class Budget extends Model
57 57
         return $this->hasManyThrough(BudgetAllocation::class, BudgetItem::class);
58 58
     }
59 59
 
60
+    /**
61
+     * Get all periods for this budget in chronological order.
62
+     *
63
+     * @return array
64
+     */
65
+    public function getPeriods(): array
66
+    {
67
+        return $this->budgetItems()
68
+            ->with('allocations')
69
+            ->get()
70
+            ->flatMap(fn ($item) => $item->allocations)
71
+            ->sortBy('start_date')
72
+            ->pluck('period')
73
+            ->unique()
74
+            ->values()
75
+            ->toArray();
76
+    }
77
+
78
+
60 79
     public function isDraft(): bool
61 80
     {
62 81
         return $this->status === BudgetStatus::Draft;

+ 1
- 2
composer.json ファイルの表示

@@ -62,8 +62,7 @@
62 62
             "@php artisan filament:upgrade"
63 63
         ],
64 64
         "post-update-cmd": [
65
-            "@php artisan vendor:publish --tag=laravel-assets --ansi --force",
66
-            "npm up && npm run build || echo \"Skipping npm update and build (npm not available)\""
65
+            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
67 66
         ],
68 67
         "post-root-package-install": [
69 68
             "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""

+ 82
- 81
composer.lock ファイルの表示

@@ -302,16 +302,16 @@
302 302
         },
303 303
         {
304 304
             "name": "anourvalar/eloquent-serialize",
305
-            "version": "1.2.29",
305
+            "version": "1.3.0",
306 306
             "source": {
307 307
                 "type": "git",
308 308
                 "url": "https://github.com/AnourValar/eloquent-serialize.git",
309
-                "reference": "0919c91e548d01261308fd54d27fc05a83c79d03"
309
+                "reference": "91188f82c5ec2842a5469fca6d7d64baa37ea593"
310 310
             },
311 311
             "dist": {
312 312
                 "type": "zip",
313
-                "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/0919c91e548d01261308fd54d27fc05a83c79d03",
314
-                "reference": "0919c91e548d01261308fd54d27fc05a83c79d03",
313
+                "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/91188f82c5ec2842a5469fca6d7d64baa37ea593",
314
+                "reference": "91188f82c5ec2842a5469fca6d7d64baa37ea593",
315 315
                 "shasum": ""
316 316
             },
317 317
             "require": {
@@ -362,9 +362,9 @@
362 362
             ],
363 363
             "support": {
364 364
                 "issues": "https://github.com/AnourValar/eloquent-serialize/issues",
365
-                "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.2.29"
365
+                "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.3.0"
366 366
             },
367
-            "time": "2025-02-25T05:18:46+00:00"
367
+            "time": "2025-03-22T08:49:12+00:00"
368 368
         },
369 369
         {
370 370
             "name": "awcodes/filament-table-repeater",
@@ -497,16 +497,16 @@
497 497
         },
498 498
         {
499 499
             "name": "aws/aws-sdk-php",
500
-            "version": "3.342.8",
500
+            "version": "3.342.11",
501 501
             "source": {
502 502
                 "type": "git",
503 503
                 "url": "https://github.com/aws/aws-sdk-php.git",
504
-                "reference": "d8279a481cf87482a1fb74784f76e4160efcce90"
504
+                "reference": "e0afed3d0e2c89362f6c9b6bf8f278b04a4858b6"
505 505
             },
506 506
             "dist": {
507 507
                 "type": "zip",
508
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d8279a481cf87482a1fb74784f76e4160efcce90",
509
-                "reference": "d8279a481cf87482a1fb74784f76e4160efcce90",
508
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e0afed3d0e2c89362f6c9b6bf8f278b04a4858b6",
509
+                "reference": "e0afed3d0e2c89362f6c9b6bf8f278b04a4858b6",
510 510
                 "shasum": ""
511 511
             },
512 512
             "require": {
@@ -588,9 +588,9 @@
588 588
             "support": {
589 589
                 "forum": "https://github.com/aws/aws-sdk-php/discussions",
590 590
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
591
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.342.8"
591
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.342.11"
592 592
             },
593
-            "time": "2025-03-18T18:15:40+00:00"
593
+            "time": "2025-03-21T18:11:10+00:00"
594 594
         },
595 595
         {
596 596
             "name": "aws/aws-sdk-php-laravel",
@@ -1666,16 +1666,16 @@
1666 1666
         },
1667 1667
         {
1668 1668
             "name": "egulias/email-validator",
1669
-            "version": "4.0.3",
1669
+            "version": "4.0.4",
1670 1670
             "source": {
1671 1671
                 "type": "git",
1672 1672
                 "url": "https://github.com/egulias/EmailValidator.git",
1673
-                "reference": "b115554301161fa21467629f1e1391c1936de517"
1673
+                "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa"
1674 1674
             },
1675 1675
             "dist": {
1676 1676
                 "type": "zip",
1677
-                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517",
1678
-                "reference": "b115554301161fa21467629f1e1391c1936de517",
1677
+                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa",
1678
+                "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa",
1679 1679
                 "shasum": ""
1680 1680
             },
1681 1681
             "require": {
@@ -1721,7 +1721,7 @@
1721 1721
             ],
1722 1722
             "support": {
1723 1723
                 "issues": "https://github.com/egulias/EmailValidator/issues",
1724
-                "source": "https://github.com/egulias/EmailValidator/tree/4.0.3"
1724
+                "source": "https://github.com/egulias/EmailValidator/tree/4.0.4"
1725 1725
             },
1726 1726
             "funding": [
1727 1727
                 {
@@ -1729,20 +1729,20 @@
1729 1729
                     "type": "github"
1730 1730
                 }
1731 1731
             ],
1732
-            "time": "2024-12-27T00:36:43+00:00"
1732
+            "time": "2025-03-06T22:45:56+00:00"
1733 1733
         },
1734 1734
         {
1735 1735
             "name": "filament/actions",
1736
-            "version": "v3.3.4",
1736
+            "version": "v3.3.5",
1737 1737
             "source": {
1738 1738
                 "type": "git",
1739 1739
                 "url": "https://github.com/filamentphp/actions.git",
1740
-                "reference": "dd738da99c8032986e7628b09f185d8f0db7850a"
1740
+                "reference": "66fc3526f39ec09156928fcdf2cd4cb44e97efc4"
1741 1741
             },
1742 1742
             "dist": {
1743 1743
                 "type": "zip",
1744
-                "url": "https://api.github.com/repos/filamentphp/actions/zipball/dd738da99c8032986e7628b09f185d8f0db7850a",
1745
-                "reference": "dd738da99c8032986e7628b09f185d8f0db7850a",
1744
+                "url": "https://api.github.com/repos/filamentphp/actions/zipball/66fc3526f39ec09156928fcdf2cd4cb44e97efc4",
1745
+                "reference": "66fc3526f39ec09156928fcdf2cd4cb44e97efc4",
1746 1746
                 "shasum": ""
1747 1747
             },
1748 1748
             "require": {
@@ -1782,20 +1782,20 @@
1782 1782
                 "issues": "https://github.com/filamentphp/filament/issues",
1783 1783
                 "source": "https://github.com/filamentphp/filament"
1784 1784
             },
1785
-            "time": "2025-03-11T16:33:01+00:00"
1785
+            "time": "2025-03-20T09:28:45+00:00"
1786 1786
         },
1787 1787
         {
1788 1788
             "name": "filament/filament",
1789
-            "version": "v3.3.4",
1789
+            "version": "v3.3.5",
1790 1790
             "source": {
1791 1791
                 "type": "git",
1792 1792
                 "url": "https://github.com/filamentphp/panels.git",
1793
-                "reference": "ae0288f28054c88a9f36f666f4752660ce72cb08"
1793
+                "reference": "173e4695ed4c7318e26b11dafb79294f56775d55"
1794 1794
             },
1795 1795
             "dist": {
1796 1796
                 "type": "zip",
1797
-                "url": "https://api.github.com/repos/filamentphp/panels/zipball/ae0288f28054c88a9f36f666f4752660ce72cb08",
1798
-                "reference": "ae0288f28054c88a9f36f666f4752660ce72cb08",
1797
+                "url": "https://api.github.com/repos/filamentphp/panels/zipball/173e4695ed4c7318e26b11dafb79294f56775d55",
1798
+                "reference": "173e4695ed4c7318e26b11dafb79294f56775d55",
1799 1799
                 "shasum": ""
1800 1800
             },
1801 1801
             "require": {
@@ -1847,20 +1847,20 @@
1847 1847
                 "issues": "https://github.com/filamentphp/filament/issues",
1848 1848
                 "source": "https://github.com/filamentphp/filament"
1849 1849
             },
1850
-            "time": "2025-03-11T16:33:11+00:00"
1850
+            "time": "2025-03-20T09:28:52+00:00"
1851 1851
         },
1852 1852
         {
1853 1853
             "name": "filament/forms",
1854
-            "version": "v3.3.4",
1854
+            "version": "v3.3.5",
1855 1855
             "source": {
1856 1856
                 "type": "git",
1857 1857
                 "url": "https://github.com/filamentphp/forms.git",
1858
-                "reference": "647f03f3d7a15a9ce71e803926b2e89f88693e8e"
1858
+                "reference": "e98beabb94e290b0edd837ffa4e6f821df5fcc89"
1859 1859
             },
1860 1860
             "dist": {
1861 1861
                 "type": "zip",
1862
-                "url": "https://api.github.com/repos/filamentphp/forms/zipball/647f03f3d7a15a9ce71e803926b2e89f88693e8e",
1863
-                "reference": "647f03f3d7a15a9ce71e803926b2e89f88693e8e",
1862
+                "url": "https://api.github.com/repos/filamentphp/forms/zipball/e98beabb94e290b0edd837ffa4e6f821df5fcc89",
1863
+                "reference": "e98beabb94e290b0edd837ffa4e6f821df5fcc89",
1864 1864
                 "shasum": ""
1865 1865
             },
1866 1866
             "require": {
@@ -1903,20 +1903,20 @@
1903 1903
                 "issues": "https://github.com/filamentphp/filament/issues",
1904 1904
                 "source": "https://github.com/filamentphp/filament"
1905 1905
             },
1906
-            "time": "2025-03-11T16:33:00+00:00"
1906
+            "time": "2025-03-20T09:29:10+00:00"
1907 1907
         },
1908 1908
         {
1909 1909
             "name": "filament/infolists",
1910
-            "version": "v3.3.4",
1910
+            "version": "v3.3.5",
1911 1911
             "source": {
1912 1912
                 "type": "git",
1913 1913
                 "url": "https://github.com/filamentphp/infolists.git",
1914
-                "reference": "a1355ace7341e4e44d31dc30cfc6129bd61c7d8f"
1914
+                "reference": "cdf80f01fd822cbd7830dbb5892a1d1245e237fa"
1915 1915
             },
1916 1916
             "dist": {
1917 1917
                 "type": "zip",
1918
-                "url": "https://api.github.com/repos/filamentphp/infolists/zipball/a1355ace7341e4e44d31dc30cfc6129bd61c7d8f",
1919
-                "reference": "a1355ace7341e4e44d31dc30cfc6129bd61c7d8f",
1918
+                "url": "https://api.github.com/repos/filamentphp/infolists/zipball/cdf80f01fd822cbd7830dbb5892a1d1245e237fa",
1919
+                "reference": "cdf80f01fd822cbd7830dbb5892a1d1245e237fa",
1920 1920
                 "shasum": ""
1921 1921
             },
1922 1922
             "require": {
@@ -1954,11 +1954,11 @@
1954 1954
                 "issues": "https://github.com/filamentphp/filament/issues",
1955 1955
                 "source": "https://github.com/filamentphp/filament"
1956 1956
             },
1957
-            "time": "2025-03-11T16:33:01+00:00"
1957
+            "time": "2025-03-20T09:28:28+00:00"
1958 1958
         },
1959 1959
         {
1960 1960
             "name": "filament/notifications",
1961
-            "version": "v3.3.4",
1961
+            "version": "v3.3.5",
1962 1962
             "source": {
1963 1963
                 "type": "git",
1964 1964
                 "url": "https://github.com/filamentphp/notifications.git",
@@ -2010,16 +2010,16 @@
2010 2010
         },
2011 2011
         {
2012 2012
             "name": "filament/support",
2013
-            "version": "v3.3.4",
2013
+            "version": "v3.3.5",
2014 2014
             "source": {
2015 2015
                 "type": "git",
2016 2016
                 "url": "https://github.com/filamentphp/support.git",
2017
-                "reference": "fb5ff99b8f7559815434c109d505c12c141510da"
2017
+                "reference": "cf3fa32f6e419ca768e88ac061dc3c47d01ed401"
2018 2018
             },
2019 2019
             "dist": {
2020 2020
                 "type": "zip",
2021
-                "url": "https://api.github.com/repos/filamentphp/support/zipball/fb5ff99b8f7559815434c109d505c12c141510da",
2022
-                "reference": "fb5ff99b8f7559815434c109d505c12c141510da",
2021
+                "url": "https://api.github.com/repos/filamentphp/support/zipball/cf3fa32f6e419ca768e88ac061dc3c47d01ed401",
2022
+                "reference": "cf3fa32f6e419ca768e88ac061dc3c47d01ed401",
2023 2023
                 "shasum": ""
2024 2024
             },
2025 2025
             "require": {
@@ -2065,20 +2065,20 @@
2065 2065
                 "issues": "https://github.com/filamentphp/filament/issues",
2066 2066
                 "source": "https://github.com/filamentphp/filament"
2067 2067
             },
2068
-            "time": "2025-03-05T09:26:25+00:00"
2068
+            "time": "2025-03-20T09:29:02+00:00"
2069 2069
         },
2070 2070
         {
2071 2071
             "name": "filament/tables",
2072
-            "version": "v3.3.4",
2072
+            "version": "v3.3.5",
2073 2073
             "source": {
2074 2074
                 "type": "git",
2075 2075
                 "url": "https://github.com/filamentphp/tables.git",
2076
-                "reference": "8f9bb6449c7ff74e234848f336161af5a64561c6"
2076
+                "reference": "b153de29ffe0cd5ef77d5c09a871c45f4d04b667"
2077 2077
             },
2078 2078
             "dist": {
2079 2079
                 "type": "zip",
2080
-                "url": "https://api.github.com/repos/filamentphp/tables/zipball/8f9bb6449c7ff74e234848f336161af5a64561c6",
2081
-                "reference": "8f9bb6449c7ff74e234848f336161af5a64561c6",
2080
+                "url": "https://api.github.com/repos/filamentphp/tables/zipball/b153de29ffe0cd5ef77d5c09a871c45f4d04b667",
2081
+                "reference": "b153de29ffe0cd5ef77d5c09a871c45f4d04b667",
2082 2082
                 "shasum": ""
2083 2083
             },
2084 2084
             "require": {
@@ -2117,11 +2117,11 @@
2117 2117
                 "issues": "https://github.com/filamentphp/filament/issues",
2118 2118
                 "source": "https://github.com/filamentphp/filament"
2119 2119
             },
2120
-            "time": "2025-03-11T16:33:31+00:00"
2120
+            "time": "2025-03-20T09:28:46+00:00"
2121 2121
         },
2122 2122
         {
2123 2123
             "name": "filament/widgets",
2124
-            "version": "v3.3.4",
2124
+            "version": "v3.3.5",
2125 2125
             "source": {
2126 2126
                 "type": "git",
2127 2127
                 "url": "https://github.com/filamentphp/widgets.git",
@@ -6120,16 +6120,16 @@
6120 6120
         },
6121 6121
         {
6122 6122
             "name": "ramsey/collection",
6123
-            "version": "2.1.0",
6123
+            "version": "2.1.1",
6124 6124
             "source": {
6125 6125
                 "type": "git",
6126 6126
                 "url": "https://github.com/ramsey/collection.git",
6127
-                "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109"
6127
+                "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
6128 6128
             },
6129 6129
             "dist": {
6130 6130
                 "type": "zip",
6131
-                "url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
6132
-                "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
6131
+                "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
6132
+                "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
6133 6133
                 "shasum": ""
6134 6134
             },
6135 6135
             "require": {
@@ -6190,9 +6190,9 @@
6190 6190
             ],
6191 6191
             "support": {
6192 6192
                 "issues": "https://github.com/ramsey/collection/issues",
6193
-                "source": "https://github.com/ramsey/collection/tree/2.1.0"
6193
+                "source": "https://github.com/ramsey/collection/tree/2.1.1"
6194 6194
             },
6195
-            "time": "2025-03-02T04:48:29+00:00"
6195
+            "time": "2025-03-22T05:38:12+00:00"
6196 6196
         },
6197 6197
         {
6198 6198
             "name": "ramsey/uuid",
@@ -6484,16 +6484,16 @@
6484 6484
         },
6485 6485
         {
6486 6486
             "name": "spatie/laravel-package-tools",
6487
-            "version": "1.19.0",
6487
+            "version": "1.91.1",
6488 6488
             "source": {
6489 6489
                 "type": "git",
6490 6490
                 "url": "https://github.com/spatie/laravel-package-tools.git",
6491
-                "reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa"
6491
+                "reference": "b0b509b9b01d77caa431ce9af3a706bc678e09c9"
6492 6492
             },
6493 6493
             "dist": {
6494 6494
                 "type": "zip",
6495
-                "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa",
6496
-                "reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa",
6495
+                "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/b0b509b9b01d77caa431ce9af3a706bc678e09c9",
6496
+                "reference": "b0b509b9b01d77caa431ce9af3a706bc678e09c9",
6497 6497
                 "shasum": ""
6498 6498
             },
6499 6499
             "require": {
@@ -6532,7 +6532,7 @@
6532 6532
             ],
6533 6533
             "support": {
6534 6534
                 "issues": "https://github.com/spatie/laravel-package-tools/issues",
6535
-                "source": "https://github.com/spatie/laravel-package-tools/tree/1.19.0"
6535
+                "source": "https://github.com/spatie/laravel-package-tools/tree/1.91.1"
6536 6536
             },
6537 6537
             "funding": [
6538 6538
                 {
@@ -6540,7 +6540,7 @@
6540 6540
                     "type": "github"
6541 6541
                 }
6542 6542
             ],
6543
-            "time": "2025-02-06T14:58:20+00:00"
6543
+            "time": "2025-03-21T09:50:49+00:00"
6544 6544
         },
6545 6545
         {
6546 6546
             "name": "squirephp/model",
@@ -9645,16 +9645,16 @@
9645 9645
         },
9646 9646
         {
9647 9647
             "name": "jean85/pretty-package-versions",
9648
-            "version": "2.1.0",
9648
+            "version": "2.1.1",
9649 9649
             "source": {
9650 9650
                 "type": "git",
9651 9651
                 "url": "https://github.com/Jean85/pretty-package-versions.git",
9652
-                "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
9652
+                "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a"
9653 9653
             },
9654 9654
             "dist": {
9655 9655
                 "type": "zip",
9656
-                "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
9657
-                "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
9656
+                "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a",
9657
+                "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a",
9658 9658
                 "shasum": ""
9659 9659
             },
9660 9660
             "require": {
@@ -9664,8 +9664,9 @@
9664 9664
             "require-dev": {
9665 9665
                 "friendsofphp/php-cs-fixer": "^3.2",
9666 9666
                 "jean85/composer-provided-replaced-stub-package": "^1.0",
9667
-                "phpstan/phpstan": "^1.4",
9667
+                "phpstan/phpstan": "^2.0",
9668 9668
                 "phpunit/phpunit": "^7.5|^8.5|^9.6",
9669
+                "rector/rector": "^2.0",
9669 9670
                 "vimeo/psalm": "^4.3 || ^5.0"
9670 9671
             },
9671 9672
             "type": "library",
@@ -9698,9 +9699,9 @@
9698 9699
             ],
9699 9700
             "support": {
9700 9701
                 "issues": "https://github.com/Jean85/pretty-package-versions/issues",
9701
-                "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
9702
+                "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1"
9702 9703
             },
9703
-            "time": "2024-11-18T16:19:46+00:00"
9704
+            "time": "2025-03-19T14:43:43+00:00"
9704 9705
         },
9705 9706
         {
9706 9707
             "name": "laravel/pint",
@@ -11413,16 +11414,16 @@
11413 11414
         },
11414 11415
         {
11415 11416
             "name": "sebastian/code-unit",
11416
-            "version": "3.0.2",
11417
+            "version": "3.0.3",
11417 11418
             "source": {
11418 11419
                 "type": "git",
11419 11420
                 "url": "https://github.com/sebastianbergmann/code-unit.git",
11420
-                "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca"
11421
+                "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64"
11421 11422
             },
11422 11423
             "dist": {
11423 11424
                 "type": "zip",
11424
-                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca",
11425
-                "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca",
11425
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64",
11426
+                "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64",
11426 11427
                 "shasum": ""
11427 11428
             },
11428 11429
             "require": {
@@ -11458,7 +11459,7 @@
11458 11459
             "support": {
11459 11460
                 "issues": "https://github.com/sebastianbergmann/code-unit/issues",
11460 11461
                 "security": "https://github.com/sebastianbergmann/code-unit/security/policy",
11461
-                "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.2"
11462
+                "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3"
11462 11463
             },
11463 11464
             "funding": [
11464 11465
                 {
@@ -11466,7 +11467,7 @@
11466 11467
                     "type": "github"
11467 11468
                 }
11468 11469
             ],
11469
-            "time": "2024-12-12T09:59:06+00:00"
11470
+            "time": "2025-03-19T07:56:08+00:00"
11470 11471
         },
11471 11472
         {
11472 11473
             "name": "sebastian/code-unit-reverse-lookup",
@@ -12800,16 +12801,16 @@
12800 12801
         },
12801 12802
         {
12802 12803
             "name": "spatie/ray",
12803
-            "version": "1.41.5",
12804
+            "version": "1.41.6",
12804 12805
             "source": {
12805 12806
                 "type": "git",
12806 12807
                 "url": "https://github.com/spatie/ray.git",
12807
-                "reference": "9d078f04ffa32ad543a20716844ec343fdd7d856"
12808
+                "reference": "ae6e32a54a901544a3d70b12b865900bc240f71c"
12808 12809
             },
12809 12810
             "dist": {
12810 12811
                 "type": "zip",
12811
-                "url": "https://api.github.com/repos/spatie/ray/zipball/9d078f04ffa32ad543a20716844ec343fdd7d856",
12812
-                "reference": "9d078f04ffa32ad543a20716844ec343fdd7d856",
12812
+                "url": "https://api.github.com/repos/spatie/ray/zipball/ae6e32a54a901544a3d70b12b865900bc240f71c",
12813
+                "reference": "ae6e32a54a901544a3d70b12b865900bc240f71c",
12813 12814
                 "shasum": ""
12814 12815
             },
12815 12816
             "require": {
@@ -12869,7 +12870,7 @@
12869 12870
             ],
12870 12871
             "support": {
12871 12872
                 "issues": "https://github.com/spatie/ray/issues",
12872
-                "source": "https://github.com/spatie/ray/tree/1.41.5"
12873
+                "source": "https://github.com/spatie/ray/tree/1.41.6"
12873 12874
             },
12874 12875
             "funding": [
12875 12876
                 {
@@ -12881,7 +12882,7 @@
12881 12882
                     "type": "other"
12882 12883
                 }
12883 12884
             ],
12884
-            "time": "2025-02-14T12:51:43+00:00"
12885
+            "time": "2025-03-21T08:56:30+00:00"
12885 12886
         },
12886 12887
         {
12887 12888
             "name": "staabm/side-effects-detector",

+ 122
- 18
resources/css/filament/company/form-fields.css ファイルの表示

@@ -53,40 +53,144 @@
53 53
     cursor: pointer;
54 54
 }
55 55
 
56
-/* Table Repeater Styles */
56
+/* Base horizontal scrolling for all TableRepeater components */
57 57
 .table-repeater-container {
58
-    @apply rounded-none ring-0;
58
+    overflow-x: auto;
59
+    max-width: 100%;
60
+    -webkit-overflow-scrolling: touch;
59 61
 }
60 62
 
61
-.table-repeater-component {
62
-    @apply space-y-10;
63
+.table-repeater-container:has(.choices.is-open) {
64
+    overflow: visible;
63 65
 }
64 66
 
65
-.table-repeater-component ul {
66
-    @apply justify-start;
67
+.table-repeater-container table {
68
+    min-width: 100%;
69
+    width: max-content;
67 70
 }
68 71
 
69
-.table-repeater-row {
70
-    @apply divide-x-0 !important;
72
+/* Excel/Spreadsheet styling */
73
+.is-spreadsheet .table-repeater-container {
74
+    border-radius: 0 !important;
75
+    border: 1px solid #e5e7eb !important;
76
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
77
+    @apply ring-0 !important;
71 78
 }
72 79
 
73
-.table-repeater-column {
74
-    @apply py-2 !important;
80
+.is-spreadsheet .table-repeater-header {
81
+    background-color: #f8f9fa !important;
82
+    border-radius: 0 !important;
75 83
 }
76 84
 
77
-.table-repeater-header {
78
-    @apply rounded-t-none !important;
85
+/* Fix for input alignment with headers */
86
+.is-spreadsheet .table-repeater-header-column,
87
+.is-spreadsheet .table-repeater-column {
88
+    padding: 6px 8px !important;
79 89
 }
80 90
 
81
-.table-repeater-rows-wrapper {
82
-    @apply divide-gray-300 last:border-b last:border-gray-300 dark:divide-white/20 dark:last:border-white/20;
91
+/* Right-align all inputs */
92
+.is-spreadsheet .table-repeater-column input {
93
+    text-align: right !important;
94
+    width: 100% !important;
83 95
 }
84 96
 
85
-.table-repeater-header tr {
86
-    @apply divide-x-0 text-base sm:text-sm sm:leading-6 !important;
97
+/* Remove any additional padding from input containers */
98
+.is-spreadsheet .fi-input-wrapper,
99
+.is-spreadsheet .fi-input {
100
+    padding: 0 !important;
101
+    width: 100% !important;
87 102
 }
88 103
 
89
-.table-repeater-header-column {
90
-    @apply ps-3 pe-3 font-semibold bg-gray-200 dark:bg-gray-800 rounded-none !important;
104
+.is-spreadsheet .table-repeater-header-column {
105
+    border-radius: 0 !important;
106
+    border: 1px solid #e5e7eb !important;
107
+    background-color: #f8f9fa !important;
108
+    font-weight: 600 !important;
109
+    padding: 6px 8px !important;
110
+}
111
+
112
+.is-spreadsheet .table-repeater-column {
113
+    border: 1px solid #e5e7eb !important;
114
+    padding: 4px 8px !important;
115
+    position: relative !important;
116
+}
117
+
118
+/* Incorporate flat input styling from streamlined */
119
+.is-spreadsheet .fi-input-wrp,
120
+.is-spreadsheet .fi-fo-file-upload .filepond--root {
121
+    @apply ring-0 bg-transparent shadow-none !important;
122
+}
123
+
124
+.is-spreadsheet .fi-input-wrp input {
125
+    @apply bg-transparent border-0 shadow-none !important;
126
+}
127
+
128
+.is-spreadsheet .fi-select-trigger {
129
+    @apply ring-0 bg-transparent shadow-none !important;
130
+}
131
+
132
+/* Excel-like row styles */
133
+.is-spreadsheet .table-repeater-row:nth-child(even) {
134
+    background-color: #f9fafb;
135
+}
136
+
137
+/* Excel-like focus/selection styles */
138
+.is-spreadsheet .table-repeater-column:focus-within {
139
+    outline: 2px solid #2563eb !important;
140
+    outline-offset: -2px !important;
141
+    z-index: 1 !important;
142
+}
143
+
144
+.is-spreadsheet .fi-input-wrp:focus-within {
145
+    @apply ring-0 shadow-none !important;
146
+}
147
+
148
+.is-spreadsheet input:focus,
149
+.is-spreadsheet select:focus,
150
+.is-spreadsheet textarea:focus {
151
+    @apply ring-0 shadow-none !important;
152
+    outline: none !important;
153
+}
154
+
155
+/* Spacing for form controls */
156
+.is-spreadsheet .fi-fo-field-wrp:has(.fi-fo-checkbox-list),
157
+.is-spreadsheet .fi-fo-field-wrp:has(.fi-checkbox-input),
158
+.is-spreadsheet .fi-fo-field-wrp:has(.fi-fo-radio) {
159
+    @apply py-2 px-3 !important;
160
+}
161
+
162
+.is-spreadsheet .fi-fo-field-wrp:has(.fi-fo-toggle) {
163
+    @apply inline-block mt-1 !important;
164
+}
165
+
166
+/* Preserve responsive behavior */
167
+@media (max-width: theme('screens.sm')) {
168
+    .table-repeater-component.break-point-sm .table-repeater-container {
169
+        overflow-x: visible;
170
+    }
171
+}
172
+
173
+@media (max-width: theme('screens.md')) {
174
+    .table-repeater-component.break-point-md .table-repeater-container {
175
+        overflow-x: visible;
176
+    }
177
+}
178
+
179
+@media (max-width: theme('screens.lg')) {
180
+    .table-repeater-component.break-point-lg .table-repeater-container {
181
+        overflow-x: visible;
182
+    }
183
+}
184
+
185
+@media (max-width: theme('screens.xl')) {
186
+    .table-repeater-component.break-point-xl .table-repeater-container {
187
+        overflow-x: visible;
188
+    }
189
+}
190
+
191
+@media (max-width: theme('screens.2xl')) {
192
+    .table-repeater-component.break-point-2xl .table-repeater-container {
193
+        overflow-x: visible;
194
+    }
91 195
 }
92 196
 

+ 12
- 10
resources/css/filament/company/modal.css ファイルの表示

@@ -1,18 +1,20 @@
1 1
 /* Journal Entry Modal Styles */
2 2
 .fi-modal.fi-width-screen {
3
-    .fi-modal-header {
4
-        @apply xl:px-80;
3
+    .fi-modal-window.journal-transaction-modal {
4
+        .fi-modal-header {
5
+            @apply xl:px-80;
5 6
 
6
-        .absolute.end-4.top-4 {
7
-            @apply xl:end-80;
7
+            .absolute.end-4.top-4 {
8
+                @apply xl:end-80;
9
+            }
8 10
         }
9
-    }
10 11
 
11
-    .fi-modal-content {
12
-        @apply xl:px-80;
13
-    }
12
+        .fi-modal-content {
13
+            @apply xl:px-80;
14
+        }
14 15
 
15
-    .fi-modal-footer {
16
-        @apply xl:px-80;
16
+        .fi-modal-footer {
17
+            @apply xl:px-80;
18
+        }
17 19
     }
18 20
 }

読み込み中…
キャンセル
保存