Pārlūkot izejas kodu

wip budgets

3.x
Andrew Wallo 7 mēnešus atpakaļ
vecāks
revīzija
3180d2a5da

+ 94
- 48
app/Filament/Company/Resources/Accounting/BudgetResource.php Parādīt failu

@@ -3,15 +3,16 @@
3 3
 namespace App\Filament\Company\Resources\Accounting;
4 4
 
5 5
 use App\Filament\Company\Resources\Accounting\BudgetResource\Pages;
6
+use App\Filament\Forms\Components\CustomSection;
6 7
 use App\Models\Accounting\Account;
7 8
 use App\Models\Accounting\Budget;
8
-use Awcodes\TableRepeater\Components\TableRepeater;
9
-use Awcodes\TableRepeater\Header;
9
+use App\Models\Accounting\BudgetItem;
10 10
 use Filament\Forms;
11 11
 use Filament\Forms\Form;
12 12
 use Filament\Resources\Resource;
13 13
 use Filament\Tables;
14 14
 use Filament\Tables\Table;
15
+use Illuminate\Support\Carbon;
15 16
 
16 17
 class BudgetResource extends Resource
17 18
 {
@@ -24,16 +25,11 @@ class BudgetResource extends Resource
24 25
         return $form
25 26
             ->schema([
26 27
                 Forms\Components\Section::make('Budget Details')
28
+                    ->columns()
27 29
                     ->schema([
28 30
                         Forms\Components\TextInput::make('name')
29 31
                             ->required()
30 32
                             ->maxLength(255),
31
-
32
-                        Forms\Components\Grid::make(2)->schema([
33
-                            Forms\Components\DatePicker::make('start_date')->required(),
34
-                            Forms\Components\DatePicker::make('end_date')->required(),
35
-                        ]),
36
-
37 33
                         Forms\Components\Select::make('interval_type')
38 34
                             ->label('Budget Interval')
39 35
                             ->options([
@@ -46,33 +42,35 @@ class BudgetResource extends Resource
46 42
                             ->default('month')
47 43
                             ->required()
48 44
                             ->live(),
49
-
45
+                        Forms\Components\DatePicker::make('start_date')
46
+                            ->required()
47
+                            ->default(now()->startOfYear())
48
+                            ->live(),
49
+                        Forms\Components\DatePicker::make('end_date')
50
+                            ->required()
51
+                            ->default(now()->endOfYear())
52
+                            ->live(),
50 53
                         Forms\Components\Textarea::make('notes')->columnSpanFull(),
51 54
                     ]),
52 55
 
53 56
                 Forms\Components\Section::make('Budget Items')
54 57
                     ->schema([
55
-                        TableRepeater::make('budgetItems')
58
+                        Forms\Components\Repeater::make('budgetItems')
56 59
                             ->relationship()
57
-                            ->saveRelationshipsUsing(null)
58
-                            ->dehydrated(true)
59
-                            ->headers(fn (Forms\Get $get) => self::getHeaders($get('interval_type')))
60
+                            ->columns(4)
61
+                            ->hiddenLabel()
60 62
                             ->schema([
61 63
                                 Forms\Components\Select::make('account_id')
62 64
                                     ->label('Account')
63 65
                                     ->options(Account::query()->pluck('name', 'id'))
64 66
                                     ->searchable()
67
+                                    ->columnSpan(1)
65 68
                                     ->required(),
66 69
 
67
-                                Forms\Components\Grid::make(2)->schema([
68
-                                    Forms\Components\DatePicker::make('start_date')->required(),
69
-                                    Forms\Components\DatePicker::make('end_date')->required(),
70
-                                ]),
71
-
72
-                                Forms\Components\TextInput::make('amount')
73
-                                    ->numeric()
74
-                                    ->suffix('USD')
75
-                                    ->required(),
70
+                                CustomSection::make('Budget Allocations')
71
+                                    ->contained(false)
72
+                                    ->columns(4)
73
+                                    ->schema(static fn (Forms\Get $get) => self::getAllocationFields($get('../../start_date'), $get('../../end_date'), $get('../../interval_type'))),
76 74
                             ])
77 75
                             ->defaultItems(1)
78 76
                             ->addActionLabel('Add Budget Item'),
@@ -100,39 +98,87 @@ class BudgetResource extends Resource
100 98
             ]);
101 99
     }
102 100
 
103
-    private static function getHeaders(?string $intervalType): array
101
+    private static function getAllocationFields(?string $startDate, ?string $endDate, ?string $intervalType): array
104 102
     {
105
-        $headers = [
106
-            Header::make('Account')->width('20%'),
107
-            Header::make('Start Date')->width('15%'),
108
-            Header::make('End Date')->width('15%'),
109
-        ];
110
-
111
-        // Adjust the number of columns dynamically based on interval type
112
-        switch ($intervalType) {
113
-            case 'day':
114
-                $headers[] = Header::make('Daily Budget')->width('20%')->align('right');
103
+        if (! $startDate || ! $endDate || ! $intervalType) {
104
+            return [];
105
+        }
115 106
 
116
-                break;
117
-            case 'week':
118
-                $headers[] = Header::make('Weekly Budget')->width('20%')->align('right');
107
+        $start = Carbon::parse($startDate);
108
+        $end = Carbon::parse($endDate);
109
+        $fields = [];
110
+
111
+        while ($start->lte($end)) {
112
+            $label = match ($intervalType) {
113
+                'month' => $start->format('M'), // Example: Jan, Feb, Mar
114
+                'quarter' => 'Q' . $start->quarter, // Example: Q1, Q2, Q3
115
+                'year' => (string) $start->year, // Example: 2024, 2025
116
+                default => '',
117
+            };
118
+
119
+            $fields[] = Forms\Components\TextInput::make("amounts.{$label}")
120
+                ->label($label)
121
+                ->numeric()
122
+                ->suffix('USD')
123
+                ->required();
124
+
125
+            // Move to the next period
126
+            match ($intervalType) {
127
+                'month' => $start->addMonth(),
128
+                'quarter' => $start->addQuarter(),
129
+                'year' => $start->addYear(),
130
+                default => null,
131
+            };
132
+        }
119 133
 
120
-                break;
121
-            case 'month':
122
-                $headers[] = Header::make('Monthly Budget')->width('20%')->align('right');
134
+        return $fields;
135
+    }
123 136
 
124
-                break;
125
-            case 'quarter':
126
-                $headers[] = Header::make('Quarterly Budget')->width('20%')->align('right');
137
+    /**
138
+     * Generates an array of interval labels (e.g., Jan 2024, Q1 2024, etc.).
139
+     */
140
+    private static function generateIntervals(string $startDate, string $endDate, string $intervalType): array
141
+    {
142
+        $start = Carbon::parse($startDate);
143
+        $end = Carbon::parse($endDate);
144
+        $intervals = [];
145
+
146
+        while ($start->lte($end)) {
147
+            if ($intervalType === 'month') {
148
+                $intervals[] = $start->format('M Y'); // Example: Jan 2024
149
+                $start->addMonth();
150
+            } elseif ($intervalType === 'quarter') {
151
+                $intervals[] = 'Q' . $start->quarter . ' ' . $start->year; // Example: Q1 2024
152
+                $start->addQuarter();
153
+            } elseif ($intervalType === 'year') {
154
+                $intervals[] = $start->year; // Example: 2024
155
+                $start->addYear();
156
+            }
157
+        }
127 158
 
128
-                break;
129
-            case 'year':
130
-                $headers[] = Header::make('Yearly Budget')->width('20%')->align('right');
159
+        return $intervals;
160
+    }
131 161
 
132
-                break;
162
+    /**
163
+     * Saves budget allocations correctly in `budget_allocations` table.
164
+     */
165
+    public static function saveBudgetAllocations(BudgetItem $record, array $data): void
166
+    {
167
+        $record->update($data);
168
+
169
+        $intervals = self::generateIntervals($data['start_date'], $data['end_date'], $data['interval_type']);
170
+
171
+        foreach ($intervals as $interval) {
172
+            $record->allocations()->updateOrCreate(
173
+                ['period' => $interval],
174
+                [
175
+                    'interval_type' => $data['interval_type'],
176
+                    'start_date' => Carbon::parse($interval)->startOfMonth(),
177
+                    'end_date' => Carbon::parse($interval)->endOfMonth(),
178
+                    'amount' => $data['allocations'][$interval] ?? 0,
179
+                ]
180
+            );
133 181
         }
134
-
135
-        return $headers;
136 182
     }
137 183
 
138 184
     public static function getRelations(): array

+ 4
- 1
resources/data/lang/en.json Parādīt failu

@@ -197,5 +197,8 @@
197 197
     "account": "account",
198 198
     "currency": "currency",
199 199
     "Estimate": "Estimate",
200
-    "Column Labels": "Column Labels"
200
+    "Column Labels": "Column Labels",
201
+    "Budget Details": "Budget Details",
202
+    "Budget Items": "Budget Items",
203
+    "Budget Allocations": "Budget Allocations"
201 204
 }

Notiek ielāde…
Atcelt
Saglabāt