浏览代码

wip balance sheet

3.x
Andrew Wallo 1年前
父节点
当前提交
c50bf4bffc

+ 3
- 0
app/Filament/Company/Clusters/Settings/Resources/CurrencyResource.php 查看文件

185
                                     $action->cancel();
185
                                     $action->cancel();
186
                                 }
186
                                 }
187
                             }
187
                             }
188
+                        })
189
+                        ->hidden(function (Table $table) {
190
+                            return $table->getAllSelectableRecordsCount() === 0;
188
                         }),
191
                         }),
189
                 ]),
192
                 ]),
190
             ])
193
             ])

+ 1
- 6
app/Filament/Company/Pages/Accounting/AccountChart.php 查看文件

33
     protected static string $view = 'filament.company.pages.accounting.chart';
33
     protected static string $view = 'filament.company.pages.accounting.chart';
34
 
34
 
35
     #[Url]
35
     #[Url]
36
-    public ?string $activeTab = null;
37
-
38
-    public function mount(): void
39
-    {
40
-        $this->activeTab = $this->activeTab ?? AccountCategory::Asset->value;
41
-    }
36
+    public ?string $activeTab = AccountCategory::Asset->value;
42
 
37
 
43
     protected function configureAction(Action $action): void
38
     protected function configureAction(Action $action): void
44
     {
39
     {

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

459
     protected function getFormDefaultsForType(TransactionType $type): array
459
     protected function getFormDefaultsForType(TransactionType $type): array
460
     {
460
     {
461
         $commonDefaults = [
461
         $commonDefaults = [
462
-            'posted_at' => now()->format('Y-m-d'),
462
+            'posted_at' => today(),
463
         ];
463
         ];
464
 
464
 
465
         return match ($type) {
465
         return match ($type) {

+ 4
- 0
app/Filament/Company/Pages/Reports/BalanceSheet.php 查看文件

11
 use App\Transformers\BalanceSheetReportTransformer;
11
 use App\Transformers\BalanceSheetReportTransformer;
12
 use Filament\Forms\Form;
12
 use Filament\Forms\Form;
13
 use Filament\Support\Enums\Alignment;
13
 use Filament\Support\Enums\Alignment;
14
+use Livewire\Attributes\Url;
14
 use Symfony\Component\HttpFoundation\StreamedResponse;
15
 use Symfony\Component\HttpFoundation\StreamedResponse;
15
 
16
 
16
 class BalanceSheet extends BaseReportPage
17
 class BalanceSheet extends BaseReportPage
23
 
24
 
24
     protected ExportService $exportService;
25
     protected ExportService $exportService;
25
 
26
 
27
+    #[Url]
28
+    public ?string $activeTab = 'summary';
29
+
26
     public function boot(ReportService $reportService, ExportService $exportService): void
30
     public function boot(ReportService $reportService, ExportService $exportService): void
27
     {
31
     {
28
         $this->reportService = $reportService;
32
         $this->reportService = $reportService;

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

143
                 Tables\Actions\BulkActionGroup::make([
143
                 Tables\Actions\BulkActionGroup::make([
144
                     Tables\Actions\DeleteBulkAction::make()
144
                     Tables\Actions\DeleteBulkAction::make()
145
                         ->requiresConfirmation()
145
                         ->requiresConfirmation()
146
-                        ->modalDescription('Are you sure you want to delete the selected accounts? All transactions associated with the accounts will be deleted as well.'),
146
+                        ->modalDescription('Are you sure you want to delete the selected accounts? All transactions associated with the accounts will be deleted as well.')
147
+                        ->hidden(function (Table $table) {
148
+                            return $table->getAllSelectableRecordsCount() === 0;
149
+                        }),
147
                 ]),
150
                 ]),
148
             ])
151
             ])
149
             ->checkIfRecordIsSelectableUsing(static function (BankAccount $record) {
152
             ->checkIfRecordIsSelectableUsing(static function (BankAccount $record) {

+ 2
- 1
app/Filament/Company/Resources/Banking/AccountResource/Pages/EditAccount.php 查看文件

3
 namespace App\Filament\Company\Resources\Banking\AccountResource\Pages;
3
 namespace App\Filament\Company\Resources\Banking\AccountResource\Pages;
4
 
4
 
5
 use App\Filament\Company\Resources\Banking\AccountResource;
5
 use App\Filament\Company\Resources\Banking\AccountResource;
6
+use Filament\Actions;
6
 use Filament\Resources\Pages\EditRecord;
7
 use Filament\Resources\Pages\EditRecord;
7
 
8
 
8
 class EditAccount extends EditRecord
9
 class EditAccount extends EditRecord
12
     protected function getHeaderActions(): array
13
     protected function getHeaderActions(): array
13
     {
14
     {
14
         return [
15
         return [
15
-            //
16
+            Actions\DeleteAction::make(),
16
         ];
17
         ];
17
     }
18
     }
18
 
19
 

+ 1
- 1
app/Listeners/UpdateAccountBalances.php 查看文件

58
                         'type' => $transactionType,
58
                         'type' => $transactionType,
59
                         'amount' => $formattedSimpleDifference,
59
                         'amount' => $formattedSimpleDifference,
60
                         'payment_channel' => 'other',
60
                         'payment_channel' => 'other',
61
-                        'posted_at' => now(),
61
+                        'posted_at' => today(),
62
                         'description' => $description,
62
                         'description' => $description,
63
                         'pending' => false,
63
                         'pending' => false,
64
                         'reviewed' => false,
64
                         'reviewed' => false,

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

48
         'amount' => TransactionAmountCast::class,
48
         'amount' => TransactionAmountCast::class,
49
         'pending' => 'boolean',
49
         'pending' => 'boolean',
50
         'reviewed' => 'boolean',
50
         'reviewed' => 'boolean',
51
-        'posted_at' => 'datetime',
51
+        'posted_at' => 'date',
52
     ];
52
     ];
53
 
53
 
54
     public function account(): BelongsTo
54
     public function account(): BelongsTo

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

228
     {
228
     {
229
         $earliestDate = Transaction::min('posted_at');
229
         $earliestDate = Transaction::min('posted_at');
230
 
230
 
231
-        return $earliestDate ?? now()->toDateTimeString();
231
+        return $earliestDate ?? today()->toDateTimeString();
232
     }
232
     }
233
 }
233
 }

+ 27
- 34
app/Services/ReportService.php 查看文件

9
 use App\DTO\AccountTypeDTO;
9
 use App\DTO\AccountTypeDTO;
10
 use App\DTO\ReportDTO;
10
 use App\DTO\ReportDTO;
11
 use App\Enums\Accounting\AccountCategory;
11
 use App\Enums\Accounting\AccountCategory;
12
+use App\Enums\Accounting\AccountType;
12
 use App\Models\Accounting\Account;
13
 use App\Models\Accounting\Account;
13
 use App\Support\Column;
14
 use App\Support\Column;
14
 use App\Utilities\Currency\CurrencyAccessor;
15
 use App\Utilities\Currency\CurrencyAccessor;
436
         $asOfDateCarbon = Carbon::parse($asOfDate);
437
         $asOfDateCarbon = Carbon::parse($asOfDate);
437
         $startDateCarbon = Carbon::parse($this->accountService->getEarliestTransactionDate());
438
         $startDateCarbon = Carbon::parse($this->accountService->getEarliestTransactionDate());
438
 
439
 
439
-        $orderedCategories = AccountCategory::getOrderedCategories();
440
-
441
-        // Filter out non-real categories like Revenue and Expense
442
-        $orderedCategories = array_filter($orderedCategories, fn (AccountCategory $category) => $category->isReal());
440
+        $orderedCategories = array_filter(AccountCategory::getOrderedCategories(), fn (AccountCategory $category) => $category->isReal());
443
 
441
 
444
-        // Fetch account balances
445
         $accounts = $this->accountService->getAccountBalances($startDateCarbon->toDateTimeString(), $asOfDateCarbon->toDateTimeString())
442
         $accounts = $this->accountService->getAccountBalances($startDateCarbon->toDateTimeString(), $asOfDateCarbon->toDateTimeString())
443
+            ->whereIn('category', $orderedCategories)
444
+            ->orderByRaw('LENGTH(code), code')
446
             ->get();
445
             ->get();
447
 
446
 
448
         $accountCategories = [];
447
         $accountCategories = [];
455
         foreach ($orderedCategories as $category) {
454
         foreach ($orderedCategories as $category) {
456
             $categorySummaryBalances = ['ending_balance' => 0];
455
             $categorySummaryBalances = ['ending_balance' => 0];
457
 
456
 
458
-            // Group the accounts by their type within the current category
459
             $categoryAccountsByType = [];
457
             $categoryAccountsByType = [];
458
+            $categoryAccounts = [];
460
             $subCategoryTotals = [];
459
             $subCategoryTotals = [];
461
 
460
 
461
+            foreach (AccountType::cases() as $accountType) {
462
+                if ($accountType->getCategory() === $category && $accountType !== AccountType::Equity) {
463
+                    $categoryAccountsByType[$accountType->getPluralLabel()] = [];
464
+                    $subCategoryTotals[$accountType->getPluralLabel()] = 0;
465
+                }
466
+            }
467
+
462
             /** @var Account $account */
468
             /** @var Account $account */
463
             foreach ($accounts as $account) {
469
             foreach ($accounts as $account) {
464
-                // Ensure that the account type's category matches the current loop category
465
                 if ($account->type->getCategory() === $category) {
470
                 if ($account->type->getCategory() === $category) {
466
                     $accountBalances = $this->calculateAccountBalances($account, $category);
471
                     $accountBalances = $this->calculateAccountBalances($account, $category);
467
                     $endingBalance = $accountBalances['ending_balance'] ?? $accountBalances['net_movement'];
472
                     $endingBalance = $accountBalances['ending_balance'] ?? $accountBalances['net_movement'];
470
 
475
 
471
                     $formattedAccountBalances = $this->formatBalances($accountBalances);
476
                     $formattedAccountBalances = $this->formatBalances($accountBalances);
472
 
477
 
473
-                    // Create a DTO for each account
474
                     $accountDTO = new AccountDTO(
478
                     $accountDTO = new AccountDTO(
475
                         $account->name,
479
                         $account->name,
476
                         $account->code,
480
                         $account->code,
480
                         endDate: $asOfDateCarbon->toDateString(),
484
                         endDate: $asOfDateCarbon->toDateString(),
481
                     );
485
                     );
482
 
486
 
483
-                    // Group by account type label and accumulate subcategory totals
484
-                    $accountType = $account->type->getPluralLabel();
485
-                    $categoryAccountsByType[$accountType][] = $accountDTO;
486
-
487
-                    // Track totals for the subcategory (not formatted)
488
-                    $subCategoryTotals[$accountType] = ($subCategoryTotals[$accountType] ?? 0) + $endingBalance;
487
+                    if ($category === AccountCategory::Equity && $account->type === AccountType::Equity) {
488
+                        $categoryAccounts[] = $accountDTO;
489
+                    } else {
490
+                        $accountType = $account->type->getPluralLabel();
491
+                        $categoryAccountsByType[$accountType][] = $accountDTO;
492
+                        $subCategoryTotals[$accountType] += $endingBalance;
493
+                    }
489
                 }
494
                 }
490
             }
495
             }
491
 
496
 
492
-            // If the category is Equity, include Retained Earnings
493
             if ($category === AccountCategory::Equity) {
497
             if ($category === AccountCategory::Equity) {
494
                 $retainedEarningsAmount = $this->calculateRetainedEarnings($startDateCarbon->toDateTimeString(), $asOfDateCarbon->toDateTimeString())->getAmount();
498
                 $retainedEarningsAmount = $this->calculateRetainedEarnings($startDateCarbon->toDateTimeString(), $asOfDateCarbon->toDateTimeString())->getAmount();
495
 
499
 
496
                 $categorySummaryBalances['ending_balance'] += $retainedEarningsAmount;
500
                 $categorySummaryBalances['ending_balance'] += $retainedEarningsAmount;
497
 
501
 
498
-                $accountDTO = new AccountDTO(
502
+                $retainedEarningsDTO = new AccountDTO(
499
                     'Retained Earnings',
503
                     'Retained Earnings',
500
                     'RE',
504
                     'RE',
501
                     null,
505
                     null,
504
                     endDate: $asOfDateCarbon->toDateString(),
508
                     endDate: $asOfDateCarbon->toDateString(),
505
                 );
509
                 );
506
 
510
 
507
-                // Add Retained Earnings to the Equity type
508
-                $categoryAccountsByType['Equity'][] = $accountDTO;
509
-
510
-                // Add to subcategory total as well
511
-                $subCategoryTotals['Equity'] = ($subCategoryTotals['Equity'] ?? 0) + $retainedEarningsAmount;
511
+                $categoryAccounts[] = $retainedEarningsDTO;
512
             }
512
             }
513
 
513
 
514
-            // Create SubCategory DTOs for each account type within the category
515
             $subCategories = [];
514
             $subCategories = [];
516
             foreach ($categoryAccountsByType as $accountType => $accountsInType) {
515
             foreach ($categoryAccountsByType as $accountType => $accountsInType) {
517
                 $subCategorySummary = $this->formatBalances([
516
                 $subCategorySummary = $this->formatBalances([
524
                 );
523
                 );
525
             }
524
             }
526
 
525
 
527
-            // Add category totals to the overall totals
528
-            if ($category === AccountCategory::Asset) {
529
-                $reportTotalBalances['assets'] += $categorySummaryBalances['ending_balance'];
530
-            } elseif ($category === AccountCategory::Liability) {
531
-                $reportTotalBalances['liabilities'] += $categorySummaryBalances['ending_balance'];
532
-            } elseif ($category === AccountCategory::Equity) {
533
-                $reportTotalBalances['equity'] += $categorySummaryBalances['ending_balance'];
534
-            }
526
+            $reportTotalBalances[match ($category) {
527
+                AccountCategory::Asset => 'assets',
528
+                AccountCategory::Liability => 'liabilities',
529
+                AccountCategory::Equity => 'equity',
530
+            }] += $categorySummaryBalances['ending_balance'];
535
 
531
 
536
-            // Store the subcategories and the summary in the accountCategories array
537
             $accountCategories[$category->getPluralLabel()] = new AccountCategoryDTO(
532
             $accountCategories[$category->getPluralLabel()] = new AccountCategoryDTO(
533
+                accounts: $categoryAccounts,
538
                 types: $subCategories,
534
                 types: $subCategories,
539
                 summary: $this->formatBalances($categorySummaryBalances),
535
                 summary: $this->formatBalances($categorySummaryBalances),
540
             );
536
             );
541
         }
537
         }
542
 
538
 
543
-        // Calculate Net Assets (Assets - Liabilities)
544
         $netAssets = $reportTotalBalances['assets'] - $reportTotalBalances['liabilities'];
539
         $netAssets = $reportTotalBalances['assets'] - $reportTotalBalances['liabilities'];
545
 
540
 
546
-        // Format the overall totals for the report
547
         $formattedReportTotalBalances = $this->formatBalances(['ending_balance' => $netAssets]);
541
         $formattedReportTotalBalances = $this->formatBalances(['ending_balance' => $netAssets]);
548
 
542
 
549
-        // Return the constructed ReportDTO
550
         return new ReportDTO($accountCategories, $formattedReportTotalBalances, $columns);
543
         return new ReportDTO($accountCategories, $formattedReportTotalBalances, $columns);
551
     }
544
     }
552
 }
545
 }

+ 118
- 5
app/Transformers/BalanceSheetReportTransformer.php 查看文件

6
 use App\DTO\ReportCategoryDTO;
6
 use App\DTO\ReportCategoryDTO;
7
 use App\DTO\ReportTypeDTO;
7
 use App\DTO\ReportTypeDTO;
8
 use App\Support\Column;
8
 use App\Support\Column;
9
+use App\Utilities\Currency\CurrencyAccessor;
9
 
10
 
10
 class BalanceSheetReportTransformer extends BaseReportTransformer
11
 class BalanceSheetReportTransformer extends BaseReportTransformer
11
 {
12
 {
41
         $categories = [];
42
         $categories = [];
42
 
43
 
43
         foreach ($this->report->categories as $accountCategoryName => $accountCategory) {
44
         foreach ($this->report->categories as $accountCategoryName => $accountCategory) {
45
+            // Header for the main category
44
             $header = [];
46
             $header = [];
45
-
46
             foreach ($this->getColumns() as $index => $column) {
47
             foreach ($this->getColumns() as $index => $column) {
47
                 if ($column->getName() === 'account_name') {
48
                 if ($column->getName() === 'account_name') {
48
                     $header[$index] = $accountCategoryName;
49
                     $header[$index] = $accountCategoryName;
61
                 };
62
                 };
62
             }
63
             }
63
 
64
 
65
+            // Accounts directly under the main category
66
+            $data = array_map(function (AccountDTO $account) {
67
+                $row = [];
68
+                foreach ($this->getColumns() as $column) {
69
+                    $row[] = match ($column->getName()) {
70
+                        'account_code' => $account->accountCode,
71
+                        'account_name' => [
72
+                            'name' => $account->accountName,
73
+                            'id' => $account->accountId ?? null,
74
+                            'start_date' => $account->startDate,
75
+                            'end_date' => $account->endDate,
76
+                        ],
77
+                        'ending_balance' => $account->balance->endingBalance ?? '',
78
+                        default => '',
79
+                    };
80
+                }
81
+
82
+                return $row;
83
+            }, $accountCategory->accounts ?? []);
84
+
64
             // Subcategories (types) under the main category
85
             // Subcategories (types) under the main category
65
             $types = [];
86
             $types = [];
66
             foreach ($accountCategory->types as $typeName => $type) {
87
             foreach ($accountCategory->types as $typeName => $type) {
71
                 }
92
                 }
72
 
93
 
73
                 // Account data for the subcategory
94
                 // Account data for the subcategory
74
-                $data = array_map(function (AccountDTO $account) {
95
+                $typeData = array_map(function (AccountDTO $account) {
75
                     $row = [];
96
                     $row = [];
76
                     foreach ($this->getColumns() as $column) {
97
                     foreach ($this->getColumns() as $column) {
77
                         $row[] = match ($column->getName()) {
98
                         $row[] = match ($column->getName()) {
103
                 // Add subcategory (type) to the list
124
                 // Add subcategory (type) to the list
104
                 $types[$typeName] = new ReportTypeDTO(
125
                 $types[$typeName] = new ReportTypeDTO(
105
                     header: $typeHeader,
126
                     header: $typeHeader,
106
-                    data: $data,
127
+                    data: $typeData,
107
                     summary: $typeSummary,
128
                     summary: $typeSummary,
108
                 );
129
                 );
109
             }
130
             }
110
 
131
 
111
-            // Add the category to the final array with its subcategories (types)
132
+            // Add the category to the final array with its direct accounts and subcategories (types)
112
             $categories[$accountCategoryName] = new ReportCategoryDTO(
133
             $categories[$accountCategoryName] = new ReportCategoryDTO(
113
                 header: $header,
134
                 header: $header,
135
+                data: $data, // Direct accounts under the category
136
+                summary: $categorySummary,
137
+                types: $types, // Subcategories (types) under the category
138
+            );
139
+        }
140
+
141
+        return $categories;
142
+    }
143
+
144
+    public function getSummaryCategories(): array
145
+    {
146
+        $summaryCategories = [];
147
+
148
+        $columns = [
149
+            'account_name',
150
+            'ending_balance',
151
+        ];
152
+
153
+        foreach ($this->report->categories as $accountCategoryName => $accountCategory) {
154
+            $categoryHeader = [];
155
+
156
+            foreach ($columns as $index => $column) {
157
+                $categoryHeader[$index] = $column === 'account_name' ? $accountCategoryName : '';
158
+            }
159
+
160
+            $categorySummary = [];
161
+            foreach ($columns as $column) {
162
+                $categorySummary[] = match ($column) {
163
+                    'account_name' => 'Total ' . $accountCategoryName,
164
+                    'ending_balance' => $accountCategory->summary->endingBalance ?? '',
165
+                    default => '',
166
+                };
167
+            }
168
+
169
+            $types = [];
170
+            $totalTypeSummaries = 0;
171
+
172
+            // Iterate through each account type and calculate type summaries
173
+            foreach ($accountCategory->types as $typeName => $type) {
174
+                $typeSummary = [];
175
+                $typeEndingBalance = 0;
176
+
177
+                foreach ($columns as $column) {
178
+                    $typeSummary[] = match ($column) {
179
+                        'account_name' => 'Total ' . $typeName,
180
+                        'ending_balance' => $type->summary->endingBalance ?? '',
181
+                        default => '',
182
+                    };
183
+
184
+                    if ($column === 'ending_balance') {
185
+                        $typeEndingBalance = $type->summary->endingBalance ?? 0;
186
+                    }
187
+                }
188
+
189
+                $typeEndingBalance = money($typeEndingBalance, CurrencyAccessor::getDefaultCurrency())->getAmount();
190
+
191
+                $totalTypeSummaries += $typeEndingBalance;
192
+
193
+                $types[$typeName] = new ReportTypeDTO(
194
+                    header: [],
195
+                    data: [],
196
+                    summary: $typeSummary,
197
+                );
198
+            }
199
+
200
+            // Only for the "Equity" category, calculate and add "Total Other Equity"
201
+            if ($accountCategoryName === 'Equity') {
202
+                $totalEquitySummary = $accountCategory->summary->endingBalance ?? 0;
203
+                $totalEquitySummary = money($totalEquitySummary, CurrencyAccessor::getDefaultCurrency())->getAmount();
204
+                $totalOtherEquity = $totalEquitySummary - $totalTypeSummaries;
205
+                $totalOtherEquity = money($totalOtherEquity, CurrencyAccessor::getDefaultCurrency(), true)->format();
206
+
207
+                // Add "Total Other Equity" as a new "type"
208
+                $otherEquitySummary = [];
209
+                foreach ($columns as $column) {
210
+                    $otherEquitySummary[] = match ($column) {
211
+                        'account_name' => 'Total Other Equity',
212
+                        'ending_balance' => $totalOtherEquity,
213
+                        default => '',
214
+                    };
215
+                }
216
+
217
+                $types['Total Other Equity'] = new ReportTypeDTO(
218
+                    header: [],
219
+                    data: [],
220
+                    summary: $otherEquitySummary,
221
+                );
222
+            }
223
+
224
+            // Add the category with its types and summary to the final array
225
+            $summaryCategories[$accountCategoryName] = new ReportCategoryDTO(
226
+                header: $categoryHeader,
114
                 data: [],
227
                 data: [],
115
                 summary: $categorySummary,
228
                 summary: $categorySummary,
116
                 types: $types,
229
                 types: $types,
117
             );
230
             );
118
         }
231
         }
119
 
232
 
120
-        return $categories;
233
+        return $summaryCategories;
121
     }
234
     }
122
 
235
 
123
     public function getOverallTotals(): array
236
     public function getOverallTotals(): array

+ 6
- 6
composer.lock 查看文件

10736
         },
10736
         },
10737
         {
10737
         {
10738
             "name": "phpstan/phpdoc-parser",
10738
             "name": "phpstan/phpdoc-parser",
10739
-            "version": "1.32.0",
10739
+            "version": "1.33.0",
10740
             "source": {
10740
             "source": {
10741
                 "type": "git",
10741
                 "type": "git",
10742
                 "url": "https://github.com/phpstan/phpdoc-parser.git",
10742
                 "url": "https://github.com/phpstan/phpdoc-parser.git",
10743
-                "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4"
10743
+                "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140"
10744
             },
10744
             },
10745
             "dist": {
10745
             "dist": {
10746
                 "type": "zip",
10746
                 "type": "zip",
10747
-                "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6ca22b154efdd9e3c68c56f5d94670920a1c19a4",
10748
-                "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4",
10747
+                "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140",
10748
+                "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140",
10749
                 "shasum": ""
10749
                 "shasum": ""
10750
             },
10750
             },
10751
             "require": {
10751
             "require": {
10777
             "description": "PHPDoc parser with support for nullable, intersection and generic types",
10777
             "description": "PHPDoc parser with support for nullable, intersection and generic types",
10778
             "support": {
10778
             "support": {
10779
                 "issues": "https://github.com/phpstan/phpdoc-parser/issues",
10779
                 "issues": "https://github.com/phpstan/phpdoc-parser/issues",
10780
-                "source": "https://github.com/phpstan/phpdoc-parser/tree/1.32.0"
10780
+                "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0"
10781
             },
10781
             },
10782
-            "time": "2024-09-26T07:23:32+00:00"
10782
+            "time": "2024-10-13T11:25:22+00:00"
10783
         },
10783
         },
10784
         {
10784
         {
10785
             "name": "phpstan/phpstan",
10785
             "name": "phpstan/phpstan",

+ 15
- 13
config/chart-of-accounts.php 查看文件

67
                 'description' => 'Accounts that accumulate depreciation of tangible assets and amortization of intangible assets, reflecting the reduction in value over time.',
67
                 'description' => 'Accounts that accumulate depreciation of tangible assets and amortization of intangible assets, reflecting the reduction in value over time.',
68
                 'multi_currency' => false,
68
                 'multi_currency' => false,
69
                 'base_code' => '1900',
69
                 'base_code' => '1900',
70
+                'accounts' => [
71
+                    'Accumulated Depreciation' => [
72
+                        'description' => 'Used to account for the depreciation of fixed assets over time, offsetting assets like equipment or property.',
73
+                    ],
74
+                ],
70
             ],
75
             ],
71
             'Allowances for Receivables' => [
76
             'Allowances for Receivables' => [
72
                 'description' => 'Accounts representing estimated uncollected receivables, used to adjust the value of gross receivables to a realistic collectible amount.',
77
                 'description' => 'Accounts representing estimated uncollected receivables, used to adjust the value of gross receivables to a realistic collectible amount.',
73
                 'multi_currency' => false,
78
                 'multi_currency' => false,
74
                 'base_code' => '1940',
79
                 'base_code' => '1940',
80
+                'accounts' => [
81
+                    'Allowance for Doubtful Accounts' => [
82
+                        'description' => 'Used to account for potential bad debts that may not be collectable, offsetting receivables.',
83
+                    ],
84
+                ],
75
             ],
85
             ],
76
             'Valuation Adjustments' => [
86
             'Valuation Adjustments' => [
77
                 'description' => 'Accounts used to record adjustments in asset values due to impairments, market changes, or other factors affecting their recoverable amount.',
87
                 'description' => 'Accounts used to record adjustments in asset values due to impairments, market changes, or other factors affecting their recoverable amount.',
154
                     'Owner\'s Investment' => [
164
                     'Owner\'s Investment' => [
155
                         'description' => 'The amount of money invested by the owner(s) or shareholders to start or expand the business.',
165
                         'description' => 'The amount of money invested by the owner(s) or shareholders to start or expand the business.',
156
                     ],
166
                     ],
157
-                    'Owner\'s Drawings' => [
158
-                        'description' => 'The amount of money withdrawn by the owner(s) or shareholders from the business for personal use.',
159
-                    ],
160
-                ],
161
-            ],
162
-            'Retained Earnings: Profit' => [
163
-                'description' => 'Cumulative profits retained in the business and not distributed as dividends. Indicates the company\'s financial health and profit-generating ability.',
164
-                'multi_currency' => false,
165
-                'base_code' => '3100',
166
-                'accounts' => [
167
-                    'Owner\'s Equity' => [
168
-                        'description' => 'Owner\'s equity is what remains after you subtract business liabilities from business assets. In other words, it\'s what\'s left over for you if you sell all your assets and pay all your debts.',
169
-                    ],
170
                 ],
167
                 ],
171
             ],
168
             ],
172
         ],
169
         ],
175
                 'description' => 'Equity that is deducted from gross equity to arrive at net equity. This includes treasury stock, which is stock that has been repurchased by the company.',
172
                 'description' => 'Equity that is deducted from gross equity to arrive at net equity. This includes treasury stock, which is stock that has been repurchased by the company.',
176
                 'multi_currency' => false,
173
                 'multi_currency' => false,
177
                 'base_code' => '3900',
174
                 'base_code' => '3900',
175
+                'accounts' => [
176
+                    'Owner\'s Drawings' => [
177
+                        'description' => 'The amount of money withdrawn by the owner(s) or shareholders from the business for personal use, reducing equity.',
178
+                    ],
179
+                ],
178
             ],
180
             ],
179
         ],
181
         ],
180
         'operating_revenue' => [
182
         'operating_revenue' => [

+ 3
- 4
database/factories/Accounting/TransactionFactory.php 查看文件

57
 
57
 
58
             $account = Account::where('category', $this->faker->randomElement($associatedAccountTypes))
58
             $account = Account::where('category', $this->faker->randomElement($associatedAccountTypes))
59
                 ->where('company_id', $company->id)
59
                 ->where('company_id', $company->id)
60
-                ->where('id', '<>', $accountIdForBankAccount)
60
+                ->whereKeyNot($accountIdForBankAccount)
61
                 ->inRandomOrder()
61
                 ->inRandomOrder()
62
                 ->first();
62
                 ->first();
63
 
63
 
64
-            // If no matching account is found, use a fallback
65
             if (! $account) {
64
             if (! $account) {
66
                 $account = Account::where('company_id', $company->id)
65
                 $account = Account::where('company_id', $company->id)
67
-                    ->where('id', '<>', $accountIdForBankAccount)
66
+                    ->whereKeyNot($accountIdForBankAccount)
68
                     ->inRandomOrder()
67
                     ->inRandomOrder()
69
-                    ->firstOrFail(); // Ensure there is at least some account
68
+                    ->firstOrFail();
70
             }
69
             }
71
 
70
 
72
             return [
71
             return [

+ 5
- 0
database/factories/Setting/CompanyDefaultFactory.php 查看文件

72
     {
72
     {
73
         return Currency::factory()->forCurrency($currencyCode)->createQuietly([
73
         return Currency::factory()->forCurrency($currencyCode)->createQuietly([
74
             'company_id' => $company->id,
74
             'company_id' => $company->id,
75
+            'enabled' => true,
75
             'created_by' => $user->id,
76
             'created_by' => $user->id,
76
             'updated_by' => $user->id,
77
             'updated_by' => $user->id,
77
         ]);
78
         ]);
81
     {
82
     {
82
         return Tax::factory()->salesTax()->createQuietly([
83
         return Tax::factory()->salesTax()->createQuietly([
83
             'company_id' => $company->id,
84
             'company_id' => $company->id,
85
+            'enabled' => true,
84
             'created_by' => $user->id,
86
             'created_by' => $user->id,
85
             'updated_by' => $user->id,
87
             'updated_by' => $user->id,
86
         ]);
88
         ]);
90
     {
92
     {
91
         return Tax::factory()->purchaseTax()->createQuietly([
93
         return Tax::factory()->purchaseTax()->createQuietly([
92
             'company_id' => $company->id,
94
             'company_id' => $company->id,
95
+            'enabled' => true,
93
             'created_by' => $user->id,
96
             'created_by' => $user->id,
94
             'updated_by' => $user->id,
97
             'updated_by' => $user->id,
95
         ]);
98
         ]);
99
     {
102
     {
100
         return Discount::factory()->salesDiscount()->createQuietly([
103
         return Discount::factory()->salesDiscount()->createQuietly([
101
             'company_id' => $company->id,
104
             'company_id' => $company->id,
105
+            'enabled' => true,
102
             'created_by' => $user->id,
106
             'created_by' => $user->id,
103
             'updated_by' => $user->id,
107
             'updated_by' => $user->id,
104
         ]);
108
         ]);
108
     {
112
     {
109
         return Discount::factory()->purchaseDiscount()->createQuietly([
113
         return Discount::factory()->purchaseDiscount()->createQuietly([
110
             'company_id' => $company->id,
114
             'company_id' => $company->id,
115
+            'enabled' => true,
111
             'created_by' => $user->id,
116
             'created_by' => $user->id,
112
             'updated_by' => $user->id,
117
             'updated_by' => $user->id,
113
         ]);
118
         ]);

+ 2
- 2
database/factories/Setting/CurrencyFactory.php 查看文件

33
             'symbol_first' => $defaultCurrency->isSymbolFirst(),
33
             'symbol_first' => $defaultCurrency->isSymbolFirst(),
34
             'decimal_mark' => $defaultCurrency->getDecimalMark(),
34
             'decimal_mark' => $defaultCurrency->getDecimalMark(),
35
             'thousands_separator' => $defaultCurrency->getThousandsSeparator(),
35
             'thousands_separator' => $defaultCurrency->getThousandsSeparator(),
36
-            'enabled' => true,
36
+            'enabled' => false,
37
         ];
37
         ];
38
     }
38
     }
39
 
39
 
53
             'symbol_first' => $currency->isSymbolFirst(),
53
             'symbol_first' => $currency->isSymbolFirst(),
54
             'decimal_mark' => $currency->getDecimalMark(),
54
             'decimal_mark' => $currency->getDecimalMark(),
55
             'thousands_separator' => $currency->getThousandsSeparator(),
55
             'thousands_separator' => $currency->getThousandsSeparator(),
56
-            'enabled' => true,
56
+            'enabled' => false,
57
         ]);
57
         ]);
58
     }
58
     }
59
 }
59
 }

+ 28
- 0
database/migrations/2024_10_13_163049_update_posted_at_column_in_transactions_table.php 查看文件

1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::table('transactions', function (Blueprint $table) {
15
+            $table->date('posted_at')->change();
16
+        });
17
+    }
18
+
19
+    /**
20
+     * Reverse the migrations.
21
+     */
22
+    public function down(): void
23
+    {
24
+        Schema::table('transactions', function (Blueprint $table) {
25
+            $table->dateTime('posted_at')->change();
26
+        });
27
+    }
28
+};

+ 3
- 3
package-lock.json 查看文件

2735
             }
2735
             }
2736
         },
2736
         },
2737
         "node_modules/yaml": {
2737
         "node_modules/yaml": {
2738
-            "version": "2.5.1",
2739
-            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz",
2740
-            "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==",
2738
+            "version": "2.6.0",
2739
+            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz",
2740
+            "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==",
2741
             "dev": true,
2741
             "dev": true,
2742
             "license": "ISC",
2742
             "license": "ISC",
2743
             "bin": {
2743
             "bin": {

+ 55
- 0
resources/views/components/company/tables/reports/balance-sheet-summary.blade.php 查看文件

1
+<table class="w-full table-auto divide-y divide-gray-200 dark:divide-white/5">
2
+    <thead class="divide-y divide-gray-200 dark:divide-white/5">
3
+    <tr class="bg-gray-50 dark:bg-white/5">
4
+        <th class="px-3 py-3.5 sm:first-of-type:ps-6 sm:last-of-type:pe-6 text-left">
5
+            <span class="text-sm font-semibold text-gray-950 dark:text-white">
6
+                Accounts
7
+            </span>
8
+        </th>
9
+        <th class="px-3 py-3.5 sm:first-of-type:ps-6 sm:last-of-type:pe-6 text-right">
10
+            <span class="text-sm font-semibold text-gray-950 dark:text-white">
11
+                Amount
12
+            </span>
13
+        </th>
14
+    </tr>
15
+    </thead>
16
+    @foreach($report->getSummaryCategories() as $accountCategory)
17
+        <tbody class="divide-y divide-gray-200 whitespace-nowrap dark:divide-white/5">
18
+        <tr class="bg-gray-50 dark:bg-white/5">
19
+            @foreach($accountCategory->header as $accountCategoryHeaderIndex => $accountCategoryHeaderCell)
20
+                <x-filament-tables::cell class="{{ $accountCategoryHeaderIndex === 0 ? 'text-left' : 'text-right' }}">
21
+                    <div class="px-3 py-2 text-sm font-semibold text-gray-950 dark:text-white">
22
+                        {{ $accountCategoryHeaderCell }}
23
+                    </div>
24
+                </x-filament-tables::cell>
25
+            @endforeach
26
+        </tr>
27
+        @foreach($accountCategory->types as $accountType)
28
+            <tr>
29
+                @foreach($accountType->summary as $accountTypeSummaryIndex => $accountTypeSummaryCell)
30
+                    <x-filament-tables::cell
31
+                        class="{{ $accountTypeSummaryIndex === 0 ? 'text-left' : 'text-right' }} ps-8">
32
+                        <div class="px-3 py-2 text-sm leading-6 font-normal text-gray-950 dark:text-white">
33
+                            {{ $accountTypeSummaryCell }}
34
+                        </div>
35
+                    </x-filament-tables::cell>
36
+                @endforeach
37
+            </tr>
38
+        @endforeach
39
+        <tr>
40
+            @foreach($accountCategory->summary as $accountCategorySummaryIndex => $accountCategorySummaryCell)
41
+                <x-filament-tables::cell class="{{ $accountCategorySummaryIndex === 0 ? 'text-left' : 'text-right' }}">
42
+                    <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
43
+                        {{ $accountCategorySummaryCell }}
44
+                    </div>
45
+                </x-filament-tables::cell>
46
+            @endforeach
47
+        </tr>
48
+        <tr>
49
+            <x-filament-tables::cell colspan="2">
50
+                <div class="px-3 py-2 leading-6 invisible">Hidden Text</div>
51
+            </x-filament-tables::cell>
52
+        </tr>
53
+        </tbody>
54
+    @endforeach
55
+</table>

+ 85
- 39
resources/views/components/company/tables/reports/balance-sheet.blade.php 查看文件

1
 <table class="w-full table-auto divide-y divide-gray-200 dark:divide-white/5">
1
 <table class="w-full table-auto divide-y divide-gray-200 dark:divide-white/5">
2
     <thead class="divide-y divide-gray-200 dark:divide-white/5">
2
     <thead class="divide-y divide-gray-200 dark:divide-white/5">
3
     <tr class="bg-gray-50 dark:bg-white/5">
3
     <tr class="bg-gray-50 dark:bg-white/5">
4
-        @foreach($report->getHeaders() as $index => $header)
5
-            <th class="px-3 py-3.5 sm:first-of-type:ps-6 sm:last-of-type:pe-6 {{ $report->getAlignmentClass($index) }}">
4
+        @foreach($report->getHeaders() as $reportHeaderIndex => $reportHeaderCell)
5
+            <th class="px-3 py-3.5 sm:first-of-type:ps-6 sm:last-of-type:pe-6 {{ $report->getAlignmentClass($reportHeaderIndex) }}">
6
                 <span class="text-sm font-semibold text-gray-950 dark:text-white">
6
                 <span class="text-sm font-semibold text-gray-950 dark:text-white">
7
-                    {{ $header }}
7
+                    {{ $reportHeaderCell }}
8
                 </span>
8
                 </span>
9
             </th>
9
             </th>
10
         @endforeach
10
         @endforeach
11
     </tr>
11
     </tr>
12
     </thead>
12
     </thead>
13
-    @foreach($report->getCategories() as $categoryIndex => $category)
14
-        @ray($category)
13
+    @foreach($report->getCategories() as $accountCategory)
15
         <tbody class="divide-y divide-gray-200 whitespace-nowrap dark:divide-white/5">
14
         <tbody class="divide-y divide-gray-200 whitespace-nowrap dark:divide-white/5">
16
         <tr class="bg-gray-50 dark:bg-white/5">
15
         <tr class="bg-gray-50 dark:bg-white/5">
17
-            @foreach($category->header as $headerIndex => $header)
18
-                <x-filament-tables::cell class="{{ $report->getAlignmentClass($headerIndex) }}">
16
+            @foreach($accountCategory->header as $accountCategoryHeaderIndex => $accountCategoryHeaderCell)
17
+                <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountCategoryHeaderIndex) }}">
19
                     <div class="px-3 py-2 text-sm font-semibold text-gray-950 dark:text-white">
18
                     <div class="px-3 py-2 text-sm font-semibold text-gray-950 dark:text-white">
20
-                        {{ $header }}
19
+                        {{ $accountCategoryHeaderCell }}
21
                     </div>
20
                     </div>
22
                 </x-filament-tables::cell>
21
                 </x-filament-tables::cell>
23
             @endforeach
22
             @endforeach
24
         </tr>
23
         </tr>
25
-        @foreach($category->types as $subcategory)
24
+        @foreach($accountCategory->data as $categoryAccount)
25
+            <tr>
26
+                @foreach($categoryAccount as $accountIndex => $categoryAccountCell)
27
+                    <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountIndex) }}"
28
+                                             style="padding-left: 1.5rem;">
29
+                        <div class="px-3 py-4 text-sm leading-6 text-gray-950 dark:text-white">
30
+                            @if(is_array($categoryAccountCell) && isset($categoryAccountCell['name']))
31
+                                @if($categoryAccountCell['name'] === 'Retained Earnings' && isset($categoryAccountCell['start_date']) && isset($categoryAccountCell['end_date']))
32
+                                    <x-filament::link
33
+                                        color="primary"
34
+                                        target="_blank"
35
+                                        icon="heroicon-o-arrow-top-right-on-square"
36
+                                        :icon-position="\Filament\Support\Enums\IconPosition::After"
37
+                                        :icon-size="\Filament\Support\Enums\IconSize::Small"
38
+                                        href="{{ \App\Filament\Company\Pages\Reports\IncomeStatement::getUrl([
39
+                                            'startDate' => $categoryAccountCell['start_date'],
40
+                                            'endDate' => $categoryAccountCell['end_date']
41
+                                        ]) }}"
42
+                                    >
43
+                                        {{ $categoryAccountCell['name'] }}
44
+                                    </x-filament::link>
45
+                                @elseif(isset($categoryAccountCell['id']) && isset($categoryAccountCell['start_date']) && isset($categoryAccountCell['end_date']))
46
+                                    <x-filament::link
47
+                                        color="primary"
48
+                                        target="_blank"
49
+                                        icon="heroicon-o-arrow-top-right-on-square"
50
+                                        :icon-position="\Filament\Support\Enums\IconPosition::After"
51
+                                        :icon-size="\Filament\Support\Enums\IconSize::Small"
52
+                                        href="{{ \App\Filament\Company\Pages\Reports\AccountTransactions::getUrl([
53
+                                            'startDate' => $categoryAccountCell['start_date'],
54
+                                            'endDate' => $categoryAccountCell['end_date'],
55
+                                            'selectedAccount' => $categoryAccountCell['id']
56
+                                        ]) }}"
57
+                                    >
58
+                                        {{ $categoryAccountCell['name'] }}
59
+                                    </x-filament::link>
60
+                                @else
61
+                                    {{ $categoryAccountCell['name'] }}
62
+                                @endif
63
+                            @else
64
+                                {{ $categoryAccountCell }}
65
+                            @endif
66
+                        </div>
67
+                    </x-filament-tables::cell>
68
+                @endforeach
69
+            </tr>
70
+        @endforeach
71
+        @foreach($accountCategory->types as $accountType)
26
             <tr class="bg-gray-50 dark:bg-white/5">
72
             <tr class="bg-gray-50 dark:bg-white/5">
27
-                @foreach($subcategory->header as $headerIndex => $header)
28
-                    <x-filament-tables::cell class="{{ $report->getAlignmentClass($headerIndex) }}"
29
-                                             style="padding-left: 2rem;">
73
+                @foreach($accountType->header as $accountTypeHeaderIndex => $accountTypeHeaderCell)
74
+                    <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountTypeHeaderIndex) }}"
75
+                                             style="padding-left: 1.5rem;">
30
                         <div class="px-3 py-2 text-sm font-semibold text-gray-950 dark:text-white">
76
                         <div class="px-3 py-2 text-sm font-semibold text-gray-950 dark:text-white">
31
-                            {{ $header }}
77
+                            {{ $accountTypeHeaderCell }}
32
                         </div>
78
                         </div>
33
                     </x-filament-tables::cell>
79
                     </x-filament-tables::cell>
34
                 @endforeach
80
                 @endforeach
35
             </tr>
81
             </tr>
36
-            @foreach($subcategory->data as $dataIndex => $account)
82
+            @foreach($accountType->data as $typeAccount)
37
                 <tr>
83
                 <tr>
38
-                    @foreach($account as $cellIndex => $cell)
39
-                        <x-filament-tables::cell class="{{ $report->getAlignmentClass($cellIndex) }}"
40
-                                                 style="padding-left: 2rem;">
84
+                    @foreach($typeAccount as $accountIndex => $typeAccountCell)
85
+                        <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountIndex) }}"
86
+                                                 style="padding-left: 1.5rem;">
41
                             <div class="px-3 py-4 text-sm leading-6 text-gray-950 dark:text-white">
87
                             <div class="px-3 py-4 text-sm leading-6 text-gray-950 dark:text-white">
42
-                                @if(is_array($cell) && isset($cell['name']))
43
-                                    @if($cell['name'] === 'Retained Earnings' && isset($cell['start_date']) && isset($cell['end_date']))
88
+                                @if(is_array($typeAccountCell) && isset($typeAccountCell['name']))
89
+                                    @if($typeAccountCell['name'] === 'Retained Earnings' && isset($typeAccountCell['start_date']) && isset($typeAccountCell['end_date']))
44
                                         <x-filament::link
90
                                         <x-filament::link
45
                                             color="primary"
91
                                             color="primary"
46
                                             target="_blank"
92
                                             target="_blank"
48
                                             :icon-position="\Filament\Support\Enums\IconPosition::After"
94
                                             :icon-position="\Filament\Support\Enums\IconPosition::After"
49
                                             :icon-size="\Filament\Support\Enums\IconSize::Small"
95
                                             :icon-size="\Filament\Support\Enums\IconSize::Small"
50
                                             href="{{ \App\Filament\Company\Pages\Reports\IncomeStatement::getUrl([
96
                                             href="{{ \App\Filament\Company\Pages\Reports\IncomeStatement::getUrl([
51
-                                            'startDate' => $cell['start_date'],
52
-                                            'endDate' => $cell['end_date']
97
+                                            'startDate' => $typeAccountCell['start_date'],
98
+                                            'endDate' => $typeAccountCell['end_date']
53
                                         ]) }}"
99
                                         ]) }}"
54
                                         >
100
                                         >
55
-                                            {{ $cell['name'] }}
101
+                                            {{ $typeAccountCell['name'] }}
56
                                         </x-filament::link>
102
                                         </x-filament::link>
57
-                                    @elseif(isset($cell['id']) && isset($cell['start_date']) && isset($cell['end_date']))
103
+                                    @elseif(isset($typeAccountCell['id']) && isset($typeAccountCell['start_date']) && isset($typeAccountCell['end_date']))
58
                                         <x-filament::link
104
                                         <x-filament::link
59
                                             color="primary"
105
                                             color="primary"
60
                                             target="_blank"
106
                                             target="_blank"
62
                                             :icon-position="\Filament\Support\Enums\IconPosition::After"
108
                                             :icon-position="\Filament\Support\Enums\IconPosition::After"
63
                                             :icon-size="\Filament\Support\Enums\IconSize::Small"
109
                                             :icon-size="\Filament\Support\Enums\IconSize::Small"
64
                                             href="{{ \App\Filament\Company\Pages\Reports\AccountTransactions::getUrl([
110
                                             href="{{ \App\Filament\Company\Pages\Reports\AccountTransactions::getUrl([
65
-                                            'startDate' => $cell['start_date'],
66
-                                            'endDate' => $cell['end_date'],
67
-                                            'selectedAccount' => $cell['id']
111
+                                            'startDate' => $typeAccountCell['start_date'],
112
+                                            'endDate' => $typeAccountCell['end_date'],
113
+                                            'selectedAccount' => $typeAccountCell['id']
68
                                         ]) }}"
114
                                         ]) }}"
69
                                         >
115
                                         >
70
-                                            {{ $cell['name'] }}
116
+                                            {{ $typeAccountCell['name'] }}
71
                                         </x-filament::link>
117
                                         </x-filament::link>
72
                                     @else
118
                                     @else
73
-                                        {{ $cell['name'] }}
119
+                                        {{ $typeAccountCell['name'] }}
74
                                     @endif
120
                                     @endif
75
                                 @else
121
                                 @else
76
-                                    {{ $cell }}
122
+                                    {{ $typeAccountCell }}
77
                                 @endif
123
                                 @endif
78
                             </div>
124
                             </div>
79
                         </x-filament-tables::cell>
125
                         </x-filament-tables::cell>
81
                 </tr>
127
                 </tr>
82
             @endforeach
128
             @endforeach
83
             <tr>
129
             <tr>
84
-                @foreach($subcategory->summary as $summaryIndex => $cell)
85
-                    <x-filament-tables::cell class="{{ $report->getAlignmentClass($summaryIndex) }}"
86
-                                             style="padding-left: 2rem;">
130
+                @foreach($accountType->summary as $accountTypeSummaryIndex => $accountTypeSummaryCell)
131
+                    <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountTypeSummaryIndex) }}"
132
+                                             style="padding-left: 1.5rem;">
87
                         <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
133
                         <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
88
-                            {{ $cell }}
134
+                            {{ $accountTypeSummaryCell }}
89
                         </div>
135
                         </div>
90
                     </x-filament-tables::cell>
136
                     </x-filament-tables::cell>
91
                 @endforeach
137
                 @endforeach
92
             </tr>
138
             </tr>
93
         @endforeach
139
         @endforeach
94
         <tr>
140
         <tr>
95
-            @foreach($category->summary as $summaryIndex => $cell)
96
-                <x-filament-tables::cell class="{{ $report->getAlignmentClass($summaryIndex) }}">
141
+            @foreach($accountCategory->summary as $accountCategorySummaryIndex => $accountCategorySummaryCell)
142
+                <x-filament-tables::cell class="{{ $report->getAlignmentClass($accountCategorySummaryIndex) }}">
97
                     <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
143
                     <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
98
-                        {{ $cell }}
144
+                        {{ $accountCategorySummaryCell }}
99
                     </div>
145
                     </div>
100
                 </x-filament-tables::cell>
146
                 </x-filament-tables::cell>
101
             @endforeach
147
             @endforeach
110
     @if(! empty($report->getOverallTotals()))
156
     @if(! empty($report->getOverallTotals()))
111
         <tfoot>
157
         <tfoot>
112
         <tr class="bg-gray-50 dark:bg-white/5">
158
         <tr class="bg-gray-50 dark:bg-white/5">
113
-            @foreach($report->getOverallTotals() as $index => $total)
114
-                <x-filament-tables::cell class="{{ $report->getAlignmentClass($index) }}">
159
+            @foreach($report->getOverallTotals() as $reportOverallTotalIndex => $reportOverallTotalCell)
160
+                <x-filament-tables::cell class="{{ $report->getAlignmentClass($reportOverallTotalIndex) }}">
115
                     <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
161
                     <div class="px-3 py-2 text-sm leading-6 font-semibold text-gray-950 dark:text-white">
116
-                        {{ $total }}
162
+                        {{ $reportOverallTotalCell }}
117
                     </div>
163
                     </div>
118
                 </x-filament-tables::cell>
164
                 </x-filament-tables::cell>
119
             @endforeach
165
             @endforeach

+ 12
- 6
resources/views/filament/company/pages/accounting/chart.blade.php 查看文件

15
 
15
 
16
         @foreach($this->categories as $categoryValue => $subtypes)
16
         @foreach($this->categories as $categoryValue => $subtypes)
17
             @if($activeTab === $categoryValue)
17
             @if($activeTab === $categoryValue)
18
-                <div class="es-table__container overflow-hidden rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:divide-white/10 dark:bg-gray-900 dark:ring-white/10">
18
+                <div
19
+                    class="es-table__container overflow-hidden rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:divide-white/10 dark:bg-gray-900 dark:ring-white/10">
19
                     <div class="es-table__header-ctn"></div>
20
                     <div class="es-table__header-ctn"></div>
20
                     <div class="es-table__content overflow-x-auto">
21
                     <div class="es-table__content overflow-x-auto">
21
-                        <table class="es-table table-fixed w-full divide-y divide-gray-200 text-start text-sm dark:divide-white/5">
22
+                        <table
23
+                            class="es-table table-fixed w-full divide-y divide-gray-200 text-start text-sm dark:divide-white/5">
22
                             <colgroup>
24
                             <colgroup>
23
                                 <col span="1" style="width: 12.5%;">
25
                                 <col span="1" style="width: 12.5%;">
24
                                 <col span="1" style="width: 20%;">
26
                                 <col span="1" style="width: 20%;">
28
                                 <col span="1" style="width: 7.5%;">
30
                                 <col span="1" style="width: 7.5%;">
29
                             </colgroup>
31
                             </colgroup>
30
                             @foreach($subtypes as $subtype)
32
                             @foreach($subtypes as $subtype)
31
-                                <tbody class="es-table__rowgroup divide-y divide-gray-200 whitespace-nowrap dark:divide-white/5">
33
+                                <tbody
34
+                                    class="es-table__rowgroup divide-y divide-gray-200 whitespace-nowrap dark:divide-white/5">
32
                                 <!-- Subtype Name Header Row -->
35
                                 <!-- Subtype Name Header Row -->
33
                                 <tr class="es-table__row--header bg-gray-50 dark:bg-white/5">
36
                                 <tr class="es-table__row--header bg-gray-50 dark:bg-white/5">
34
                                     <td colspan="6" class="es-table__cell px-4 py-4">
37
                                     <td colspan="6" class="es-table__cell px-4 py-4">
35
                                         <div class="es-table__row-content flex items-center space-x-2">
38
                                         <div class="es-table__row-content flex items-center space-x-2">
36
-                                            <span class="es-table__row-title text-gray-800 dark:text-gray-200 font-semibold tracking-wider">
39
+                                            <span
40
+                                                class="es-table__row-title text-gray-800 dark:text-gray-200 font-semibold tracking-wider">
37
                                                 {{ $subtype->name }}
41
                                                 {{ $subtype->name }}
38
                                             </span>
42
                                             </span>
39
                                             <x-tooltip
43
                                             <x-tooltip
61
                                                 @endif
65
                                                 @endif
62
                                             </small>
66
                                             </small>
63
                                         </td>
67
                                         </td>
64
-                                        <td colspan="2" class="es-table__cell px-4 py-4">{{ $account->description }}</td>
68
+                                        <td colspan="2"
69
+                                            class="es-table__cell px-4 py-4">{{ $account->description }}</td>
65
                                         <td colspan="1" class="es-table__cell px-4 py-4">
70
                                         <td colspan="1" class="es-table__cell px-4 py-4">
66
                                             @if($account->archived)
71
                                             @if($account->archived)
67
                                                 <x-filament::badge color="gray" size="sm">
72
                                                 <x-filament::badge color="gray" size="sm">
80
                                 @empty
85
                                 @empty
81
                                     <!-- No Accounts Available Row -->
86
                                     <!-- No Accounts Available Row -->
82
                                     <tr class="es-table__row">
87
                                     <tr class="es-table__row">
83
-                                        <td colspan="5" class="es-table__cell px-4 py-4 italic text-xs text-gray-500 dark:text-gray-400">
88
+                                        <td colspan="5"
89
+                                            class="es-table__cell px-4 py-4 italic text-xs text-gray-500 dark:text-gray-400">
84
                                             {{ __("You haven't added any {$subtype->name} accounts yet.") }}
90
                                             {{ __("You haven't added any {$subtype->name} accounts yet.") }}
85
                                         </td>
91
                                         </td>
86
                                     </tr>
92
                                     </tr>

+ 21
- 1
resources/views/filament/company/pages/reports/balance-sheet.blade.php 查看文件

60
         @endif
60
         @endif
61
     </x-filament::section>
61
     </x-filament::section>
62
 
62
 
63
+    <x-filament::tabs>
64
+        <x-filament::tabs.item
65
+            :active="$activeTab === 'summary'"
66
+            wire:click="$set('activeTab', 'summary')"
67
+        >
68
+            Summary
69
+        </x-filament::tabs.item>
70
+
71
+        <x-filament::tabs.item
72
+            :active="$activeTab === 'details'"
73
+            wire:click="$set('activeTab', 'details')"
74
+        >
75
+            Details
76
+        </x-filament::tabs.item>
77
+    </x-filament::tabs>
78
+
63
     <x-filament-tables::container>
79
     <x-filament-tables::container>
64
         <div class="es-table__header-ctn"></div>
80
         <div class="es-table__header-ctn"></div>
65
         <div
81
         <div
73
             @if($this->reportLoaded)
89
             @if($this->reportLoaded)
74
                 <div wire:loading.remove wire:target="applyFilters">
90
                 <div wire:loading.remove wire:target="applyFilters">
75
                     @if($this->report)
91
                     @if($this->report)
76
-                        <x-company.tables.reports.balance-sheet :report="$this->report"/>
92
+                        @if($activeTab === 'summary')
93
+                            <x-company.tables.reports.balance-sheet-summary :report="$this->report"/>
94
+                        @elseif($activeTab === 'details')
95
+                            <x-company.tables.reports.balance-sheet :report="$this->report"/>
96
+                        @endif
77
                     @endif
97
                     @endif
78
                 </div>
98
                 </div>
79
             @endif
99
             @endif

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

226
     livewire(Transactions::class)
226
     livewire(Transactions::class)
227
         ->mountAction($actionName)
227
         ->mountAction($actionName)
228
         ->assertActionDataSet([
228
         ->assertActionDataSet([
229
-            'posted_at' => now()->toDateTimeString(),
229
+            'posted_at' => today(),
230
             'type' => $transactionType,
230
             'type' => $transactionType,
231
             'bank_account_id' => $defaultBankAccount->id,
231
             'bank_account_id' => $defaultBankAccount->id,
232
             'amount' => '0.00',
232
             'amount' => '0.00',
260
     livewire(Transactions::class)
260
     livewire(Transactions::class)
261
         ->mountAction('addTransfer')
261
         ->mountAction('addTransfer')
262
         ->assertActionDataSet([
262
         ->assertActionDataSet([
263
-            'posted_at' => now()->toDateTimeString(),
263
+            'posted_at' => today(),
264
             'type' => TransactionType::Transfer,
264
             'type' => TransactionType::Transfer,
265
             'bank_account_id' => $sourceBankAccount->id,
265
             'bank_account_id' => $sourceBankAccount->id,
266
             'amount' => '0.00',
266
             'amount' => '0.00',
293
     livewire(Transactions::class)
293
     livewire(Transactions::class)
294
         ->mountAction('addJournalTransaction')
294
         ->mountAction('addJournalTransaction')
295
         ->assertActionDataSet([
295
         ->assertActionDataSet([
296
-            'posted_at' => now()->toDateTimeString(),
296
+            'posted_at' => today(),
297
             'journalEntries' => [
297
             'journalEntries' => [
298
                 ['type' => JournalEntryType::Debit, 'account_id' => $defaultDebitAccount->id, 'amount' => '0.00'],
298
                 ['type' => JournalEntryType::Debit, 'account_id' => $defaultDebitAccount->id, 'amount' => '0.00'],
299
                 ['type' => JournalEntryType::Credit, 'account_id' => $defaultCreditAccount->id, 'amount' => '0.00'],
299
                 ['type' => JournalEntryType::Credit, 'account_id' => $defaultCreditAccount->id, 'amount' => '0.00'],

正在加载...
取消
保存