Andrew Wallo 5 个月前
父节点
当前提交
d7f6231361

+ 3
- 18
app/Concerns/HasTransactionAction.php 查看文件

@@ -2,11 +2,9 @@
2 2
 
3 3
 namespace App\Concerns;
4 4
 
5
-use App\Enums\Accounting\AccountCategory;
6 5
 use App\Enums\Accounting\JournalEntryType;
7 6
 use App\Enums\Accounting\TransactionType;
8 7
 use App\Filament\Forms\Components\CustomTableRepeater;
9
-use App\Models\Accounting\Account;
10 8
 use App\Models\Accounting\JournalEntry;
11 9
 use App\Models\Accounting\Transaction;
12 10
 use App\Models\Banking\BankAccount;
@@ -60,7 +58,7 @@ trait HasTransactionAction
60 58
     {
61 59
         return [
62 60
             'type' => $journalEntryType,
63
-            'account_id' => static::getUncategorizedAccountByType($journalEntryType->isDebit() ? TransactionType::Withdrawal : TransactionType::Deposit)?->id,
61
+            'account_id' => Transaction::getUncategorizedAccountByType($journalEntryType->isDebit() ? TransactionType::Withdrawal : TransactionType::Deposit)?->id,
64 62
             'amount' => '0.00',
65 63
         ];
66 64
     }
@@ -71,7 +69,7 @@ trait HasTransactionAction
71 69
             'type' => $type,
72 70
             'bank_account_id' => BankAccount::where('enabled', true)->first()?->id,
73 71
             'amount' => '0.00',
74
-            'account_id' => ! $type->isTransfer() ? static::getUncategorizedAccountByType($type)->id : null,
72
+            'account_id' => ! $type->isTransfer() ? Transaction::getUncategorizedAccountByType($type)->id : null,
75 73
         ];
76 74
     }
77 75
 
@@ -109,7 +107,7 @@ trait HasTransactionAction
109 107
                         TransactionType::Withdrawal->value => TransactionType::Withdrawal->getLabel(),
110 108
                     ])
111 109
                     ->required()
112
-                    ->afterStateUpdated(static fn (Forms\Set $set, $state) => $set('account_id', static::getUncategorizedAccountByType(TransactionType::parse($state))?->id)),
110
+                    ->afterStateUpdated(static fn (Forms\Set $set, $state) => $set('account_id', Transaction::getUncategorizedAccountByType(TransactionType::parse($state))?->id)),
113 111
                 Forms\Components\TextInput::make('amount')
114 112
                     ->label('Amount')
115 113
                     ->money(static fn (Forms\Get $get) => BankAccount::find($get('bank_account_id'))?->account?->currency_code ?? CurrencyAccessor::getDefaultCurrency())
@@ -389,17 +387,4 @@ trait HasTransactionAction
389 387
             ],
390 388
         );
391 389
     }
392
-
393
-    public static function getUncategorizedAccountByType(TransactionType $type): ?Account
394
-    {
395
-        [$category, $accountName] = match ($type) {
396
-            TransactionType::Deposit => [AccountCategory::Revenue, 'Uncategorized Income'],
397
-            TransactionType::Withdrawal => [AccountCategory::Expense, 'Uncategorized Expense'],
398
-            default => [null, null],
399
-        };
400
-
401
-        return Account::where('category', $category)
402
-            ->where('name', $accountName)
403
-            ->first();
404
-    }
405 390
 }

+ 0
- 880
app/Filament/Company/Pages/Accounting/Transactions.php 查看文件

@@ -1,880 +0,0 @@
1
-<?php
2
-
3
-namespace App\Filament\Company\Pages\Accounting;
4
-
5
-use App\Concerns\HasJournalEntryActions;
6
-use App\Enums\Accounting\AccountCategory;
7
-use App\Enums\Accounting\JournalEntryType;
8
-use App\Enums\Accounting\TransactionType;
9
-use App\Facades\Accounting;
10
-use App\Filament\Company\Pages\Service\ConnectedAccount;
11
-use App\Filament\Forms\Components\CustomTableRepeater;
12
-use App\Filament\Forms\Components\DateRangeSelect;
13
-use App\Filament\Tables\Actions\ReplicateBulkAction;
14
-use App\Models\Accounting\Account;
15
-use App\Models\Accounting\JournalEntry;
16
-use App\Models\Accounting\Transaction;
17
-use App\Models\Banking\BankAccount;
18
-use App\Models\Company;
19
-use App\Services\PlaidService;
20
-use App\Utilities\Currency\CurrencyAccessor;
21
-use App\Utilities\Currency\CurrencyConverter;
22
-use Awcodes\TableRepeater\Header;
23
-use Exception;
24
-use Filament\Actions;
25
-use Filament\Facades\Filament;
26
-use Filament\Forms;
27
-use Filament\Forms\Components\Actions\Action as FormAction;
28
-use Filament\Forms\Components\DatePicker;
29
-use Filament\Forms\Components\Grid;
30
-use Filament\Forms\Components\Select;
31
-use Filament\Forms\Components\Tabs;
32
-use Filament\Forms\Components\Tabs\Tab;
33
-use Filament\Forms\Components\Textarea;
34
-use Filament\Forms\Components\TextInput;
35
-use Filament\Forms\Form;
36
-use Filament\Forms\Get;
37
-use Filament\Forms\Set;
38
-use Filament\Notifications\Notification;
39
-use Filament\Pages\Page;
40
-use Filament\Support\Colors\Color;
41
-use Filament\Support\Enums\FontWeight;
42
-use Filament\Support\Enums\IconPosition;
43
-use Filament\Support\Enums\IconSize;
44
-use Filament\Support\Enums\MaxWidth;
45
-use Filament\Tables;
46
-use Filament\Tables\Concerns\InteractsWithTable;
47
-use Filament\Tables\Contracts\HasTable;
48
-use Filament\Tables\Table;
49
-use Illuminate\Contracts\View\View;
50
-use Illuminate\Database\Eloquent\Builder;
51
-use Illuminate\Support\Carbon;
52
-use Illuminate\Support\Collection;
53
-use Illuminate\Support\Str;
54
-
55
-/**
56
- * @property Form $form
57
- */
58
-class Transactions extends Page implements HasTable
59
-{
60
-    use HasJournalEntryActions;
61
-    use InteractsWithTable;
62
-
63
-    protected static string $view = 'filament.company.pages.accounting.transactions';
64
-
65
-    protected static ?string $model = Transaction::class;
66
-
67
-    protected static ?string $navigationGroup = 'Accounting';
68
-
69
-    public string $fiscalYearStartDate = '';
70
-
71
-    public string $fiscalYearEndDate = '';
72
-
73
-    public function mount(): void
74
-    {
75
-        /** @var Company $company */
76
-        $company = Filament::getTenant();
77
-        $this->fiscalYearStartDate = $company->locale->fiscalYearStartDate();
78
-        $this->fiscalYearEndDate = $company->locale->fiscalYearEndDate();
79
-    }
80
-
81
-    public static function getModel(): string
82
-    {
83
-        return static::$model;
84
-    }
85
-
86
-    public static function getEloquentQuery(): Builder
87
-    {
88
-        return static::getModel()::query();
89
-    }
90
-
91
-    public function getMaxContentWidth(): MaxWidth | string | null
92
-    {
93
-        return 'max-w-8xl';
94
-    }
95
-
96
-    protected function getHeaderActions(): array
97
-    {
98
-        return [
99
-            $this->buildTransactionAction('addIncome', 'Add income', TransactionType::Deposit),
100
-            $this->buildTransactionAction('addExpense', 'Add expense', TransactionType::Withdrawal),
101
-            Actions\CreateAction::make('addTransfer')
102
-                ->label('Add transfer')
103
-                ->modalHeading('Add Transfer')
104
-                ->modalWidth(MaxWidth::ThreeExtraLarge)
105
-                ->model(static::getModel())
106
-                ->fillForm(fn (): array => $this->getFormDefaultsForType(TransactionType::Transfer))
107
-                ->form(fn (Form $form) => $this->transferForm($form))
108
-                ->button()
109
-                ->outlined(),
110
-            Actions\ActionGroup::make([
111
-                Actions\CreateAction::make('addJournalTransaction')
112
-                    ->label('Add journal transaction')
113
-                    ->fillForm(fn (): array => $this->getFormDefaultsForType(TransactionType::Journal))
114
-                    ->modalWidth(MaxWidth::Screen)
115
-                    ->extraModalWindowAttributes([
116
-                        'class' => 'journal-transaction-modal',
117
-                    ])
118
-                    ->model(static::getModel())
119
-                    ->form(fn (Form $form) => $this->journalTransactionForm($form))
120
-                    ->modalSubmitAction(fn (Actions\StaticAction $action) => $action->disabled(! $this->isJournalEntryBalanced()))
121
-                    ->groupedIcon(null)
122
-                    ->modalHeading('Journal Entry')
123
-                    ->mutateFormDataUsing(static fn (array $data) => array_merge($data, ['type' => TransactionType::Journal]))
124
-                    ->afterFormFilled(fn () => $this->resetJournalEntryAmounts())
125
-                    ->after(fn (Transaction $transaction) => $transaction->updateAmountIfBalanced()),
126
-                Actions\Action::make('connectBank')
127
-                    ->label('Connect your bank')
128
-                    ->visible(app(PlaidService::class)->isEnabled())
129
-                    ->url(ConnectedAccount::getUrl()),
130
-            ])
131
-                ->label('More')
132
-                ->button()
133
-                ->outlined()
134
-                ->dropdownWidth('max-w-fit')
135
-                ->dropdownPlacement('bottom-end')
136
-                ->icon('heroicon-c-chevron-down')
137
-                ->iconSize(IconSize::Small)
138
-                ->iconPosition(IconPosition::After),
139
-        ];
140
-    }
141
-
142
-    public function transferForm(Form $form): Form
143
-    {
144
-        return $form
145
-            ->schema([
146
-                Forms\Components\DatePicker::make('posted_at')
147
-                    ->label('Date')
148
-                    ->required(),
149
-                Forms\Components\TextInput::make('description')
150
-                    ->label('Description'),
151
-                Forms\Components\Select::make('bank_account_id')
152
-                    ->label('From account')
153
-                    ->options(fn (Get $get, ?Transaction $transaction) => $this->getBankAccountOptions(excludedAccountId: $get('account_id'), currentBankAccountId: $transaction?->bank_account_id))
154
-                    ->live()
155
-                    ->searchable()
156
-                    ->afterStateUpdated(function (Set $set, $state, $old, Get $get) {
157
-                        $amount = CurrencyConverter::convertAndSet(
158
-                            BankAccount::find($state)->account->currency_code,
159
-                            BankAccount::find($old)->account->currency_code ?? CurrencyAccessor::getDefaultCurrency(),
160
-                            $get('amount')
161
-                        );
162
-
163
-                        if ($amount !== null) {
164
-                            $set('amount', $amount);
165
-                        }
166
-                    })
167
-                    ->required(),
168
-                Forms\Components\Select::make('type')
169
-                    ->label('Type')
170
-                    ->options([
171
-                        TransactionType::Transfer->value => TransactionType::Transfer->getLabel(),
172
-                    ])
173
-                    ->disabled()
174
-                    ->dehydrated()
175
-                    ->required(),
176
-                Forms\Components\TextInput::make('amount')
177
-                    ->label('Amount')
178
-                    ->money(static fn (Forms\Get $get) => BankAccount::find($get('bank_account_id'))?->account?->currency_code ?? CurrencyAccessor::getDefaultCurrency())
179
-                    ->required(),
180
-                Forms\Components\Select::make('account_id')
181
-                    ->label('To account')
182
-                    ->live()
183
-                    ->options(fn (Get $get, ?Transaction $transaction) => $this->getBankAccountAccountOptions(excludedBankAccountId: $get('bank_account_id'), currentAccountId: $transaction?->account_id))
184
-                    ->searchable()
185
-                    ->required(),
186
-                Forms\Components\Textarea::make('notes')
187
-                    ->label('Notes')
188
-                    ->autosize()
189
-                    ->rows(10)
190
-                    ->columnSpanFull(),
191
-            ])
192
-            ->columns();
193
-    }
194
-
195
-    public function transactionForm(Form $form): Form
196
-    {
197
-        return $form
198
-            ->schema([
199
-                Forms\Components\DatePicker::make('posted_at')
200
-                    ->label('Date')
201
-                    ->required(),
202
-                Forms\Components\TextInput::make('description')
203
-                    ->label('Description'),
204
-                Forms\Components\Select::make('bank_account_id')
205
-                    ->label('Account')
206
-                    ->options(fn (?Transaction $transaction) => $this->getBankAccountOptions(currentBankAccountId: $transaction?->bank_account_id))
207
-                    ->live()
208
-                    ->searchable()
209
-                    ->afterStateUpdated(function (Set $set, $state, $old, Get $get) {
210
-                        $amount = CurrencyConverter::convertAndSet(
211
-                            BankAccount::find($state)->account->currency_code,
212
-                            BankAccount::find($old)->account->currency_code ?? CurrencyAccessor::getDefaultCurrency(),
213
-                            $get('amount')
214
-                        );
215
-
216
-                        if ($amount !== null) {
217
-                            $set('amount', $amount);
218
-                        }
219
-                    })
220
-                    ->required(),
221
-                Forms\Components\Select::make('type')
222
-                    ->label('Type')
223
-                    ->live()
224
-                    ->options([
225
-                        TransactionType::Deposit->value => TransactionType::Deposit->getLabel(),
226
-                        TransactionType::Withdrawal->value => TransactionType::Withdrawal->getLabel(),
227
-                    ])
228
-                    ->required()
229
-                    ->afterStateUpdated(static fn (Forms\Set $set, $state) => $set('account_id', static::getUncategorizedAccountByType(TransactionType::parse($state))?->id)),
230
-                Forms\Components\TextInput::make('amount')
231
-                    ->label('Amount')
232
-                    ->money(static fn (Forms\Get $get) => BankAccount::find($get('bank_account_id'))?->account?->currency_code ?? CurrencyAccessor::getDefaultCurrency())
233
-                    ->required(),
234
-                Forms\Components\Select::make('account_id')
235
-                    ->label('Category')
236
-                    ->options(fn (Forms\Get $get, ?Transaction $transaction) => $this->getChartAccountOptions(type: TransactionType::parse($get('type')), nominalAccountsOnly: true, currentAccountId: $transaction?->account_id))
237
-                    ->searchable()
238
-                    ->preload()
239
-                    ->required(),
240
-                Forms\Components\Textarea::make('notes')
241
-                    ->label('Notes')
242
-                    ->autosize()
243
-                    ->rows(10)
244
-                    ->columnSpanFull(),
245
-            ])
246
-            ->columns();
247
-    }
248
-
249
-    public function journalTransactionForm(Form $form): Form
250
-    {
251
-        return $form
252
-            ->schema([
253
-                Tabs::make('Tabs')
254
-                    ->contained(false)
255
-                    ->tabs([
256
-                        $this->getJournalTransactionFormEditTab(),
257
-                        $this->getJournalTransactionFormNotesTab(),
258
-                    ]),
259
-            ])
260
-            ->columns(1);
261
-    }
262
-
263
-    /**
264
-     * @throws Exception
265
-     */
266
-    public function table(Table $table): Table
267
-    {
268
-        return $table
269
-            ->query(static::getEloquentQuery())
270
-            ->modifyQueryUsing(function (Builder $query) {
271
-                $query->with([
272
-                    'account',
273
-                    'bankAccount.account',
274
-                    'journalEntries.account',
275
-                ])
276
-                    ->where(function (Builder $query) {
277
-                        $query->whereNull('transactionable_id')
278
-                            ->orWhere('is_payment', true);
279
-                    });
280
-            })
281
-            ->columns([
282
-                Tables\Columns\TextColumn::make('posted_at')
283
-                    ->label('Date')
284
-                    ->sortable()
285
-                    ->defaultDateFormat(),
286
-                Tables\Columns\TextColumn::make('type')
287
-                    ->label('Type')
288
-                    ->sortable()
289
-                    ->toggleable(isToggledHiddenByDefault: true),
290
-                Tables\Columns\TextColumn::make('description')
291
-                    ->label('Description')
292
-                    ->limit(50)
293
-                    ->toggleable(),
294
-                Tables\Columns\TextColumn::make('bankAccount.account.name')
295
-                    ->label('Account')
296
-                    ->toggleable(),
297
-                Tables\Columns\TextColumn::make('account.name')
298
-                    ->label('Category')
299
-                    ->prefix(static fn (Transaction $transaction) => $transaction->type->isTransfer() ? 'Transfer to ' : null)
300
-                    ->toggleable()
301
-                    ->state(static fn (Transaction $transaction) => $transaction->account->name ?? 'Journal Entry'),
302
-                Tables\Columns\TextColumn::make('amount')
303
-                    ->label('Amount')
304
-                    ->weight(static fn (Transaction $transaction) => $transaction->reviewed ? null : FontWeight::SemiBold)
305
-                    ->color(
306
-                        static fn (Transaction $transaction) => match ($transaction->type) {
307
-                            TransactionType::Deposit => Color::rgb('rgb(' . Color::Green[700] . ')'),
308
-                            TransactionType::Journal => 'primary',
309
-                            default => null,
310
-                        }
311
-                    )
312
-                    ->sortable()
313
-                    ->currency(static fn (Transaction $transaction) => $transaction->bankAccount?->account->currency_code),
314
-            ])
315
-            ->recordClasses(static fn (Transaction $transaction) => $transaction->reviewed ? 'bg-primary-300/10' : null)
316
-            ->defaultSort('posted_at', 'desc')
317
-            ->filters([
318
-                Tables\Filters\SelectFilter::make('bank_account_id')
319
-                    ->label('Account')
320
-                    ->searchable()
321
-                    ->options(fn () => $this->getBankAccountOptions(false)),
322
-                Tables\Filters\SelectFilter::make('account_id')
323
-                    ->label('Category')
324
-                    ->multiple()
325
-                    ->options(fn () => $this->getChartAccountOptions(nominalAccountsOnly: false)),
326
-                Tables\Filters\TernaryFilter::make('reviewed')
327
-                    ->label('Status')
328
-                    ->native(false)
329
-                    ->trueLabel('Reviewed')
330
-                    ->falseLabel('Not Reviewed'),
331
-                Tables\Filters\SelectFilter::make('type')
332
-                    ->label('Type')
333
-                    ->native(false)
334
-                    ->options(TransactionType::class),
335
-                $this->buildDateRangeFilter('posted_at', 'Posted', true),
336
-                $this->buildDateRangeFilter('updated_at', 'Last modified'),
337
-            ])
338
-            ->filtersFormSchema(fn (array $filters): array => [
339
-                Grid::make()
340
-                    ->schema([
341
-                        $filters['bank_account_id'],
342
-                        $filters['account_id'],
343
-                        $filters['reviewed'],
344
-                        $filters['type'],
345
-                    ])
346
-                    ->columnSpanFull()
347
-                    ->extraAttributes(['class' => 'border-b border-gray-200 dark:border-white/10 pb-8']),
348
-                $filters['posted_at'],
349
-                $filters['updated_at'],
350
-            ])
351
-            ->filtersFormWidth(MaxWidth::ThreeExtraLarge)
352
-            ->actions([
353
-                Tables\Actions\Action::make('markAsReviewed')
354
-                    ->label('Mark as reviewed')
355
-                    ->view('filament.company.components.tables.actions.mark-as-reviewed')
356
-                    ->icon(static fn (Transaction $transaction) => $transaction->reviewed ? 'heroicon-s-check-circle' : 'heroicon-o-check-circle')
357
-                    ->color(static fn (Transaction $transaction, Tables\Actions\Action $action) => match (static::determineTransactionState($transaction, $action)) {
358
-                        'reviewed' => 'primary',
359
-                        'unreviewed' => Color::rgb('rgb(' . Color::Gray[600] . ')'),
360
-                        'uncategorized' => 'gray',
361
-                    })
362
-                    ->tooltip(static fn (Transaction $transaction, Tables\Actions\Action $action) => match (static::determineTransactionState($transaction, $action)) {
363
-                        'reviewed' => 'Reviewed',
364
-                        'unreviewed' => 'Mark as reviewed',
365
-                        'uncategorized' => 'Categorize first to mark as reviewed',
366
-                    })
367
-                    ->disabled(fn (Transaction $transaction): bool => $transaction->isUncategorized())
368
-                    ->action(fn (Transaction $transaction) => $transaction->update(['reviewed' => ! $transaction->reviewed])),
369
-                Tables\Actions\ActionGroup::make([
370
-                    Tables\Actions\ActionGroup::make([
371
-                        Tables\Actions\EditAction::make('editTransaction')
372
-                            ->label('Edit transaction')
373
-                            ->modalHeading('Edit Transaction')
374
-                            ->modalWidth(MaxWidth::ThreeExtraLarge)
375
-                            ->form(fn (Form $form) => $this->transactionForm($form))
376
-                            ->visible(static fn (Transaction $transaction) => $transaction->type->isStandard() && ! $transaction->transactionable_id),
377
-                        Tables\Actions\EditAction::make('editTransfer')
378
-                            ->label('Edit transfer')
379
-                            ->modalHeading('Edit Transfer')
380
-                            ->modalWidth(MaxWidth::ThreeExtraLarge)
381
-                            ->form(fn (Form $form) => $this->transferForm($form))
382
-                            ->visible(static fn (Transaction $transaction) => $transaction->type->isTransfer()),
383
-                        Tables\Actions\EditAction::make('editJournalTransaction')
384
-                            ->label('Edit journal transaction')
385
-                            ->modalHeading('Journal Entry')
386
-                            ->modalWidth(MaxWidth::Screen)
387
-                            ->extraModalWindowAttributes([
388
-                                'class' => 'journal-transaction-modal',
389
-                            ])
390
-                            ->form(fn (Form $form) => $this->journalTransactionForm($form))
391
-                            ->afterFormFilled(function (Transaction $transaction) {
392
-                                $debitAmounts = $transaction->journalEntries->sumDebits()->getAmount();
393
-                                $creditAmounts = $transaction->journalEntries->sumCredits()->getAmount();
394
-
395
-                                $this->setDebitAmount($debitAmounts);
396
-                                $this->setCreditAmount($creditAmounts);
397
-                            })
398
-                            ->modalSubmitAction(fn (Actions\StaticAction $action) => $action->disabled(! $this->isJournalEntryBalanced()))
399
-                            ->after(fn (Transaction $transaction) => $transaction->updateAmountIfBalanced())
400
-                            ->visible(static fn (Transaction $transaction) => $transaction->type->isJournal() && ! $transaction->transactionable_id),
401
-                        Tables\Actions\ReplicateAction::make()
402
-                            ->excludeAttributes(['created_by', 'updated_by', 'created_at', 'updated_at'])
403
-                            ->modal(false)
404
-                            ->beforeReplicaSaved(static function (Transaction $replica) {
405
-                                $replica->description = '(Copy of) ' . $replica->description;
406
-                            })
407
-                            ->hidden(static fn (Transaction $transaction) => $transaction->transactionable_id)
408
-                            ->after(static function (Transaction $original, Transaction $replica) {
409
-                                $original->journalEntries->each(function (JournalEntry $entry) use ($replica) {
410
-                                    $entry->replicate([
411
-                                        'transaction_id',
412
-                                    ])->fill([
413
-                                        'transaction_id' => $replica->id,
414
-                                    ])->save();
415
-                                });
416
-                            }),
417
-                    ])->dropdown(false),
418
-                    Tables\Actions\DeleteAction::make(),
419
-                ]),
420
-            ])
421
-            ->bulkActions([
422
-                Tables\Actions\BulkActionGroup::make([
423
-                    Tables\Actions\DeleteBulkAction::make(),
424
-                    ReplicateBulkAction::make()
425
-                        ->label('Replicate')
426
-                        ->modalWidth(MaxWidth::Large)
427
-                        ->modalDescription('Replicating transactions will also replicate their journal entries. Are you sure you want to proceed?')
428
-                        ->successNotificationTitle('Transactions replicated successfully')
429
-                        ->failureNotificationTitle('Failed to replicate transactions')
430
-                        ->deselectRecordsAfterCompletion()
431
-                        ->excludeAttributes(['created_by', 'updated_by', 'created_at', 'updated_at'])
432
-                        ->beforeReplicaSaved(static function (Transaction $replica) {
433
-                            $replica->description = '(Copy of) ' . $replica->description;
434
-                        })
435
-                        ->before(function (\Illuminate\Database\Eloquent\Collection $records, ReplicateBulkAction $action) {
436
-                            $isInvalid = $records->contains(fn (Transaction $record) => $record->transactionable_id);
437
-
438
-                            if ($isInvalid) {
439
-                                Notification::make()
440
-                                    ->title('Cannot replicate transactions')
441
-                                    ->body('You cannot replicate transactions associated with bills or invoices')
442
-                                    ->persistent()
443
-                                    ->danger()
444
-                                    ->send();
445
-
446
-                                $action->cancel(true);
447
-                            }
448
-                        })
449
-                        ->withReplicatedRelationships(['journalEntries']),
450
-                ]),
451
-            ]);
452
-    }
453
-
454
-    protected function buildTransactionAction(string $name, string $label, TransactionType $type): Actions\CreateAction
455
-    {
456
-        return Actions\CreateAction::make($name)
457
-            ->label($label)
458
-            ->modalWidth(MaxWidth::ThreeExtraLarge)
459
-            ->model(static::getModel())
460
-            ->fillForm(fn (): array => $this->getFormDefaultsForType($type))
461
-            ->form(fn (Form $form) => $this->transactionForm($form))
462
-            ->button()
463
-            ->outlined();
464
-    }
465
-
466
-    protected function getFormDefaultsForType(TransactionType $type): array
467
-    {
468
-        $commonDefaults = [
469
-            'posted_at' => today(),
470
-        ];
471
-
472
-        return match ($type) {
473
-            TransactionType::Deposit, TransactionType::Withdrawal, TransactionType::Transfer => array_merge($commonDefaults, $this->transactionDefaults($type)),
474
-            TransactionType::Journal => array_merge($commonDefaults, $this->journalEntryDefaults()),
475
-        };
476
-    }
477
-
478
-    protected function journalEntryDefaults(): array
479
-    {
480
-        return [
481
-            'journalEntries' => [
482
-                $this->defaultEntry(JournalEntryType::Debit),
483
-                $this->defaultEntry(JournalEntryType::Credit),
484
-            ],
485
-        ];
486
-    }
487
-
488
-    protected function defaultEntry(JournalEntryType $journalEntryType): array
489
-    {
490
-        return [
491
-            'type' => $journalEntryType,
492
-            'account_id' => static::getUncategorizedAccountByType($journalEntryType->isDebit() ? TransactionType::Withdrawal : TransactionType::Deposit)?->id,
493
-            'amount' => '0.00',
494
-        ];
495
-    }
496
-
497
-    protected function transactionDefaults(TransactionType $type): array
498
-    {
499
-        return [
500
-            'type' => $type,
501
-            'bank_account_id' => BankAccount::where('enabled', true)->first()?->id,
502
-            'amount' => '0.00',
503
-            'account_id' => ! $type->isTransfer() ? static::getUncategorizedAccountByType($type)->id : null,
504
-        ];
505
-    }
506
-
507
-    public static function getUncategorizedAccountByType(TransactionType $type): ?Account
508
-    {
509
-        [$category, $accountName] = match ($type) {
510
-            TransactionType::Deposit => [AccountCategory::Revenue, 'Uncategorized Income'],
511
-            TransactionType::Withdrawal => [AccountCategory::Expense, 'Uncategorized Expense'],
512
-            default => [null, null],
513
-        };
514
-
515
-        return Account::where('category', $category)
516
-            ->where('name', $accountName)
517
-            ->first();
518
-    }
519
-
520
-    protected function getJournalTransactionFormEditTab(): Tab
521
-    {
522
-        return Tab::make('Edit')
523
-            ->label('Edit')
524
-            ->icon('heroicon-o-pencil-square')
525
-            ->schema([
526
-                $this->getTransactionDetailsGrid(),
527
-                $this->getJournalEntriesTableRepeater(),
528
-            ]);
529
-    }
530
-
531
-    protected function getJournalTransactionFormNotesTab(): Tab
532
-    {
533
-        return Tab::make('Notes')
534
-            ->label('Notes')
535
-            ->icon('heroicon-o-clipboard')
536
-            ->id('notes')
537
-            ->schema([
538
-                $this->getTransactionDetailsGrid(),
539
-                Textarea::make('notes')
540
-                    ->label('Notes')
541
-                    ->rows(10)
542
-                    ->autosize(),
543
-            ]);
544
-    }
545
-
546
-    protected function getTransactionDetailsGrid(): Grid
547
-    {
548
-        return Grid::make(8)
549
-            ->schema([
550
-                DatePicker::make('posted_at')
551
-                    ->label('Date')
552
-                    ->softRequired()
553
-                    ->displayFormat('Y-m-d'),
554
-                TextInput::make('description')
555
-                    ->label('Description')
556
-                    ->columnSpan(2),
557
-            ]);
558
-    }
559
-
560
-    protected function getJournalEntriesTableRepeater(): CustomTableRepeater
561
-    {
562
-        return CustomTableRepeater::make('journalEntries')
563
-            ->relationship('journalEntries')
564
-            ->hiddenLabel()
565
-            ->columns(4)
566
-            ->headers($this->getJournalEntriesTableRepeaterHeaders())
567
-            ->schema($this->getJournalEntriesTableRepeaterSchema())
568
-            ->deletable(fn (CustomTableRepeater $repeater) => $repeater->getItemsCount() > 2)
569
-            ->deleteAction(function (Forms\Components\Actions\Action $action) {
570
-                return $action
571
-                    ->action(function (array $arguments, CustomTableRepeater $component): void {
572
-                        $items = $component->getState();
573
-
574
-                        $amount = $items[$arguments['item']]['amount'];
575
-                        $type = $items[$arguments['item']]['type'];
576
-
577
-                        $this->updateJournalEntryAmount(JournalEntryType::parse($type), '0.00', $amount);
578
-
579
-                        unset($items[$arguments['item']]);
580
-
581
-                        $component->state($items);
582
-
583
-                        $component->callAfterStateUpdated();
584
-                    });
585
-            })
586
-            ->rules([
587
-                function () {
588
-                    return function (string $attribute, $value, \Closure $fail) {
589
-                        if (empty($value) || ! is_array($value)) {
590
-                            $fail('Journal entries are required.');
591
-
592
-                            return;
593
-                        }
594
-
595
-                        $hasDebit = false;
596
-                        $hasCredit = false;
597
-
598
-                        foreach ($value as $entry) {
599
-                            if (! isset($entry['type'])) {
600
-                                continue;
601
-                            }
602
-
603
-                            if (JournalEntryType::parse($entry['type'])->isDebit()) {
604
-                                $hasDebit = true;
605
-                            } elseif (JournalEntryType::parse($entry['type'])->isCredit()) {
606
-                                $hasCredit = true;
607
-                            }
608
-
609
-                            if ($hasDebit && $hasCredit) {
610
-                                break;
611
-                            }
612
-                        }
613
-
614
-                        if (! $hasDebit) {
615
-                            $fail('At least one debit entry is required.');
616
-                        }
617
-
618
-                        if (! $hasCredit) {
619
-                            $fail('At least one credit entry is required.');
620
-                        }
621
-                    };
622
-                },
623
-            ])
624
-            ->minItems(2)
625
-            ->defaultItems(2)
626
-            ->addable(false)
627
-            ->footerItem(fn (): View => $this->getJournalTransactionModalFooter())
628
-            ->extraActions([
629
-                $this->buildAddJournalEntryAction(JournalEntryType::Debit),
630
-                $this->buildAddJournalEntryAction(JournalEntryType::Credit),
631
-            ]);
632
-    }
633
-
634
-    protected function getJournalEntriesTableRepeaterHeaders(): array
635
-    {
636
-        return [
637
-            Header::make('type')
638
-                ->width('150px')
639
-                ->label('Type'),
640
-            Header::make('description')
641
-                ->width('320px')
642
-                ->label('Description'),
643
-            Header::make('account_id')
644
-                ->width('320px')
645
-                ->label('Account'),
646
-            Header::make('amount')
647
-                ->width('192px')
648
-                ->label('Amount'),
649
-        ];
650
-    }
651
-
652
-    protected function getJournalEntriesTableRepeaterSchema(): array
653
-    {
654
-        return [
655
-            Select::make('type')
656
-                ->label('Type')
657
-                ->options(JournalEntryType::class)
658
-                ->live()
659
-                ->afterStateUpdated(function (Get $get, Set $set, $state, $old) {
660
-                    $this->adjustJournalEntryAmountsForTypeChange(JournalEntryType::parse($state), JournalEntryType::parse($old), $get('amount'));
661
-                })
662
-                ->softRequired(),
663
-            TextInput::make('description')
664
-                ->label('Description'),
665
-            Select::make('account_id')
666
-                ->label('Account')
667
-                ->options(fn (?JournalEntry $journalEntry): array => $this->getChartAccountOptions(currentAccountId: $journalEntry?->account_id))
668
-                ->live()
669
-                ->softRequired()
670
-                ->searchable(),
671
-            TextInput::make('amount')
672
-                ->label('Amount')
673
-                ->live()
674
-                ->mask(moneyMask(CurrencyAccessor::getDefaultCurrency()))
675
-                ->afterStateUpdated(function (Get $get, Set $set, ?string $state, ?string $old) {
676
-                    $this->updateJournalEntryAmount(JournalEntryType::parse($get('type')), $state, $old);
677
-                })
678
-                ->softRequired(),
679
-        ];
680
-    }
681
-
682
-    protected function buildAddJournalEntryAction(JournalEntryType $type): FormAction
683
-    {
684
-        $typeLabel = $type->getLabel();
685
-
686
-        return FormAction::make("add{$typeLabel}Entry")
687
-            ->label("Add {$typeLabel} entry")
688
-            ->button()
689
-            ->outlined()
690
-            ->color($type->isDebit() ? 'primary' : 'gray')
691
-            ->iconSize(IconSize::Small)
692
-            ->iconPosition(IconPosition::Before)
693
-            ->action(function (CustomTableRepeater $component) use ($type) {
694
-                $state = $component->getState();
695
-                $newUuid = (string) Str::uuid();
696
-                $state[$newUuid] = $this->defaultEntry($type);
697
-
698
-                $component->state($state);
699
-            });
700
-    }
701
-
702
-    public function getJournalTransactionModalFooter(): View
703
-    {
704
-        return view(
705
-            'filament.company.components.actions.journal-entry-footer',
706
-            [
707
-                'debitAmount' => $this->getFormattedDebitAmount(),
708
-                'creditAmount' => $this->getFormattedCreditAmount(),
709
-                'difference' => $this->getFormattedBalanceDifference(),
710
-                'isJournalBalanced' => $this->isJournalEntryBalanced(),
711
-            ],
712
-        );
713
-    }
714
-
715
-    /**
716
-     * @throws Exception
717
-     */
718
-    protected function buildDateRangeFilter(string $fieldPrefix, string $label, bool $hasBottomBorder = false): Tables\Filters\Filter
719
-    {
720
-        return Tables\Filters\Filter::make($fieldPrefix)
721
-            ->columnSpanFull()
722
-            ->form([
723
-                Grid::make()
724
-                    ->live()
725
-                    ->schema([
726
-                        DateRangeSelect::make("{$fieldPrefix}_date_range")
727
-                            ->label($label)
728
-                            ->selectablePlaceholder(false)
729
-                            ->placeholder('Select a date range')
730
-                            ->startDateField("{$fieldPrefix}_start_date")
731
-                            ->endDateField("{$fieldPrefix}_end_date"),
732
-                        DatePicker::make("{$fieldPrefix}_start_date")
733
-                            ->label("{$label} from")
734
-                            ->columnStart(1)
735
-                            ->afterStateUpdated(static function (Set $set) use ($fieldPrefix) {
736
-                                $set("{$fieldPrefix}_date_range", 'Custom');
737
-                            }),
738
-                        DatePicker::make("{$fieldPrefix}_end_date")
739
-                            ->label("{$label} to")
740
-                            ->afterStateUpdated(static function (Set $set) use ($fieldPrefix) {
741
-                                $set("{$fieldPrefix}_date_range", 'Custom');
742
-                            }),
743
-                    ])
744
-                    ->extraAttributes($hasBottomBorder ? ['class' => 'border-b border-gray-200 dark:border-white/10 pb-8'] : []),
745
-            ])
746
-            ->query(function (Builder $query, array $data) use ($fieldPrefix): Builder {
747
-                $query
748
-                    ->when($data["{$fieldPrefix}_start_date"], fn (Builder $query, $startDate) => $query->whereDate($fieldPrefix, '>=', $startDate))
749
-                    ->when($data["{$fieldPrefix}_end_date"], fn (Builder $query, $endDate) => $query->whereDate($fieldPrefix, '<=', $endDate));
750
-
751
-                return $query;
752
-            })
753
-            ->indicateUsing(function (array $data) use ($fieldPrefix, $label): array {
754
-                $indicators = [];
755
-
756
-                $this->addIndicatorForDateRange($data, "{$fieldPrefix}_start_date", "{$fieldPrefix}_end_date", $label, $indicators);
757
-
758
-                return $indicators;
759
-            });
760
-
761
-    }
762
-
763
-    protected function addIndicatorForSingleSelection($data, $key, $label, &$indicators): void
764
-    {
765
-        if (filled($data[$key])) {
766
-            $indicators[] = Tables\Filters\Indicator::make($label)
767
-                ->removeField($key);
768
-        }
769
-    }
770
-
771
-    protected function addMultipleSelectionIndicator($data, $key, callable $labelRetriever, $field, &$indicators): void
772
-    {
773
-        if (filled($data[$key])) {
774
-            $labels = collect($data[$key])->map($labelRetriever);
775
-            $additionalCount = $labels->count() - 1;
776
-            $indicatorLabel = $additionalCount > 0 ? "{$labels->first()} + {$additionalCount}" : $labels->first();
777
-            $indicators[] = Tables\Filters\Indicator::make($indicatorLabel)
778
-                ->removeField($field);
779
-        }
780
-    }
781
-
782
-    protected function addIndicatorForDateRange($data, $startKey, $endKey, $labelPrefix, &$indicators): void
783
-    {
784
-        $formattedStartDate = filled($data[$startKey]) ? Carbon::parse($data[$startKey])->toFormattedDateString() : null;
785
-        $formattedEndDate = filled($data[$endKey]) ? Carbon::parse($data[$endKey])->toFormattedDateString() : null;
786
-        if ($formattedStartDate && $formattedEndDate) {
787
-            // If both start and end dates are set, show the combined date range as the indicator, no specific field needs to be removed since the entire filter will be removed
788
-            $indicators[] = Tables\Filters\Indicator::make("{$labelPrefix}: {$formattedStartDate} - {$formattedEndDate}");
789
-        } else {
790
-            if ($formattedStartDate) {
791
-                $indicators[] = Tables\Filters\Indicator::make("{$labelPrefix} After: {$formattedStartDate}")
792
-                    ->removeField($startKey);
793
-            }
794
-
795
-            if ($formattedEndDate) {
796
-                $indicators[] = Tables\Filters\Indicator::make("{$labelPrefix} Before: {$formattedEndDate}")
797
-                    ->removeField($endKey);
798
-            }
799
-        }
800
-    }
801
-
802
-    protected static function determineTransactionState(Transaction $transaction, Tables\Actions\Action $action): string
803
-    {
804
-        if ($transaction->reviewed) {
805
-            return 'reviewed';
806
-        }
807
-
808
-        if ($transaction->reviewed === false && $action->isEnabled()) {
809
-            return 'unreviewed';
810
-        }
811
-
812
-        return 'uncategorized';
813
-    }
814
-
815
-    protected function getBankAccountOptions(?int $excludedAccountId = null, ?int $currentBankAccountId = null): array
816
-    {
817
-        return BankAccount::query()
818
-            ->whereHas('account', function (Builder $query) {
819
-                $query->where('archived', false);
820
-            })
821
-            ->with(['account' => function ($query) {
822
-                $query->where('archived', false);
823
-            }, 'account.subtype' => function ($query) {
824
-                $query->select(['id', 'name']);
825
-            }])
826
-            ->when($excludedAccountId, fn (Builder $query) => $query->where('account_id', '!=', $excludedAccountId))
827
-            ->when($currentBankAccountId, fn (Builder $query) => $query->orWhere('id', $currentBankAccountId))
828
-            ->get()
829
-            ->groupBy('account.subtype.name')
830
-            ->map(fn (Collection $bankAccounts, string $subtype) => $bankAccounts->pluck('account.name', 'id'))
831
-            ->toArray();
832
-    }
833
-
834
-    protected function getBankAccountAccountOptions(?int $excludedBankAccountId = null, ?int $currentAccountId = null): array
835
-    {
836
-        return Account::query()
837
-            ->whereHas('bankAccount', function (Builder $query) use ($excludedBankAccountId) {
838
-                // Exclude the specific bank account if provided
839
-                if ($excludedBankAccountId) {
840
-                    $query->whereNot('id', $excludedBankAccountId);
841
-                }
842
-            })
843
-            ->where(function (Builder $query) use ($currentAccountId) {
844
-                $query->where('archived', false)
845
-                    ->orWhere('id', $currentAccountId);
846
-            })
847
-            ->get()
848
-            ->groupBy(fn (Account $account) => $account->category->getPluralLabel())
849
-            ->map(fn (Collection $accounts, string $category) => $accounts->pluck('name', 'id'))
850
-            ->toArray();
851
-    }
852
-
853
-    protected function getChartAccountOptions(?TransactionType $type = null, ?bool $nominalAccountsOnly = null, ?int $currentAccountId = null): array
854
-    {
855
-        $nominalAccountsOnly ??= false;
856
-
857
-        $excludedCategory = match ($type) {
858
-            TransactionType::Deposit => AccountCategory::Expense,
859
-            TransactionType::Withdrawal => AccountCategory::Revenue,
860
-            default => null,
861
-        };
862
-
863
-        return Account::query()
864
-            ->when($nominalAccountsOnly, fn (Builder $query) => $query->doesntHave('bankAccount'))
865
-            ->when($excludedCategory, fn (Builder $query) => $query->whereNot('category', $excludedCategory))
866
-            ->where(function (Builder $query) use ($currentAccountId) {
867
-                $query->where('archived', false)
868
-                    ->orWhere('id', $currentAccountId);
869
-            })
870
-            ->get()
871
-            ->groupBy(fn (Account $account) => $account->category->getPluralLabel())
872
-            ->map(fn (Collection $accounts, string $category) => $accounts->pluck('name', 'id'))
873
-            ->toArray();
874
-    }
875
-
876
-    protected function getBalanceForAllAccounts(): string
877
-    {
878
-        return Accounting::getTotalBalanceForAllBankAccounts($this->fiscalYearStartDate, $this->fiscalYearEndDate)->format();
879
-    }
880
-}

+ 2
- 2
app/Filament/Company/Pages/Reports/AccountTransactions.php 查看文件

@@ -4,7 +4,7 @@ namespace App\Filament\Company\Pages\Reports;
4 4
 
5 5
 use App\Contracts\ExportableReport;
6 6
 use App\DTO\ReportDTO;
7
-use App\Filament\Company\Pages\Accounting\Transactions;
7
+use App\Filament\Company\Resources\Accounting\TransactionResource;
8 8
 use App\Models\Accounting\Account;
9 9
 use App\Models\Common\Client;
10 10
 use App\Models\Common\Vendor;
@@ -194,7 +194,7 @@ class AccountTransactions extends BaseReportPage
194 194
         return [
195 195
             Action::make('createTransaction')
196 196
                 ->label('Create transaction')
197
-                ->url(Transactions::getUrl()),
197
+                ->url(TransactionResource::getUrl()),
198 198
         ];
199 199
     }
200 200
 

+ 13
- 0
app/Models/Accounting/Transaction.php 查看文件

@@ -160,6 +160,19 @@ class Transaction extends Model
160 160
             ->toArray();
161 161
     }
162 162
 
163
+    public static function getUncategorizedAccountByType(TransactionType $type): ?Account
164
+    {
165
+        [$category, $accountName] = match ($type) {
166
+            TransactionType::Deposit => [AccountCategory::Revenue, 'Uncategorized Income'],
167
+            TransactionType::Withdrawal => [AccountCategory::Expense, 'Uncategorized Expense'],
168
+            default => [null, null],
169
+        };
170
+
171
+        return Account::where('category', $category)
172
+            ->where('name', $accountName)
173
+            ->first();
174
+    }
175
+
163 176
     protected static function newFactory(): Factory
164 177
     {
165 178
         return TransactionFactory::new();

+ 0
- 2
app/Providers/Filament/CompanyPanelProvider.php 查看文件

@@ -19,7 +19,6 @@ use App\Actions\FilamentCompanies\UpdateUserPassword;
19 19
 use App\Actions\FilamentCompanies\UpdateUserProfileInformation;
20 20
 use App\Filament\Company\Clusters\Settings;
21 21
 use App\Filament\Company\Pages\Accounting\AccountChart;
22
-use App\Filament\Company\Pages\Accounting\Transactions;
23 22
 use App\Filament\Company\Pages\CreateCompany;
24 23
 use App\Filament\Company\Pages\ManageCompany;
25 24
 use App\Filament\Company\Pages\Reports;
@@ -159,7 +158,6 @@ class CompanyPanelProvider extends PanelProvider
159 158
                             ->items([
160 159
                                 // ...BudgetResource::getNavigationItems(),
161 160
                                 ...AccountChart::getNavigationItems(),
162
-                                ...Transactions::getNavigationItems(),
163 161
                                 ...TransactionResource::getNavigationItems(),
164 162
                             ]),
165 163
                         NavigationGroup::make('Banking')

+ 2
- 2
resources/views/components/company/tables/reports/account-transactions.blade.php 查看文件

@@ -1,6 +1,6 @@
1 1
 @php
2
-    use App\Filament\Company\Pages\Accounting\Transactions;
3 2
     use App\Models\Accounting\Bill;
3
+    use App\Filament\Company\Resources\Accounting\TransactionResource;
4 4
     use App\Filament\Company\Resources\Purchases\BillResource\Pages\ViewBill;
5 5
     use App\Filament\Company\Resources\Sales\InvoiceResource\Pages\ViewInvoice;
6 6
 
@@ -52,7 +52,7 @@
52 52
                                 @if(isset($cell['id']) && $cell['tableAction'])
53 53
                                     @if($cell['tableAction']['type'] === 'transaction')
54 54
                                         <x-filament::link
55
-                                            :href="Transactions::getUrl(parameters: [
55
+                                            :href="TransactionResource::getUrl(parameters: [
56 56
                                                 'tableAction' => $cell['tableAction']['action'],
57 57
                                                 'tableActionRecord' => $cell['tableAction']['id'],
58 58
                                             ])"

+ 0
- 3
resources/views/filament/company/pages/accounting/transactions.blade.php 查看文件

@@ -1,3 +0,0 @@
1
-<x-filament-panels::page>
2
-    {{ $this->table }}
3
-</x-filament-panels::page>

+ 17
- 17
tests/Feature/Accounting/TransactionTest.php 查看文件

@@ -2,7 +2,7 @@
2 2
 
3 3
 use App\Enums\Accounting\JournalEntryType;
4 4
 use App\Enums\Accounting\TransactionType;
5
-use App\Filament\Company\Pages\Accounting\Transactions;
5
+use App\Filament\Company\Resources\Accounting\TransactionResource\Pages\ListTransactions;
6 6
 use App\Filament\Forms\Components\JournalEntryRepeater;
7 7
 use App\Filament\Tables\Actions\ReplicateBulkAction;
8 8
 use App\Models\Accounting\Account;
@@ -227,9 +227,9 @@ it('handles multi-currency withdrawals correctly', function () {
227 227
 it('can add an income or expense transaction', function (TransactionType $transactionType, string $actionName) {
228 228
     $testCompany = $this->testCompany;
229 229
     $defaultBankAccount = $testCompany->default->bankAccount;
230
-    $defaultAccount = Transactions::getUncategorizedAccountByType($transactionType);
230
+    $defaultAccount = Transaction::getUncategorizedAccountByType($transactionType);
231 231
 
232
-    livewire(Transactions::class)
232
+    livewire(ListTransactions::class)
233 233
         ->mountAction($actionName)
234 234
         ->assertActionDataSet([
235 235
             'posted_at' => today(),
@@ -263,7 +263,7 @@ it('can add a transfer transaction', function () {
263 263
     $sourceBankAccount = $testCompany->default->bankAccount;
264 264
     $destinationBankAccount = Account::factory()->withBankAccount('Destination Bank Account')->create();
265 265
 
266
-    livewire(Transactions::class)
266
+    livewire(ListTransactions::class)
267 267
         ->mountAction('addTransfer')
268 268
         ->assertActionDataSet([
269 269
             'posted_at' => today(),
@@ -291,12 +291,12 @@ it('can add a transfer transaction', function () {
291 291
 });
292 292
 
293 293
 it('can add a journal transaction', function () {
294
-    $defaultDebitAccount = Transactions::getUncategorizedAccountByType(TransactionType::Withdrawal);
295
-    $defaultCreditAccount = Transactions::getUncategorizedAccountByType(TransactionType::Deposit);
294
+    $defaultDebitAccount = Transaction::getUncategorizedAccountByType(TransactionType::Withdrawal);
295
+    $defaultCreditAccount = Transaction::getUncategorizedAccountByType(TransactionType::Deposit);
296 296
 
297 297
     $undoRepeaterFake = JournalEntryRepeater::fake();
298 298
 
299
-    livewire(Transactions::class)
299
+    livewire(ListTransactions::class)
300 300
         ->mountAction('addJournalTransaction')
301 301
         ->assertActionDataSet([
302 302
             'posted_at' => today(),
@@ -334,7 +334,7 @@ it('can add a journal transaction', function () {
334 334
 });
335 335
 
336 336
 it('can update a deposit or withdrawal transaction', function (TransactionType $transactionType) {
337
-    $defaultAccount = Transactions::getUncategorizedAccountByType($transactionType);
337
+    $defaultAccount = Transaction::getUncategorizedAccountByType($transactionType);
338 338
 
339 339
     $transaction = Transaction::factory()
340 340
         ->forDefaultBankAccount()
@@ -344,7 +344,7 @@ it('can update a deposit or withdrawal transaction', function (TransactionType $
344 344
 
345 345
     $newDescription = 'Updated Description';
346 346
 
347
-    livewire(Transactions::class)
347
+    livewire(ListTransactions::class)
348 348
         ->mountTableAction('editTransaction', $transaction)
349 349
         ->assertTableActionDataSet([
350 350
             'type' => $transactionType->value,
@@ -368,7 +368,7 @@ it('can update a deposit or withdrawal transaction', function (TransactionType $
368 368
 ]);
369 369
 
370 370
 it('does not show Edit Transfer or Edit Journal Transaction for deposit or withdrawal transactions', function (TransactionType $transactionType) {
371
-    $defaultAccount = Transactions::getUncategorizedAccountByType($transactionType);
371
+    $defaultAccount = Transaction::getUncategorizedAccountByType($transactionType);
372 372
 
373 373
     $transaction = Transaction::factory()
374 374
         ->forDefaultBankAccount()
@@ -376,7 +376,7 @@ it('does not show Edit Transfer or Edit Journal Transaction for deposit or withd
376 376
         ->forType($transactionType, 1000)
377 377
         ->create();
378 378
 
379
-    livewire(Transactions::class)
379
+    livewire(ListTransactions::class)
380 380
         ->assertTableActionHidden('editTransfer', $transaction)
381 381
         ->assertTableActionHidden('editJournalTransaction', $transaction);
382 382
 })->with([
@@ -393,7 +393,7 @@ it('can update a transfer transaction', function () {
393 393
 
394 394
     $newDescription = 'Updated Transfer Description';
395 395
 
396
-    livewire(Transactions::class)
396
+    livewire(ListTransactions::class)
397 397
         ->mountTableAction('editTransfer', $transaction)
398 398
         ->assertTableActionDataSet([
399 399
             'type' => TransactionType::Transfer->value,
@@ -420,7 +420,7 @@ it('does not show Edit Transaction or Edit Journal Transaction for transfer tran
420 420
         ->asTransfer(1500)
421 421
         ->create();
422 422
 
423
-    livewire(Transactions::class)
423
+    livewire(ListTransactions::class)
424 424
         ->assertTableActionHidden('editTransaction', $transaction)
425 425
         ->assertTableActionHidden('editJournalTransaction', $transaction);
426 426
 });
@@ -432,7 +432,7 @@ it('replicates a transaction with correct journal entries', function () {
432 432
         ->asDeposit(1000)
433 433
         ->create();
434 434
 
435
-    livewire(Transactions::class)
435
+    livewire(ListTransactions::class)
436 436
         ->callTableAction(ReplicateAction::class, $originalTransaction);
437 437
 
438 438
     $replicatedTransaction = Transaction::whereKeyNot($originalTransaction->getKey())->first();
@@ -460,7 +460,7 @@ it('bulk replicates transactions with correct journal entries', function () {
460 460
         ->count(3)
461 461
         ->create();
462 462
 
463
-    livewire(Transactions::class)
463
+    livewire(ListTransactions::class)
464 464
         ->callTableBulkAction(ReplicateBulkAction::class, $originalTransactions);
465 465
 
466 466
     $replicatedTransactions = Transaction::whereKeyNot($originalTransactions->modelKeys())->get();
@@ -495,7 +495,7 @@ it('can delete a transaction with journal entries', function () {
495 495
 
496 496
     expect($transaction->journalEntries()->count())->toBe(2);
497 497
 
498
-    livewire(Transactions::class)
498
+    livewire(ListTransactions::class)
499 499
         ->callTableAction(DeleteAction::class, $transaction);
500 500
 
501 501
     $this->assertModelMissing($transaction);
@@ -513,7 +513,7 @@ it('can bulk delete transactions with journal entries', function () {
513 513
 
514 514
     expect($transactions->count())->toBe(3);
515 515
 
516
-    livewire(Transactions::class)
516
+    livewire(ListTransactions::class)
517 517
         ->callTableBulkAction(DeleteBulkAction::class, $transactions);
518 518
 
519 519
     $this->assertDatabaseEmpty('transactions');

正在加载...
取消
保存