瀏覽代碼

refactor: navigation and double-entry accounting

3.x
wallo 1 年之前
父節點
當前提交
ae1a3ff004
共有 33 個檔案被更改,包括 671 行新增394 行删除
  1. 0
    4
      app/Filament/Company/Pages/Accounting/AccountChart.php
  2. 1
    1
      app/Filament/Company/Pages/Reports.php
  3. 2
    5
      app/Filament/Company/Pages/Reports/AccountBalances.php
  4. 0
    4
      app/Filament/Company/Pages/Service/ConnectedAccount.php
  5. 0
    4
      app/Filament/Company/Pages/Service/LiveCurrency.php
  6. 0
    4
      app/Filament/Company/Pages/Setting/Appearance.php
  7. 0
    4
      app/Filament/Company/Pages/Setting/CompanyDefault.php
  8. 0
    4
      app/Filament/Company/Pages/Setting/CompanyProfile.php
  9. 0
    4
      app/Filament/Company/Pages/Setting/Invoice.php
  10. 0
    4
      app/Filament/Company/Pages/Setting/Localization.php
  11. 63
    60
      app/Filament/Company/Resources/Accounting/TransactionResource.php
  12. 0
    11
      app/Filament/Company/Resources/Accounting/TransactionResource/Pages/CreateTransaction.php
  13. 0
    19
      app/Filament/Company/Resources/Accounting/TransactionResource/Pages/EditTransaction.php
  14. 0
    19
      app/Filament/Company/Resources/Accounting/TransactionResource/Pages/ListTransactions.php
  15. 39
    49
      app/Filament/Company/Resources/Accounting/TransactionResource/Pages/ManageTransaction.php
  16. 0
    4
      app/Filament/Company/Resources/Banking/AccountResource.php
  17. 0
    4
      app/Filament/Company/Resources/Core/DepartmentResource.php
  18. 0
    5
      app/Filament/Company/Resources/Setting/CurrencyResource.php
  19. 0
    4
      app/Filament/Company/Resources/Setting/DiscountResource.php
  20. 0
    4
      app/Filament/Company/Resources/Setting/TaxResource.php
  21. 83
    0
      app/Jobs/ProcessTransactionImport.php
  22. 52
    0
      app/Listeners/ConfigureCompanyNavigation.php
  23. 9
    36
      app/Listeners/HandleTransactionImport.php
  24. 1
    2
      app/Models/Accounting/Transaction.php
  25. 4
    4
      app/Observers/TransactionObserver.php
  26. 2
    2
      app/Services/AccountService.php
  27. 6
    8
      app/Services/TransactionService.php
  28. 91
    91
      composer.lock
  29. 268
    0
      config/dompdf.php
  30. 1
    2
      database/migrations/2024_01_01_234943_create_transactions_table.php
  31. 22
    19
      package-lock.json
  32. 4
    13
      resources/views/components/company/reports/account-balances.blade.php
  33. 23
    0
      resources/views/filament/company/components/tables/actions/mark-as-reviewed.blade.php

+ 0
- 4
app/Filament/Company/Pages/Accounting/AccountChart.php 查看文件

26
 
26
 
27
 class AccountChart extends Page
27
 class AccountChart extends Page
28
 {
28
 {
29
-    protected static ?string $navigationIcon = 'heroicon-o-clipboard-document-list';
30
-
31
     protected static ?string $title = 'Chart of Accounts';
29
     protected static ?string $title = 'Chart of Accounts';
32
 
30
 
33
-    protected static ?string $navigationGroup = 'Accounting';
34
-
35
     protected static ?string $slug = 'accounting/chart';
31
     protected static ?string $slug = 'accounting/chart';
36
 
32
 
37
     protected static string $view = 'filament.company.pages.accounting.chart';
33
     protected static string $view = 'filament.company.pages.accounting.chart';

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

11
 
11
 
12
 class Reports extends Page
12
 class Reports extends Page
13
 {
13
 {
14
-    protected static ?string $navigationIcon = 'heroicon-o-document-text';
14
+    protected static ?string $navigationIcon = 'heroicon-o-document-chart-bar';
15
 
15
 
16
     protected static string $view = 'filament.company.pages.reports';
16
     protected static string $view = 'filament.company.pages.reports';
17
 
17
 

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

69
 
69
 
70
     public function loadAccountBalances(): void
70
     public function loadAccountBalances(): void
71
     {
71
     {
72
-        $startTime = microtime(true);
73
         $this->accountBalanceReport = $this->accountService->buildAccountBalanceReport($this->startDate, $this->endDate);
72
         $this->accountBalanceReport = $this->accountService->buildAccountBalanceReport($this->startDate, $this->endDate);
74
-        $endTime = microtime(true);
75
-        $executionTime = ($endTime - $startTime);
76
-        info('Account balance report loaded in ' . $executionTime . ' seconds');
77
     }
73
     }
78
 
74
 
79
     protected function getHeaderActions(): array
75
     protected function getHeaderActions(): array
109
             'accountBalanceReport' => $this->accountBalanceReport,
105
             'accountBalanceReport' => $this->accountBalanceReport,
110
             'startDate' => Carbon::parse($this->startDate)->format('M d, Y'),
106
             'startDate' => Carbon::parse($this->startDate)->format('M d, Y'),
111
             'endDate' => Carbon::parse($this->endDate)->format('M d, Y'),
107
             'endDate' => Carbon::parse($this->endDate)->format('M d, Y'),
112
-        ])->setPaper('a4')->setOption(['defaultFont' => 'sans-serif', 'isPhpEnabled' => true]);
108
+        ])->setPaper('a4');
113
 
109
 
114
         return response()->streamDownload(function () use ($pdf) {
110
         return response()->streamDownload(function () use ($pdf) {
115
             echo $pdf->stream();
111
             echo $pdf->stream();
206
             'Y' => $this->processCalendarYear($param1),
202
             'Y' => $this->processCalendarYear($param1),
207
             'Q' => $this->processCalendarQuarter($param1, $param2),
203
             'Q' => $this->processCalendarQuarter($param1, $param2),
208
             'M' => $this->processMonth("{$param1}-{$param2}"),
204
             'M' => $this->processMonth("{$param1}-{$param2}"),
205
+            'Custom' => null,
209
         };
206
         };
210
     }
207
     }
211
 
208
 

+ 0
- 4
app/Filament/Company/Pages/Service/ConnectedAccount.php 查看文件

10
 
10
 
11
 class ConnectedAccount extends Page
11
 class ConnectedAccount extends Page
12
 {
12
 {
13
-    protected static ?string $navigationIcon = 'heroicon-o-building-library';
14
-
15
     protected static ?string $title = 'Connected Accounts';
13
     protected static ?string $title = 'Connected Accounts';
16
 
14
 
17
-    protected static ?string $navigationGroup = 'Services';
18
-
19
     protected static ?string $slug = 'services/connected-accounts';
15
     protected static ?string $slug = 'services/connected-accounts';
20
 
16
 
21
     protected static string $view = 'filament.company.pages.service.connected-account';
17
     protected static string $view = 'filament.company.pages.service.connected-account';

+ 0
- 4
app/Filament/Company/Pages/Service/LiveCurrency.php 查看文件

12
 
12
 
13
 class LiveCurrency extends Page
13
 class LiveCurrency extends Page
14
 {
14
 {
15
-    protected static ?string $navigationIcon = 'icon-currency-exchange';
16
-
17
     protected static ?string $title = 'Live Currency';
15
     protected static ?string $title = 'Live Currency';
18
 
16
 
19
-    protected static ?string $navigationGroup = 'Services';
20
-
21
     protected static ?string $slug = 'services/live-currency';
17
     protected static ?string $slug = 'services/live-currency';
22
 
18
 
23
     protected static string $view = 'filament.company.pages.service.live-currency';
19
     protected static string $view = 'filament.company.pages.service.live-currency';

+ 0
- 4
app/Filament/Company/Pages/Setting/Appearance.php 查看文件

35
 {
35
 {
36
     use InteractsWithFormActions;
36
     use InteractsWithFormActions;
37
 
37
 
38
-    protected static ?string $navigationIcon = 'heroicon-o-paint-brush';
39
-
40
     protected static ?string $title = 'Appearance';
38
     protected static ?string $title = 'Appearance';
41
 
39
 
42
-    protected static ?string $navigationGroup = 'Settings';
43
-
44
     protected static ?string $slug = 'settings/appearance';
40
     protected static ?string $slug = 'settings/appearance';
45
 
41
 
46
     protected static string $view = 'filament.company.pages.setting.appearance';
42
     protected static string $view = 'filament.company.pages.setting.appearance';

+ 0
- 4
app/Filament/Company/Pages/Setting/CompanyDefault.php 查看文件

34
 {
34
 {
35
     use InteractsWithFormActions;
35
     use InteractsWithFormActions;
36
 
36
 
37
-    protected static ?string $navigationIcon = 'heroicon-o-adjustments-vertical';
38
-
39
-    protected static ?string $navigationGroup = 'Settings';
40
-
41
     protected static ?string $title = 'Default';
37
     protected static ?string $title = 'Default';
42
 
38
 
43
     protected static ?string $slug = 'settings/default';
39
     protected static ?string $slug = 'settings/default';

+ 0
- 4
app/Filament/Company/Pages/Setting/CompanyProfile.php 查看文件

39
 {
39
 {
40
     use InteractsWithFormActions;
40
     use InteractsWithFormActions;
41
 
41
 
42
-    protected static ?string $navigationIcon = 'heroicon-o-building-office-2';
43
-
44
     protected static ?string $title = 'Company Profile';
42
     protected static ?string $title = 'Company Profile';
45
 
43
 
46
-    protected static ?string $navigationGroup = 'Settings';
47
-
48
     protected static ?string $slug = 'settings/company-profile';
44
     protected static ?string $slug = 'settings/company-profile';
49
 
45
 
50
     protected static string $view = 'filament.company.pages.setting.company-profile';
46
     protected static string $view = 'filament.company.pages.setting.company-profile';

+ 0
- 4
app/Filament/Company/Pages/Setting/Invoice.php 查看文件

43
 {
43
 {
44
     use InteractsWithFormActions;
44
     use InteractsWithFormActions;
45
 
45
 
46
-    protected static ?string $navigationIcon = 'heroicon-o-document-duplicate';
47
-
48
     protected static ?string $title = 'Invoice';
46
     protected static ?string $title = 'Invoice';
49
 
47
 
50
-    protected static ?string $navigationGroup = 'Settings';
51
-
52
     protected static ?string $slug = 'settings/invoice';
48
     protected static ?string $slug = 'settings/invoice';
53
 
49
 
54
     protected static string $view = 'filament.company.pages.setting.invoice';
50
     protected static string $view = 'filament.company.pages.setting.invoice';

+ 0
- 4
app/Filament/Company/Pages/Setting/Localization.php 查看文件

38
 {
38
 {
39
     use InteractsWithFormActions;
39
     use InteractsWithFormActions;
40
 
40
 
41
-    protected static ?string $navigationIcon = 'heroicon-o-language';
42
-
43
     protected static ?string $title = 'Localization';
41
     protected static ?string $title = 'Localization';
44
 
42
 
45
-    protected static ?string $navigationGroup = 'Settings';
46
-
47
     protected static ?string $slug = 'settings/localization';
43
     protected static ?string $slug = 'settings/localization';
48
 
44
 
49
     protected static string $view = 'filament.company.pages.setting.localization';
45
     protected static string $view = 'filament.company.pages.setting.localization';

+ 63
- 60
app/Filament/Company/Resources/Accounting/TransactionResource.php 查看文件

3
 namespace App\Filament\Company\Resources\Accounting;
3
 namespace App\Filament\Company\Resources\Accounting;
4
 
4
 
5
 use App\Enums\Accounting\AccountCategory;
5
 use App\Enums\Accounting\AccountCategory;
6
+use App\Enums\Accounting\AccountType;
6
 use App\Enums\DateFormat;
7
 use App\Enums\DateFormat;
7
 use App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
8
 use App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
8
 use App\Models\Accounting\Account;
9
 use App\Models\Accounting\Account;
12
 use Filament\Forms;
13
 use Filament\Forms;
13
 use Filament\Forms\Form;
14
 use Filament\Forms\Form;
14
 use Filament\Resources\Resource;
15
 use Filament\Resources\Resource;
16
+use Filament\Support\Colors\Color;
15
 use Filament\Support\Enums\FontWeight;
17
 use Filament\Support\Enums\FontWeight;
16
 use Filament\Support\Enums\MaxWidth;
18
 use Filament\Support\Enums\MaxWidth;
17
 use Filament\Tables;
19
 use Filament\Tables;
23
 {
25
 {
24
     protected static ?string $model = Transaction::class;
26
     protected static ?string $model = Transaction::class;
25
 
27
 
26
-    protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
28
+    protected static ?string $modelLabel = 'Transaction';
27
 
29
 
28
     public static function form(Form $form): Form
30
     public static function form(Form $form): Form
29
     {
31
     {
32
                 Forms\Components\DatePicker::make('posted_at')
34
                 Forms\Components\DatePicker::make('posted_at')
33
                     ->label('Date')
35
                     ->label('Date')
34
                     ->required()
36
                     ->required()
35
-                    ->displayFormat('Y-m-d')
36
-                    ->default(now()->format('Y-m-d')),
37
+                    ->displayFormat('Y-m-d'),
37
                 Forms\Components\TextInput::make('description')
38
                 Forms\Components\TextInput::make('description')
38
                     ->label('Description'),
39
                     ->label('Description'),
39
                 Forms\Components\Select::make('bank_account_id')
40
                 Forms\Components\Select::make('bank_account_id')
40
                     ->label('Account')
41
                     ->label('Account')
41
-                    ->options(fn () => static::getBankAccountOptions())
42
+                    ->options(static fn () => static::getBankAccountOptions())
42
                     ->live()
43
                     ->live()
43
                     ->searchable()
44
                     ->searchable()
44
-                    ->preload()
45
                     ->required(),
45
                     ->required(),
46
-                Forms\Components\Select::make('method')
46
+                Forms\Components\Select::make('type')
47
                     ->label('Type')
47
                     ->label('Type')
48
                     ->live()
48
                     ->live()
49
                     ->options([
49
                     ->options([
50
                         'deposit' => 'Deposit',
50
                         'deposit' => 'Deposit',
51
                         'withdrawal' => 'Withdrawal',
51
                         'withdrawal' => 'Withdrawal',
52
                     ])
52
                     ])
53
-                    ->default('deposit')
54
-                    ->afterStateUpdated(static function (Forms\Set $set, $state) {
55
-                        if ($state === 'deposit') {
56
-                            $account = Account::where('category', AccountCategory::Revenue)
57
-                                ->where('name', 'Uncategorized Income')->first();
58
-
59
-                            if ($account->exists()) {
60
-                                $set('account_id', $account->id);
61
-                            }
62
-                        } else {
63
-                            $account = Account::where('category', AccountCategory::Expense)
64
-                                ->where('name', 'Uncategorized Expense')->first();
65
-
66
-                            if ($account->exists()) {
67
-                                $set('account_id', $account->id);
68
-                            }
69
-                        }
70
-                    })
71
-                    ->required(),
53
+                    ->required()
54
+                    ->afterStateUpdated(static fn (Forms\Set $set, $state) => $set('account_id', Pages\ManageTransaction::getUncategorizedAccountByType($state)?->id)),
72
                 Forms\Components\TextInput::make('amount')
55
                 Forms\Components\TextInput::make('amount')
73
                     ->label('Amount')
56
                     ->label('Amount')
74
-                    ->money(static function (Forms\Get $get) {
75
-                        $bankAccount = $get('bank_account_id');
76
-                        $bankAccount = BankAccount::find($bankAccount);
77
-                        $account = $bankAccount->account ?? null;
78
-
79
-                        if ($account) {
80
-                            return $account->currency_code;
81
-                        }
82
-
83
-                        return 'USD';
84
-                    })
57
+                    ->money(static fn (Forms\Get $get) => BankAccount::find($get('bank_account_id'))?->account?->currency_code ?? 'USD')
85
                     ->required(),
58
                     ->required(),
86
                 Forms\Components\Select::make('account_id')
59
                 Forms\Components\Select::make('account_id')
87
                     ->label('Category')
60
                     ->label('Category')
88
-                    ->options(static fn (Forms\Get $get) => static::getAccountOptions($get('method')))
61
+                    ->options(static fn (Forms\Get $get) => static::getAccountOptions($get('type')))
89
                     ->searchable()
62
                     ->searchable()
90
                     ->preload()
63
                     ->preload()
91
                     ->required(),
64
                     ->required(),
109
 
82
 
110
                         return Carbon::parse($state)->translatedFormat($dateFormat);
83
                         return Carbon::parse($state)->translatedFormat($dateFormat);
111
                     }),
84
                     }),
85
+                Tables\Columns\TextColumn::make('description')
86
+                    ->limit(30)
87
+                    ->label('Description'),
112
                 Tables\Columns\TextColumn::make('bankAccount.account.name')
88
                 Tables\Columns\TextColumn::make('bankAccount.account.name')
113
                     ->label('Account')
89
                     ->label('Account')
114
                     ->sortable(),
90
                     ->sortable(),
115
-                Tables\Columns\TextColumn::make('description')
116
-                    ->limit(50)
117
-                    ->label('Description'),
118
                 Tables\Columns\TextColumn::make('account.name')
91
                 Tables\Columns\TextColumn::make('account.name')
119
                     ->label('Category'),
92
                     ->label('Category'),
120
                 Tables\Columns\TextColumn::make('amount')
93
                 Tables\Columns\TextColumn::make('amount')
121
                     ->label('Amount')
94
                     ->label('Amount')
122
                     ->sortable()
95
                     ->sortable()
123
-                    ->weight(FontWeight::Medium)
124
-                    ->color(static fn (Transaction $record) => $record->type === 'expense' ? 'danger' : null)
96
+                    ->weight(static fn (Transaction $record) => $record->reviewed ? null : FontWeight::SemiBold)
97
+                    ->color(static fn (Transaction $record) => $record->type === 'deposit' ? Color::rgb('rgb(' . Color::Green[700] . ')') : null)
125
                     ->currency(static fn (Transaction $record) => $record->bankAccount->account->currency_code ?? 'USD', true),
98
                     ->currency(static fn (Transaction $record) => $record->bankAccount->account->currency_code ?? 'USD', true),
126
             ])
99
             ])
100
+            ->recordClasses(static fn (Transaction $record) => $record->reviewed ? 'bg-primary-300/10' : null)
127
             ->defaultSort('posted_at', 'desc')
101
             ->defaultSort('posted_at', 'desc')
128
             ->filters([
102
             ->filters([
129
                 //
103
                 //
130
             ])
104
             ])
131
             ->actions([
105
             ->actions([
132
-                Tables\Actions\EditAction::make()
133
-                    ->modalWidth(MaxWidth::ThreeExtraLarge)
134
-                    ->stickyModalHeader()
135
-                    ->stickyModalFooter()
136
-                    ->mutateFormDataUsing(static function (array $data): array {
137
-                        $method = $data['method'];
138
-
139
-                        if ($method === 'deposit') {
140
-                            $data['type'] = 'income';
141
-                        } else {
142
-                            $data['type'] = 'expense';
143
-                        }
144
-
145
-                        return $data;
146
-                    }),
106
+                Tables\Actions\Action::make('markAsReviewed')
107
+                    ->label('Mark as Reviewed')
108
+                    ->view('filament.company.components.tables.actions.mark-as-reviewed')
109
+                    ->icon(static fn (Transaction $record) => $record->reviewed ? 'heroicon-s-check-circle' : 'heroicon-o-check-circle')
110
+                    ->color(static fn (Transaction $record, Tables\Actions\Action $action) => match (static::determineTransactionState($record, $action)) {
111
+                        'reviewed' => 'primary',
112
+                        'unreviewed' => Color::rgb('rgb(' . Color::Gray[600] . ')'),
113
+                        'uncategorized' => 'gray',
114
+                    })
115
+                    ->tooltip(static fn (Transaction $record, Tables\Actions\Action $action) => match (static::determineTransactionState($record, $action)) {
116
+                        'reviewed' => 'Reviewed',
117
+                        'unreviewed' => 'Mark as Reviewed',
118
+                        'uncategorized' => 'Categorize first to mark as reviewed',
119
+                    })
120
+                    ->disabled(static fn (Transaction $record) => in_array($record->account->type, [AccountType::UncategorizedRevenue, AccountType::UncategorizedExpense], true))
121
+                    ->action(fn (Transaction $record) => $record->update(['reviewed' => ! $record->reviewed])),
122
+                Tables\Actions\ActionGroup::make([
123
+                    Tables\Actions\EditAction::make()
124
+                        ->modalWidth(MaxWidth::ThreeExtraLarge)
125
+                        ->stickyModalHeader()
126
+                        ->stickyModalFooter(),
127
+                    Tables\Actions\DeleteAction::make(),
128
+                    Tables\Actions\ReplicateAction::make()
129
+                        ->excludeAttributes(['created_by', 'updated_by', 'created_at', 'updated_at'])
130
+                        ->modal(false)
131
+                        ->beforeReplicaSaved(static function (Transaction $replica) {
132
+                            $replica->description = '(Copy of) ' . $replica->description;
133
+                        }),
134
+                ])
135
+                    ->dropdownPlacement('bottom-start')
136
+                    ->dropdownWidth('max-w-fit'),
147
             ])
137
             ])
148
             ->bulkActions([
138
             ->bulkActions([
149
                 Tables\Actions\BulkActionGroup::make([
139
                 Tables\Actions\BulkActionGroup::make([
152
             ]);
142
             ]);
153
     }
143
     }
154
 
144
 
145
+    protected static function determineTransactionState(Transaction $record, Tables\Actions\Action $action): string
146
+    {
147
+        if ($record->reviewed) {
148
+            return 'reviewed';
149
+        }
150
+
151
+        if ($record->reviewed === false && $action->isEnabled()) {
152
+            return 'unreviewed';
153
+        }
154
+
155
+        return 'uncategorized';
156
+    }
157
+
155
     public static function getRelations(): array
158
     public static function getRelations(): array
156
     {
159
     {
157
         return [
160
         return [
175
             ->toArray();
178
             ->toArray();
176
     }
179
     }
177
 
180
 
178
-    public static function getAccountOptions(mixed $method)
181
+    public static function getAccountOptions(string $type)
179
     {
182
     {
180
-        $excludedCategory = match ($method) {
183
+        $excludedCategory = match ($type) {
181
             'deposit' => AccountCategory::Expense,
184
             'deposit' => AccountCategory::Expense,
182
             'withdrawal' => AccountCategory::Revenue,
185
             'withdrawal' => AccountCategory::Revenue,
183
         };
186
         };
185
         $accounts = Account::whereNot('category', $excludedCategory)->get();
188
         $accounts = Account::whereNot('category', $excludedCategory)->get();
186
 
189
 
187
         return $accounts->groupBy(fn (Account $account) => $account->category->getLabel())
190
         return $accounts->groupBy(fn (Account $account) => $account->category->getLabel())
188
-            ->map(fn (Collection $accounts, string $category) => $accounts->mapWithKeys(fn (Account $account) => [$account->id => $account->name]))
191
+            ->map(fn (Collection $accounts, string $category) => $accounts->mapWithKeys(static fn (Account $account) => [$account->id => $account->name]))
189
             ->toArray();
192
             ->toArray();
190
     }
193
     }
191
 }
194
 }

+ 0
- 11
app/Filament/Company/Resources/Accounting/TransactionResource/Pages/CreateTransaction.php 查看文件

1
-<?php
2
-
3
-namespace App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
4
-
5
-use App\Filament\Company\Resources\Accounting\TransactionResource;
6
-use Filament\Resources\Pages\CreateRecord;
7
-
8
-class CreateTransaction extends CreateRecord
9
-{
10
-    protected static string $resource = TransactionResource::class;
11
-}

+ 0
- 19
app/Filament/Company/Resources/Accounting/TransactionResource/Pages/EditTransaction.php 查看文件

1
-<?php
2
-
3
-namespace App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
4
-
5
-use App\Filament\Company\Resources\Accounting\TransactionResource;
6
-use Filament\Actions;
7
-use Filament\Resources\Pages\EditRecord;
8
-
9
-class EditTransaction extends EditRecord
10
-{
11
-    protected static string $resource = TransactionResource::class;
12
-
13
-    protected function getHeaderActions(): array
14
-    {
15
-        return [
16
-            Actions\DeleteAction::make(),
17
-        ];
18
-    }
19
-}

+ 0
- 19
app/Filament/Company/Resources/Accounting/TransactionResource/Pages/ListTransactions.php 查看文件

1
-<?php
2
-
3
-namespace App\Filament\Company\Resources\Accounting\TransactionResource\Pages;
4
-
5
-use App\Filament\Company\Resources\Accounting\TransactionResource;
6
-use Filament\Actions;
7
-use Filament\Resources\Pages\ListRecords;
8
-
9
-class ListTransactions extends ListRecords
10
-{
11
-    protected static string $resource = TransactionResource::class;
12
-
13
-    protected function getHeaderActions(): array
14
-    {
15
-        return [
16
-            Actions\CreateAction::make(),
17
-        ];
18
-    }
19
-}

+ 39
- 49
app/Filament/Company/Resources/Accounting/TransactionResource/Pages/ManageTransaction.php 查看文件

17
     protected function getHeaderActions(): array
17
     protected function getHeaderActions(): array
18
     {
18
     {
19
         return [
19
         return [
20
-            Actions\CreateAction::make('addIncome')
21
-                ->label('Add Income')
22
-                ->modalWidth(MaxWidth::ThreeExtraLarge)
23
-                ->stickyModalHeader()
24
-                ->stickyModalFooter()
25
-                ->button()
26
-                ->outlined()
27
-                ->fillForm(static fn (): array => [
28
-                    'method' => 'deposit',
29
-                    'posted_at' => now()->format('Y-m-d'),
30
-                    'bank_account_id' => BankAccount::first()->isEnabled() ? BankAccount::first()->id : null,
31
-                    'amount' => '0.00',
32
-                    'account_id' => Account::where('category', AccountCategory::Revenue)->where('name', 'Uncategorized Income')->first()->id,
33
-                ])
34
-                ->mutateFormDataUsing(function (array $data): array {
35
-                    $method = $data['method'];
36
-
37
-                    if ($method === 'deposit') {
38
-                        $data['type'] = 'income';
39
-                    } else {
40
-                        $data['type'] = 'expense';
41
-                    }
42
-
43
-                    return $data;
44
-                }),
45
-            Actions\CreateAction::make('addExpense')
46
-                ->label('Add Expense')
47
-                ->modalWidth(MaxWidth::ThreeExtraLarge)
48
-                ->stickyModalHeader()
49
-                ->stickyModalFooter()
50
-                ->button()
51
-                ->outlined()
52
-                ->fillForm(static fn (): array => [
53
-                    'method' => 'withdrawal',
54
-                    'posted_at' => now()->format('Y-m-d'),
55
-                    'bank_account_id' => BankAccount::first()->isEnabled() ? BankAccount::first()->id : null,
56
-                    'amount' => '0.00',
57
-                    'account_id' => Account::where('category', AccountCategory::Expense)->where('name', 'Uncategorized Expense')->first()->id,
58
-                ])
59
-                ->mutateFormDataUsing(function (array $data): array {
60
-                    $method = $data['method'];
20
+            $this->createAction(
21
+                name: 'addIncome',
22
+                label: 'Add Income',
23
+                type: 'deposit',
24
+            ),
25
+            $this->createAction(
26
+                name: 'addExpense',
27
+                label: 'Add Expense',
28
+                type: 'withdrawal',
29
+            ),
30
+        ];
31
+    }
61
 
32
 
62
-                    if ($method === 'deposit') {
63
-                        $data['type'] = 'income';
64
-                    } else {
65
-                        $data['type'] = 'expense';
66
-                    }
33
+    protected function createAction(string $name, string $label, string $type): Actions\CreateAction
34
+    {
35
+        return Actions\CreateAction::make($name)
36
+            ->label($label)
37
+            ->modalWidth(MaxWidth::ThreeExtraLarge)
38
+            ->stickyModalHeader()
39
+            ->stickyModalFooter()
40
+            ->button()
41
+            ->outlined()
42
+            ->fillForm(static fn (): array => [
43
+                'type' => $type,
44
+                'posted_at' => now()->format('Y-m-d'),
45
+                'bank_account_id' => BankAccount::where('enabled', true)->first()->id ?? null,
46
+                'amount' => '0.00',
47
+                'account_id' => static::getUncategorizedAccountByType($type)?->id,
48
+            ]);
49
+    }
67
 
50
 
68
-                    return $data;
69
-                }),
70
-        ];
51
+    public static function getUncategorizedAccountByType(string $type): ?Account
52
+    {
53
+        [$category, $accountName] = match ($type) {
54
+            'deposit' => [AccountCategory::Revenue, 'Uncategorized Income'],
55
+            'withdrawal' => [AccountCategory::Expense, 'Uncategorized Expense'],
56
+        };
57
+
58
+        return Account::where('category', $category)
59
+            ->where('name', $accountName)
60
+            ->first();
71
     }
61
     }
72
 }
62
 }

+ 0
- 4
app/Filament/Company/Resources/Banking/AccountResource.php 查看文件

33
 
33
 
34
     protected static ?string $modelLabel = 'Account';
34
     protected static ?string $modelLabel = 'Account';
35
 
35
 
36
-    protected static ?string $navigationIcon = 'heroicon-o-credit-card';
37
-
38
-    protected static ?string $navigationGroup = 'Banking';
39
-
40
     public static function getModelLabel(): string
36
     public static function getModelLabel(): string
41
     {
37
     {
42
         $modelLabel = static::$modelLabel;
38
         $modelLabel = static::$modelLabel;

+ 0
- 4
app/Filament/Company/Resources/Core/DepartmentResource.php 查看文件

19
 
19
 
20
     protected static ?string $modelLabel = 'Department';
20
     protected static ?string $modelLabel = 'Department';
21
 
21
 
22
-    protected static ?string $navigationIcon = 'heroicon-o-square-3-stack-3d';
23
-
24
-    protected static ?string $navigationGroup = 'HR';
25
-
26
     protected static ?string $slug = 'hr/departments';
22
     protected static ?string $slug = 'hr/departments';
27
 
23
 
28
     public static function getModelLabel(): string
24
     public static function getModelLabel(): string

+ 0
- 5
app/Filament/Company/Resources/Setting/CurrencyResource.php 查看文件

4
 
4
 
5
 use App\Facades\Forex;
5
 use App\Facades\Forex;
6
 use App\Filament\Company\Resources\Setting\CurrencyResource\Pages;
6
 use App\Filament\Company\Resources\Setting\CurrencyResource\Pages;
7
-use App\Models\Banking\Account;
8
 use App\Models\Setting\Currency;
7
 use App\Models\Setting\Currency;
9
 use App\Models\Setting\Currency as CurrencyModel;
8
 use App\Models\Setting\Currency as CurrencyModel;
10
 use App\Traits\ChecksForeignKeyConstraints;
9
 use App\Traits\ChecksForeignKeyConstraints;
30
 
29
 
31
     protected static ?string $modelLabel = 'Currency';
30
     protected static ?string $modelLabel = 'Currency';
32
 
31
 
33
-    protected static ?string $navigationIcon = 'heroicon-o-currency-dollar';
34
-
35
-    protected static ?string $navigationGroup = 'Settings';
36
-
37
     protected static ?string $slug = 'settings/currencies';
32
     protected static ?string $slug = 'settings/currencies';
38
 
33
 
39
     public static function getModelLabel(): string
34
     public static function getModelLabel(): string

+ 0
- 4
app/Filament/Company/Resources/Setting/DiscountResource.php 查看文件

29
 
29
 
30
     protected static ?string $modelLabel = 'Discount';
30
     protected static ?string $modelLabel = 'Discount';
31
 
31
 
32
-    protected static ?string $navigationIcon = 'heroicon-o-tag';
33
-
34
-    protected static ?string $navigationGroup = 'Settings';
35
-
36
     protected static ?string $slug = 'settings/discounts';
32
     protected static ?string $slug = 'settings/discounts';
37
 
33
 
38
     public static function getModelLabel(): string
34
     public static function getModelLabel(): string

+ 0
- 4
app/Filament/Company/Resources/Setting/TaxResource.php 查看文件

26
 
26
 
27
     protected static ?string $modelLabel = 'Tax';
27
     protected static ?string $modelLabel = 'Tax';
28
 
28
 
29
-    protected static ?string $navigationIcon = 'heroicon-o-receipt-percent';
30
-
31
-    protected static ?string $navigationGroup = 'Settings';
32
-
33
     protected static ?string $slug = 'settings/taxes';
29
     protected static ?string $slug = 'settings/taxes';
34
 
30
 
35
     public static function getModelLabel(): string
31
     public static function getModelLabel(): string

+ 83
- 0
app/Jobs/ProcessTransactionImport.php 查看文件

1
+<?php
2
+
3
+namespace App\Jobs;
4
+
5
+use App\Models\Accounting\Account;
6
+use App\Models\Banking\BankAccount;
7
+use App\Models\Banking\ConnectedBankAccount;
8
+use App\Models\Company;
9
+use App\Services\PlaidService;
10
+use App\Services\TransactionService;
11
+use Illuminate\Bus\Queueable;
12
+use Illuminate\Contracts\Queue\ShouldQueue;
13
+use Illuminate\Foundation\Bus\Dispatchable;
14
+use Illuminate\Queue\InteractsWithQueue;
15
+use Illuminate\Queue\SerializesModels;
16
+use Illuminate\Support\Carbon;
17
+
18
+class ProcessTransactionImport implements ShouldQueue
19
+{
20
+    use Dispatchable;
21
+    use InteractsWithQueue;
22
+    use Queueable;
23
+    use SerializesModels;
24
+
25
+    protected Company $company;
26
+
27
+    protected Account $account;
28
+
29
+    protected BankAccount $bankAccount;
30
+
31
+    protected ConnectedBankAccount $connectedBankAccount;
32
+
33
+    protected string $startDate;
34
+
35
+    /**
36
+     * Create a new job instance.
37
+     */
38
+    public function __construct(Company $company, Account $account, BankAccount $bankAccount, ConnectedBankAccount $connectedBankAccount, string $startDate)
39
+    {
40
+        $this->company = $company;
41
+        $this->account = $account;
42
+        $this->bankAccount = $bankAccount;
43
+        $this->connectedBankAccount = $connectedBankAccount;
44
+        $this->startDate = $startDate;
45
+    }
46
+
47
+    /**
48
+     * Execute the job.
49
+     */
50
+    public function handle(PlaidService $plaid, TransactionService $transactionService): void
51
+    {
52
+        $accessToken = $this->connectedBankAccount->access_token;
53
+        $endDate = Carbon::now()->toDateString();
54
+        $startDate = Carbon::parse($this->startDate)->toDateString();
55
+        $allTransactions = [];
56
+        $offset = 0;
57
+
58
+        $transactionsResponse = $plaid->getTransactions($accessToken, $startDate, $endDate, [
59
+            'account_ids' => [$this->connectedBankAccount->external_account_id],
60
+        ]);
61
+
62
+        $allTransactions = [...$allTransactions, ...$transactionsResponse->transactions];
63
+        $totalTransactions = $transactionsResponse->total_transactions;
64
+
65
+        while (count($allTransactions) < $totalTransactions) {
66
+            $offset += count($transactionsResponse->transactions);
67
+            $transactionsResponse = $plaid->getTransactions($accessToken, $startDate, $endDate, [
68
+                'account_ids' => [$this->connectedBankAccount->external_account_id],
69
+                'offset' => $offset,
70
+            ]);
71
+
72
+            $allTransactions = [...$allTransactions, ...$transactionsResponse->transactions];
73
+        }
74
+
75
+        if (count($allTransactions) > 0) {
76
+            $postedTransactions = array_filter($allTransactions, static fn ($transaction) => $transaction->pending === false);
77
+            $currentBalance = $transactionsResponse->accounts[0]->balances->current;
78
+
79
+            $transactionService->createStartingBalanceIfNeeded($this->company, $this->account, $this->bankAccount, $postedTransactions, $currentBalance, $startDate);
80
+            $transactionService->storeTransactions($this->company, $this->bankAccount, $postedTransactions);
81
+        }
82
+    }
83
+}

+ 52
- 0
app/Listeners/ConfigureCompanyNavigation.php 查看文件

3
 namespace App\Listeners;
3
 namespace App\Listeners;
4
 
4
 
5
 use App\Events\CompanyConfigured;
5
 use App\Events\CompanyConfigured;
6
+use App\Filament\Company\Pages\Accounting\AccountChart;
7
+use App\Filament\Company\Pages\Reports;
6
 use App\Filament\Company\Pages\Service\ConnectedAccount;
8
 use App\Filament\Company\Pages\Service\ConnectedAccount;
7
 use App\Filament\Company\Pages\Service\LiveCurrency;
9
 use App\Filament\Company\Pages\Service\LiveCurrency;
8
 use App\Filament\Company\Pages\Setting\Appearance;
10
 use App\Filament\Company\Pages\Setting\Appearance;
10
 use App\Filament\Company\Pages\Setting\CompanyProfile;
12
 use App\Filament\Company\Pages\Setting\CompanyProfile;
11
 use App\Filament\Company\Pages\Setting\Invoice;
13
 use App\Filament\Company\Pages\Setting\Invoice;
12
 use App\Filament\Company\Pages\Setting\Localization;
14
 use App\Filament\Company\Pages\Setting\Localization;
15
+use App\Filament\Company\Resources\Accounting\TransactionResource;
13
 use App\Filament\Company\Resources\Banking\AccountResource;
16
 use App\Filament\Company\Resources\Banking\AccountResource;
14
 use App\Filament\Company\Resources\Core\DepartmentResource;
17
 use App\Filament\Company\Resources\Core\DepartmentResource;
15
 use App\Filament\Company\Resources\Setting\CurrencyResource;
18
 use App\Filament\Company\Resources\Setting\CurrencyResource;
39
             Filament::getPanel('company')->navigation(
42
             Filament::getPanel('company')->navigation(
40
                 $this->buildCompanyNavigation()
43
                 $this->buildCompanyNavigation()
41
             );
44
             );
45
+        } else {
46
+            Filament::getPanel('company')->navigation(
47
+                $this->buildCompanySidebarNavigation()
48
+            );
42
         }
49
         }
43
 
50
 
44
         NavigationGroup::configureUsing(static function (NavigationGroup $group): void {
51
         NavigationGroup::configureUsing(static function (NavigationGroup $group): void {
92
                 ...DepartmentResource::getNavigationItems(),
99
                 ...DepartmentResource::getNavigationItems(),
93
             ]);
100
             ]);
94
     }
101
     }
102
+
103
+    /**
104
+     * Build the company sidebar navigation.
105
+     */
106
+    protected function buildCompanySidebarNavigation(): callable
107
+    {
108
+        return static function (NavigationBuilder $builder): NavigationBuilder {
109
+            return $builder
110
+                ->items(Dashboard::getNavigationItems())
111
+                ->groups([
112
+                    NavigationGroup::make('Accounting')
113
+                        ->icon('heroicon-o-clipboard-document-list')
114
+                        ->extraSidebarAttributes(['class' => 'es-sidebar-group'])
115
+                        ->items([
116
+                            ...AccountChart::getNavigationItems(),
117
+                            ...TransactionResource::getNavigationItems(),
118
+                        ]),
119
+                    NavigationGroup::make('Banking')
120
+                        ->icon('heroicon-o-building-library')
121
+                        ->items(AccountResource::getNavigationItems()),
122
+                    NavigationGroup::make('HR')
123
+                        ->icon('heroicon-o-user-group')
124
+                        ->items(DepartmentResource::getNavigationItems()),
125
+                    NavigationGroup::make('Services')
126
+                        ->icon('heroicon-o-wrench-screwdriver')
127
+                        ->items([
128
+                            ...ConnectedAccount::getNavigationItems(),
129
+                            ...LiveCurrency::getNavigationItems(),
130
+                        ]),
131
+                    NavigationGroup::make('Settings')
132
+                        ->icon('heroicon-o-cog-8-tooth')
133
+                        ->items([
134
+                            ...Appearance::getNavigationItems(),
135
+                            ...CompanyProfile::getNavigationItems(),
136
+                            ...CurrencyResource::getNavigationItems(),
137
+                            ...CompanyDefault::getNavigationItems(),
138
+                            ...DiscountResource::getNavigationItems(),
139
+                            ...Invoice::getNavigationItems(),
140
+                            ...Localization::getNavigationItems(),
141
+                            ...TaxResource::getNavigationItems(),
142
+                        ]),
143
+                ])
144
+                ->items(Reports::getNavigationItems());
145
+        };
146
+    }
95
 }
147
 }

+ 9
- 36
app/Listeners/HandleTransactionImport.php 查看文件

3
 namespace App\Listeners;
3
 namespace App\Listeners;
4
 
4
 
5
 use App\Events\StartTransactionImport;
5
 use App\Events\StartTransactionImport;
6
-use App\Models\Accounting\Account;
7
-use App\Models\Banking\BankAccount;
8
-use App\Models\Banking\ConnectedBankAccount;
9
-use App\Models\Company;
6
+use App\Jobs\ProcessTransactionImport;
10
 use App\Services\ConnectedBankAccountService;
7
 use App\Services\ConnectedBankAccountService;
11
-use App\Services\PlaidService;
12
-use App\Services\TransactionService;
13
-use Illuminate\Support\Carbon;
14
 use Illuminate\Support\Facades\DB;
8
 use Illuminate\Support\Facades\DB;
15
 
9
 
16
 class HandleTransactionImport
10
 class HandleTransactionImport
17
 {
11
 {
18
-    protected PlaidService $plaid;
19
-
20
     protected ConnectedBankAccountService $connectedBankAccountService;
12
     protected ConnectedBankAccountService $connectedBankAccountService;
21
 
13
 
22
-    protected TransactionService $transactionService;
23
-
24
     /**
14
     /**
25
      * Create the event listener.
15
      * Create the event listener.
26
      */
16
      */
27
-    public function __construct(PlaidService $plaid, ConnectedBankAccountService $connectedBankAccountService, TransactionService $transactionService)
17
+    public function __construct(ConnectedBankAccountService $connectedBankAccountService)
28
     {
18
     {
29
-        $this->plaid = $plaid;
30
         $this->connectedBankAccountService = $connectedBankAccountService;
19
         $this->connectedBankAccountService = $connectedBankAccountService;
31
-        $this->transactionService = $transactionService;
32
     }
20
     }
33
 
21
 
34
     /**
22
     /**
48
         $selectedBankAccountId = $event->selectedBankAccountId;
36
         $selectedBankAccountId = $event->selectedBankAccountId;
49
         $startDate = $event->startDate;
37
         $startDate = $event->startDate;
50
 
38
 
51
-        $accessToken = $connectedBankAccount->access_token;
52
-
53
         $bankAccount = $this->connectedBankAccountService->getOrProcessBankAccountForConnectedBankAccount($company, $connectedBankAccount, $selectedBankAccountId);
39
         $bankAccount = $this->connectedBankAccountService->getOrProcessBankAccountForConnectedBankAccount($company, $connectedBankAccount, $selectedBankAccountId);
54
         $account = $this->connectedBankAccountService->getOrProcessAccountForConnectedBankAccount($bankAccount, $company, $connectedBankAccount);
40
         $account = $this->connectedBankAccountService->getOrProcessAccountForConnectedBankAccount($bankAccount, $company, $connectedBankAccount);
55
 
41
 
58
             'import_transactions' => true,
44
             'import_transactions' => true,
59
         ]);
45
         ]);
60
 
46
 
61
-        $this->processTransactions($company, $account, $bankAccount, $connectedBankAccount, $startDate, $accessToken);
62
-    }
63
-
64
-    public function processTransactions(Company $company, Account $account, BankAccount $bankAccount, ConnectedBankAccount $connectedBankAccount, string $startDate, string $accessToken): void
65
-    {
66
-        $endDate = Carbon::now()->toDateString();
67
-        $startDate = Carbon::parse($startDate)->toDateString();
68
-
69
-        $transactionsResponse = $this->plaid->getTransactions($accessToken, $startDate, $endDate, [
70
-            'account_ids' => [$connectedBankAccount->external_account_id],
71
-        ]);
72
-
73
-        if (filled($transactionsResponse->transactions)) {
74
-            $postedTransactions = array_filter($transactionsResponse->transactions, static fn ($transaction) => $transaction->pending === false);
75
-            $transactions = array_reverse($postedTransactions);
76
-            $currentBalance = $transactionsResponse->accounts[0]->balances->current;
77
-
78
-            $this->transactionService->createStartingBalanceIfNeeded($company, $account, $bankAccount, $transactions, $currentBalance, $startDate);
79
-            $this->transactionService->storeTransactions($company, $bankAccount, $transactions);
80
-        }
47
+        ProcessTransactionImport::dispatch(
48
+            $company,
49
+            $account,
50
+            $bankAccount,
51
+            $connectedBankAccount,
52
+            $startDate,
53
+        )->onQueue('transactions');
81
     }
54
     }
82
 }
55
 }

+ 1
- 2
app/Models/Accounting/Transaction.php 查看文件

29
         'account_id', // Account from Chart of Accounts (Income/Expense accounts)
29
         'account_id', // Account from Chart of Accounts (Income/Expense accounts)
30
         'bank_account_id', // Cash or Bank Account
30
         'bank_account_id', // Cash or Bank Account
31
         'contact_id',
31
         'contact_id',
32
-        'type',
33
-        'method',
32
+        'type', // 'deposit', 'withdrawal', 'journal entry'
34
         'payment_channel',
33
         'payment_channel',
35
         'description',
34
         'description',
36
         'notes',
35
         'notes',

+ 4
- 4
app/Observers/TransactionObserver.php 查看文件

17
         $chartAccount = $transaction->account;
17
         $chartAccount = $transaction->account;
18
         $bankAccount = $transaction->bankAccount->account;
18
         $bankAccount = $transaction->bankAccount->account;
19
 
19
 
20
-        $debitAccount = $transaction->type === 'expense' ? $chartAccount : $bankAccount;
21
-        $creditAccount = $transaction->type === 'expense' ? $bankAccount : $chartAccount;
20
+        $debitAccount = $transaction->type === 'withdrawal' ? $chartAccount : $bankAccount;
21
+        $creditAccount = $transaction->type === 'withdrawal' ? $bankAccount : $chartAccount;
22
 
22
 
23
         $this->createJournalEntries($transaction, $debitAccount, $creditAccount);
23
         $this->createJournalEntries($transaction, $debitAccount, $creditAccount);
24
     }
24
     }
63
         $debitEntry = $journalEntries->where('type', 'debit')->first();
63
         $debitEntry = $journalEntries->where('type', 'debit')->first();
64
         $creditEntry = $journalEntries->where('type', 'credit')->first();
64
         $creditEntry = $journalEntries->where('type', 'credit')->first();
65
 
65
 
66
-        $debitAccount = $transaction->type === 'expense' ? $chartAccount : $bankAccount;
67
-        $creditAccount = $transaction->type === 'expense' ? $bankAccount : $chartAccount;
66
+        $debitAccount = $transaction->type === 'withdrawal' ? $chartAccount : $bankAccount;
67
+        $creditAccount = $transaction->type === 'withdrawal' ? $bankAccount : $chartAccount;
68
 
68
 
69
         $debitEntry?->update([
69
         $debitEntry?->update([
70
             'account_id' => $debitAccount->id,
70
             'account_id' => $debitAccount->id,

+ 2
- 2
app/Services/AccountService.php 查看文件

39
 
39
 
40
     public function getNetMovement(Account $account, string $startDate, string $endDate): BalanceValue
40
     public function getNetMovement(Account $account, string $startDate, string $endDate): BalanceValue
41
     {
41
     {
42
-        $debitBalance = $this->getDebitBalance($account, $startDate, $endDate)->getValue();
43
-        $creditBalance = $this->getCreditBalance($account, $startDate, $endDate)->getValue();
42
+        $debitBalance = $this->journalEntryRepository->sumDebitAmounts($account, $startDate, $endDate);
43
+        $creditBalance = $this->journalEntryRepository->sumCreditAmounts($account, $startDate, $endDate);
44
         $netMovement = $this->calculateNetMovementByCategory($account->category, $debitBalance, $creditBalance);
44
         $netMovement = $this->calculateNetMovementByCategory($account->category, $debitBalance, $creditBalance);
45
 
45
 
46
         return new BalanceValue($netMovement, $account->currency_code ?? 'USD');
46
         return new BalanceValue($netMovement, $account->currency_code ?? 'USD');

+ 6
- 8
app/Services/TransactionService.php 查看文件

39
 
39
 
40
     public function createStartingBalanceTransaction(Company $company, Account $account, BankAccount $bankAccount, float $startingBalance, string $startDate): void
40
     public function createStartingBalanceTransaction(Company $company, Account $account, BankAccount $bankAccount, float $startingBalance, string $startDate): void
41
     {
41
     {
42
-        [$transactionType, $method] = $startingBalance >= 0 ? ['income', 'deposit'] : ['expense', 'withdrawal'];
42
+        $transactionType = $startingBalance >= 0 ? 'deposit' : 'withdrawal';
43
         $chartAccount = $account->where('category', AccountCategory::Equity)->where('name', 'Owner\'s Equity')->first();
43
         $chartAccount = $account->where('category', AccountCategory::Equity)->where('name', 'Owner\'s Equity')->first();
44
         $postedAt = Carbon::parse($startDate)->subDay()->toDateTimeString();
44
         $postedAt = Carbon::parse($startDate)->subDay()->toDateTimeString();
45
 
45
 
49
             'bank_account_id' => $bankAccount->id,
49
             'bank_account_id' => $bankAccount->id,
50
             'type' => $transactionType,
50
             'type' => $transactionType,
51
             'amount' => abs($startingBalance),
51
             'amount' => abs($startingBalance),
52
-            'method' => $method,
53
             'payment_channel' => 'other',
52
             'payment_channel' => 'other',
54
             'posted_at' => $postedAt,
53
             'posted_at' => $postedAt,
55
             'description' => 'Starting Balance',
54
             'description' => 'Starting Balance',
60
 
59
 
61
     public function storeTransaction(Company $company, BankAccount $bankAccount, object $transaction): void
60
     public function storeTransaction(Company $company, BankAccount $bankAccount, object $transaction): void
62
     {
61
     {
63
-        [$transactionType, $method] = $transaction->amount < 0 ? ['income', 'deposit'] : ['expense', 'withdrawal'];
62
+        $transactionType = $transaction->amount < 0 ? 'deposit' : 'withdrawal';
64
         $paymentChannel = $transaction->payment_channel;
63
         $paymentChannel = $transaction->payment_channel;
65
         $chartAccount = $this->getAccountFromTransaction($company, $transaction, $transactionType);
64
         $chartAccount = $this->getAccountFromTransaction($company, $transaction, $transactionType);
66
         $postedAt = $transaction->datetime ?? Carbon::parse($transaction->date)->toDateTimeString();
65
         $postedAt = $transaction->datetime ?? Carbon::parse($transaction->date)->toDateTimeString();
72
             'bank_account_id' => $bankAccount->id,
71
             'bank_account_id' => $bankAccount->id,
73
             'type' => $transactionType,
72
             'type' => $transactionType,
74
             'amount' => abs($transaction->amount),
73
             'amount' => abs($transaction->amount),
75
-            'method' => $method,
76
             'payment_channel' => $paymentChannel,
74
             'payment_channel' => $paymentChannel,
77
             'posted_at' => $postedAt,
75
             'posted_at' => $postedAt,
78
             'description' => $description,
76
             'description' => $description,
84
     public function getAccountFromTransaction(Company $company, object $transaction, string $transactionType): Account
82
     public function getAccountFromTransaction(Company $company, object $transaction, string $transactionType): Account
85
     {
83
     {
86
         $accountCategory = match ($transactionType) {
84
         $accountCategory = match ($transactionType) {
87
-            'income' => AccountCategory::Revenue,
88
-            'expense' => AccountCategory::Expense,
85
+            'deposit' => AccountCategory::Revenue,
86
+            'withdrawal' => AccountCategory::Expense,
89
         };
87
         };
90
 
88
 
91
         $accounts = $company->accounts()
89
         $accounts = $company->accounts()
132
     public function getUncategorizedAccount(Company $company, string $transactionType): Account
130
     public function getUncategorizedAccount(Company $company, string $transactionType): Account
133
     {
131
     {
134
         [$type, $name] = match ($transactionType) {
132
         [$type, $name] = match ($transactionType) {
135
-            'income' => [AccountType::UncategorizedRevenue, 'Uncategorized Income'],
136
-            'expense' => [AccountType::UncategorizedExpense, 'Uncategorized Expense'],
133
+            'deposit' => [AccountType::UncategorizedRevenue, 'Uncategorized Income'],
134
+            'withdrawal' => [AccountType::UncategorizedExpense, 'Uncategorized Expense'],
137
         };
135
         };
138
 
136
 
139
         return $company->accounts()
137
         return $company->accounts()

+ 91
- 91
composer.lock 查看文件

293
         },
293
         },
294
         {
294
         {
295
             "name": "anourvalar/eloquent-serialize",
295
             "name": "anourvalar/eloquent-serialize",
296
-            "version": "1.2.20",
296
+            "version": "1.2.21",
297
             "source": {
297
             "source": {
298
                 "type": "git",
298
                 "type": "git",
299
                 "url": "https://github.com/AnourValar/eloquent-serialize.git",
299
                 "url": "https://github.com/AnourValar/eloquent-serialize.git",
300
-                "reference": "f8408e92768ff295990e3a1edb7e47950e008c63"
300
+                "reference": "39766b21c8de0dbbff8a9368c2579502fd1d248e"
301
             },
301
             },
302
             "dist": {
302
             "dist": {
303
                 "type": "zip",
303
                 "type": "zip",
304
-                "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/f8408e92768ff295990e3a1edb7e47950e008c63",
305
-                "reference": "f8408e92768ff295990e3a1edb7e47950e008c63",
304
+                "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/39766b21c8de0dbbff8a9368c2579502fd1d248e",
305
+                "reference": "39766b21c8de0dbbff8a9368c2579502fd1d248e",
306
                 "shasum": ""
306
                 "shasum": ""
307
             },
307
             },
308
             "require": {
308
             "require": {
353
             ],
353
             ],
354
             "support": {
354
             "support": {
355
                 "issues": "https://github.com/AnourValar/eloquent-serialize/issues",
355
                 "issues": "https://github.com/AnourValar/eloquent-serialize/issues",
356
-                "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.2.20"
356
+                "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.2.21"
357
             },
357
             },
358
-            "time": "2024-03-08T14:48:54+00:00"
358
+            "time": "2024-03-15T14:33:22+00:00"
359
         },
359
         },
360
         {
360
         {
361
             "name": "aws/aws-crt-php",
361
             "name": "aws/aws-crt-php",
413
         },
413
         },
414
         {
414
         {
415
             "name": "aws/aws-sdk-php",
415
             "name": "aws/aws-sdk-php",
416
-            "version": "3.300.16",
416
+            "version": "3.301.1",
417
             "source": {
417
             "source": {
418
                 "type": "git",
418
                 "type": "git",
419
                 "url": "https://github.com/aws/aws-sdk-php.git",
419
                 "url": "https://github.com/aws/aws-sdk-php.git",
420
-                "reference": "d6afaeaa0c0e2c3be5f5223f72c0b5e2b2667b67"
420
+                "reference": "0a910d2b35e7087337cdf3569dc9b6ce232aafba"
421
             },
421
             },
422
             "dist": {
422
             "dist": {
423
                 "type": "zip",
423
                 "type": "zip",
424
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d6afaeaa0c0e2c3be5f5223f72c0b5e2b2667b67",
425
-                "reference": "d6afaeaa0c0e2c3be5f5223f72c0b5e2b2667b67",
424
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0a910d2b35e7087337cdf3569dc9b6ce232aafba",
425
+                "reference": "0a910d2b35e7087337cdf3569dc9b6ce232aafba",
426
                 "shasum": ""
426
                 "shasum": ""
427
             },
427
             },
428
             "require": {
428
             "require": {
502
             "support": {
502
             "support": {
503
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
503
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
504
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
504
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
505
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.300.16"
505
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.301.1"
506
             },
506
             },
507
-            "time": "2024-03-12T18:04:55+00:00"
507
+            "time": "2024-03-15T18:14:42+00:00"
508
         },
508
         },
509
         {
509
         {
510
             "name": "aws/aws-sdk-php-laravel",
510
             "name": "aws/aws-sdk-php-laravel",
585
         },
585
         },
586
         {
586
         {
587
             "name": "barryvdh/laravel-dompdf",
587
             "name": "barryvdh/laravel-dompdf",
588
-            "version": "v2.1.0",
588
+            "version": "v2.1.1",
589
             "source": {
589
             "source": {
590
                 "type": "git",
590
                 "type": "git",
591
                 "url": "https://github.com/barryvdh/laravel-dompdf.git",
591
                 "url": "https://github.com/barryvdh/laravel-dompdf.git",
592
-                "reference": "c8b8a8490e5f7348cf99054821fb248f103e7d24"
592
+                "reference": "cb37868365f9b937039d316727a1fced1e87b31c"
593
             },
593
             },
594
             "dist": {
594
             "dist": {
595
                 "type": "zip",
595
                 "type": "zip",
596
-                "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/c8b8a8490e5f7348cf99054821fb248f103e7d24",
597
-                "reference": "c8b8a8490e5f7348cf99054821fb248f103e7d24",
596
+                "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/cb37868365f9b937039d316727a1fced1e87b31c",
597
+                "reference": "cb37868365f9b937039d316727a1fced1e87b31c",
598
                 "shasum": ""
598
                 "shasum": ""
599
             },
599
             },
600
             "require": {
600
             "require": {
646
             ],
646
             ],
647
             "support": {
647
             "support": {
648
                 "issues": "https://github.com/barryvdh/laravel-dompdf/issues",
648
                 "issues": "https://github.com/barryvdh/laravel-dompdf/issues",
649
-                "source": "https://github.com/barryvdh/laravel-dompdf/tree/v2.1.0"
649
+                "source": "https://github.com/barryvdh/laravel-dompdf/tree/v2.1.1"
650
             },
650
             },
651
             "funding": [
651
             "funding": [
652
                 {
652
                 {
658
                     "type": "github"
658
                     "type": "github"
659
                 }
659
                 }
660
             ],
660
             ],
661
-            "time": "2024-03-04T08:18:20+00:00"
661
+            "time": "2024-03-15T12:48:39+00:00"
662
         },
662
         },
663
         {
663
         {
664
             "name": "bezhansalleh/filament-panel-switch",
664
             "name": "bezhansalleh/filament-panel-switch",
1896
         },
1896
         },
1897
         {
1897
         {
1898
             "name": "filament/actions",
1898
             "name": "filament/actions",
1899
-            "version": "v3.2.47",
1899
+            "version": "v3.2.50",
1900
             "source": {
1900
             "source": {
1901
                 "type": "git",
1901
                 "type": "git",
1902
                 "url": "https://github.com/filamentphp/actions.git",
1902
                 "url": "https://github.com/filamentphp/actions.git",
1903
-                "reference": "15f1f627b3a6d271e998228d591508c705491061"
1903
+                "reference": "07bb64870f6552e4e979894b6eea1404cad2d0f1"
1904
             },
1904
             },
1905
             "dist": {
1905
             "dist": {
1906
                 "type": "zip",
1906
                 "type": "zip",
1907
-                "url": "https://api.github.com/repos/filamentphp/actions/zipball/15f1f627b3a6d271e998228d591508c705491061",
1908
-                "reference": "15f1f627b3a6d271e998228d591508c705491061",
1907
+                "url": "https://api.github.com/repos/filamentphp/actions/zipball/07bb64870f6552e4e979894b6eea1404cad2d0f1",
1908
+                "reference": "07bb64870f6552e4e979894b6eea1404cad2d0f1",
1909
                 "shasum": ""
1909
                 "shasum": ""
1910
             },
1910
             },
1911
             "require": {
1911
             "require": {
1945
                 "issues": "https://github.com/filamentphp/filament/issues",
1945
                 "issues": "https://github.com/filamentphp/filament/issues",
1946
                 "source": "https://github.com/filamentphp/filament"
1946
                 "source": "https://github.com/filamentphp/filament"
1947
             },
1947
             },
1948
-            "time": "2024-03-11T11:21:19+00:00"
1948
+            "time": "2024-03-14T14:13:40+00:00"
1949
         },
1949
         },
1950
         {
1950
         {
1951
             "name": "filament/filament",
1951
             "name": "filament/filament",
1952
-            "version": "v3.2.47",
1952
+            "version": "v3.2.50",
1953
             "source": {
1953
             "source": {
1954
                 "type": "git",
1954
                 "type": "git",
1955
                 "url": "https://github.com/filamentphp/panels.git",
1955
                 "url": "https://github.com/filamentphp/panels.git",
1956
-                "reference": "20a6939fb454b16fe48b205d1b815cdd6cc1446e"
1956
+                "reference": "39ca57471511129e854d138528cefad335c88b08"
1957
             },
1957
             },
1958
             "dist": {
1958
             "dist": {
1959
                 "type": "zip",
1959
                 "type": "zip",
1960
-                "url": "https://api.github.com/repos/filamentphp/panels/zipball/20a6939fb454b16fe48b205d1b815cdd6cc1446e",
1961
-                "reference": "20a6939fb454b16fe48b205d1b815cdd6cc1446e",
1960
+                "url": "https://api.github.com/repos/filamentphp/panels/zipball/39ca57471511129e854d138528cefad335c88b08",
1961
+                "reference": "39ca57471511129e854d138528cefad335c88b08",
1962
                 "shasum": ""
1962
                 "shasum": ""
1963
             },
1963
             },
1964
             "require": {
1964
             "require": {
2010
                 "issues": "https://github.com/filamentphp/filament/issues",
2010
                 "issues": "https://github.com/filamentphp/filament/issues",
2011
                 "source": "https://github.com/filamentphp/filament"
2011
                 "source": "https://github.com/filamentphp/filament"
2012
             },
2012
             },
2013
-            "time": "2024-03-11T11:21:25+00:00"
2013
+            "time": "2024-03-14T14:14:03+00:00"
2014
         },
2014
         },
2015
         {
2015
         {
2016
             "name": "filament/forms",
2016
             "name": "filament/forms",
2017
-            "version": "v3.2.47",
2017
+            "version": "v3.2.50",
2018
             "source": {
2018
             "source": {
2019
                 "type": "git",
2019
                 "type": "git",
2020
                 "url": "https://github.com/filamentphp/forms.git",
2020
                 "url": "https://github.com/filamentphp/forms.git",
2021
-                "reference": "5ddef657a1127e081e5f03de8b1c432d65d4b9eb"
2021
+                "reference": "21515f37ee2de29f9753302112723a7b73162793"
2022
             },
2022
             },
2023
             "dist": {
2023
             "dist": {
2024
                 "type": "zip",
2024
                 "type": "zip",
2025
-                "url": "https://api.github.com/repos/filamentphp/forms/zipball/5ddef657a1127e081e5f03de8b1c432d65d4b9eb",
2026
-                "reference": "5ddef657a1127e081e5f03de8b1c432d65d4b9eb",
2025
+                "url": "https://api.github.com/repos/filamentphp/forms/zipball/21515f37ee2de29f9753302112723a7b73162793",
2026
+                "reference": "21515f37ee2de29f9753302112723a7b73162793",
2027
                 "shasum": ""
2027
                 "shasum": ""
2028
             },
2028
             },
2029
             "require": {
2029
             "require": {
2066
                 "issues": "https://github.com/filamentphp/filament/issues",
2066
                 "issues": "https://github.com/filamentphp/filament/issues",
2067
                 "source": "https://github.com/filamentphp/filament"
2067
                 "source": "https://github.com/filamentphp/filament"
2068
             },
2068
             },
2069
-            "time": "2024-03-11T11:21:19+00:00"
2069
+            "time": "2024-03-14T10:54:01+00:00"
2070
         },
2070
         },
2071
         {
2071
         {
2072
             "name": "filament/infolists",
2072
             "name": "filament/infolists",
2073
-            "version": "v3.2.47",
2073
+            "version": "v3.2.50",
2074
             "source": {
2074
             "source": {
2075
                 "type": "git",
2075
                 "type": "git",
2076
                 "url": "https://github.com/filamentphp/infolists.git",
2076
                 "url": "https://github.com/filamentphp/infolists.git",
2077
-                "reference": "302e210bade862ba633fc7ccadb6d2c01aab8d36"
2077
+                "reference": "72217e2ae055bfea51feb3351e00f269b188796d"
2078
             },
2078
             },
2079
             "dist": {
2079
             "dist": {
2080
                 "type": "zip",
2080
                 "type": "zip",
2081
-                "url": "https://api.github.com/repos/filamentphp/infolists/zipball/302e210bade862ba633fc7ccadb6d2c01aab8d36",
2082
-                "reference": "302e210bade862ba633fc7ccadb6d2c01aab8d36",
2081
+                "url": "https://api.github.com/repos/filamentphp/infolists/zipball/72217e2ae055bfea51feb3351e00f269b188796d",
2082
+                "reference": "72217e2ae055bfea51feb3351e00f269b188796d",
2083
                 "shasum": ""
2083
                 "shasum": ""
2084
             },
2084
             },
2085
             "require": {
2085
             "require": {
2117
                 "issues": "https://github.com/filamentphp/filament/issues",
2117
                 "issues": "https://github.com/filamentphp/filament/issues",
2118
                 "source": "https://github.com/filamentphp/filament"
2118
                 "source": "https://github.com/filamentphp/filament"
2119
             },
2119
             },
2120
-            "time": "2024-03-11T11:21:22+00:00"
2120
+            "time": "2024-03-14T10:54:02+00:00"
2121
         },
2121
         },
2122
         {
2122
         {
2123
             "name": "filament/notifications",
2123
             "name": "filament/notifications",
2124
-            "version": "v3.2.47",
2124
+            "version": "v3.2.50",
2125
             "source": {
2125
             "source": {
2126
                 "type": "git",
2126
                 "type": "git",
2127
                 "url": "https://github.com/filamentphp/notifications.git",
2127
                 "url": "https://github.com/filamentphp/notifications.git",
2128
-                "reference": "93c1d72b12ff1bed520d082a1292ab25a566a8d8"
2128
+                "reference": "a25fe75eeebc61d4a6e2bfa88e9e501a5f8020bd"
2129
             },
2129
             },
2130
             "dist": {
2130
             "dist": {
2131
                 "type": "zip",
2131
                 "type": "zip",
2132
-                "url": "https://api.github.com/repos/filamentphp/notifications/zipball/93c1d72b12ff1bed520d082a1292ab25a566a8d8",
2133
-                "reference": "93c1d72b12ff1bed520d082a1292ab25a566a8d8",
2132
+                "url": "https://api.github.com/repos/filamentphp/notifications/zipball/a25fe75eeebc61d4a6e2bfa88e9e501a5f8020bd",
2133
+                "reference": "a25fe75eeebc61d4a6e2bfa88e9e501a5f8020bd",
2134
                 "shasum": ""
2134
                 "shasum": ""
2135
             },
2135
             },
2136
             "require": {
2136
             "require": {
2169
                 "issues": "https://github.com/filamentphp/filament/issues",
2169
                 "issues": "https://github.com/filamentphp/filament/issues",
2170
                 "source": "https://github.com/filamentphp/filament"
2170
                 "source": "https://github.com/filamentphp/filament"
2171
             },
2171
             },
2172
-            "time": "2024-02-29T12:30:04+00:00"
2172
+            "time": "2024-03-14T10:54:06+00:00"
2173
         },
2173
         },
2174
         {
2174
         {
2175
             "name": "filament/spatie-laravel-tags-plugin",
2175
             "name": "filament/spatie-laravel-tags-plugin",
2176
-            "version": "v3.2.47",
2176
+            "version": "v3.2.50",
2177
             "source": {
2177
             "source": {
2178
                 "type": "git",
2178
                 "type": "git",
2179
                 "url": "https://github.com/filamentphp/spatie-laravel-tags-plugin.git",
2179
                 "url": "https://github.com/filamentphp/spatie-laravel-tags-plugin.git",
2210
         },
2210
         },
2211
         {
2211
         {
2212
             "name": "filament/support",
2212
             "name": "filament/support",
2213
-            "version": "v3.2.47",
2213
+            "version": "v3.2.50",
2214
             "source": {
2214
             "source": {
2215
                 "type": "git",
2215
                 "type": "git",
2216
                 "url": "https://github.com/filamentphp/support.git",
2216
                 "url": "https://github.com/filamentphp/support.git",
2217
-                "reference": "811a57072a6e8677e42d1b745291def5f26a8d62"
2217
+                "reference": "f10144d4758d7873ee8d471530a4455a1105ca53"
2218
             },
2218
             },
2219
             "dist": {
2219
             "dist": {
2220
                 "type": "zip",
2220
                 "type": "zip",
2221
-                "url": "https://api.github.com/repos/filamentphp/support/zipball/811a57072a6e8677e42d1b745291def5f26a8d62",
2222
-                "reference": "811a57072a6e8677e42d1b745291def5f26a8d62",
2221
+                "url": "https://api.github.com/repos/filamentphp/support/zipball/f10144d4758d7873ee8d471530a4455a1105ca53",
2222
+                "reference": "f10144d4758d7873ee8d471530a4455a1105ca53",
2223
                 "shasum": ""
2223
                 "shasum": ""
2224
             },
2224
             },
2225
             "require": {
2225
             "require": {
2229
                 "illuminate/contracts": "^10.45|^11.0",
2229
                 "illuminate/contracts": "^10.45|^11.0",
2230
                 "illuminate/support": "^10.45|^11.0",
2230
                 "illuminate/support": "^10.45|^11.0",
2231
                 "illuminate/view": "^10.45|^11.0",
2231
                 "illuminate/view": "^10.45|^11.0",
2232
-                "livewire/livewire": "^3.2.3",
2232
+                "livewire/livewire": "^3.4.9",
2233
                 "php": "^8.1",
2233
                 "php": "^8.1",
2234
                 "ryangjchandler/blade-capture-directive": "^0.2|^0.3|^1.0",
2234
                 "ryangjchandler/blade-capture-directive": "^0.2|^0.3|^1.0",
2235
                 "spatie/color": "^1.5",
2235
                 "spatie/color": "^1.5",
2263
                 "issues": "https://github.com/filamentphp/filament/issues",
2263
                 "issues": "https://github.com/filamentphp/filament/issues",
2264
                 "source": "https://github.com/filamentphp/filament"
2264
                 "source": "https://github.com/filamentphp/filament"
2265
             },
2265
             },
2266
-            "time": "2024-03-08T12:54:38+00:00"
2266
+            "time": "2024-03-14T14:14:06+00:00"
2267
         },
2267
         },
2268
         {
2268
         {
2269
             "name": "filament/tables",
2269
             "name": "filament/tables",
2270
-            "version": "v3.2.47",
2270
+            "version": "v3.2.50",
2271
             "source": {
2271
             "source": {
2272
                 "type": "git",
2272
                 "type": "git",
2273
                 "url": "https://github.com/filamentphp/tables.git",
2273
                 "url": "https://github.com/filamentphp/tables.git",
2274
-                "reference": "68900e0443ad84f027a06e19429bd47672c7733f"
2274
+                "reference": "260fa164f4f5c792da40c0a3fa8bb274b64dbf56"
2275
             },
2275
             },
2276
             "dist": {
2276
             "dist": {
2277
                 "type": "zip",
2277
                 "type": "zip",
2278
-                "url": "https://api.github.com/repos/filamentphp/tables/zipball/68900e0443ad84f027a06e19429bd47672c7733f",
2279
-                "reference": "68900e0443ad84f027a06e19429bd47672c7733f",
2278
+                "url": "https://api.github.com/repos/filamentphp/tables/zipball/260fa164f4f5c792da40c0a3fa8bb274b64dbf56",
2279
+                "reference": "260fa164f4f5c792da40c0a3fa8bb274b64dbf56",
2280
                 "shasum": ""
2280
                 "shasum": ""
2281
             },
2281
             },
2282
             "require": {
2282
             "require": {
2316
                 "issues": "https://github.com/filamentphp/filament/issues",
2316
                 "issues": "https://github.com/filamentphp/filament/issues",
2317
                 "source": "https://github.com/filamentphp/filament"
2317
                 "source": "https://github.com/filamentphp/filament"
2318
             },
2318
             },
2319
-            "time": "2024-03-11T11:21:42+00:00"
2319
+            "time": "2024-03-14T10:54:32+00:00"
2320
         },
2320
         },
2321
         {
2321
         {
2322
             "name": "filament/widgets",
2322
             "name": "filament/widgets",
2323
-            "version": "v3.2.47",
2323
+            "version": "v3.2.50",
2324
             "source": {
2324
             "source": {
2325
                 "type": "git",
2325
                 "type": "git",
2326
                 "url": "https://github.com/filamentphp/widgets.git",
2326
                 "url": "https://github.com/filamentphp/widgets.git",
2327
-                "reference": "dc074f0f78ae2ba6d176249b00e05f10d4a939a3"
2327
+                "reference": "38a011b9a556a2786028eb80aa135e171569d2af"
2328
             },
2328
             },
2329
             "dist": {
2329
             "dist": {
2330
                 "type": "zip",
2330
                 "type": "zip",
2331
-                "url": "https://api.github.com/repos/filamentphp/widgets/zipball/dc074f0f78ae2ba6d176249b00e05f10d4a939a3",
2332
-                "reference": "dc074f0f78ae2ba6d176249b00e05f10d4a939a3",
2331
+                "url": "https://api.github.com/repos/filamentphp/widgets/zipball/38a011b9a556a2786028eb80aa135e171569d2af",
2332
+                "reference": "38a011b9a556a2786028eb80aa135e171569d2af",
2333
                 "shasum": ""
2333
                 "shasum": ""
2334
             },
2334
             },
2335
             "require": {
2335
             "require": {
2360
                 "issues": "https://github.com/filamentphp/filament/issues",
2360
                 "issues": "https://github.com/filamentphp/filament/issues",
2361
                 "source": "https://github.com/filamentphp/filament"
2361
                 "source": "https://github.com/filamentphp/filament"
2362
             },
2362
             },
2363
-            "time": "2024-03-11T11:21:45+00:00"
2363
+            "time": "2024-03-14T10:54:33+00:00"
2364
         },
2364
         },
2365
         {
2365
         {
2366
             "name": "fruitcake/php-cors",
2366
             "name": "fruitcake/php-cors",
2497
         },
2497
         },
2498
         {
2498
         {
2499
             "name": "guava/filament-clusters",
2499
             "name": "guava/filament-clusters",
2500
-            "version": "1.1.0",
2500
+            "version": "1.2.0",
2501
             "source": {
2501
             "source": {
2502
                 "type": "git",
2502
                 "type": "git",
2503
                 "url": "https://github.com/GuavaCZ/filament-clusters.git",
2503
                 "url": "https://github.com/GuavaCZ/filament-clusters.git",
2504
-                "reference": "4801324f633e4db0532ee0a1d64ed57c8afcfe4a"
2504
+                "reference": "b9bd5a413e8f392653c06e77acb19c20b6a26924"
2505
             },
2505
             },
2506
             "dist": {
2506
             "dist": {
2507
                 "type": "zip",
2507
                 "type": "zip",
2508
-                "url": "https://api.github.com/repos/GuavaCZ/filament-clusters/zipball/4801324f633e4db0532ee0a1d64ed57c8afcfe4a",
2509
-                "reference": "4801324f633e4db0532ee0a1d64ed57c8afcfe4a",
2508
+                "url": "https://api.github.com/repos/GuavaCZ/filament-clusters/zipball/b9bd5a413e8f392653c06e77acb19c20b6a26924",
2509
+                "reference": "b9bd5a413e8f392653c06e77acb19c20b6a26924",
2510
                 "shasum": ""
2510
                 "shasum": ""
2511
             },
2511
             },
2512
             "require": {
2512
             "require": {
2513
                 "filament/filament": "^3.0",
2513
                 "filament/filament": "^3.0",
2514
-                "illuminate/contracts": "^10.0",
2514
+                "illuminate/contracts": "^10.0 | ^11.0",
2515
                 "php": "^8.1",
2515
                 "php": "^8.1",
2516
                 "spatie/laravel-package-tools": "^1.14.0"
2516
                 "spatie/laravel-package-tools": "^1.14.0"
2517
             },
2517
             },
2560
             ],
2560
             ],
2561
             "support": {
2561
             "support": {
2562
                 "issues": "https://github.com/GuavaCZ/filament-clusters/issues",
2562
                 "issues": "https://github.com/GuavaCZ/filament-clusters/issues",
2563
-                "source": "https://github.com/GuavaCZ/filament-clusters/tree/1.1.0"
2563
+                "source": "https://github.com/GuavaCZ/filament-clusters/tree/1.2.0"
2564
             },
2564
             },
2565
             "funding": [
2565
             "funding": [
2566
                 {
2566
                 {
2568
                     "type": "github"
2568
                     "type": "github"
2569
                 }
2569
                 }
2570
             ],
2570
             ],
2571
-            "time": "2023-10-18T12:19:40+00:00"
2571
+            "time": "2024-03-15T12:43:01+00:00"
2572
         },
2572
         },
2573
         {
2573
         {
2574
             "name": "guzzlehttp/guzzle",
2574
             "name": "guzzlehttp/guzzle",
3045
         },
3045
         },
3046
         {
3046
         {
3047
             "name": "laravel/framework",
3047
             "name": "laravel/framework",
3048
-            "version": "v10.48.2",
3048
+            "version": "v10.48.3",
3049
             "source": {
3049
             "source": {
3050
                 "type": "git",
3050
                 "type": "git",
3051
                 "url": "https://github.com/laravel/framework.git",
3051
                 "url": "https://github.com/laravel/framework.git",
3052
-                "reference": "32a8bb151d748b579c3794dea53b56bd40dfbbd3"
3052
+                "reference": "5791c052b41c6b593556adc687076bfbdd13c501"
3053
             },
3053
             },
3054
             "dist": {
3054
             "dist": {
3055
                 "type": "zip",
3055
                 "type": "zip",
3056
-                "url": "https://api.github.com/repos/laravel/framework/zipball/32a8bb151d748b579c3794dea53b56bd40dfbbd3",
3057
-                "reference": "32a8bb151d748b579c3794dea53b56bd40dfbbd3",
3056
+                "url": "https://api.github.com/repos/laravel/framework/zipball/5791c052b41c6b593556adc687076bfbdd13c501",
3057
+                "reference": "5791c052b41c6b593556adc687076bfbdd13c501",
3058
                 "shasum": ""
3058
                 "shasum": ""
3059
             },
3059
             },
3060
             "require": {
3060
             "require": {
3248
                 "issues": "https://github.com/laravel/framework/issues",
3248
                 "issues": "https://github.com/laravel/framework/issues",
3249
                 "source": "https://github.com/laravel/framework"
3249
                 "source": "https://github.com/laravel/framework"
3250
             },
3250
             },
3251
-            "time": "2024-03-12T16:35:43+00:00"
3251
+            "time": "2024-03-15T10:17:07+00:00"
3252
         },
3252
         },
3253
         {
3253
         {
3254
             "name": "laravel/prompts",
3254
             "name": "laravel/prompts",
4304
         },
4304
         },
4305
         {
4305
         {
4306
             "name": "livewire/livewire",
4306
             "name": "livewire/livewire",
4307
-            "version": "v3.4.8",
4307
+            "version": "v3.4.9",
4308
             "source": {
4308
             "source": {
4309
                 "type": "git",
4309
                 "type": "git",
4310
                 "url": "https://github.com/livewire/livewire.git",
4310
                 "url": "https://github.com/livewire/livewire.git",
4311
-                "reference": "0335b8f022ac535fc3cf29fd8a8fcb275353a470"
4311
+                "reference": "c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0"
4312
             },
4312
             },
4313
             "dist": {
4313
             "dist": {
4314
                 "type": "zip",
4314
                 "type": "zip",
4315
-                "url": "https://api.github.com/repos/livewire/livewire/zipball/0335b8f022ac535fc3cf29fd8a8fcb275353a470",
4316
-                "reference": "0335b8f022ac535fc3cf29fd8a8fcb275353a470",
4315
+                "url": "https://api.github.com/repos/livewire/livewire/zipball/c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0",
4316
+                "reference": "c65b3f0798ab2c9338213ede3588c3cdf4e6fcc0",
4317
                 "shasum": ""
4317
                 "shasum": ""
4318
             },
4318
             },
4319
             "require": {
4319
             "require": {
4367
             "description": "A front-end framework for Laravel.",
4367
             "description": "A front-end framework for Laravel.",
4368
             "support": {
4368
             "support": {
4369
                 "issues": "https://github.com/livewire/livewire/issues",
4369
                 "issues": "https://github.com/livewire/livewire/issues",
4370
-                "source": "https://github.com/livewire/livewire/tree/v3.4.8"
4370
+                "source": "https://github.com/livewire/livewire/tree/v3.4.9"
4371
             },
4371
             },
4372
             "funding": [
4372
             "funding": [
4373
                 {
4373
                 {
4375
                     "type": "github"
4375
                     "type": "github"
4376
                 }
4376
                 }
4377
             ],
4377
             ],
4378
-            "time": "2024-03-08T13:01:50+00:00"
4378
+            "time": "2024-03-14T14:03:32+00:00"
4379
         },
4379
         },
4380
         {
4380
         {
4381
             "name": "masterminds/html5",
4381
             "name": "masterminds/html5",
5272
         },
5272
         },
5273
         {
5273
         {
5274
             "name": "phenx/php-svg-lib",
5274
             "name": "phenx/php-svg-lib",
5275
-            "version": "0.5.2",
5275
+            "version": "0.5.3",
5276
             "source": {
5276
             "source": {
5277
                 "type": "git",
5277
                 "type": "git",
5278
                 "url": "https://github.com/dompdf/php-svg-lib.git",
5278
                 "url": "https://github.com/dompdf/php-svg-lib.git",
5279
-                "reference": "732faa9fb4309221e2bd9b2fda5de44f947133aa"
5279
+                "reference": "0e46722c154726a5f9ac218197ccc28adba16fcf"
5280
             },
5280
             },
5281
             "dist": {
5281
             "dist": {
5282
                 "type": "zip",
5282
                 "type": "zip",
5283
-                "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/732faa9fb4309221e2bd9b2fda5de44f947133aa",
5284
-                "reference": "732faa9fb4309221e2bd9b2fda5de44f947133aa",
5283
+                "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/0e46722c154726a5f9ac218197ccc28adba16fcf",
5284
+                "reference": "0e46722c154726a5f9ac218197ccc28adba16fcf",
5285
                 "shasum": ""
5285
                 "shasum": ""
5286
             },
5286
             },
5287
             "require": {
5287
             "require": {
5300
             },
5300
             },
5301
             "notification-url": "https://packagist.org/downloads/",
5301
             "notification-url": "https://packagist.org/downloads/",
5302
             "license": [
5302
             "license": [
5303
-                "LGPL-3.0"
5303
+                "LGPL-3.0-or-later"
5304
             ],
5304
             ],
5305
             "authors": [
5305
             "authors": [
5306
                 {
5306
                 {
5312
             "homepage": "https://github.com/PhenX/php-svg-lib",
5312
             "homepage": "https://github.com/PhenX/php-svg-lib",
5313
             "support": {
5313
             "support": {
5314
                 "issues": "https://github.com/dompdf/php-svg-lib/issues",
5314
                 "issues": "https://github.com/dompdf/php-svg-lib/issues",
5315
-                "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.2"
5315
+                "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.3"
5316
             },
5316
             },
5317
-            "time": "2024-02-07T12:49:40+00:00"
5317
+            "time": "2024-02-23T20:39:24+00:00"
5318
         },
5318
         },
5319
         {
5319
         {
5320
             "name": "phpoption/phpoption",
5320
             "name": "phpoption/phpoption",
5854
         },
5854
         },
5855
         {
5855
         {
5856
             "name": "psy/psysh",
5856
             "name": "psy/psysh",
5857
-            "version": "v0.12.0",
5857
+            "version": "v0.12.1",
5858
             "source": {
5858
             "source": {
5859
                 "type": "git",
5859
                 "type": "git",
5860
                 "url": "https://github.com/bobthecow/psysh.git",
5860
                 "url": "https://github.com/bobthecow/psysh.git",
5861
-                "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d"
5861
+                "reference": "39621c73e0754328252f032c6997b983afc50431"
5862
             },
5862
             },
5863
             "dist": {
5863
             "dist": {
5864
                 "type": "zip",
5864
                 "type": "zip",
5865
-                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/750bf031a48fd07c673dbe3f11f72362ea306d0d",
5866
-                "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d",
5865
+                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/39621c73e0754328252f032c6997b983afc50431",
5866
+                "reference": "39621c73e0754328252f032c6997b983afc50431",
5867
                 "shasum": ""
5867
                 "shasum": ""
5868
             },
5868
             },
5869
             "require": {
5869
             "require": {
5927
             ],
5927
             ],
5928
             "support": {
5928
             "support": {
5929
                 "issues": "https://github.com/bobthecow/psysh/issues",
5929
                 "issues": "https://github.com/bobthecow/psysh/issues",
5930
-                "source": "https://github.com/bobthecow/psysh/tree/v0.12.0"
5930
+                "source": "https://github.com/bobthecow/psysh/tree/v0.12.1"
5931
             },
5931
             },
5932
-            "time": "2023-12-20T15:28:09+00:00"
5932
+            "time": "2024-03-15T03:22:57+00:00"
5933
         },
5933
         },
5934
         {
5934
         {
5935
             "name": "ralouphie/getallheaders",
5935
             "name": "ralouphie/getallheaders",

+ 268
- 0
config/dompdf.php 查看文件

1
+<?php
2
+
3
+return [
4
+
5
+    /*
6
+    |--------------------------------------------------------------------------
7
+    | Settings
8
+    |--------------------------------------------------------------------------
9
+    |
10
+    | Set some default values. It is possible to add all defines that can be set
11
+    | in dompdf_config.inc.php. You can also override the entire config file.
12
+    |
13
+    */
14
+    'show_warnings' => false,   // Throw an Exception on warnings from dompdf
15
+
16
+    'public_path' => null,  // Override the public path if needed
17
+
18
+    /*
19
+     * Dejavu Sans font is missing glyphs for converted entities, turn it off if you need to show € and £.
20
+     */
21
+    'convert_entities' => true,
22
+
23
+    'options' => [
24
+        /**
25
+         * The location of the DOMPDF font directory
26
+         *
27
+         * The location of the directory where DOMPDF will store fonts and font metrics
28
+         * Note: This directory must exist and be writable by the webserver process.
29
+         * *Please note the trailing slash.*
30
+         *
31
+         * Notes regarding fonts:
32
+         * Additional .afm font metrics can be added by executing load_font.php from command line.
33
+         *
34
+         * Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
35
+         * be embedded in the pdf file or the PDF may not display correctly. This can significantly
36
+         * increase file size unless font subsetting is enabled. Before embedding a font please
37
+         * review your rights under the font license.
38
+         *
39
+         * Any font specification in the source HTML is translated to the closest font available
40
+         * in the font directory.
41
+         *
42
+         * The pdf standard "Base 14 fonts" are:
43
+         * Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
44
+         * Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
45
+         * Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
46
+         * Symbol, ZapfDingbats.
47
+         */
48
+        'font_dir' => storage_path('fonts'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
49
+
50
+        /**
51
+         * The location of the DOMPDF font cache directory
52
+         *
53
+         * This directory contains the cached font metrics for the fonts used by DOMPDF.
54
+         * This directory can be the same as DOMPDF_FONT_DIR
55
+         *
56
+         * Note: This directory must exist and be writable by the webserver process.
57
+         */
58
+        'font_cache' => storage_path('fonts'),
59
+
60
+        /**
61
+         * The location of a temporary directory.
62
+         *
63
+         * The directory specified must be writeable by the webserver process.
64
+         * The temporary directory is required to download remote images and when
65
+         * using the PDFLib back end.
66
+         */
67
+        'temp_dir' => sys_get_temp_dir(),
68
+
69
+        /**
70
+         * ==== IMPORTANT ====
71
+         *
72
+         * dompdf's "chroot": Prevents dompdf from accessing system files or other
73
+         * files on the webserver.  All local files opened by dompdf must be in a
74
+         * subdirectory of this directory.  DO NOT set it to '/' since this could
75
+         * allow an attacker to use dompdf to read any files on the server.  This
76
+         * should be an absolute path.
77
+         * This is only checked on command line call by dompdf.php, but not by
78
+         * direct class use like:
79
+         * $dompdf = new DOMPDF();  $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
80
+         */
81
+        'chroot' => realpath(base_path()),
82
+
83
+        /**
84
+         * Protocol whitelist
85
+         *
86
+         * Protocols and PHP wrappers allowed in URIs, and the validation rules
87
+         * that determine if a resource may be loaded. Full support is not guaranteed
88
+         * for the protocols/wrappers specified
89
+         * by this array.
90
+         *
91
+         * @var array
92
+         */
93
+        'allowed_protocols' => [
94
+            'file://' => ['rules' => []],
95
+            'http://' => ['rules' => []],
96
+            'https://' => ['rules' => []],
97
+        ],
98
+
99
+
100
+        'log_output_file' => null,
101
+
102
+        /**
103
+         * Whether to enable font subsetting or not.
104
+         */
105
+        'enable_font_subsetting' => true,
106
+
107
+        /**
108
+         * The PDF rendering backend to use
109
+         *
110
+         * Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
111
+         * 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
112
+         * fall back on CPDF. 'GD' renders PDFs to graphic files. {@link * Canvas_Factory} ultimately determines which rendering class to instantiate
113
+         * based on this setting.
114
+         *
115
+         * Both PDFLib & CPDF rendering backends provide sufficient rendering
116
+         * capabilities for dompdf, however additional features (e.g. object,
117
+         * image and font support, etc.) differ between backends.  Please see
118
+         * {@link PDFLib_Adapter} for more information on the PDFLib backend
119
+         * and {@link CPDF_Adapter} and lib/class.pdf.php for more information
120
+         * on CPDF. Also see the documentation for each backend at the links
121
+         * below.
122
+         *
123
+         * The GD rendering backend is a little different than PDFLib and
124
+         * CPDF. Several features of CPDF and PDFLib are not supported or do
125
+         * not make any sense when creating image files.  For example,
126
+         * multiple pages are not supported, nor are PDF 'objects'.  Have a
127
+         * look at {@link GD_Adapter} for more information.  GD support is
128
+         * experimental, so use it at your own risk.
129
+         *
130
+         * @link http://www.pdflib.com
131
+         * @link http://www.ros.co.nz/pdf
132
+         * @link http://www.php.net/image
133
+         */
134
+        'pdf_backend' => 'CPDF',
135
+
136
+        /**
137
+         * PDFlib license key
138
+         *
139
+         * If you are using a licensed, commercial version of PDFlib, specify
140
+         * your license key here.  If you are using PDFlib-Lite or are evaluating
141
+         * the commercial version of PDFlib, comment out this setting.
142
+         *
143
+         * @link http://www.pdflib.com
144
+         *
145
+         * If pdflib present in web server and auto or selected explicitly above,
146
+         * a real license code must exist!
147
+         */
148
+        //"DOMPDF_PDFLIB_LICENSE" => "your license key here",
149
+
150
+        /**
151
+         * html target media view which should be rendered into pdf.
152
+         * List of types and parsing rules for future extensions:
153
+         * http://www.w3.org/TR/REC-html40/types.html
154
+         *   screen, tty, tv, projection, handheld, print, braille, aural, all
155
+         * Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
156
+         * Note, even though the generated pdf file is intended for print output,
157
+         * the desired content might be different (e.g. screen or projection view of html file).
158
+         * Therefore allow specification of content here.
159
+         */
160
+        'default_media_type' => 'screen',
161
+
162
+        /**
163
+         * The default paper size.
164
+         *
165
+         * North America standard is "letter"; other countries generally "a4"
166
+         *
167
+         * @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
168
+         */
169
+        'default_paper_size' => 'a4',
170
+
171
+        /**
172
+         * The default paper orientation.
173
+         *
174
+         * The orientation of the page (portrait or landscape).
175
+         */
176
+        'default_paper_orientation' => 'portrait',
177
+
178
+        /**
179
+         * The default font family
180
+         *
181
+         * Used if no suitable fonts can be found. This must exist in the font folder.
182
+         */
183
+        'default_font' => 'sans-serif',
184
+
185
+        /**
186
+         * Image DPI setting
187
+         *
188
+         * This setting determines the default DPI setting for images and fonts.  The
189
+         * DPI may be overridden for inline images by explicitly setting the
190
+         * image's width & height style attributes (i.e. if the image's native
191
+         * width is 600 pixels and you specify the image's width as 72 points,
192
+         * the image will have a DPI of 600 in the rendered PDF.  The DPI of
193
+         * background images can not be overridden and is controlled entirely
194
+         * via this parameter.
195
+         *
196
+         * For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
197
+         * If a size in html is given as px (or without unit as image size),
198
+         * this tells the corresponding size in pt.
199
+         * This adjusts the relative sizes to be similar to the rendering of the
200
+         * html page in a reference browser.
201
+         *
202
+         * In pdf, always 1 pt = 1/72 inch
203
+         *
204
+         * Rendering resolution of various browsers in px per inch:
205
+         * Windows Firefox and Internet Explorer:
206
+         *   SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
207
+         * Linux Firefox:
208
+         *   about:config *resolution: Default:96
209
+         *   (xorg screen dimension in mm and Desktop font dpi settings are ignored)
210
+         *
211
+         * Take care about extra font/image zoom factor of browser.
212
+         *
213
+         * In images, <img> size in pixel attribute, img css style, are overriding
214
+         * the real image dimension in px for rendering.
215
+         */
216
+        'dpi' => 96,
217
+
218
+        /**
219
+         * Enable inline PHP
220
+         *
221
+         * If this setting is set to true then DOMPDF will automatically evaluate
222
+         * inline PHP contained within <script type="text/php"> ... </script> tags.
223
+         *
224
+         * Enabling this for documents you do not trust (e.g. arbitrary remote html
225
+         * pages) is a security risk.  Set this option to false if you wish to process
226
+         * untrusted documents.
227
+         */
228
+        'enable_php' => true,
229
+
230
+        /**
231
+         * Enable inline Javascript
232
+         *
233
+         * If this setting is set to true then DOMPDF will automatically insert
234
+         * JavaScript code contained within <script type="text/javascript"> ... </script> tags.
235
+         */
236
+        'enable_javascript' => true,
237
+
238
+        /**
239
+         * Enable remote file access
240
+         *
241
+         * If this setting is set to true, DOMPDF will access remote sites for
242
+         * images and CSS files as required.
243
+         * This is required for part of test case www/test/image_variants.html through www/examples.php
244
+         *
245
+         * Attention!
246
+         * This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and
247
+         * allowing remote access to dompdf.php or on allowing remote html code to be passed to
248
+         * $dompdf = new DOMPDF(, $dompdf->load_html(...,
249
+         * This allows anonymous users to download legally doubtful internet content which on
250
+         * tracing back appears to being downloaded by your server, or allows malicious php code
251
+         * in remote html pages to be executed by your server with your account privileges.
252
+         */
253
+        'enable_remote' => true,
254
+
255
+        /**
256
+         * A ratio applied to the fonts height to be more like browsers' line height
257
+         */
258
+        'font_height_ratio' => 1.1,
259
+
260
+        /**
261
+         * Use the HTML5 Lib parser
262
+         *
263
+         * @deprecated This feature is now always on in dompdf 2.x
264
+         */
265
+        'enable_html5_parser' => true,
266
+    ],
267
+
268
+];

+ 1
- 2
database/migrations/2024_01_01_234943_create_transactions_table.php 查看文件

17
             $table->foreignId('account_id')->nullable()->constrained()->nullOnDelete();
17
             $table->foreignId('account_id')->nullable()->constrained()->nullOnDelete();
18
             $table->foreignId('bank_account_id')->nullable()->constrained()->nullOnDelete();
18
             $table->foreignId('bank_account_id')->nullable()->constrained()->nullOnDelete();
19
             $table->foreignId('contact_id')->nullable()->constrained()->nullOnDelete();
19
             $table->foreignId('contact_id')->nullable()->constrained()->nullOnDelete();
20
-            $table->string('type'); // income, expense, other
21
-            $table->string('method'); // deposit, withdrawal
20
+            $table->string('type'); // deposit, withdrawal, journal entry
22
             $table->string('payment_channel')->nullable(); // online, in store, other
21
             $table->string('payment_channel')->nullable(); // online, in store, other
23
             $table->string('description')->nullable();
22
             $table->string('description')->nullable();
24
             $table->text('notes')->nullable();
23
             $table->text('notes')->nullable();

+ 22
- 19
package-lock.json 查看文件

609
             }
609
             }
610
         },
610
         },
611
         "node_modules/axios": {
611
         "node_modules/axios": {
612
-            "version": "1.6.7",
613
-            "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
614
-            "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
612
+            "version": "1.6.8",
613
+            "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
614
+            "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
615
             "dev": true,
615
             "dev": true,
616
             "dependencies": {
616
             "dependencies": {
617
-                "follow-redirects": "^1.15.4",
617
+                "follow-redirects": "^1.15.6",
618
                 "form-data": "^4.0.0",
618
                 "form-data": "^4.0.0",
619
                 "proxy-from-env": "^1.1.0"
619
                 "proxy-from-env": "^1.1.0"
620
             }
620
             }
626
             "dev": true
626
             "dev": true
627
         },
627
         },
628
         "node_modules/binary-extensions": {
628
         "node_modules/binary-extensions": {
629
-            "version": "2.2.0",
630
-            "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
631
-            "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
629
+            "version": "2.3.0",
630
+            "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
631
+            "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
632
             "dev": true,
632
             "dev": true,
633
             "engines": {
633
             "engines": {
634
                 "node": ">=8"
634
                 "node": ">=8"
635
+            },
636
+            "funding": {
637
+                "url": "https://github.com/sponsors/sindresorhus"
635
             }
638
             }
636
         },
639
         },
637
         "node_modules/brace-expansion": {
640
         "node_modules/brace-expansion": {
845
             "dev": true
848
             "dev": true
846
         },
849
         },
847
         "node_modules/electron-to-chromium": {
850
         "node_modules/electron-to-chromium": {
848
-            "version": "1.4.701",
849
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.701.tgz",
850
-            "integrity": "sha512-K3WPQ36bUOtXg/1+69bFlFOvdSm0/0bGqmsfPDLRXLanoKXdA+pIWuf/VbA9b+2CwBFuONgl4NEz4OEm+OJOKA==",
851
+            "version": "1.4.708",
852
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.708.tgz",
853
+            "integrity": "sha512-iWgEEvREL4GTXXHKohhh33+6Y8XkPI5eHihDmm8zUk5Zo7HICEW+wI/j5kJ2tbuNUCXJ/sNXa03ajW635DiJXA==",
851
             "dev": true
854
             "dev": true
852
         },
855
         },
853
         "node_modules/emoji-regex": {
856
         "node_modules/emoji-regex": {
952
             }
955
             }
953
         },
956
         },
954
         "node_modules/follow-redirects": {
957
         "node_modules/follow-redirects": {
955
-            "version": "1.15.5",
956
-            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
957
-            "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
958
+            "version": "1.15.6",
959
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
960
+            "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
958
             "dev": true,
961
             "dev": true,
959
             "funding": [
962
             "funding": [
960
                 {
963
                 {
1582
             }
1585
             }
1583
         },
1586
         },
1584
         "node_modules/postcss-nested/node_modules/postcss-selector-parser": {
1587
         "node_modules/postcss-nested/node_modules/postcss-selector-parser": {
1585
-            "version": "6.0.15",
1586
-            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
1587
-            "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
1588
+            "version": "6.0.16",
1589
+            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
1590
+            "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
1588
             "dev": true,
1591
             "dev": true,
1589
             "dependencies": {
1592
             "dependencies": {
1590
                 "cssesc": "^3.0.0",
1593
                 "cssesc": "^3.0.0",
1936
             }
1939
             }
1937
         },
1940
         },
1938
         "node_modules/tailwindcss/node_modules/postcss-selector-parser": {
1941
         "node_modules/tailwindcss/node_modules/postcss-selector-parser": {
1939
-            "version": "6.0.15",
1940
-            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
1941
-            "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
1942
+            "version": "6.0.16",
1943
+            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
1944
+            "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
1942
             "dev": true,
1945
             "dev": true,
1943
             "dependencies": {
1946
             "dependencies": {
1944
                 "cssesc": "^3.0.0",
1947
                 "cssesc": "^3.0.0",

+ 4
- 13
resources/views/components/company/reports/account-balances.blade.php 查看文件

1
 <!DOCTYPE html>
1
 <!DOCTYPE html>
2
 <html lang="en">
2
 <html lang="en">
3
 <head>
3
 <head>
4
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1">
5
     <title>Account Balances</title>
6
     <title>Account Balances</title>
6
     <style>
7
     <style>
7
         @page {
8
         @page {
8
-            margin: 0.25in 0.25in 1in 0.25in;
9
+            size: A4;
10
+            margin: 8.5mm 8.5mm 30mm 8.5mm;
9
         }
11
         }
10
 
12
 
11
         .header {
13
         .header {
122
             </tr>
124
             </tr>
123
         </tfoot>
125
         </tfoot>
124
     </table>
126
     </table>
125
-    <script type="text/php">
126
-        if (isset($pdf)) {
127
-            $font = $fontMetrics->getFont("Inter, sans-serif", "normal");
128
-            $size = 8;
129
-
130
-            $pageText = "Page {PAGE_NUM} of {PAGE_COUNT}";
131
-            $x = 533;
132
-            $y = 820;
133
-            $pdf->page_text($x, $y, $pageText, $font, $size);
134
-        }
135
-    </script>
136
 </body>
127
 </body>

+ 23
- 0
resources/views/filament/company/components/tables/actions/mark-as-reviewed.blade.php 查看文件

1
+@php
2
+    $isDisabled = $action->isDisabled();
3
+@endphp
4
+
5
+<span
6
+    x-data="{}"
7
+    x-tooltip="{
8
+        content: @js($action->getTooltip()),
9
+        theme: $store.theme === 'dark' ? 'light' : 'dark',
10
+        placement: 'left',
11
+    }"
12
+>
13
+    <x-filament::icon-button
14
+        @class([
15
+            'disabled:cursor-not-allowed disabled:pointer-events-auto disabled:hover:text-gray-400',
16
+        ])
17
+        :icon="$action->getIcon()"
18
+        :color="$action->getColor()"
19
+        :disabled="$isDisabled"
20
+        :size="$action->getIconSize()"
21
+        :wire:click="$action->getLivewireClickHandler()"
22
+    />
23
+</span>

Loading…
取消
儲存