Andrew Wallo 1年前
父节点
当前提交
645dc36638

+ 0
- 25
app/Events/CompanyGenerated.php 查看文件

@@ -1,25 +0,0 @@
1
-<?php
2
-
3
-namespace App\Events;
4
-
5
-use App\Models\Company;
6
-use App\Models\User;
7
-use Illuminate\Foundation\Events\Dispatchable;
8
-use Illuminate\Queue\SerializesModels;
9
-
10
-class CompanyGenerated
11
-{
12
-    use Dispatchable;
13
-    use SerializesModels;
14
-
15
-    /**
16
-     * Create a new event instance.
17
-     */
18
-    public function __construct(
19
-        public User $user,
20
-        public Company $company,
21
-        public string $country,
22
-        public string $language = 'en',
23
-        public string $currency = 'USD'
24
-    ) {}
25
-}

+ 20
- 17
app/Filament/Company/Pages/CreateCompany.php 查看文件

@@ -3,16 +3,17 @@
3 3
 namespace App\Filament\Company\Pages;
4 4
 
5 5
 use App\Enums\Setting\EntityType;
6
-use App\Events\CompanyGenerated;
7 6
 use App\Models\Company;
8 7
 use App\Models\Locale\Country;
9 8
 use App\Models\Setting\Localization;
9
+use App\Services\CompanyDefaultService;
10 10
 use App\Utilities\Currency\CurrencyAccessor;
11 11
 use Filament\Forms\Components\Select;
12 12
 use Filament\Forms\Components\TextInput;
13 13
 use Filament\Forms\Form;
14 14
 use Illuminate\Database\Eloquent\Model;
15 15
 use Illuminate\Support\Facades\Auth;
16
+use Illuminate\Support\Facades\DB;
16 17
 use Illuminate\Support\Facades\Gate;
17 18
 use Wallo\FilamentCompanies\Events\AddingCompany;
18 19
 use Wallo\FilamentCompanies\FilamentCompanies;
@@ -69,26 +70,28 @@ class CreateCompany extends FilamentCreateCompany
69 70
 
70 71
         $personalCompany = $user?->personalCompany() === null;
71 72
 
72
-        /** @var Company $company */
73
-        $company = $user?->ownedCompanies()->create([
74
-            'name' => $data['name'],
75
-            'personal_company' => $personalCompany,
76
-        ]);
73
+        return DB::transaction(function () use ($user, $data, $personalCompany) {
74
+            /** @var Company $company */
75
+            $company = $user?->ownedCompanies()->create([
76
+                'name' => $data['name'],
77
+                'personal_company' => $personalCompany,
78
+            ]);
77 79
 
78
-        $company->profile()->create([
79
-            'email' => $data['profile']['email'],
80
-            'entity_type' => $data['profile']['entity_type'],
81
-            'country' => $data['profile']['country'],
82
-        ]);
80
+            $company->profile()->create([
81
+                'email' => $data['profile']['email'],
82
+                'entity_type' => $data['profile']['entity_type'],
83
+                'country' => $data['profile']['country'],
84
+            ]);
83 85
 
84
-        $user?->switchCompany($company);
86
+            $user?->switchCompany($company);
85 87
 
86
-        $name = $data['name'];
88
+            $companyDefaultService = app()->make(CompanyDefaultService::class);
89
+            $user = $company->owner ?? $user;
90
+            $companyDefaultService->createCompanyDefaults($company, $user, $data['currencies']['code'], $data['profile']['country'], $data['locale']['language']);
87 91
 
88
-        CompanyGenerated::dispatch($user ?? Auth::user(), $company, $data['profile']['country'], $data['locale']['language'], $data['currencies']['code']);
92
+            $this->companyCreated($data['name']);
89 93
 
90
-        $this->companyCreated($name);
91
-
92
-        return $company;
94
+            return $company;
95
+        });
93 96
     }
94 97
 }

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

@@ -4,6 +4,7 @@ namespace App\Filament\Company\Pages\Reports;
4 4
 
5 5
 use App\Contracts\ExportableReport;
6 6
 use App\DTO\ReportDTO;
7
+use App\Filament\Company\Pages\Accounting\Transactions;
7 8
 use App\Models\Accounting\Account;
8 9
 use App\Services\ExportService;
9 10
 use App\Services\ReportService;
@@ -13,9 +14,10 @@ use Filament\Forms\Components\Actions;
13 14
 use Filament\Forms\Components\Select;
14 15
 use Filament\Forms\Form;
15 16
 use Filament\Support\Enums\Alignment;
17
+use Filament\Tables\Actions\Action;
16 18
 use Guava\FilamentClusters\Forms\Cluster;
19
+use Illuminate\Contracts\Support\Htmlable;
17 20
 use Illuminate\Support\Collection;
18
-use Livewire\Attributes\Session;
19 21
 use Symfony\Component\HttpFoundation\StreamedResponse;
20 22
 
21 23
 class AccountTransactions extends BaseReportPage
@@ -30,7 +32,6 @@ class AccountTransactions extends BaseReportPage
30 32
 
31 33
     protected ExportService $exportService;
32 34
 
33
-    #[Session]
34 35
     public ?string $account_id = 'all';
35 36
 
36 37
     public function boot(ReportService $reportService, ExportService $exportService): void
@@ -122,4 +123,37 @@ class AccountTransactions extends BaseReportPage
122 123
     {
123 124
         return $this->exportService->exportToPdf($this->company, $this->report, $this->startDate, $this->endDate);
124 125
     }
126
+
127
+    public function getEmptyStateHeading(): string | Htmlable
128
+    {
129
+        return 'No Transactions Found';
130
+    }
131
+
132
+    public function getEmptyStateDescription(): string | Htmlable | null
133
+    {
134
+        return 'Adjust the account or date range, or start by creating a transaction.';
135
+    }
136
+
137
+    public function getEmptyStateIcon(): string
138
+    {
139
+        return 'heroicon-o-x-mark';
140
+    }
141
+
142
+    public function getEmptyStateActions(): array
143
+    {
144
+        return [
145
+            Action::make('createTransaction')
146
+                ->label('Create Transaction')
147
+                ->url(Transactions::getUrl()),
148
+        ];
149
+    }
150
+
151
+    public function tableHasEmptyState(): bool
152
+    {
153
+        if ($this->report) {
154
+            return empty($this->report->getCategories());
155
+        } else {
156
+            return true;
157
+        }
158
+    }
125 159
 }

+ 0
- 3
app/Filament/Company/Pages/Reports/BaseReportPage.php 查看文件

@@ -26,13 +26,10 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
26 26
 
27 27
 abstract class BaseReportPage extends Page
28 28
 {
29
-    #[Session]
30 29
     public string $startDate = '';
31 30
 
32
-    #[Session]
33 31
     public string $endDate = '';
34 32
 
35
-    #[Session]
36 33
     public string $dateRange = '';
37 34
 
38 35
     public string $fiscalYearStartDate = '';

+ 0
- 29
app/Listeners/ConfigureChartOfAccounts.php 查看文件

@@ -1,29 +0,0 @@
1
-<?php
2
-
3
-namespace App\Listeners;
4
-
5
-use App\Events\CompanyGenerated;
6
-use App\Services\ChartOfAccountsService;
7
-
8
-class ConfigureChartOfAccounts
9
-{
10
-    /**
11
-     * Create the event listener.
12
-     */
13
-    public function __construct()
14
-    {
15
-        //
16
-    }
17
-
18
-    /**
19
-     * Handle the event.
20
-     */
21
-    public function handle(CompanyGenerated $event): void
22
-    {
23
-        $company = $event->company;
24
-
25
-        $chartOfAccountsService = new ChartOfAccountsService();
26
-
27
-        $chartOfAccountsService->createChartOfAccounts($company);
28
-    }
29
-}

+ 0
- 33
app/Listeners/CreateCompanyDefaults.php 查看文件

@@ -1,33 +0,0 @@
1
-<?php
2
-
3
-namespace App\Listeners;
4
-
5
-use App\Events\CompanyGenerated;
6
-use App\Services\CompanyDefaultService;
7
-
8
-class CreateCompanyDefaults
9
-{
10
-    /**
11
-     * Create the event listener.
12
-     */
13
-    public function __construct()
14
-    {
15
-        //
16
-    }
17
-
18
-    /**
19
-     * Handle the event.
20
-     */
21
-    public function handle(CompanyGenerated $event): void
22
-    {
23
-        $company = $event->company;
24
-        $countryCode = $event->country;
25
-        $languageCode = $event->language;
26
-        $currency = $event->currency;
27
-
28
-        $user = $company->owner;
29
-
30
-        $companyDefaultService = new CompanyDefaultService();
31
-        $companyDefaultService->createCompanyDefaults($company, $user, $currency, $countryCode, $languageCode);
32
-    }
33
-}

+ 5
- 0
app/Services/ChartOfAccountsService.php 查看文件

@@ -81,4 +81,9 @@ class ChartOfAccountsService
81 81
             'updated_by' => $company->owner->id,
82 82
         ]);
83 83
     }
84
+
85
+    public function getDefaultBankAccount(Company $company): ?BankAccount
86
+    {
87
+        return $company->bankAccounts()->where('enabled', true)->first();
88
+    }
84 89
 }

+ 15
- 90
app/Services/CompanyDefaultService.php 查看文件

@@ -3,12 +3,7 @@
3 3
 namespace App\Services;
4 4
 
5 5
 use App\Models\Company;
6
-use App\Models\Setting\Appearance;
7
-use App\Models\Setting\Currency;
8
-use App\Models\Setting\Discount;
9
-use App\Models\Setting\DocumentDefault;
10
-use App\Models\Setting\Localization;
11
-use App\Models\Setting\Tax;
6
+use App\Models\Setting\CompanyDefault;
12 7
 use App\Models\User;
13 8
 use Illuminate\Support\Facades\DB;
14 9
 
@@ -16,93 +11,23 @@ class CompanyDefaultService
16 11
 {
17 12
     public function createCompanyDefaults(Company $company, User $user, string $currencyCode, string $countryCode, string $language): void
18 13
     {
19
-        DB::transaction(function () use ($company, $user, $currencyCode, $countryCode, $language) {
20
-            $this->createCurrency($company, $user, $currencyCode);
21
-            $this->createSalesTax($company, $user);
22
-            $this->createPurchaseTax($company, $user);
23
-            $this->createSalesDiscount($company, $user);
24
-            $this->createPurchaseDiscount($company, $user);
25
-            $this->createAppearance($company, $user);
26
-            $this->createDocumentDefaults($company, $user);
27
-            $this->createLocalization($company, $user, $countryCode, $language);
28
-        }, 5);
29
-    }
30
-
31
-    private function createCurrency(Company $company, User $user, string $currencyCode): void
32
-    {
33
-        Currency::factory()->forCurrency($currencyCode)->create([
34
-            'company_id' => $company->id,
35
-            'created_by' => $user->id,
36
-            'updated_by' => $user->id,
37
-        ]);
38
-    }
14
+        DB::transaction(function () use ($user, $company, $currencyCode, $countryCode, $language) {
15
+            // Create the company defaults
16
+            $companyDefaultFactory = CompanyDefault::factory()->withDefault($user, $company, $currencyCode, $countryCode, $language);
17
+            $companyDefaults = $companyDefaultFactory->make()->toArray();
39 18
 
40
-    private function createSalesTax(Company $company, User $user): void
41
-    {
42
-        Tax::factory()->salesTax()->create([
43
-            'company_id' => $company->id,
44
-            'created_by' => $user->id,
45
-            'updated_by' => $user->id,
46
-        ]);
47
-    }
19
+            $companyDefault = CompanyDefault::create($companyDefaults);
48 20
 
49
-    private function createPurchaseTax(Company $company, User $user): void
50
-    {
51
-        Tax::factory()->purchaseTax()->create([
52
-            'company_id' => $company->id,
53
-            'created_by' => $user->id,
54
-            'updated_by' => $user->id,
55
-        ]);
56
-    }
21
+            // Create Chart of Accounts
22
+            $chartOfAccountsService = app()->make(ChartOfAccountsService::class);
23
+            $chartOfAccountsService->createChartOfAccounts($company);
57 24
 
58
-    private function createSalesDiscount(Company $company, User $user): void
59
-    {
60
-        Discount::factory()->salesDiscount()->create([
61
-            'company_id' => $company->id,
62
-            'created_by' => $user->id,
63
-            'updated_by' => $user->id,
64
-        ]);
65
-    }
25
+            // Get the default bank account and update the company default record
26
+            $defaultBankAccount = $chartOfAccountsService->getDefaultBankAccount($company);
66 27
 
67
-    private function createPurchaseDiscount(Company $company, User $user): void
68
-    {
69
-        Discount::factory()->purchaseDiscount()->create([
70
-            'company_id' => $company->id,
71
-            'created_by' => $user->id,
72
-            'updated_by' => $user->id,
73
-        ]);
74
-    }
75
-
76
-    private function createAppearance(Company $company, User $user): void
77
-    {
78
-        Appearance::factory()->create([
79
-            'company_id' => $company->id,
80
-            'created_by' => $user->id,
81
-            'updated_by' => $user->id,
82
-        ]);
83
-    }
84
-
85
-    private function createDocumentDefaults(Company $company, User $user): void
86
-    {
87
-        DocumentDefault::factory()->invoice()->create([
88
-            'company_id' => $company->id,
89
-            'created_by' => $user->id,
90
-            'updated_by' => $user->id,
91
-        ]);
92
-
93
-        DocumentDefault::factory()->bill()->create([
94
-            'company_id' => $company->id,
95
-            'created_by' => $user->id,
96
-            'updated_by' => $user->id,
97
-        ]);
98
-    }
99
-
100
-    private function createLocalization(Company $company, User $user, string $countryCode, string $language): void
101
-    {
102
-        Localization::factory()->withCountry($countryCode, $language)->create([
103
-            'company_id' => $company->id,
104
-            'created_by' => $user->id,
105
-            'updated_by' => $user->id,
106
-        ]);
28
+            $companyDefault->update([
29
+                'bank_account_id' => $defaultBankAccount?->id,
30
+            ]);
31
+        }, 5);
107 32
     }
108 33
 }

+ 8
- 7
database/factories/Setting/CompanyDefaultFactory.php 查看文件

@@ -37,12 +37,13 @@ class CompanyDefaultFactory extends Factory
37 37
         ];
38 38
     }
39 39
 
40
-    public function withDefault(User $user, Company $company, string $country, string $language = 'en'): static
40
+    public function withDefault(User $user, Company $company, ?string $currencyCode, string $countryCode, string $language = 'en'): static
41 41
     {
42
-        /** @var CurrencyCode $currencyFaker */
43
-        $currencyFaker = $this->faker;
44
-
45
-        $currencyCode = $currencyFaker->currencyCode($country);
42
+        if ($currencyCode === null) {
43
+            /** @var CurrencyCode $currencyFaker */
44
+            $currencyFaker = $this->faker;
45
+            $currencyCode = $currencyFaker->currencyCode($countryCode);
46
+        }
46 47
 
47 48
         $currency = $this->createCurrency($company, $user, $currencyCode);
48 49
         $salesTax = $this->createSalesTax($company, $user);
@@ -51,7 +52,7 @@ class CompanyDefaultFactory extends Factory
51 52
         $purchaseDiscount = $this->createPurchaseDiscount($company, $user);
52 53
         $this->createAppearance($company, $user);
53 54
         $this->createDocumentDefaults($company, $user);
54
-        $this->createLocalization($company, $user, $country, $language);
55
+        $this->createLocalization($company, $user, $countryCode, $language);
55 56
 
56 57
         $companyDefaults = [
57 58
             'company_id' => $company->id,
@@ -67,7 +68,7 @@ class CompanyDefaultFactory extends Factory
67 68
         return $this->state($companyDefaults);
68 69
     }
69 70
 
70
-    private function createCurrency(Company $company, User $user, string $currencyCode)
71
+    private function createCurrency(Company $company, User $user, string $currencyCode): Currency
71 72
     {
72 73
         return Currency::factory()->forCurrency($currencyCode)->create([
73 74
             'company_id' => $company->id,

+ 1
- 21
database/factories/UserFactory.php 查看文件

@@ -5,7 +5,6 @@ namespace Database\Factories;
5 5
 use App\Models\Company;
6 6
 use App\Models\Setting\CompanyProfile;
7 7
 use App\Models\User;
8
-use App\Services\ChartOfAccountsService;
9 8
 use App\Services\CompanyDefaultService;
10 9
 use Database\Factories\Accounting\TransactionFactory;
11 10
 use Illuminate\Database\Eloquent\Factories\Factory;
@@ -75,26 +74,7 @@ class UserFactory extends Factory
75 74
                         $companyDefaultService = app()->make(CompanyDefaultService::class);
76 75
                         $companyDefaultService->createCompanyDefaults($company, $user, 'USD', $countryCode, 'en');
77 76
 
78
-                        $chartOfAccountsService = app()->make(ChartOfAccountsService::class);
79
-                        $chartOfAccountsService->createChartOfAccounts($company);
80
-
81
-                        $defaultBankAccount = $company->bankAccounts()->where('enabled', true)->first();
82
-                        $defaultCurrency = $company->currencies()->where('enabled', true)->first();
83
-                        $defaultSalesTax = $company->taxes()->where('type', 'sales')->where('enabled', true)->first();
84
-                        $defaultPurchaseTax = $company->taxes()->where('type', 'purchase')->where('enabled', true)->first();
85
-                        $defaultSalesDiscount = $company->discounts()->where('type', 'sales')->where('enabled', true)->first();
86
-                        $defaultPurchaseDiscount = $company->discounts()->where('type', 'purchase')->where('enabled', true)->first();
87
-
88
-                        $company->default()->create([
89
-                            'bank_account_id' => $defaultBankAccount?->id,
90
-                            'currency_code' => $defaultCurrency?->code,
91
-                            'sales_tax_id' => $defaultSalesTax?->id,
92
-                            'purchase_tax_id' => $defaultPurchaseTax?->id,
93
-                            'sales_discount_id' => $defaultSalesDiscount?->id,
94
-                            'purchase_discount_id' => $defaultPurchaseDiscount?->id,
95
-                            'created_by' => $user->id,
96
-                            'updated_by' => $user->id,
97
-                        ]);
77
+                        $defaultBankAccount = $company->default->bankAccount;
98 78
 
99 79
                         TransactionFactory::new()
100 80
                             ->forCompanyAndBankAccount($company, $defaultBankAccount)

+ 17
- 8
resources/views/filament/company/pages/reports/account-transactions.blade.php 查看文件

@@ -3,18 +3,27 @@
3 3
         <form wire:submit="loadReportData" class="p-6">
4 4
             {{ $this->form }}
5 5
         </form>
6
-        <div class="divide-y divide-gray-200 overflow-x-auto overflow-y-hidden dark:divide-white/10 dark:border-t-white/10">
7
-            <div wire:init="loadReportData" class="flex items-center justify-center">
8
-                <div wire:loading.delay wire:target="loadReportData">
6
+        <div class="relative divide-y divide-gray-200 overflow-x-auto dark:divide-white/10 dark:border-t-white/10 min-h-64">
7
+            <div wire:init="loadReportData" class="flex items-center justify-center w-full h-full absolute">
8
+                <div wire:loading wire:target="loadReportData">
9 9
                     <x-filament::loading-indicator class="p-6 text-primary-700 dark:text-primary-300" />
10 10
                 </div>
11 11
             </div>
12 12
 
13
-            <div wire:loading.remove wire:target="loadReportData">
14
-                @if($this->report)
15
-                    <x-company.tables.reports.account-transactions :report="$this->report" />
16
-                @endif
17
-            </div>
13
+            @if($this->reportLoaded)
14
+                <div wire:loading.remove wire:target="loadReportData">
15
+                    @if($this->report && !$this->tableHasEmptyState())
16
+                        <x-company.tables.reports.account-transactions :report="$this->report" />
17
+                    @else
18
+                        <x-filament-tables::empty-state
19
+                            :actions="$this->getEmptyStateActions()"
20
+                            :description="$this->getEmptyStateDescription()"
21
+                            :heading="$this->getEmptyStateHeading()"
22
+                            :icon="$this->getEmptyStateIcon()"
23
+                        />
24
+                    @endif
25
+                </div>
26
+            @endif
18 27
         </div>
19 28
         <div class="es-table__footer-ctn border-t border-gray-200"></div>
20 29
     </x-filament-tables::container>

+ 24
- 24
resources/views/filament/company/pages/reports/detailed-report.blade.php 查看文件

@@ -1,33 +1,33 @@
1 1
 <x-filament-panels::page>
2 2
     <x-filament-tables::container>
3
-        <div class="p-6 divide-y divide-gray-200 dark:divide-white/5">
4
-            <form wire:submit="loadReportData">
5
-                <div class="flex flex-col md:flex-row items-start md:items-center justify-center gap-4 md:gap-12">
6
-                    {{ $this->form }}
7
-                    @if($this->hasToggleableColumns())
8
-                        <x-filament-tables::column-toggle.dropdown
9
-                            :form="$this->toggleTableColumnForm"
10
-                            :trigger-action="$this->toggleColumnsAction"
11
-                        />
12
-                    @endif
13
-                    <x-filament::button type="submit" wire:target="loadReportData" class="flex-shrink-0">
14
-                        Update Report
15
-                    </x-filament::button>
16
-                </div>
17
-            </form>
18
-        </div>
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 wire:init="loadReportData" class="flex items-center justify-center">
21
-                <div wire:loading.delay wire:target="loadReportData">
3
+        <form wire:submit="loadReportData" class="p-6">
4
+            <div class="flex flex-col md:flex-row items-start md:items-center justify-center gap-4 md:gap-12">
5
+                {{ $this->form }}
6
+                @if($this->hasToggleableColumns())
7
+                    <x-filament-tables::column-toggle.dropdown
8
+                        :form="$this->toggleTableColumnForm"
9
+                        :trigger-action="$this->toggleColumnsAction"
10
+                    />
11
+                @endif
12
+                <x-filament::button type="submit" wire:target="loadReportData" class="flex-shrink-0">
13
+                    Update Report
14
+                </x-filament::button>
15
+            </div>
16
+        </form>
17
+        <div class="relative divide-y divide-gray-200 overflow-x-auto dark:divide-white/10 dark:border-t-white/10 min-h-64">
18
+            <div wire:init="loadReportData" class="flex items-center justify-center w-full h-full absolute">
19
+                <div wire:loading wire:target="loadReportData">
22 20
                     <x-filament::loading-indicator class="p-6 text-primary-700 dark:text-primary-300" />
23 21
                 </div>
24 22
             </div>
25 23
 
26
-            <div wire:loading.remove wire:target="loadReportData">
27
-                @if($this->report)
28
-                    <x-company.tables.reports.detailed-report :report="$this->report" />
29
-                @endif
30
-            </div>
24
+            @if($this->reportLoaded)
25
+                <div wire:loading.remove wire:target="loadReportData">
26
+                    @if($this->report)
27
+                        <x-company.tables.reports.detailed-report :report="$this->report" />
28
+                    @endif
29
+                </div>
30
+            @endif
31 31
         </div>
32 32
         <div class="es-table__footer-ctn border-t border-gray-200"></div>
33 33
     </x-filament-tables::container>

正在加载...
取消
保存