Bläddra i källkod

performance improvements and bug fixes

3.x
Andrew Wallo 1 år sedan
förälder
incheckning
f1aca87651

+ 1
- 1
app/Contracts/AccountHandler.php Visa fil

@@ -17,7 +17,7 @@ interface AccountHandler
17 17
 
18 18
     public function getEndingBalance(Account $account, string $startDate, string $endDate): ?Money;
19 19
 
20
-    public function getBalances(Account $account, string $startDate, string $endDate): array;
20
+    public function getBalances(Account $account, string $startDate, string $endDate, array $fields): array;
21 21
 
22 22
     public function getTotalBalanceForAllBankAccounts(string $startDate, string $endDate): Money;
23 23
 

+ 2
- 2
app/DTO/AccountBalanceDTO.php Visa fil

@@ -8,8 +8,8 @@ class AccountBalanceDTO implements Wireable
8 8
 {
9 9
     public function __construct(
10 10
         public ?string $startingBalance,
11
-        public string $debitBalance,
12
-        public string $creditBalance,
11
+        public ?string $debitBalance,
12
+        public ?string $creditBalance,
13 13
         public ?string $netMovement,
14 14
         public ?string $endingBalance,
15 15
     ) {}

+ 49
- 21
app/Services/AccountService.php Visa fil

@@ -33,11 +33,9 @@ class AccountService implements AccountHandler
33 33
 
34 34
     public function getNetMovement(Account $account, string $startDate, string $endDate): Money
35 35
     {
36
-        $debitBalance = $this->journalEntryRepository->sumDebitAmounts($account, $startDate, $endDate);
37
-        $creditBalance = $this->journalEntryRepository->sumCreditAmounts($account, $startDate, $endDate);
38
-        $netMovement = $this->calculateNetMovementByCategory($account->category, $debitBalance, $creditBalance);
36
+        $balances = $this->calculateBalances($account, $startDate, $endDate);
39 37
 
40
-        return new Money($netMovement, $account->currency_code);
38
+        return new Money($balances['net_movement'], $account->currency_code);
41 39
     }
42 40
 
43 41
     public function getStartingBalance(Account $account, string $startDate): ?Money
@@ -46,23 +44,23 @@ class AccountService implements AccountHandler
46 44
             return null;
47 45
         }
48 46
 
49
-        $debitBalanceBefore = $this->journalEntryRepository->sumDebitAmounts($account, $startDate);
50
-        $creditBalanceBefore = $this->journalEntryRepository->sumCreditAmounts($account, $startDate);
51
-        $startingBalance = $this->calculateNetMovementByCategory($account->category, $debitBalanceBefore, $creditBalanceBefore);
47
+        $balances = $this->calculateStartingBalances($account, $startDate);
52 48
 
53
-        return new Money($startingBalance, $account->currency_code);
49
+        return new Money($balances['starting_balance'], $account->currency_code);
54 50
     }
55 51
 
56 52
     public function getEndingBalance(Account $account, string $startDate, string $endDate): ?Money
57 53
     {
58
-        $netMovement = $this->getNetMovement($account, $startDate, $endDate)->getAmount();
54
+        $calculatedBalances = $this->calculateBalances($account, $startDate, $endDate);
55
+        $startingBalances = $this->calculateStartingBalances($account, $startDate);
56
+
57
+        $netMovement = $calculatedBalances['net_movement'];
59 58
 
60 59
         if (in_array($account->category, [AccountCategory::Expense, AccountCategory::Revenue], true)) {
61 60
             return new Money($netMovement, $account->currency_code);
62 61
         }
63 62
 
64
-        $startingBalance = $this->getStartingBalance($account, $startDate)?->getAmount();
65
-        $endingBalance = $startingBalance + $netMovement;
63
+        $endingBalance = $startingBalances['starting_balance'] + $netMovement;
66 64
 
67 65
         return new Money($endingBalance, $account->currency_code);
68 66
     }
@@ -75,24 +73,54 @@ class AccountService implements AccountHandler
75 73
         };
76 74
     }
77 75
 
78
-    public function getBalances(Account $account, string $startDate, string $endDate): array
76
+    private function calculateBalances(Account $account, string $startDate, string $endDate): array
79 77
     {
80
-        $debitBalance = $this->getDebitBalance($account, $startDate, $endDate)->getAmount();
81
-        $creditBalance = $this->getCreditBalance($account, $startDate, $endDate)->getAmount();
82
-        $netMovement = $this->getNetMovement($account, $startDate, $endDate)->getAmount();
78
+        $debitBalance = $this->journalEntryRepository->sumDebitAmounts($account, $startDate, $endDate);
79
+        $creditBalance = $this->journalEntryRepository->sumCreditAmounts($account, $startDate, $endDate);
83 80
 
84
-        $balances = [
81
+        return [
85 82
             'debit_balance' => $debitBalance,
86 83
             'credit_balance' => $creditBalance,
87
-            'net_movement' => $netMovement,
84
+            'net_movement' => $this->calculateNetMovementByCategory($account->category, $debitBalance, $creditBalance),
85
+        ];
86
+    }
87
+
88
+    private function calculateStartingBalances(Account $account, string $startDate): array
89
+    {
90
+        $debitBalanceBefore = $this->journalEntryRepository->sumDebitAmounts($account, $startDate);
91
+        $creditBalanceBefore = $this->journalEntryRepository->sumCreditAmounts($account, $startDate);
92
+
93
+        return [
94
+            'debit_balance_before' => $debitBalanceBefore,
95
+            'credit_balance_before' => $creditBalanceBefore,
96
+            'starting_balance' => $this->calculateNetMovementByCategory($account->category, $debitBalanceBefore, $creditBalanceBefore),
88 97
         ];
98
+    }
99
+
100
+    public function getBalances(Account $account, string $startDate, string $endDate, array $fields): array
101
+    {
102
+        $balances = [];
103
+        $calculatedBalances = $this->calculateBalances($account, $startDate, $endDate);
104
+
105
+        // Calculate starting balances only if needed
106
+        $startingBalances = null;
107
+        $needStartingBalances = ! in_array($account->category, [AccountCategory::Expense, AccountCategory::Revenue], true)
108
+                                && (in_array('starting_balance', $fields) || in_array('ending_balance', $fields));
109
+
110
+        if ($needStartingBalances) {
111
+            $startingBalances = $this->calculateStartingBalances($account, $startDate);
112
+        }
89 113
 
90
-        if (! in_array($account->category, [AccountCategory::Expense, AccountCategory::Revenue], true)) {
91
-            $balances['starting_balance'] = $this->getStartingBalance($account, $startDate)?->getAmount();
92
-            $balances['ending_balance'] = $this->getEndingBalance($account, $startDate, $endDate)?->getAmount();
114
+        foreach ($fields as $field) {
115
+            $balances[$field] = match ($field) {
116
+                'debit_balance', 'credit_balance', 'net_movement' => $calculatedBalances[$field],
117
+                'starting_balance' => $needStartingBalances ? $startingBalances['starting_balance'] : null,
118
+                'ending_balance' => $needStartingBalances ? $startingBalances['starting_balance'] + $calculatedBalances['net_movement'] : null,
119
+                default => null,
120
+            };
93 121
         }
94 122
 
95
-        return $balances;
123
+        return array_filter($balances, static fn ($value) => $value !== null);
96 124
     }
97 125
 
98 126
     public function getTotalBalanceForAllBankAccounts(string $startDate, string $endDate): Money

+ 9
- 4
app/Services/ReportService.php Visa fil

@@ -8,6 +8,7 @@ use App\DTO\AccountDTO;
8 8
 use App\DTO\ReportDTO;
9 9
 use App\Enums\Accounting\AccountCategory;
10 10
 use App\Models\Accounting\Account;
11
+use App\Support\Column;
11 12
 use App\Utilities\Currency\CurrencyAccessor;
12 13
 use Illuminate\Database\Eloquent\Collection;
13 14
 
@@ -27,8 +28,8 @@ class ReportService
27 28
 
28 29
         return new AccountBalanceDTO(
29 30
             startingBalance: $balances['starting_balance'] ?? null,
30
-            debitBalance: $balances['debit_balance'],
31
-            creditBalance: $balances['credit_balance'],
31
+            debitBalance: $balances['debit_balance'] ?? null,
32
+            creditBalance: $balances['credit_balance'] ?? null,
32 33
             netMovement: $balances['net_movement'] ?? null,
33 34
             endingBalance: $balances['ending_balance'] ?? null,
34 35
         );
@@ -56,11 +57,15 @@ class ReportService
56 57
 
57 58
         $balanceFields = ['starting_balance', 'debit_balance', 'credit_balance', 'net_movement', 'ending_balance'];
58 59
 
60
+        $columnNameKeys = array_map(fn (Column $column) => $column->getName(), $columns);
61
+
62
+        $updatedBalanceFields = array_filter($balanceFields, fn (string $balanceField) => in_array($balanceField, $columnNameKeys, true));
63
+
59 64
         return $this->buildReport(
60 65
             $allCategories,
61 66
             $categoryGroupedAccounts,
62
-            fn (Account $account) => $this->accountService->getBalances($account, $startDate, $endDate),
63
-            $balanceFields,
67
+            fn (Account $account) => $this->accountService->getBalances($account, $startDate, $endDate, $updatedBalanceFields),
68
+            $updatedBalanceFields,
64 69
             $columns,
65 70
             fn (string $categoryName, array &$categorySummaryBalances) => $this->adjustAccountBalanceCategoryFields($categoryName, $categorySummaryBalances),
66 71
         );

+ 41
- 1
database/factories/Accounting/TransactionFactory.php Visa fil

@@ -18,7 +18,47 @@ class TransactionFactory extends Factory
18 18
     public function definition(): array
19 19
     {
20 20
         return [
21
-            //
21
+            'company_id' => 1,
22
+            'account_id' => $this->faker->numberBetween(1, 30),
23
+            'bank_account_id' => 1,
24
+            'type' => $this->faker->randomElement(['deposit', 'withdrawal', 'journal']),
25
+            'payment_channel' => $this->faker->randomElement(['online', 'in store', 'other']),
26
+            'description' => $this->faker->sentence,
27
+            'notes' => $this->faker->paragraph,
28
+            'reference' => $this->faker->word,
29
+            'amount' => $this->faker->numberBetween(100, 5000),
30
+            'pending' => $this->faker->boolean,
31
+            'reviewed' => $this->faker->boolean,
32
+            'posted_at' => $this->faker->dateTimeBetween('-2 years'),
33
+            'created_by' => 1,
34
+            'updated_by' => 1,
22 35
         ];
23 36
     }
37
+
38
+    public function configure(): static
39
+    {
40
+        return $this->afterCreating(function (Transaction $transaction) {
41
+            $transaction->journalEntries()->create([
42
+                'company_id' => $transaction->company_id,
43
+                'account_id' => $transaction->account_id,
44
+                'transaction_id' => $transaction->id,
45
+                'type' => 'debit',
46
+                'amount' => $transaction->amount,
47
+                'description' => $transaction->description,
48
+                'created_by' => $transaction->created_by,
49
+                'updated_by' => $transaction->updated_by,
50
+            ]);
51
+
52
+            $transaction->journalEntries()->create([
53
+                'company_id' => $transaction->company_id,
54
+                'account_id' => $transaction->account_id,
55
+                'transaction_id' => $transaction->id,
56
+                'type' => 'credit',
57
+                'amount' => $transaction->amount,
58
+                'description' => $transaction->description,
59
+                'created_by' => $transaction->created_by,
60
+                'updated_by' => $transaction->updated_by,
61
+            ]);
62
+        });
63
+    }
24 64
 }

+ 10
- 0
database/factories/UserFactory.php Visa fil

@@ -6,6 +6,7 @@ use App\Events\CompanyGenerated;
6 6
 use App\Models\Company;
7 7
 use App\Models\Setting\CompanyProfile;
8 8
 use App\Models\User;
9
+use Database\Factories\Accounting\TransactionFactory;
9 10
 use Illuminate\Database\Eloquent\Factories\Factory;
10 11
 use Illuminate\Support\Facades\Hash;
11 12
 use Illuminate\Support\Str;
@@ -87,6 +88,15 @@ class UserFactory extends Factory
87 88
                         'created_by' => $user->id,
88 89
                         'updated_by' => $user->id,
89 90
                     ]);
91
+
92
+                    TransactionFactory::new()
93
+                        ->count(2000)
94
+                        ->create([
95
+                            'company_id' => $company->id,
96
+                            'bank_account_id' => $defaultBankAccount?->id,
97
+                            'created_by' => $user->id,
98
+                            'updated_by' => $user->id,
99
+                        ]);
90 100
                 })
91 101
                 ->create([
92 102
                     'name' => $user->name . '\'s Company',

+ 3
- 0
database/migrations/2024_01_01_234943_create_transactions_table.php Visa fil

@@ -30,6 +30,9 @@ return new class extends Migration
30 30
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
31 31
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
32 32
             $table->timestamps();
33
+
34
+            $table->index(['company_id', 'account_id', 'posted_at']);
35
+            $table->index(['company_id', 'bank_account_id', 'posted_at']);
33 36
         });
34 37
     }
35 38
 

+ 3
- 0
database/migrations/2024_01_11_062614_create_journal_entries_table.php Visa fil

@@ -22,6 +22,9 @@ return new class extends Migration
22 22
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
23 23
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
24 24
             $table->timestamps();
25
+
26
+            $table->index(['company_id', 'account_id', 'type']);
27
+            $table->index(['company_id', 'account_id', 'transaction_id']);
25 28
         });
26 29
     }
27 30
 

+ 10
- 82
database/seeders/DatabaseSeeder.php Visa fil

@@ -12,93 +12,21 @@ class DatabaseSeeder extends Seeder
12 12
      */
13 13
     public function run(): void
14 14
     {
15
-        $startDate = today()->startOfYear();
16
-        $endDate = today();
17
-
18
-        // Change Company Name to ERPSAAS after Login
19
-        $firstCompanyOwner = User::factory()
20
-            ->withPersonalCompany()
15
+        // Create a single admin user and their personal company
16
+        $adminUser = User::factory()
17
+            ->withPersonalCompany()  // Ensures the user has a personal company created alongside
21 18
             ->create([
22 19
                 'name' => 'Admin',
23 20
                 'email' => 'admin@gmail.com',
24 21
                 'password' => bcrypt('password'),
25
-                'current_company_id' => 1,
26
-                'created_at' => $startDate->copy(),
22
+                'current_company_id' => 1,  // Assuming this will be the ID of the created company
23
+                'created_at' => now(),
27 24
             ]);
28 25
 
29
-        $firstCompanyOwner->ownedCompanies->first()->update(['created_at' => $startDate->copy()]);
30
-
31
-        // Function to create employees for a company (also creates companies for the employees)
32
-        $createUsers = static function ($company_id, $userCount, $minPercentage, $maxPercentage) use ($endDate, $startDate) {
33
-            $users = User::factory($userCount)
34
-                ->withPersonalCompany()
35
-                ->create([
36
-                    'password' => bcrypt('password'),
37
-                    'current_company_id' => $company_id,
38
-                ]);
39
-
40
-            $dateRange = $endDate->diffInMinutes($startDate);
41
-            $minOffset = (int) ($dateRange * $minPercentage);
42
-            $maxOffset = (int) ($dateRange * $maxPercentage);
43
-
44
-            for ($i = 0; $i < $userCount; $i++) {
45
-                $increment = (int) ($minOffset + ($i * ($maxOffset - $minOffset) / $userCount));
46
-                $userCreatedAt = $startDate->copy()->addMinutes($increment);
47
-
48
-                $user = $users[$i];
49
-
50
-                // Randomly assign a role to the user
51
-                $roles = ['editor', 'admin'];
52
-                $role = $roles[array_rand($roles)];
53
-
54
-                $user->companies()->attach($company_id, compact('role'));
55
-
56
-                $user->update(['created_at' => $userCreatedAt]);
57
-                $user->ownedCompanies->first()?->update(['created_at' => $userCreatedAt]);
58
-
59
-                // Generate random created_at date for the company_user pivot table (for employees)
60
-                $user->companies->first()?->users()->updateExistingPivot($user->id, ['created_at' => $userCreatedAt]);
61
-            }
62
-        };
63
-
64
-        // Users for the first company (excluding the first company owner)
65
-        $createUsers(1, 5, 0, 0.1);
66
-
67
-        // Second company owner
68
-        $secondCompanyOwner = User::factory()
69
-            ->withPersonalCompany()
70
-            ->create([
71
-                'password' => bcrypt('admin2'),
72
-                'current_company_id' => 2,
73
-                'created_at' => $startDate->addMinutes($endDate->diffInMinutes($startDate) * 0.1),
74
-            ]);
75
-
76
-        $secondCompanyOwner->ownedCompanies->first()->update(['created_at' => $startDate->addMinutes($endDate->diffInMinutes($startDate) * 0.1)]);
77
-
78
-        // Users for the second company (excluding the second company owner)
79
-        $createUsers(2, 5, 0.1, 0.2);
80
-
81
-        // Third company owner
82
-        $thirdCompanyOwner = User::factory()
83
-            ->withPersonalCompany()
84
-            ->create([
85
-                'password' => bcrypt('admin3'),
86
-                'current_company_id' => 3,
87
-                'created_at' => $startDate->addMinutes($endDate->diffInMinutes($startDate) * 0.2),
88
-            ]);
89
-
90
-        $thirdCompanyOwner->ownedCompanies->first()->update(['created_at' => $startDate->addMinutes($endDate->diffInMinutes($startDate) * 0.2)]);
91
-
92
-        // Users for the third company (excluding the third company owner)
93
-        $createUsers(3, 5, 0.2, 0.3);
94
-
95
-        // Create employees for each company (each employee has a company)
96
-        $createUsers(4, 5, 0.3, 0.4);
97
-        $createUsers(5, 5, 0.4, 0.5);
98
-        $createUsers(6, 5, 0.5, 0.6);
99
-        $createUsers(7, 5, 0.6, 0.7);
100
-        $createUsers(8, 5, 0.7, 0.8);
101
-        $createUsers(9, 5, 0.8, 0.9);
102
-        $createUsers(10, 5, 0.9, 1);
26
+        // Optionally, set additional properties or create related entities specific to this company
27
+        $adminUser->ownedCompanies->first()->update([
28
+            'name' => 'ERPSAAS',
29
+            'created_at' => now(),
30
+        ]);
103 31
     }
104 32
 }

+ 4
- 4
resources/views/components/panel-shift-dropdown.blade.php Visa fil

@@ -92,9 +92,7 @@
92 92
             },
93 93
 
94 94
             setActiveMenu(menu) {
95
-                if (this.open) {
96
-                    this.transitionPanel(menu, 'forward');
97
-                }
95
+                this.transitionPanel(menu, 'forward');
98 96
             },
99 97
 
100 98
             focusMenuItem(menuItemRef) {
@@ -160,7 +158,9 @@
160 158
                             mainPanel.style.transform = 'translateX(0)';
161 159
                         }
162 160
                     } else {
163
-                        this.navigationStack = ['main'];
161
+                        if (this.currentActiveMenu() !== 'main') {
162
+                            this.setActiveMenu('main');
163
+                        }
164 164
                     }
165 165
                 });
166 166
             },

+ 10
- 2
resources/views/filament/company/pages/reports/detailed-report.blade.php Visa fil

@@ -16,8 +16,16 @@
16 16
                     </div>
17 17
                 </form>
18 18
             </div>
19
-            <div class="relative divide-y divide-gray-200 overflow-x-auto dark:divide-white/10 dark:border-t-white/10">
20
-                <x-company.tables.reports.detailed-report :report="$this->report" />
19
+            <div class="divide-y divide-gray-200 overflow-x-auto overflow-y-hidden dark:divide-white/10 dark:border-t-white/10">
20
+                <div class="flex items-center justify-center">
21
+                    <div wire:loading.delay wire:target="loadReportData">
22
+                        <x-filament::loading-indicator class="p-6 text-primary-700 dark:text-primary-300" />
23
+                    </div>
24
+                </div>
25
+
26
+                <div wire:loading.remove wire:target="loadReportData">
27
+                    <x-company.tables.reports.detailed-report :report="$this->report" />
28
+                </div>
21 29
             </div>
22 30
             <div class="es-table__footer-ctn border-t border-gray-200"></div>
23 31
         </x-filament-tables::container>

Laddar…
Avbryt
Spara