Andrew Wallo 2 年之前
父節點
當前提交
76c99c99dc
共有 55 個檔案被更改,包括 5178 行新增345 行删除
  1. 29
    0
      app/Actions/Banking/CreateCurrencyFromAccount.php
  2. 52
    10
      app/Filament/Pages/Widgets/Companies/Charts/CompanyStatsOverview.php
  3. 241
    0
      app/Filament/Resources/AccountResource.php
  4. 52
    0
      app/Filament/Resources/AccountResource/Pages/CreateAccount.php
  5. 59
    0
      app/Filament/Resources/AccountResource/Pages/EditAccount.php
  6. 19
    0
      app/Filament/Resources/AccountResource/Pages/ListAccounts.php
  7. 228
    0
      app/Filament/Resources/CurrencyResource.php
  8. 53
    0
      app/Filament/Resources/CurrencyResource/Pages/CreateCurrency.php
  9. 59
    0
      app/Filament/Resources/CurrencyResource/Pages/EditCurrency.php
  10. 19
    0
      app/Filament/Resources/CurrencyResource/Pages/ListCurrencies.php
  11. 216
    0
      app/Filament/Resources/CustomerResource.php
  12. 25
    0
      app/Filament/Resources/CustomerResource/Pages/CreateCustomer.php
  13. 19
    0
      app/Filament/Resources/CustomerResource/Pages/EditCustomer.php
  14. 19
    0
      app/Filament/Resources/CustomerResource/Pages/ListCustomers.php
  15. 76
    0
      app/Filament/Resources/InvoiceResource.php
  16. 12
    0
      app/Filament/Resources/InvoiceResource/Pages/CreateInvoice.php
  17. 19
    0
      app/Filament/Resources/InvoiceResource/Pages/EditInvoice.php
  18. 19
    0
      app/Filament/Resources/InvoiceResource/Pages/ListInvoices.php
  19. 81
    0
      app/Models/Banking/Account.php
  20. 123
    0
      app/Models/Company.php
  21. 96
    0
      app/Models/Contact.php
  22. 100
    0
      app/Models/Document/Document.php
  23. 97
    0
      app/Models/Document/DocumentItem.php
  24. 60
    0
      app/Models/Document/DocumentTotal.php
  25. 82
    0
      app/Models/Item.php
  26. 68
    0
      app/Models/Setting/Category.php
  27. 68
    0
      app/Models/Setting/Currency.php
  28. 65
    0
      app/Models/Setting/Discount.php
  29. 72
    0
      app/Models/Setting/Tax.php
  30. 66
    0
      app/Policies/AccountPolicy.php
  31. 77
    80
      composer.lock
  32. 1808
    0
      config/money.php
  33. 84
    0
      database/factories/AccountFactory.php
  34. 31
    0
      database/factories/CategoryFactory.php
  35. 31
    0
      database/factories/ContactFactory.php
  36. 79
    0
      database/factories/CurrencyFactory.php
  37. 31
    0
      database/factories/DiscountFactory.php
  38. 31
    0
      database/factories/DocumentFactory.php
  39. 31
    0
      database/factories/DocumentItemFactory.php
  40. 31
    0
      database/factories/DocumentTotalFactory.php
  41. 29
    0
      database/factories/ItemFactory.php
  42. 31
    0
      database/factories/TaxFactory.php
  43. 40
    0
      database/migrations/2023_05_10_040940_create_currencies_table.php
  44. 41
    0
      database/migrations/2023_05_11_044321_create_accounts_table.php
  45. 33
    0
      database/migrations/2023_05_12_042255_create_categories_table.php
  46. 47
    0
      database/migrations/2023_05_19_042232_create_contacts_table.php
  47. 36
    0
      database/migrations/2023_05_20_080131_create_taxes_table.php
  48. 35
    0
      database/migrations/2023_05_21_163808_create_discounts_table.php
  49. 40
    0
      database/migrations/2023_05_22_073252_create_items_table.php
  50. 46
    0
      database/migrations/2023_05_23_141215_create_documents_table.php
  51. 39
    0
      database/migrations/2023_05_23_151550_create_document_items_table.php
  52. 37
    0
      database/migrations/2023_05_23_173412_create_document_totals_table.php
  53. 20
    0
      database/seeders/AccountSeeder.php
  54. 20
    0
      database/seeders/CurrencySeeder.php
  55. 256
    255
      package-lock.json

+ 29
- 0
app/Actions/Banking/CreateCurrencyFromAccount.php 查看文件

1
+<?php
2
+
3
+namespace App\Actions\Banking;
4
+
5
+use App\Models\Setting\Currency;
6
+use Illuminate\Support\Facades\Auth;
7
+
8
+class CreateCurrencyFromAccount
9
+{
10
+    public function create(string $code, string $name, string $rate): Currency
11
+    {
12
+        $companyId = Auth::user()->currentCompany->id;
13
+
14
+        $hasDefaultCurrency = Currency::where('company_id', $companyId)->where('enabled', true)->exists();
15
+
16
+        return Currency::create([
17
+            'name' => $name,
18
+            'code' => $code,
19
+            'rate' => $rate,
20
+            'precision' => config("money.{$code}.precision"),
21
+            'symbol' => config("money.{$code}.symbol"),
22
+            'symbol_first' => config("money.{$code}.symbol_first"),
23
+            'decimal_mark' => config("money.{$code}.decimal_mark"),
24
+            'thousands_separator' => config("money.{$code}.thousands_separator"),
25
+            'enabled' => !$hasDefaultCurrency,
26
+            'company_id' => $companyId,
27
+        ]);
28
+    }
29
+}

+ 52
- 10
app/Filament/Pages/Widgets/Companies/Charts/CompanyStatsOverview.php 查看文件

15
     }
15
     }
16
 
16
 
17
     /**
17
     /**
18
-     * Holt's Linear Trend
18
+     * Holt's Linear Trend Method
19
      */
19
      */
20
     protected function holtLinearTrend($data, $alpha, $beta): array
20
     protected function holtLinearTrend($data, $alpha, $beta): array
21
     {
21
     {
33
         return $forecast;
33
         return $forecast;
34
     }
34
     }
35
 
35
 
36
+    /**
37
+     * Adjusts the alpha and beta parameters based on the model's performance
38
+     */
39
+    protected function adjustTrendParameters($data, $alpha, $beta): array
40
+    {
41
+        $minError = PHP_INT_MAX;
42
+        $bestAlpha = $alpha;
43
+        $bestBeta = $beta;
44
+
45
+        // try different alpha and beta values within a reasonable range
46
+        for ($alpha = 0.1; $alpha <= 1; $alpha += 0.1) {
47
+            for ($beta = 0.1; $beta <= 1; $beta += 0.1) {
48
+                $forecast = $this->holtLinearTrend($data, $alpha, $beta);
49
+                $error = $this->calculateError($data, $forecast);
50
+                if ($error < $minError) {
51
+                    $minError = $error;
52
+                    $bestAlpha = $alpha;
53
+                    $bestBeta = $beta;
54
+                }
55
+            }
56
+        }
57
+
58
+        return [$bestAlpha, $bestBeta];
59
+    }
60
+
61
+    /**
62
+     * Calculates the sum of squared errors between the actual data and the forecast
63
+     */
64
+    protected function calculateError($data, $forecast): float
65
+    {
66
+        $error = 0;
67
+        for ($i = 0; $i < count($data); $i++) {
68
+            $error += pow($data[$i] - $forecast[$i], 2);
69
+        }
70
+
71
+        return $error;
72
+    }
73
+
36
     /**
74
     /**
37
      * Chart Options
75
      * Chart Options
38
      */
76
      */
58
             $weeks[$week->format('oW')] = 0;
96
             $weeks[$week->format('oW')] = 0;
59
         }
97
         }
60
 
98
 
61
-        // Get Weekly Data
99
+        // Get Weekly Data for Company Data
62
         $weeklyData = collect($weeks)->mapWithKeys(static function ($value, $week) use ($companyData) {
100
         $weeklyData = collect($weeks)->mapWithKeys(static function ($value, $week) use ($companyData) {
63
             $matchingData = $companyData->firstWhere('week', $week);
101
             $matchingData = $companyData->firstWhere('week', $week);
64
             return [$week => $matchingData ? $matchingData->aggregate : 0];
102
             return [$week => $matchingData ? $matchingData->aggregate : 0];
65
         });
103
         });
66
 
104
 
67
-        // Calculate total companies
105
+        // Calculate total companies per week
68
         $totalCompanies = $weeklyData->reduce(static function ($carry, $value) {
106
         $totalCompanies = $weeklyData->reduce(static function ($carry, $value) {
69
             $carry[] = ($carry ? end($carry) : 0) + $value;
107
             $carry[] = ($carry ? end($carry) : 0) + $value;
70
             return $carry;
108
             return $carry;
71
         }, []);
109
         }, []);
72
 
110
 
73
-        // Calculate new companies and percentage change
111
+        // Calculate new companies and percentage change per week
74
         $newCompanies = [0];
112
         $newCompanies = [0];
75
         $weeklyPercentageChange = [0];
113
         $weeklyPercentageChange = [0];
76
         for ($i = 1; $i < count($totalCompanies); $i++) {
114
         for ($i = 1; $i < count($totalCompanies); $i++) {
80
 
118
 
81
         // Calculate average weekly growth rate
119
         // Calculate average weekly growth rate
82
         $totalWeeks = $startOfYear->diffInWeeks($today);
120
         $totalWeeks = $startOfYear->diffInWeeks($today);
83
-        $averageWeeklyGrowthRate = round(array_sum($weeklyPercentageChange) / ($totalWeeks), 2);
121
+        $averageWeeklyGrowthRate = round(array_sum($weeklyPercentageChange) / $totalWeeks, 2);
84
 
122
 
85
-        // Calculate Holt's forecast
86
         $weeklyDataArray = $weeklyData->values()->toArray();
123
         $weeklyDataArray = $weeklyData->values()->toArray();
87
-        $holt_forecast = $this->holtLinearTrend($weeklyDataArray, $alpha, $beta);
88
-        $expectedNewCompanies = round(end($holt_forecast));
89
 
124
 
90
-        // Prepare cards for return
125
+        // Adjust alpha and beta parameters
126
+        [$alpha, $beta] = $this->adjustTrendParameters($weeklyDataArray, $alpha, $beta);
127
+
128
+        // Calculate Holt's Linear Trend Forecast for next week
129
+        $holtForecast = $this->holtLinearTrend($weeklyDataArray, $alpha, $beta);
130
+        $expectedNewCompanies = round(end($holtForecast));
131
+
132
+        // Company Stats Overview Cards
91
         return [
133
         return [
92
-            StatsOverviewWidget\Card::make("New Companies Forecast (Holt's Trend)", $expectedNewCompanies),
134
+            StatsOverviewWidget\Card::make("New Companies Forecast (Holt's Linear Trend)", $expectedNewCompanies),
93
             StatsOverviewWidget\Card::make('Average Weekly Growth Rate', $averageWeeklyGrowthRate . '%'),
135
             StatsOverviewWidget\Card::make('Average Weekly Growth Rate', $averageWeeklyGrowthRate . '%'),
94
             StatsOverviewWidget\Card::make('Personal Companies', Company::sum('personal_company')),
136
             StatsOverviewWidget\Card::make('Personal Companies', Company::sum('personal_company')),
95
         ];
137
         ];

+ 241
- 0
app/Filament/Resources/AccountResource.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Actions\Banking\CreateCurrencyFromAccount;
6
+use App\Filament\Resources\AccountResource\Pages;
7
+use App\Filament\Resources\AccountResource\RelationManagers;
8
+use App\Models\Banking\Account;
9
+use Closure;
10
+use Exception;
11
+use Filament\Forms;
12
+use Filament\Forms\Components\TextInput\Mask;
13
+use Filament\Notifications\Notification;
14
+use Filament\Resources\Form;
15
+use Filament\Resources\Resource;
16
+use Filament\Resources\Table;
17
+use Filament\Tables;
18
+use Illuminate\Database\Eloquent\Builder;
19
+use Illuminate\Database\Eloquent\Model;
20
+use Illuminate\Database\Eloquent\SoftDeletingScope;
21
+use Illuminate\Support\Collection;
22
+use Illuminate\Support\Facades\Auth;
23
+use Illuminate\Support\Facades\DB;
24
+use Illuminate\Validation\Rule;
25
+use Illuminate\Validation\Rules\Unique;
26
+
27
+class AccountResource extends Resource
28
+{
29
+    protected static ?string $model = Account::class;
30
+
31
+    protected static ?string $navigationIcon = 'heroicon-o-credit-card';
32
+
33
+    protected static ?string $navigationGroup = 'Banking';
34
+
35
+    public static function getEloquentQuery(): Builder
36
+    {
37
+        return parent::getEloquentQuery()->where('company_id', Auth::user()->currentCompany->id);
38
+    }
39
+
40
+    public static function form(Form $form): Form
41
+    {
42
+        return $form
43
+            ->schema([
44
+                Forms\Components\Section::make('General')
45
+                    ->schema([
46
+                        Forms\Components\Radio::make('type')
47
+                            ->label('Type')
48
+                            ->options(Account::getAccountTypes())
49
+                            ->inline()
50
+                            ->default('bank')
51
+                            ->reactive()
52
+                            ->afterStateUpdated(static fn (Closure $set, $state) => $state === 'card' ? $set('enabled', 'hidden'): $set('enabled', null))
53
+                            ->required()
54
+                            ->columnSpanFull(),
55
+                        Forms\Components\TextInput::make('name')
56
+                            ->label('Name')
57
+                            ->maxLength(100)
58
+                            ->required(),
59
+                        Forms\Components\TextInput::make('number')
60
+                            ->label('Account Number')
61
+                            ->unique(callback: static function (Unique $rule, $state) {
62
+                                $companyId = Auth::user()->currentCompany->id;
63
+
64
+                                return $rule->where('company_id', $companyId)->where('number', $state);
65
+                            }, ignoreRecord: true)
66
+                            ->maxLength(20)
67
+                            ->required(),
68
+                        Forms\Components\Select::make('currency_code')
69
+                            ->label('Currency')
70
+                            ->relationship('currency', 'name', static fn (Builder $query) => $query->where('company_id', Auth::user()->currentCompany->id))
71
+                            ->preload()
72
+                            ->default(Account::getDefaultCurrencyCode())
73
+                            ->searchable()
74
+                            ->reactive()
75
+                            ->required()
76
+                            ->createOptionForm([
77
+                                Forms\Components\Select::make('currency.code')
78
+                                    ->label('Code')
79
+                                    ->searchable()
80
+                                    ->options(Account::getCurrencyCodes())
81
+                                    ->reactive()
82
+                                    ->afterStateUpdated(static function (callable $set, $state) {
83
+                                        $code = $state;
84
+                                        $name = config("money.{$code}.name");
85
+                                        $set('currency.name', $name);
86
+                                    })
87
+                                    ->required(),
88
+                                Forms\Components\TextInput::make('currency.name')
89
+                                    ->label('Name')
90
+                                    ->maxLength(100)
91
+                                    ->required(),
92
+                                Forms\Components\TextInput::make('currency.rate')
93
+                                    ->label('Rate')
94
+                                    ->numeric()
95
+                                    ->mask(static fn (Forms\Components\TextInput\Mask $mask) => $mask
96
+                                        ->numeric()
97
+                                        ->decimalPlaces(4)
98
+                                        ->signed(false)
99
+                                        ->padFractionalZeros(false)
100
+                                        ->normalizeZeros(false)
101
+                                        ->minValue(0.0001)
102
+                                        ->maxValue(999999.9999)
103
+                                        ->lazyPlaceholder(false))
104
+                                    ->required(),
105
+                            ])->createOptionAction(static function (Forms\Components\Actions\Action $action) {
106
+                                return $action
107
+                                    ->label('Add Currency')
108
+                                    ->modalHeading('Add Currency')
109
+                                    ->modalButton('Add')
110
+                                    ->action(static function (array $data) {
111
+                                        return DB::transaction(static function () use ($data) {
112
+                                            $code = $data['currency']['code'];
113
+                                            $name = $data['currency']['name'];
114
+                                            $rate = $data['currency']['rate'];
115
+
116
+                                            return (new CreateCurrencyFromAccount())->create($code, $name, $rate);
117
+                                        });
118
+                                    });
119
+                            }),
120
+                        Forms\Components\TextInput::make('opening_balance')
121
+                            ->label('Opening Balance')
122
+                            ->required()
123
+                            ->default('0')
124
+                            ->numeric()
125
+                            ->mask(static fn (Forms\Components\TextInput\Mask $mask, Closure $get) => $mask
126
+                                ->patternBlocks([
127
+                                    'money' => static fn (Mask $mask) => $mask
128
+                                        ->numeric()
129
+                                        ->decimalPlaces(config('money.' . $get('currency_code') . '.precision'))
130
+                                        ->decimalSeparator(config('money.' . $get('currency_code') . '.decimal_mark'))
131
+                                        ->thousandsSeparator(config('money.' . $get('currency_code') . '.thousands_separator'))
132
+                                        ->signed()
133
+                                        ->padFractionalZeros()
134
+                                        ->normalizeZeros(false),
135
+                            ])
136
+                            ->pattern(config('money.' . $get('currency_code') . '.symbol_first') ? config('money.' . $get('currency_code') . '.symbol') . 'money' : 'money' . config('money.' . $get('currency_code') . '.symbol'))
137
+                            ->lazyPlaceholder(false)),
138
+                        Forms\Components\Toggle::make('enabled')
139
+                            ->hidden(fn (Closure $get) => $get('type') === 'card')
140
+                            ->label('Default Account'),
141
+                    ])->columns(),
142
+                Forms\Components\Section::make('Bank')
143
+                    ->schema([
144
+                        Forms\Components\TextInput::make('bank_name')
145
+                            ->label('Bank Name')
146
+                            ->maxLength(100),
147
+                        Forms\Components\TextInput::make('bank_phone')
148
+                            ->label('Bank Phone')
149
+                            ->mask(static fn (Forms\Components\TextInput\Mask $mask) => $mask->pattern('(000) 000-0000'))
150
+                            ->maxLength(20),
151
+                        Forms\Components\Textarea::make('bank_address')
152
+                            ->label('Bank Address')
153
+                            ->columnSpanFull(),
154
+                        ])->columns(),
155
+            ]);
156
+    }
157
+
158
+    /**
159
+     * @throws Exception
160
+     */
161
+    public static function table(Table $table): Table
162
+    {
163
+        return $table
164
+            ->columns([
165
+                Tables\Columns\TextColumn::make('name')
166
+                    ->searchable()
167
+                    ->weight('semibold')
168
+                    ->icon(static fn (Account $record) => $record->enabled ? 'heroicon-o-lock-closed' : null)
169
+                    ->tooltip(static fn (Account $record) => $record->enabled ? 'Default Account' : null)
170
+                    ->iconPosition('after')
171
+                    ->sortable(),
172
+                Tables\Columns\TextColumn::make('number')
173
+                    ->label('Account Number')
174
+                    ->searchable()
175
+                    ->sortable(),
176
+                Tables\Columns\TextColumn::make('bank_name')
177
+                    ->label('Bank Name')
178
+                    ->searchable()
179
+                    ->sortable(),
180
+                Tables\Columns\TextColumn::make('bank_phone')
181
+                    ->label('Phone')
182
+                    ->formatStateUsing(static fn ($record) => ($record->bank_phone !== '') ? vsprintf('(%d%d%d) %d%d%d-%d%d%d%d', str_split($record->bank_phone)) : '-'),
183
+                Tables\Columns\TextColumn::make('opening_balance')
184
+                    ->label('Current Balance')
185
+                    ->sortable()
186
+                    ->money(static fn ($record) => $record->currency_code, true),
187
+            ])
188
+            ->filters([
189
+                //
190
+            ])
191
+            ->actions([
192
+                Tables\Actions\EditAction::make(),
193
+                Tables\Actions\DeleteAction::make()
194
+                    ->before(static function (Tables\Actions\DeleteAction $action, Account $record) {
195
+                        if ($record->enabled) {
196
+                            Notification::make()
197
+                                ->danger()
198
+                                ->title('Action Denied')
199
+                                ->body(__('The :name account is currently set as your default account and cannot be deleted. Please set a different account as your default before attempting to delete this one.', ['name' => $record->name]))
200
+                                ->persistent()
201
+                                ->send();
202
+
203
+                            $action->cancel();
204
+                        }
205
+                    }),
206
+            ])
207
+            ->bulkActions([
208
+                Tables\Actions\DeleteBulkAction::make()
209
+                    ->before(static function (Tables\Actions\DeleteBulkAction $action, Collection $records) {
210
+                        foreach ($records as $record) {
211
+                            if ($record->enabled) {
212
+                                Notification::make()
213
+                                    ->danger()
214
+                                    ->title('Action Denied')
215
+                                    ->body(__('The :name account is currently set as your default account and cannot be deleted. Please set a different account as your default before attempting to delete this one.', ['name' => $record->name]))
216
+                                    ->persistent()
217
+                                    ->send();
218
+
219
+                                $action->cancel();
220
+                            }
221
+                        }
222
+                    }),
223
+            ]);
224
+    }
225
+    
226
+    public static function getRelations(): array
227
+    {
228
+        return [
229
+            //
230
+        ];
231
+    }
232
+    
233
+    public static function getPages(): array
234
+    {
235
+        return [
236
+            'index' => Pages\ListAccounts::route('/'),
237
+            'create' => Pages\CreateAccount::route('/create'),
238
+            'edit' => Pages\EditAccount::route('/{record}/edit'),
239
+        ];
240
+    }    
241
+}

+ 52
- 0
app/Filament/Resources/AccountResource/Pages/CreateAccount.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources\AccountResource\Pages;
4
+
5
+use App\Filament\Resources\AccountResource;
6
+use App\Models\Banking\Account;
7
+use Filament\Pages\Actions;
8
+use Filament\Resources\Pages\CreateRecord;
9
+use Illuminate\Database\Eloquent\Model;
10
+use Illuminate\Support\Facades\DB;
11
+
12
+class CreateAccount extends CreateRecord
13
+{
14
+    protected static string $resource = AccountResource::class;
15
+
16
+    protected function getRedirectUrl(): string
17
+    {
18
+        return $this->getResource()::getUrl('index');
19
+    }
20
+
21
+    protected function mutateFormDataBeforeCreate(array $data): array
22
+    {
23
+        $data['company_id'] = auth()->user()->currentCompany->id;
24
+        return $data;
25
+    }
26
+
27
+    protected function handleRecordCreation(array $data): Model
28
+    {
29
+        $currentCompanyId = auth()->user()->currentCompany->id;
30
+        $accountId = $data['id'] ?? null;
31
+        $enabledAccountsCount = Account::where('company_id', $currentCompanyId)
32
+            ->where('enabled', true)
33
+            ->where('id', '!=', $accountId)
34
+            ->count();
35
+
36
+        if ($data['enabled'] === true && $enabledAccountsCount > 0) {
37
+            $this->disableOtherAccounts($currentCompanyId, $accountId);
38
+        } elseif ($data['enabled'] === false && $enabledAccountsCount < 1) {
39
+            $data['enabled'] = true;
40
+        }
41
+
42
+        return parent::handleRecordCreation($data);
43
+    }
44
+
45
+    protected function disableOtherAccounts($companyId, $accountId): void
46
+    {
47
+        DB::table('accounts')
48
+            ->where('company_id', $companyId)
49
+            ->where('id', '!=', $accountId)
50
+            ->update(['enabled' => false]);
51
+    }
52
+}

+ 59
- 0
app/Filament/Resources/AccountResource/Pages/EditAccount.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources\AccountResource\Pages;
4
+
5
+use App\Filament\Resources\AccountResource;
6
+use App\Models\Banking\Account;
7
+use Filament\Pages\Actions;
8
+use Filament\Resources\Pages\EditRecord;
9
+use Illuminate\Database\Eloquent\Model;
10
+use Illuminate\Support\Facades\DB;
11
+
12
+class EditAccount extends EditRecord
13
+{
14
+    protected static string $resource = AccountResource::class;
15
+
16
+    protected function getActions(): array
17
+    {
18
+        return [
19
+            Actions\DeleteAction::make(),
20
+        ];
21
+    }
22
+
23
+    protected function getRedirectUrl(): string
24
+    {
25
+        return $this->getResource()::getUrl('index');
26
+    }
27
+
28
+    protected function mutateFormDataBeforeSave(array $data): array
29
+    {
30
+        $data['company_id'] = auth()->user()->currentCompany->id;
31
+        return $data;
32
+    }
33
+
34
+    protected function handleRecordUpdate(Model|Account $record, array $data): Model|Account
35
+    {
36
+        $currentCompanyId = auth()->user()->currentCompany->id;
37
+        $accountId = $record->id;
38
+        $enabledAccountsCount = Account::where('company_id', $currentCompanyId)
39
+            ->where('enabled', true)
40
+            ->where('id', '!=', $accountId)
41
+            ->count();
42
+
43
+        if ($data['enabled'] === true && $enabledAccountsCount > 0) {
44
+            $this->disableOtherAccounts($currentCompanyId, $accountId);
45
+        } elseif ($data['enabled'] === false && $enabledAccountsCount < 1) {
46
+            $data['enabled'] = true;
47
+        }
48
+
49
+        return parent::handleRecordUpdate($record, $data);
50
+    }
51
+
52
+    protected function disableOtherAccounts($companyId, $accountId): void
53
+    {
54
+        DB::table('accounts')
55
+            ->where('company_id', $companyId)
56
+            ->where('id', '!=', $accountId)
57
+            ->update(['enabled' => false]);
58
+    }
59
+}

+ 19
- 0
app/Filament/Resources/AccountResource/Pages/ListAccounts.php 查看文件

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

+ 228
- 0
app/Filament/Resources/CurrencyResource.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Filament\Resources\CurrencyResource\Pages;
6
+use App\Filament\Resources\CurrencyResource\RelationManagers;
7
+use App\Models\Banking\Account;
8
+use App\Models\Setting\Currency;
9
+use Closure;
10
+use Exception;
11
+use Filament\Forms;
12
+use Filament\Notifications\Notification;
13
+use Filament\Resources\Form;
14
+use Filament\Resources\Resource;
15
+use Filament\Resources\Table;
16
+use Filament\Tables;
17
+use Illuminate\Database\Eloquent\Builder;
18
+use Illuminate\Database\Eloquent\Model;
19
+use Illuminate\Database\Eloquent\SoftDeletingScope;
20
+use Illuminate\Support\Collection;
21
+use Illuminate\Support\Facades\Auth;
22
+
23
+class CurrencyResource extends Resource
24
+{
25
+    protected static ?string $model = Currency::class;
26
+
27
+    protected static ?string $navigationIcon = 'heroicon-o-currency-dollar';
28
+
29
+    protected static ?string $navigationGroup = 'Settings';
30
+
31
+    public static function getEloquentQuery(): Builder
32
+    {
33
+        return parent::getEloquentQuery()->where('company_id', Auth::user()->currentCompany->id);
34
+    }
35
+
36
+    public static function form(Form $form): Form
37
+    {
38
+        return $form
39
+            ->schema([
40
+                Forms\Components\Section::make('General')
41
+                    ->schema([
42
+                        Forms\Components\Select::make('code')
43
+                            ->label('Code')
44
+                            ->options(Currency::getCurrencyCodes())
45
+                            ->searchable()
46
+                            ->placeholder('- Select Code -')
47
+                            ->reactive()
48
+                            ->afterStateUpdated(static function (Closure $set, $state) {
49
+                                $code = $state;
50
+                                $name = config("money.{$code}.name");
51
+                                $precision = config("money.{$code}.precision");
52
+                                $symbol = config("money.{$code}.symbol");
53
+                                $symbol_first = config("money.{$code}.symbol_first");
54
+                                $decimal_mark = config("money.{$code}.decimal_mark");
55
+                                $thousands_separator = config("money.{$code}.thousands_separator");
56
+
57
+                                $set('name', $name);
58
+                                $set('precision', $precision);
59
+                                $set('symbol', $symbol);
60
+                                $set('symbol_first', $symbol_first);
61
+                                $set('decimal_mark', $decimal_mark);
62
+                                $set('thousands_separator', $thousands_separator);
63
+                            })
64
+                            ->required(),
65
+                        Forms\Components\TextInput::make('name')
66
+                            ->translateLabel()
67
+                            ->placeholder('Enter Name')
68
+                            ->maxLength(100)
69
+                            ->required(),
70
+                        Forms\Components\TextInput::make('rate')
71
+                            ->label('Rate')
72
+                            ->placeholder('Enter Rate')
73
+                            ->dehydrateStateUsing(static fn (Closure $get, $state): bool => $get('enabled') === true ? '1' : $state) // rate is 1 when enabled is true
74
+                            ->numeric()
75
+                            ->disabled(static fn (Closure $get): bool => $get('enabled') === true) // disabled is true when enabled is true
76
+                            ->mask(static fn (Forms\Components\TextInput\Mask $mask) => $mask
77
+                                ->numeric()
78
+                                ->decimalPlaces(4)
79
+                                ->signed(false)
80
+                                ->padFractionalZeros(false)
81
+                                ->normalizeZeros(false)
82
+                                ->minValue(0.0001)
83
+                                ->maxValue(999999.9999)
84
+                                ->lazyPlaceholder(false))
85
+                            ->required(),
86
+                        Forms\Components\Select::make('precision')
87
+                            ->label('Precision')
88
+                            ->searchable()
89
+                            ->placeholder('- Select Precision -')
90
+                            ->options(['0', '1', '2', '3', '4'])
91
+                            ->required(),
92
+                        Forms\Components\TextInput::make('symbol')
93
+                            ->label('Symbol')
94
+                            ->placeholder('Enter Symbol')
95
+                            ->maxLength(5)
96
+                            ->required(),
97
+                        Forms\Components\Select::make('symbol_first')
98
+                            ->label('Symbol Position')
99
+                            ->searchable()
100
+                            ->boolean('Before Amount', 'After Amount', '- Select Symbol Position -')
101
+                            ->required(),
102
+                        Forms\Components\TextInput::make('decimal_mark')
103
+                            ->label('Decimal Separator')
104
+                            ->placeholder('Enter Decimal Separator')
105
+                            ->maxLength(1)
106
+                            ->required(),
107
+                        Forms\Components\TextInput::make('thousands_separator')
108
+                            ->label('Thousands Separator')
109
+                            ->placeholder('Enter Thousands Separator')
110
+                            ->maxLength(1)
111
+                            ->required(),
112
+                        Forms\Components\Toggle::make('enabled')
113
+                            ->label('Default Currency')
114
+                            ->reactive()
115
+                            ->inline()
116
+                            ->afterStateUpdated(static fn (Closure $set, $state) => $state ? $set('rate', '1') : $set('rate', null))
117
+                            ->default(false),
118
+                    ])->columns(),
119
+            ]);
120
+    }
121
+
122
+    /**
123
+     * @throws Exception
124
+     */
125
+    public static function table(Table $table): Table
126
+    {
127
+        return $table
128
+            ->columns([
129
+                Tables\Columns\TextColumn::make('name')
130
+                    ->label('Name')
131
+                    ->weight('semibold')
132
+                    ->icon(static fn (Currency $record) => $record->enabled ? 'heroicon-o-lock-closed' : null)
133
+                    ->tooltip(static fn (Currency $record) => $record->enabled ? 'Default Currency' : null)
134
+                    ->iconPosition('after')
135
+                    ->searchable()
136
+                    ->sortable(),
137
+                Tables\Columns\TextColumn::make('code')
138
+                    ->label('Code')
139
+                    ->searchable()
140
+                    ->sortable(),
141
+                Tables\Columns\TextColumn::make('symbol')
142
+                    ->label('Symbol')
143
+                    ->searchable()
144
+                    ->sortable(),
145
+                Tables\Columns\TextColumn::make('rate')
146
+                    ->label('Rate')
147
+                    ->formatStateUsing(static fn ($state) => str_contains($state, '.') ? rtrim(rtrim($state, '0'), '.') : null)
148
+                    ->searchable()
149
+                    ->sortable(),
150
+            ])
151
+            ->filters([
152
+                //
153
+            ])
154
+            ->actions([
155
+                Tables\Actions\EditAction::make(),
156
+                Tables\Actions\DeleteAction::make()
157
+                    ->before(static function (Tables\Actions\DeleteAction $action, Currency $record) {
158
+                        $defaultCurrency = $record->enabled;
159
+                        $accountUsesCurrency = Account::where('currency_code', $record->code)->exists();
160
+
161
+                        if ($defaultCurrency) {
162
+                            Notification::make()
163
+                                ->danger()
164
+                                ->title('Action Denied')
165
+                                ->body(__('The :name currency is currently set as the default currency and cannot be deleted. Please set a different currency as your default before attempting to delete this one.', ['name' => $record->name]))
166
+                                ->persistent()
167
+                                ->send();
168
+
169
+                            $action->cancel();
170
+                        } elseif ($accountUsesCurrency) {
171
+                            Notification::make()
172
+                                ->danger()
173
+                                ->title('Action Denied')
174
+                                ->body(__('The :name currency is currently in use by one or more accounts and cannot be deleted. Please remove this currency from all accounts before attempting to delete it.', ['name' => $record->name]))
175
+                                ->persistent()
176
+                                ->send();
177
+
178
+                            $action->cancel();
179
+                        }
180
+                    }),
181
+            ])
182
+            ->bulkActions([
183
+                Tables\Actions\DeleteBulkAction::make()
184
+                    ->before(static function (Tables\Actions\DeleteBulkAction $action, Collection $records) {
185
+                        foreach ($records as $record) {
186
+                            $defaultCurrency = $record->enabled;
187
+                            $accountUsesCurrency = Account::where('currency_code', $record->code)->exists();
188
+
189
+                            if ($defaultCurrency) {
190
+                                Notification::make()
191
+                                    ->danger()
192
+                                    ->title('Action Denied')
193
+                                    ->body(__('The :name currency is currently set as the default currency and cannot be deleted. Please set a different currency as your default before attempting to delete this one.', ['name' => $record->name]))
194
+                                    ->persistent()
195
+                                    ->send();
196
+
197
+                                $action->cancel();
198
+                            } elseif ($accountUsesCurrency) {
199
+                                Notification::make()
200
+                                    ->danger()
201
+                                    ->title('Action Denied')
202
+                                    ->body(__('The :name currency is currently in use by one or more accounts and cannot be deleted. Please remove this currency from all accounts before attempting to delete it.', ['name' => $record->name]))
203
+                                    ->persistent()
204
+                                    ->send();
205
+
206
+                                $action->cancel();
207
+                            }
208
+                        }
209
+                    }),
210
+            ]);
211
+    }
212
+    
213
+    public static function getRelations(): array
214
+    {
215
+        return [
216
+            //
217
+        ];
218
+    }
219
+    
220
+    public static function getPages(): array
221
+    {
222
+        return [
223
+            'index' => Pages\ListCurrencies::route('/'),
224
+            'create' => Pages\CreateCurrency::route('/create'),
225
+            'edit' => Pages\EditCurrency::route('/{record}/edit'),
226
+        ];
227
+    }    
228
+}

+ 53
- 0
app/Filament/Resources/CurrencyResource/Pages/CreateCurrency.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources\CurrencyResource\Pages;
4
+
5
+use App\Filament\Resources\CurrencyResource;
6
+use App\Models\Setting\Currency;
7
+use Filament\Pages\Actions;
8
+use Filament\Resources\Pages\CreateRecord;
9
+use Illuminate\Database\Eloquent\Model;
10
+use Illuminate\Support\Facades\DB;
11
+
12
+class CreateCurrency extends CreateRecord
13
+{
14
+    protected static string $resource = CurrencyResource::class;
15
+
16
+    protected function getRedirectUrl(): string
17
+    {
18
+        return $this->getResource()::getUrl('index');
19
+    }
20
+
21
+    protected function mutateFormDataBeforeCreate(array $data): array
22
+    {
23
+        $data['company_id'] = auth()->user()->currentCompany->id;
24
+
25
+        return $data;
26
+    }
27
+
28
+    protected function handleRecordCreation(array $data): Model
29
+    {
30
+        $currentCompanyId = auth()->user()->currentCompany->id;
31
+        $currencyId = $data['id'] ?? null;
32
+        $enabledCurrenciesCount = Currency::where('company_id', $currentCompanyId)
33
+            ->where('enabled', '1')
34
+            ->where('id', '!=', $currencyId)
35
+            ->count();
36
+
37
+        if ($data['enabled'] === '1' && $enabledCurrenciesCount > 0) {
38
+            $this->disableOtherCurrencies($currentCompanyId, $currencyId);
39
+        } elseif ($data['enabled'] === '0' && $enabledCurrenciesCount < 1) {
40
+            $data['enabled'] = '1';
41
+        }
42
+
43
+        return parent::handleRecordCreation($data);
44
+    }
45
+
46
+    protected function disableOtherCurrencies($companyId, $currencyId): void
47
+    {
48
+        DB::table('currencies')
49
+            ->where('company_id', $companyId)
50
+            ->where('id', '!=', $currencyId)
51
+            ->update(['enabled' => '0']);
52
+    }
53
+}

+ 59
- 0
app/Filament/Resources/CurrencyResource/Pages/EditCurrency.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources\CurrencyResource\Pages;
4
+
5
+use App\Filament\Resources\CurrencyResource;
6
+use App\Models\Setting\Currency;
7
+use Filament\Pages\Actions;
8
+use Filament\Resources\Pages\EditRecord;
9
+use Illuminate\Database\Eloquent\Model;
10
+use Illuminate\Support\Facades\DB;
11
+
12
+class EditCurrency extends EditRecord
13
+{
14
+    protected static string $resource = CurrencyResource::class;
15
+
16
+    protected function getActions(): array
17
+    {
18
+        return [
19
+            Actions\DeleteAction::make(),
20
+        ];
21
+    }
22
+
23
+    protected function getRedirectUrl(): string
24
+    {
25
+        return $this->getResource()::getUrl('index');
26
+    }
27
+
28
+    protected function mutateFormDataBeforeSave(array $data): array
29
+    {
30
+        $data['company_id'] = auth()->user()->currentCompany->id;
31
+        return $data;
32
+    }
33
+
34
+    protected function handleRecordUpdate(Model|Currency $record, array $data): Model|Currency
35
+    {
36
+        $currentCompanyId = auth()->user()->currentCompany->id;
37
+        $currencyId = $record->id;
38
+        $enabledCurrenciesCount = Currency::where('company_id', $currentCompanyId)
39
+            ->where('enabled', true)
40
+            ->where('id', '!=', $currencyId)
41
+            ->count();
42
+
43
+        if ($data['enabled'] === true && $enabledCurrenciesCount > 0) {
44
+            $this->disableOtherCurrencies($currentCompanyId, $currencyId);
45
+        } elseif ($data['enabled'] === false && $enabledCurrenciesCount < 1) {
46
+            $data['enabled'] = true;
47
+        }
48
+
49
+        return parent::handleRecordUpdate($record, $data);
50
+    }
51
+
52
+    protected function disableOtherCurrencies($companyId, $currencyId): void
53
+    {
54
+        DB::table('currencies')
55
+            ->where('company_id', $companyId)
56
+            ->where('id', '!=', $currencyId)
57
+            ->update(['enabled' => false]);
58
+    }
59
+}

+ 19
- 0
app/Filament/Resources/CurrencyResource/Pages/ListCurrencies.php 查看文件

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

+ 216
- 0
app/Filament/Resources/CustomerResource.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Actions\Banking\CreateCurrencyFromAccount;
6
+use App\Filament\Resources\CustomerResource\Pages;
7
+use App\Filament\Resources\CustomerResource\RelationManagers;
8
+use App\Models\Banking\Account;
9
+use App\Models\Contact;
10
+use Filament\Forms;
11
+use Filament\Resources\Form;
12
+use Filament\Resources\Resource;
13
+use Filament\Resources\Table;
14
+use Filament\Tables;
15
+use Illuminate\Database\Eloquent\Builder;
16
+use Illuminate\Database\Eloquent\SoftDeletingScope;
17
+use Illuminate\Support\Facades\Auth;
18
+use Illuminate\Support\Facades\DB;
19
+
20
+class CustomerResource extends Resource
21
+{
22
+    protected static ?string $model = Contact::class;
23
+
24
+    protected static ?string $navigationIcon = 'heroicon-o-collection';
25
+
26
+    protected static ?string $navigationGroup = 'Sales';
27
+
28
+    protected static ?string $navigationLabel = 'Customers';
29
+
30
+    protected static ?string $modelLabel = 'customer';
31
+
32
+    public static function getEloquentQuery(): Builder
33
+    {
34
+        return parent::getEloquentQuery()
35
+            ->where('type', 'customer')
36
+            ->where('company_id', Auth::user()->currentCompany->id);
37
+    }
38
+
39
+    public static function form(Form $form): Form
40
+    {
41
+        return $form
42
+            ->schema([
43
+                Forms\Components\Section::make('General')
44
+                    ->schema([
45
+                        Forms\Components\Radio::make('entity')
46
+                            ->options([
47
+                                'company' => 'Company',
48
+                                'individual' => 'Individual',
49
+                            ])
50
+                            ->inline()
51
+                            ->default('company')
52
+                            ->required()
53
+                            ->columnSpanFull(),
54
+                        Forms\Components\TextInput::make('name')
55
+                            ->maxLength(100)
56
+                            ->placeholder('Enter Name')
57
+                            ->required(),
58
+                        Forms\Components\TextInput::make('email')
59
+                            ->email()
60
+                            ->placeholder('Enter Email')
61
+                            ->nullable(),
62
+                        Forms\Components\TextInput::make('phone')
63
+                            ->label('Phone')
64
+                            ->tel()
65
+                            ->placeholder('Enter Phone')
66
+                            ->maxLength(20),
67
+                        Forms\Components\TextInput::make('website')
68
+                            ->maxLength(100)
69
+                            ->prefix('https://')
70
+                            ->placeholder('Enter Website')
71
+                            ->nullable(),
72
+                        Forms\Components\TextInput::make('reference')
73
+                            ->maxLength(100)
74
+                            ->placeholder('Enter Reference')
75
+                            ->nullable(),
76
+                    ])->columns(2),
77
+                Forms\Components\Section::make('Billing')
78
+                    ->schema([
79
+                        Forms\Components\TextInput::make('tax_number')
80
+                            ->maxLength(100)
81
+                            ->placeholder('Enter Tax Number')
82
+                            ->nullable(),
83
+                        Forms\Components\Select::make('currency_code')
84
+                            ->label('Currency')
85
+                            ->relationship('currency', 'name', static fn (Builder $query) => $query->where('company_id', Auth::user()->currentCompany->id))
86
+                            ->preload()
87
+                            ->default(Account::getDefaultCurrencyCode())
88
+                            ->searchable()
89
+                            ->reactive()
90
+                            ->required()
91
+                            ->createOptionForm([
92
+                                Forms\Components\Select::make('currency.code')
93
+                                    ->label('Code')
94
+                                    ->searchable()
95
+                                    ->options(Account::getCurrencyCodes())
96
+                                    ->reactive()
97
+                                    ->afterStateUpdated(static function (callable $set, $state) {
98
+                                        $code = $state;
99
+                                        $name = config("money.{$code}.name");
100
+                                        $set('currency.name', $name);
101
+                                    })
102
+                                    ->required(),
103
+                                Forms\Components\TextInput::make('currency.name')
104
+                                    ->label('Name')
105
+                                    ->maxLength(100)
106
+                                    ->required(),
107
+                                Forms\Components\TextInput::make('currency.rate')
108
+                                    ->label('Rate')
109
+                                    ->numeric()
110
+                                    ->mask(static fn (Forms\Components\TextInput\Mask $mask) => $mask
111
+                                        ->numeric()
112
+                                        ->decimalPlaces(4)
113
+                                        ->signed(false)
114
+                                        ->padFractionalZeros(false)
115
+                                        ->normalizeZeros(false)
116
+                                        ->minValue(0.0001)
117
+                                        ->maxValue(999999.9999)
118
+                                        ->lazyPlaceholder(false))
119
+                                    ->required(),
120
+                            ])->createOptionAction(static function (Forms\Components\Actions\Action $action) {
121
+                                return $action
122
+                                    ->label('Add Currency')
123
+                                    ->modalHeading('Add Currency')
124
+                                    ->modalButton('Add')
125
+                                    ->action(static function (array $data) {
126
+                                        return DB::transaction(static function () use ($data) {
127
+                                            $code = $data['currency']['code'];
128
+                                            $name = $data['currency']['name'];
129
+                                            $rate = $data['currency']['rate'];
130
+
131
+                                            return (new CreateCurrencyFromAccount())->create($code, $name, $rate);
132
+                                        });
133
+                                    });
134
+                            }),
135
+                ])->columns(2),
136
+                Forms\Components\Section::make('Address')
137
+                    ->schema([
138
+                        Forms\Components\Textarea::make('address')
139
+                            ->label('Address')
140
+                            ->maxLength(100)
141
+                            ->placeholder('Enter Address')
142
+                            ->columnSpanFull()
143
+                            ->nullable(),
144
+                        Forms\Components\TextInput::make('city')
145
+                            ->label('Town/City')
146
+                            ->maxLength(100)
147
+                            ->placeholder('Enter Town/City')
148
+                            ->nullable(),
149
+                        Forms\Components\TextInput::make('zip_code')
150
+                            ->label('Postal/Zip Code')
151
+                            ->maxLength(100)
152
+                            ->placeholder('Enter Postal/Zip Code')
153
+                            ->nullable(),
154
+                        Forms\Components\TextInput::make('state')
155
+                            ->label('Province/State')
156
+                            ->maxLength(100)
157
+                            ->placeholder('Enter Province/State')
158
+                            ->required(),
159
+                        Forms\Components\TextInput::make('country')
160
+                            ->label('Country')
161
+                            ->maxLength(100)
162
+                            ->placeholder('Enter Country')
163
+                            ->required(),
164
+                    ])->columns(2),
165
+            ]);
166
+    }
167
+
168
+    public static function table(Table $table): Table
169
+    {
170
+        return $table
171
+            ->columns([
172
+                Tables\Columns\TextColumn::make('name')
173
+                    ->weight('semibold')
174
+                    ->searchable()
175
+                    ->sortable(),
176
+                Tables\Columns\TextColumn::make('tax_number')
177
+                    ->searchable()
178
+                    ->sortable(),
179
+                Tables\Columns\TextColumn::make('email')
180
+                    ->searchable(),
181
+                Tables\Columns\TextColumn::make('phone')
182
+                    ->searchable(),
183
+                Tables\Columns\TextColumn::make('country')
184
+                    ->searchable()
185
+                    ->sortable(),
186
+                Tables\Columns\TextColumn::make('currency.name')
187
+                    ->searchable()
188
+                    ->sortable(),
189
+            ])
190
+            ->filters([
191
+                //
192
+            ])
193
+            ->actions([
194
+                Tables\Actions\EditAction::make(),
195
+            ])
196
+            ->bulkActions([
197
+                Tables\Actions\DeleteBulkAction::make(),
198
+            ]);
199
+    }
200
+    
201
+    public static function getRelations(): array
202
+    {
203
+        return [
204
+            //
205
+        ];
206
+    }
207
+    
208
+    public static function getPages(): array
209
+    {
210
+        return [
211
+            'index' => Pages\ListCustomers::route('/'),
212
+            'create' => Pages\CreateCustomer::route('/create'),
213
+            'edit' => Pages\EditCustomer::route('/{record}/edit'),
214
+        ];
215
+    }    
216
+}

+ 25
- 0
app/Filament/Resources/CustomerResource/Pages/CreateCustomer.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources\CustomerResource\Pages;
4
+
5
+use App\Filament\Resources\CustomerResource;
6
+use Filament\Pages\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateCustomer extends CreateRecord
10
+{
11
+    protected static string $resource = CustomerResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        return $this->getResource()::getUrl('index');
16
+    }
17
+
18
+    protected function mutateFormDataBeforeCreate(array $data): array
19
+    {
20
+        $data['company_id'] = auth()->user()->currentCompany->id;
21
+        $data['type'] = 'customer';
22
+        $data['created_by'] = auth()->id();
23
+        return $data;
24
+    }
25
+}

+ 19
- 0
app/Filament/Resources/CustomerResource/Pages/EditCustomer.php 查看文件

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

+ 19
- 0
app/Filament/Resources/CustomerResource/Pages/ListCustomers.php 查看文件

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

+ 76
- 0
app/Filament/Resources/InvoiceResource.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources;
4
+
5
+use App\Filament\Resources\InvoiceResource\Pages;
6
+use App\Filament\Resources\InvoiceResource\RelationManagers;
7
+use App\Models\Document\Document;
8
+use Filament\Forms;
9
+use Filament\Resources\Form;
10
+use Filament\Resources\Resource;
11
+use Filament\Resources\Table;
12
+use Filament\Tables;
13
+use Illuminate\Database\Eloquent\Builder;
14
+use Illuminate\Database\Eloquent\SoftDeletingScope;
15
+use Illuminate\Support\Facades\Auth;
16
+
17
+class InvoiceResource extends Resource
18
+{
19
+    protected static ?string $model = Document::class;
20
+
21
+    protected static ?string $navigationIcon = 'heroicon-o-collection';
22
+
23
+    protected static ?string $navigationGroup = 'Sales';
24
+
25
+    protected static ?string $navigationLabel = 'Invoices';
26
+
27
+    protected static ?string $modelLabel = 'invoice';
28
+
29
+    public static function getEloquentQuery(): Builder
30
+    {
31
+        return parent::getEloquentQuery()
32
+            ->where('type', 'invoice')
33
+            ->where('company_id', Auth::user()->currentCompany->id);
34
+    }
35
+
36
+    public static function form(Form $form): Form
37
+    {
38
+        return $form
39
+            ->schema([
40
+                //
41
+            ]);
42
+    }
43
+
44
+    public static function table(Table $table): Table
45
+    {
46
+        return $table
47
+            ->columns([
48
+                //
49
+            ])
50
+            ->filters([
51
+                //
52
+            ])
53
+            ->actions([
54
+                Tables\Actions\EditAction::make(),
55
+            ])
56
+            ->bulkActions([
57
+                Tables\Actions\DeleteBulkAction::make(),
58
+            ]);
59
+    }
60
+    
61
+    public static function getRelations(): array
62
+    {
63
+        return [
64
+            //
65
+        ];
66
+    }
67
+    
68
+    public static function getPages(): array
69
+    {
70
+        return [
71
+            'index' => Pages\ListInvoices::route('/'),
72
+            'create' => Pages\CreateInvoice::route('/create'),
73
+            'edit' => Pages\EditInvoice::route('/{record}/edit'),
74
+        ];
75
+    }    
76
+}

+ 12
- 0
app/Filament/Resources/InvoiceResource/Pages/CreateInvoice.php 查看文件

1
+<?php
2
+
3
+namespace App\Filament\Resources\InvoiceResource\Pages;
4
+
5
+use App\Filament\Resources\InvoiceResource;
6
+use Filament\Pages\Actions;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateInvoice extends CreateRecord
10
+{
11
+    protected static string $resource = InvoiceResource::class;
12
+}

+ 19
- 0
app/Filament/Resources/InvoiceResource/Pages/EditInvoice.php 查看文件

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

+ 19
- 0
app/Filament/Resources/InvoiceResource/Pages/ListInvoices.php 查看文件

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

+ 81
- 0
app/Models/Banking/Account.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Banking;
4
+
5
+use App\Models\Setting\Currency;
6
+use Database\Factories\AccountFactory;
7
+use Illuminate\Database\Eloquent\Factories\Factory;
8
+use Illuminate\Database\Eloquent\Factories\HasFactory;
9
+use Illuminate\Database\Eloquent\Model;
10
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
11
+use Illuminate\Support\Facades\Auth;
12
+use Illuminate\Support\Facades\Config;
13
+use Wallo\FilamentCompanies\FilamentCompanies;
14
+
15
+class Account extends Model
16
+{
17
+    use HasFactory;
18
+
19
+    protected $table = 'accounts';
20
+
21
+    protected $fillable = [
22
+        'type',
23
+        'name',
24
+        'number',
25
+        'currency_code',
26
+        'opening_balance',
27
+        'enabled',
28
+        'bank_name',
29
+        'bank_phone',
30
+        'bank_address',
31
+        'company_id',
32
+    ];
33
+
34
+    protected $casts = [
35
+        'enabled' => 'boolean',
36
+    ];
37
+
38
+    public function company(): BelongsTo
39
+    {
40
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
41
+    }
42
+
43
+    public function owner(): BelongsTo
44
+    {
45
+        return $this->company->owner;
46
+    }
47
+
48
+    public function currency(): BelongsTo
49
+    {
50
+        return $this->belongsTo(Currency::class, 'currency_code', 'code');
51
+    }
52
+
53
+    public static function getAccountTypes(): array
54
+    {
55
+        return [
56
+            'bank' => 'Bank',
57
+            'card' => 'Credit Card',
58
+        ];
59
+    }
60
+
61
+    public static function getCurrencyCodes(): array
62
+    {
63
+        $codes = array_keys(Config::get('money'));
64
+
65
+        return array_combine($codes, $codes);
66
+    }
67
+
68
+    public static function getDefaultCurrencyCode(): ?string
69
+    {
70
+        $defaultCurrency = Currency::where('enabled', true)
71
+            ->where('company_id', Auth::user()->currentCompany->id)
72
+            ->first();
73
+
74
+        return $defaultCurrency?->code;
75
+    }
76
+
77
+    protected static function newFactory(): Factory
78
+    {
79
+        return AccountFactory::new();
80
+    }
81
+}

+ 123
- 0
app/Models/Company.php 查看文件

2
 
2
 
3
 namespace App\Models;
3
 namespace App\Models;
4
 
4
 
5
+use App\Models\Banking\Account;
6
+use App\Models\Document\Document;
7
+use App\Models\Document\DocumentItem;
8
+use App\Models\Document\DocumentTotal;
9
+use App\Models\Setting\Currency;
10
+use App\Models\Setting\Category;
11
+use App\Models\Setting\Discount;
12
+use App\Models\Setting\Tax;
5
 use Illuminate\Database\Eloquent\Factories\HasFactory;
13
 use Illuminate\Database\Eloquent\Factories\HasFactory;
14
+use Illuminate\Database\Eloquent\Relations\HasMany;
6
 use Wallo\FilamentCompanies\Company as FilamentCompaniesCompany;
15
 use Wallo\FilamentCompanies\Company as FilamentCompaniesCompany;
7
 use Wallo\FilamentCompanies\Events\CompanyCreated;
16
 use Wallo\FilamentCompanies\Events\CompanyCreated;
8
 use Wallo\FilamentCompanies\Events\CompanyDeleted;
17
 use Wallo\FilamentCompanies\Events\CompanyDeleted;
41
         'updated' => CompanyUpdated::class,
50
         'updated' => CompanyUpdated::class,
42
         'deleted' => CompanyDeleted::class,
51
         'deleted' => CompanyDeleted::class,
43
     ];
52
     ];
53
+
54
+    public function accounts(): HasMany
55
+    {
56
+        return $this->hasMany(Account::class);
57
+    }
58
+
59
+    public function currencies(): HasMany
60
+    {
61
+        return $this->hasMany(Currency::class);
62
+    }
63
+
64
+    public function categories(): HasMany
65
+    {
66
+        return $this->hasMany(Category::class);
67
+    }
68
+
69
+    public function taxes(): HasMany
70
+    {
71
+        return $this->hasMany(Tax::class);
72
+    }
73
+
74
+    public function discounts(): HasMany
75
+    {
76
+        return $this->hasMany(Discount::class);
77
+    }
78
+
79
+    public function contacts(): HasMany
80
+    {
81
+        return $this->hasMany(Contact::class);
82
+    }
83
+
84
+    public function customers(): HasMany
85
+    {
86
+        return $this->contacts()->where('type', 'customer');
87
+    }
88
+
89
+    public function company_customers(): HasMany
90
+    {
91
+        return $this->contacts()->where('type', 'customer')
92
+            ->where('entity', 'company');
93
+    }
94
+
95
+    public function individual_customers(): HasMany
96
+    {
97
+        return $this->contacts()->where('type', 'customer')
98
+            ->where('entity', 'individual');
99
+    }
100
+
101
+    public function vendors(): HasMany
102
+    {
103
+        return $this->contacts()->where('type', 'vendor');
104
+    }
105
+
106
+    public function company_vendors(): HasMany
107
+    {
108
+        return $this->contacts()->where('type', 'vendor')
109
+            ->where('entity', 'company');
110
+    }
111
+
112
+    public function individual_vendors(): HasMany
113
+    {
114
+        return $this->contacts()->where('type', 'vendor')
115
+            ->where('entity', 'individual');
116
+    }
117
+
118
+    public function items(): HasMany
119
+    {
120
+        return $this->hasMany(Item::class);
121
+    }
122
+
123
+    public function documents(): HasMany
124
+    {
125
+        return $this->hasMany(Document::class);
126
+    }
127
+
128
+    public function document_items(): HasMany
129
+    {
130
+        return $this->hasMany(DocumentItem::class);
131
+    }
132
+
133
+    public function document_totals(): HasMany
134
+    {
135
+        return $this->hasMany(DocumentTotal::class);
136
+    }
137
+
138
+    public function bills(): HasMany
139
+    {
140
+        return $this->documents()->where('type', 'bill');
141
+    }
142
+
143
+    public function invoices(): HasMany
144
+    {
145
+        return $this->documents()->where('type', 'invoice');
146
+    }
147
+
148
+    public function bill_items(): HasMany
149
+    {
150
+        return $this->document_items()->where('type', 'bill');
151
+    }
152
+
153
+    public function bill_totals(): HasMany
154
+    {
155
+        return $this->document_totals()->where('type', 'bill');
156
+    }
157
+
158
+    public function invoice_items(): HasMany
159
+    {
160
+        return $this->document_items()->where('type', 'invoice');
161
+    }
162
+
163
+    public function invoice_totals(): HasMany
164
+    {
165
+        return $this->document_totals()->where('type', 'invoice');
166
+    }
44
 }
167
 }

+ 96
- 0
app/Models/Contact.php 查看文件

1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use App\Models\Document\Document;
6
+use App\Models\Setting\Currency;
7
+use Illuminate\Database\Eloquent\Factories\HasFactory;
8
+use Illuminate\Database\Eloquent\Model;
9
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
10
+use Illuminate\Database\Eloquent\Relations\HasMany;
11
+use Wallo\FilamentCompanies\FilamentCompanies;
12
+
13
+class Contact extends Model
14
+{
15
+    use HasFactory;
16
+
17
+    protected $table = 'contacts';
18
+
19
+    protected $fillable = [
20
+        'company_id',
21
+        'entity',
22
+        'type',
23
+        'name',
24
+        'email',
25
+        'tax_number',
26
+        'phone',
27
+        'address',
28
+        'city',
29
+        'zip_code',
30
+        'state',
31
+        'country',
32
+        'website',
33
+        'currency_code',
34
+        'reference',
35
+        'created_by',
36
+    ];
37
+
38
+    protected $casts = [
39
+        'enabled' => 'boolean',
40
+    ];
41
+
42
+    public function company(): BelongsTo
43
+    {
44
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
45
+    }
46
+
47
+    public function createdBy(): BelongsTo
48
+    {
49
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
50
+    }
51
+
52
+    public function currency(): BelongsTo
53
+    {
54
+        return $this->belongsTo(Currency::class, 'currency_code', 'code');
55
+    }
56
+
57
+    public function documents(): HasMany
58
+    {
59
+        return $this->hasMany(Document::class);
60
+    }
61
+
62
+    public function bills(): HasMany
63
+    {
64
+        return $this->documents()->where('type', 'bill');
65
+    }
66
+
67
+    public function invoices(): HasMany
68
+    {
69
+        return $this->documents()->where('type', 'invoice');
70
+    }
71
+
72
+    public function scopeVendor($query)
73
+    {
74
+        return $query->where('type', 'vendor');
75
+    }
76
+
77
+    public function scopeCustomer($query)
78
+    {
79
+        return $query->where('type', 'customer');
80
+    }
81
+
82
+    public function scopeEmployee($query)
83
+    {
84
+        return $query->where('type', 'employee');
85
+    }
86
+
87
+    public function scopeCompany($query)
88
+    {
89
+        return $query->where('entity', 'company');
90
+    }
91
+
92
+    public function scopeIndividual($query)
93
+    {
94
+        return $query->where('entity', 'individual');
95
+    }
96
+}

+ 100
- 0
app/Models/Document/Document.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Document;
4
+
5
+use App\Models\Contact;
6
+use App\Models\Setting\Category;
7
+use App\Models\Setting\Currency;
8
+use App\Models\Setting\Discount;
9
+use App\Models\Setting\Tax;
10
+use Database\Factories\DocumentFactory;
11
+use Illuminate\Database\Eloquent\Factories\Factory;
12
+use Illuminate\Database\Eloquent\Factories\HasFactory;
13
+use Illuminate\Database\Eloquent\Model;
14
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
15
+use Illuminate\Database\Eloquent\Relations\HasMany;
16
+use Illuminate\Database\Eloquent\Relations\HasOne;
17
+use Wallo\FilamentCompanies\FilamentCompanies;
18
+
19
+class Document extends Model
20
+{
21
+    use HasFactory;
22
+
23
+    protected $table = 'documents';
24
+
25
+    protected $fillable = [
26
+        'company_id',
27
+        'type',
28
+        'document_number',
29
+        'order_number',
30
+        'status',
31
+        'document_date',
32
+        'due_date',
33
+        'paid_date',
34
+        'amount',
35
+        'tax_id',
36
+        'discount_id',
37
+        'reference',
38
+        'currency_code',
39
+        'category_id',
40
+        'contact_id',
41
+        'notes',
42
+        'created_by',
43
+    ];
44
+
45
+    protected $casts = [
46
+        'document_date' => 'datetime',
47
+        'due_date' => 'datetime',
48
+        'paid_date' => 'datetime',
49
+    ];
50
+
51
+    public function company(): BelongsTo
52
+    {
53
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
54
+    }
55
+
56
+    public function createdBy(): BelongsTo
57
+    {
58
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
59
+    }
60
+
61
+    public function tax(): BelongsTo
62
+    {
63
+        return $this->belongsTo(Tax::class);
64
+    }
65
+
66
+    public function discount(): BelongsTo
67
+    {
68
+        return $this->belongsTo(Discount::class);
69
+    }
70
+
71
+    public function currency(): BelongsTo
72
+    {
73
+        return $this->belongsTo(Currency::class, 'currency_code', 'code');
74
+    }
75
+
76
+    public function category(): BelongsTo
77
+    {
78
+        return $this->belongsTo(Category::class);
79
+    }
80
+
81
+    public function contact(): BelongsTo
82
+    {
83
+        return $this->belongsTo(Contact::class);
84
+    }
85
+
86
+    public function items(): HasMany
87
+    {
88
+        return $this->hasMany(DocumentItem::class);
89
+    }
90
+
91
+    public function total(): HasOne
92
+    {
93
+        return $this->hasOne(DocumentTotal::class);
94
+    }
95
+
96
+    protected static function newFactory(): Factory
97
+    {
98
+        return DocumentFactory::new();
99
+    }
100
+}

+ 97
- 0
app/Models/Document/DocumentItem.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Document;
4
+
5
+use App\Models\Item;
6
+use App\Models\Setting\Discount;
7
+use App\Models\Setting\Tax;
8
+use Database\Factories\DocumentItemFactory;
9
+use Illuminate\Database\Eloquent\Factories\Factory;
10
+use Illuminate\Database\Eloquent\Factories\HasFactory;
11
+use Illuminate\Database\Eloquent\Model;
12
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
13
+use Wallo\FilamentCompanies\FilamentCompanies;
14
+
15
+class DocumentItem extends Model
16
+{
17
+    use HasFactory;
18
+
19
+    protected $table = 'document_items';
20
+
21
+    protected $fillable = [
22
+        'company_id',
23
+        'document_id',
24
+        'item_id',
25
+        'type',
26
+        'name',
27
+        'description',
28
+        'quantity',
29
+        'price',
30
+        'tax_id',
31
+        'discount_id',
32
+        'total',
33
+        'created_by',
34
+    ];
35
+
36
+    protected $casts = [
37
+        'quantity' => 'decimal:2',
38
+        'price' => 'decimal:4',
39
+        'total' => 'decimal:4',
40
+    ];
41
+
42
+    public function company(): BelongsTo
43
+    {
44
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
45
+    }
46
+
47
+    public function createdBy(): BelongsTo
48
+    {
49
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
50
+    }
51
+
52
+    public function document(): BelongsTo
53
+    {
54
+        return $this->belongsTo(Document::class);
55
+    }
56
+
57
+    public function item(): BelongsTo
58
+    {
59
+        return $this->belongsTo(Item::class);
60
+    }
61
+
62
+    public function tax(): BelongsTo
63
+    {
64
+        return $this->belongsTo(Tax::class);
65
+    }
66
+
67
+    public function discount(): BelongsTo
68
+    {
69
+        return $this->belongsTo(Discount::class);
70
+    }
71
+
72
+    public function scopeBill($query)
73
+    {
74
+        return $query->where('type', 'bill');
75
+    }
76
+
77
+    public function scopeInvoice($query)
78
+    {
79
+        return $query->where('type', 'invoice');
80
+    }
81
+
82
+    /**
83
+     * Calculate and return the net price (price - discount + tax)
84
+     */
85
+    public function getNetPriceAttribute()
86
+    {
87
+        $discountAmount = $this->discount ? ($this->price * $this->discount->rate / 100) : 0;
88
+        $taxAmount = $this->tax ? ($this->price * $this->tax->rate / 100) : 0;
89
+
90
+        return $this->price - $discountAmount + $taxAmount;
91
+    }
92
+
93
+    protected static function newFactory(): Factory
94
+    {
95
+        return DocumentItemFactory::new();
96
+    }
97
+}

+ 60
- 0
app/Models/Document/DocumentTotal.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Document;
4
+
5
+use Database\Factories\DocumentTotalFactory;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+use Illuminate\Database\Eloquent\Factories\HasFactory;
8
+use Illuminate\Database\Eloquent\Model;
9
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
10
+use Wallo\FilamentCompanies\FilamentCompanies;
11
+
12
+class DocumentTotal extends Model
13
+{
14
+    use HasFactory;
15
+
16
+    protected $table = 'document_totals';
17
+
18
+    protected $fillable = [
19
+        'company_id',
20
+        'document_id',
21
+        'type',
22
+        'code',
23
+        'name',
24
+        'subtotal',
25
+        'discount',
26
+        'tax',
27
+        'total',
28
+        'created_by',
29
+    ];
30
+
31
+    public function company(): BelongsTo
32
+    {
33
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
34
+    }
35
+
36
+    public function createdBy(): BelongsTo
37
+    {
38
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
39
+    }
40
+
41
+    public function document(): BelongsTo
42
+    {
43
+        return $this->belongsTo(Document::class);
44
+    }
45
+
46
+    public function scopeInvoice($query)
47
+    {
48
+        return $query->where('type', 'invoice');
49
+    }
50
+
51
+    public function scopeBill($query)
52
+    {
53
+        return $query->where('type', 'bill');
54
+    }
55
+
56
+    protected static function newFactory(): Factory
57
+    {
58
+        return DocumentTotalFactory::new();
59
+    }
60
+}

+ 82
- 0
app/Models/Item.php 查看文件

1
+<?php
2
+
3
+namespace App\Models;
4
+
5
+use App\Models\Document\DocumentItem;
6
+use App\Models\Setting\Category;
7
+use App\Models\Setting\Discount;
8
+use App\Models\Setting\Tax;
9
+use Illuminate\Database\Eloquent\Factories\HasFactory;
10
+use Illuminate\Database\Eloquent\Model;
11
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
12
+use Illuminate\Database\Eloquent\Relations\HasMany;
13
+use Wallo\FilamentCompanies\FilamentCompanies;
14
+
15
+class Item extends Model
16
+{
17
+    use HasFactory;
18
+
19
+    protected $table = 'items';
20
+
21
+    protected $fillable = [
22
+        'company_id',
23
+        'type',
24
+        'name',
25
+        'sku',
26
+        'description',
27
+        'sale_price',
28
+        'purchase_price',
29
+        'quantity',
30
+        'category_id',
31
+        'tax_id',
32
+        'discount_id',
33
+        'enabled',
34
+        'created_by',
35
+    ];
36
+
37
+    protected $casts = [
38
+        'enabled' => 'boolean',
39
+    ];
40
+
41
+    public function company(): BelongsTo
42
+    {
43
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
44
+    }
45
+
46
+    public function createdBy(): BelongsTo
47
+    {
48
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
49
+    }
50
+
51
+    public function category(): BelongsTo
52
+    {
53
+        return $this->belongsTo(Category::class, 'category_id')->withDefault([
54
+            'name' => 'General',
55
+        ]);
56
+    }
57
+
58
+    public function tax(): BelongsTo
59
+    {
60
+        return $this->belongsTo(Tax::class, 'tax_id');
61
+    }
62
+
63
+    public function discount(): BelongsTo
64
+    {
65
+        return $this->belongsTo(Discount::class, 'discount_id');
66
+    }
67
+
68
+    public function document_items(): HasMany
69
+    {
70
+        return $this->hasMany(DocumentItem::class);
71
+    }
72
+
73
+    public function bill_items(): HasMany
74
+    {
75
+        return $this->document_items()->where('type', 'bill');
76
+    }
77
+
78
+    public function invoice_items(): HasMany
79
+    {
80
+        return $this->document_items()->where('type', 'invoice');
81
+    }
82
+}

+ 68
- 0
app/Models/Setting/Category.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Setting;
4
+
5
+use App\Models\Document\Document;
6
+use App\Models\Item;
7
+use Database\Factories\CategoryFactory;
8
+use Illuminate\Database\Eloquent\Factories\Factory;
9
+use Illuminate\Database\Eloquent\Factories\HasFactory;
10
+use Illuminate\Database\Eloquent\Model;
11
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
12
+use Illuminate\Database\Eloquent\Relations\HasMany;
13
+use Wallo\FilamentCompanies\FilamentCompanies;
14
+
15
+class Category extends Model
16
+{
17
+    use HasFactory;
18
+
19
+    protected $table = 'categories';
20
+
21
+    protected $fillable = [
22
+        'company_id',
23
+        'name',
24
+        'type',
25
+        'color',
26
+        'enabled',
27
+        'created_by',
28
+    ];
29
+
30
+    protected $casts = [
31
+        'enabled' => 'boolean',
32
+    ];
33
+
34
+    public function company(): BelongsTo
35
+    {
36
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
37
+    }
38
+
39
+    public function createdBy(): BelongsTo
40
+    {
41
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
42
+    }
43
+
44
+    public function items(): HasMany
45
+    {
46
+        return $this->hasMany(Item::class);
47
+    }
48
+
49
+    public function documents(): HasMany
50
+    {
51
+        return $this->hasMany(Document::class);
52
+    }
53
+
54
+    public function bills(): HasMany
55
+    {
56
+        return $this->documents()->where('type', 'bill');
57
+    }
58
+
59
+    public function invoices(): HasMany
60
+    {
61
+        return $this->documents()->where('type', 'invoice');
62
+    }
63
+
64
+    protected static function newFactory(): Factory
65
+    {
66
+        return CategoryFactory::new();
67
+    }
68
+}

+ 68
- 0
app/Models/Setting/Currency.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Setting;
4
+
5
+use App\Models\Banking\Account;
6
+use Database\Factories\CurrencyFactory;
7
+use Illuminate\Database\Eloquent\Factories\Factory;
8
+use Illuminate\Database\Eloquent\Factories\HasFactory;
9
+use Illuminate\Database\Eloquent\Model;
10
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
11
+use Illuminate\Database\Eloquent\Relations\HasMany;
12
+use Illuminate\Support\Facades\Auth;
13
+use Illuminate\Support\Facades\Config;
14
+use Wallo\FilamentCompanies\FilamentCompanies;
15
+
16
+class Currency extends Model
17
+{
18
+    use HasFactory;
19
+
20
+    protected $table = 'currencies';
21
+
22
+    protected $fillable = [
23
+        'name',
24
+        'code',
25
+        'rate',
26
+        'precision',
27
+        'symbol',
28
+        'symbol_first',
29
+        'decimal_mark',
30
+        'thousands_separator',
31
+        'enabled',
32
+        'company_id',
33
+    ];
34
+
35
+    protected $casts = [
36
+        'enabled' => 'boolean',
37
+        'symbol_first' => 'boolean',
38
+    ];
39
+
40
+    public function accounts(): HasMany
41
+    {
42
+        return $this->hasMany(Account::class, 'currency_code', 'code');
43
+    }
44
+
45
+    public function company(): BelongsTo
46
+    {
47
+        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
48
+    }
49
+
50
+    public static function getCurrencyCodes(): array
51
+    {
52
+        $allCodes = array_keys(Config::get('money'));
53
+
54
+        $storedCodes = static::query()
55
+            ->where('company_id', Auth::user()->currentCompany->id)
56
+            ->pluck('code')
57
+            ->toArray();
58
+
59
+        $codes = array_diff($allCodes, $storedCodes);
60
+
61
+        return array_combine($codes, $codes);
62
+    }
63
+
64
+    protected static function newFactory(): Factory
65
+    {
66
+        return CurrencyFactory::new();
67
+    }
68
+}

+ 65
- 0
app/Models/Setting/Discount.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Setting;
4
+
5
+use App\Models\Document\DocumentItem;
6
+use App\Models\Item;
7
+use App\Models\User;
8
+use Database\Factories\DiscountFactory;
9
+use Illuminate\Database\Eloquent\Factories\Factory;
10
+use Illuminate\Database\Eloquent\Factories\HasFactory;
11
+use Illuminate\Database\Eloquent\Model;
12
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
13
+use Illuminate\Database\Eloquent\Relations\HasMany;
14
+
15
+class Discount extends Model
16
+{
17
+    use HasFactory;
18
+
19
+    protected $table = 'discounts';
20
+
21
+    protected $fillable = [
22
+        'name',
23
+        'description',
24
+        'rate',
25
+        'computation',
26
+        'type',
27
+        'scope',
28
+        'enabled',
29
+        'created_by',
30
+    ];
31
+
32
+    protected $casts = [
33
+        'enabled' => 'boolean',
34
+    ];
35
+
36
+    public function createdBy(): BelongsTo
37
+    {
38
+        return $this->belongsTo(User::class, 'created_by');
39
+    }
40
+
41
+    public function items(): HasMany
42
+    {
43
+        return $this->hasMany(Item::class);
44
+    }
45
+
46
+    public function document_items(): HasMany
47
+    {
48
+        return $this->hasMany(DocumentItem::class);
49
+    }
50
+
51
+    public function bill_items(): HasMany
52
+    {
53
+        return $this->document_items()->where('type', 'bill');
54
+    }
55
+
56
+    public function invoice_items(): HasMany
57
+    {
58
+        return $this->document_items()->where('type', 'invoice');
59
+    }
60
+
61
+    protected static function newFactory(): Factory
62
+    {
63
+        return DiscountFactory::new();
64
+    }
65
+}

+ 72
- 0
app/Models/Setting/Tax.php 查看文件

1
+<?php
2
+
3
+namespace App\Models\Setting;
4
+
5
+use App\Models\Company;
6
+use App\Models\Document\DocumentItem;
7
+use App\Models\Item;
8
+use App\Models\User;
9
+use Database\Factories\TaxFactory;
10
+use Illuminate\Database\Eloquent\Factories\Factory;
11
+use Illuminate\Database\Eloquent\Factories\HasFactory;
12
+use Illuminate\Database\Eloquent\Model;
13
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
14
+use Illuminate\Database\Eloquent\Relations\HasMany;
15
+
16
+class Tax extends Model
17
+{
18
+    use HasFactory;
19
+
20
+    protected $table = 'taxes';
21
+
22
+    protected $fillable = [
23
+        'company_id',
24
+        'name',
25
+        'description',
26
+        'rate',
27
+        'computation',
28
+        'type',
29
+        'scope',
30
+        'enabled',
31
+        'created_by',
32
+    ];
33
+
34
+    protected $casts = [
35
+        'enabled' => 'boolean',
36
+    ];
37
+
38
+    public function company(): BelongsTo
39
+    {
40
+        return $this->belongsTo(Company::class, 'company_id');
41
+    }
42
+
43
+    public function createdBy(): BelongsTo
44
+    {
45
+        return $this->belongsTo(User::class, 'created_by');
46
+    }
47
+
48
+    public function items(): HasMany
49
+    {
50
+        return $this->hasMany(Item::class);
51
+    }
52
+
53
+    public function document_items(): HasMany
54
+    {
55
+        return $this->hasMany(DocumentItem::class);
56
+    }
57
+
58
+    public function bill_items(): HasMany
59
+    {
60
+        return $this->document_items()->where('type', 'bill');
61
+    }
62
+
63
+    public function invoice_items(): HasMany
64
+    {
65
+        return $this->document_items()->where('type', 'invoice');
66
+    }
67
+
68
+    protected static function newFactory(): Factory
69
+    {
70
+        return TaxFactory::new();
71
+    }
72
+}

+ 66
- 0
app/Policies/AccountPolicy.php 查看文件

1
+<?php
2
+
3
+namespace App\Policies;
4
+
5
+use App\Models\Banking\Account;
6
+use App\Models\User;
7
+use Illuminate\Auth\Access\Response;
8
+
9
+class AccountPolicy
10
+{
11
+    /**
12
+     * Determine whether the user can view any models.
13
+     */
14
+    public function viewAny(User $user): bool
15
+    {
16
+        return true;
17
+    }
18
+
19
+    /**
20
+     * Determine whether the user can view the model.
21
+     */
22
+    public function view(User $user, Account $account): bool
23
+    {
24
+        return $user->belongsToCompany($account->company);
25
+    }
26
+
27
+    /**
28
+     * Determine whether the user can create models.
29
+     */
30
+    public function create(User $user): bool
31
+    {
32
+        return true;
33
+    }
34
+
35
+    /**
36
+     * Determine whether the user can update the model.
37
+     */
38
+    public function update(User $user, Account $account): bool
39
+    {
40
+        return $user->ownsCompany($account->company);
41
+    }
42
+
43
+    /**
44
+     * Determine whether the user can delete the model.
45
+     */
46
+    public function delete(User $user, Account $account): bool
47
+    {
48
+        return $user->ownsCompany($account->company);
49
+    }
50
+
51
+    /**
52
+     * Determine whether the user can restore the model.
53
+     */
54
+    public function restore(User $user, Account $account): bool
55
+    {
56
+        return $user->ownsCompany($account->company);
57
+    }
58
+
59
+    /**
60
+     * Determine whether the user can permanently delete the model.
61
+     */
62
+    public function forceDelete(User $user, Account $account): bool
63
+    {
64
+        return $user->ownsCompany($account->company);
65
+    }
66
+}

+ 77
- 80
composer.lock 查看文件

934
         },
934
         },
935
         {
935
         {
936
             "name": "filament/filament",
936
             "name": "filament/filament",
937
-            "version": "v2.17.38",
937
+            "version": "v2.17.43",
938
             "source": {
938
             "source": {
939
                 "type": "git",
939
                 "type": "git",
940
                 "url": "https://github.com/filamentphp/app.git",
940
                 "url": "https://github.com/filamentphp/app.git",
941
-                "reference": "0719a1fcebcad120dd4e254938cfb08470c90105"
941
+                "reference": "d3e067e44b981f8212740ad32e9c8d733e562b2c"
942
             },
942
             },
943
             "dist": {
943
             "dist": {
944
                 "type": "zip",
944
                 "type": "zip",
945
-                "url": "https://api.github.com/repos/filamentphp/app/zipball/0719a1fcebcad120dd4e254938cfb08470c90105",
946
-                "reference": "0719a1fcebcad120dd4e254938cfb08470c90105",
945
+                "url": "https://api.github.com/repos/filamentphp/app/zipball/d3e067e44b981f8212740ad32e9c8d733e562b2c",
946
+                "reference": "d3e067e44b981f8212740ad32e9c8d733e562b2c",
947
                 "shasum": ""
947
                 "shasum": ""
948
             },
948
             },
949
             "require": {
949
             "require": {
993
                 "issues": "https://github.com/filamentphp/filament/issues",
993
                 "issues": "https://github.com/filamentphp/filament/issues",
994
                 "source": "https://github.com/filamentphp/filament"
994
                 "source": "https://github.com/filamentphp/filament"
995
             },
995
             },
996
-            "time": "2023-05-08T15:39:08+00:00"
996
+            "time": "2023-05-22T21:18:35+00:00"
997
         },
997
         },
998
         {
998
         {
999
             "name": "filament/forms",
999
             "name": "filament/forms",
1000
-            "version": "v2.17.38",
1000
+            "version": "v2.17.43",
1001
             "source": {
1001
             "source": {
1002
                 "type": "git",
1002
                 "type": "git",
1003
                 "url": "https://github.com/filamentphp/forms.git",
1003
                 "url": "https://github.com/filamentphp/forms.git",
1004
-                "reference": "49bafbf87f0d7f23e7b62a6d40591fd3ea81a55b"
1004
+                "reference": "a8acd3681f2b2163d6cad3478a5fe14489d53217"
1005
             },
1005
             },
1006
             "dist": {
1006
             "dist": {
1007
                 "type": "zip",
1007
                 "type": "zip",
1008
-                "url": "https://api.github.com/repos/filamentphp/forms/zipball/49bafbf87f0d7f23e7b62a6d40591fd3ea81a55b",
1009
-                "reference": "49bafbf87f0d7f23e7b62a6d40591fd3ea81a55b",
1008
+                "url": "https://api.github.com/repos/filamentphp/forms/zipball/a8acd3681f2b2163d6cad3478a5fe14489d53217",
1009
+                "reference": "a8acd3681f2b2163d6cad3478a5fe14489d53217",
1010
                 "shasum": ""
1010
                 "shasum": ""
1011
             },
1011
             },
1012
             "require": {
1012
             "require": {
1051
                 "issues": "https://github.com/filamentphp/filament/issues",
1051
                 "issues": "https://github.com/filamentphp/filament/issues",
1052
                 "source": "https://github.com/filamentphp/filament"
1052
                 "source": "https://github.com/filamentphp/filament"
1053
             },
1053
             },
1054
-            "time": "2023-05-08T09:55:16+00:00"
1054
+            "time": "2023-05-22T21:18:31+00:00"
1055
         },
1055
         },
1056
         {
1056
         {
1057
             "name": "filament/notifications",
1057
             "name": "filament/notifications",
1058
-            "version": "v2.17.38",
1058
+            "version": "v2.17.43",
1059
             "source": {
1059
             "source": {
1060
                 "type": "git",
1060
                 "type": "git",
1061
                 "url": "https://github.com/filamentphp/notifications.git",
1061
                 "url": "https://github.com/filamentphp/notifications.git",
1108
         },
1108
         },
1109
         {
1109
         {
1110
             "name": "filament/support",
1110
             "name": "filament/support",
1111
-            "version": "v2.17.38",
1111
+            "version": "v2.17.43",
1112
             "source": {
1112
             "source": {
1113
                 "type": "git",
1113
                 "type": "git",
1114
                 "url": "https://github.com/filamentphp/support.git",
1114
                 "url": "https://github.com/filamentphp/support.git",
1115
-                "reference": "1a411197122524886c81a74c7044258d64d56308"
1115
+                "reference": "1e03d08cb6df27fd64e658b5316fd34f81554a8d"
1116
             },
1116
             },
1117
             "dist": {
1117
             "dist": {
1118
                 "type": "zip",
1118
                 "type": "zip",
1119
-                "url": "https://api.github.com/repos/filamentphp/support/zipball/1a411197122524886c81a74c7044258d64d56308",
1120
-                "reference": "1a411197122524886c81a74c7044258d64d56308",
1119
+                "url": "https://api.github.com/repos/filamentphp/support/zipball/1e03d08cb6df27fd64e658b5316fd34f81554a8d",
1120
+                "reference": "1e03d08cb6df27fd64e658b5316fd34f81554a8d",
1121
                 "shasum": ""
1121
                 "shasum": ""
1122
             },
1122
             },
1123
             "require": {
1123
             "require": {
1154
                 "issues": "https://github.com/filamentphp/filament/issues",
1154
                 "issues": "https://github.com/filamentphp/filament/issues",
1155
                 "source": "https://github.com/filamentphp/filament"
1155
                 "source": "https://github.com/filamentphp/filament"
1156
             },
1156
             },
1157
-            "time": "2023-05-04T23:08:15+00:00"
1157
+            "time": "2023-05-22T21:18:29+00:00"
1158
         },
1158
         },
1159
         {
1159
         {
1160
             "name": "filament/tables",
1160
             "name": "filament/tables",
1161
-            "version": "v2.17.38",
1161
+            "version": "v2.17.43",
1162
             "source": {
1162
             "source": {
1163
                 "type": "git",
1163
                 "type": "git",
1164
                 "url": "https://github.com/filamentphp/tables.git",
1164
                 "url": "https://github.com/filamentphp/tables.git",
1165
-                "reference": "b23b5cc95c7b1afb650b366545942b1ccad993af"
1165
+                "reference": "1a57eac2388d2336c66dedf840b20a6b66a9b127"
1166
             },
1166
             },
1167
             "dist": {
1167
             "dist": {
1168
                 "type": "zip",
1168
                 "type": "zip",
1169
-                "url": "https://api.github.com/repos/filamentphp/tables/zipball/b23b5cc95c7b1afb650b366545942b1ccad993af",
1170
-                "reference": "b23b5cc95c7b1afb650b366545942b1ccad993af",
1169
+                "url": "https://api.github.com/repos/filamentphp/tables/zipball/1a57eac2388d2336c66dedf840b20a6b66a9b127",
1170
+                "reference": "1a57eac2388d2336c66dedf840b20a6b66a9b127",
1171
                 "shasum": ""
1171
                 "shasum": ""
1172
             },
1172
             },
1173
             "require": {
1173
             "require": {
1210
                 "issues": "https://github.com/filamentphp/filament/issues",
1210
                 "issues": "https://github.com/filamentphp/filament/issues",
1211
                 "source": "https://github.com/filamentphp/filament"
1211
                 "source": "https://github.com/filamentphp/filament"
1212
             },
1212
             },
1213
-            "time": "2023-05-08T09:55:33+00:00"
1213
+            "time": "2023-05-22T21:18:35+00:00"
1214
         },
1214
         },
1215
         {
1215
         {
1216
             "name": "flowframe/laravel-trend",
1216
             "name": "flowframe/laravel-trend",
1421
         },
1421
         },
1422
         {
1422
         {
1423
             "name": "guzzlehttp/guzzle",
1423
             "name": "guzzlehttp/guzzle",
1424
-            "version": "7.5.1",
1424
+            "version": "7.7.0",
1425
             "source": {
1425
             "source": {
1426
                 "type": "git",
1426
                 "type": "git",
1427
                 "url": "https://github.com/guzzle/guzzle.git",
1427
                 "url": "https://github.com/guzzle/guzzle.git",
1428
-                "reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9"
1428
+                "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5"
1429
             },
1429
             },
1430
             "dist": {
1430
             "dist": {
1431
                 "type": "zip",
1431
                 "type": "zip",
1432
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b964ca597e86b752cd994f27293e9fa6b6a95ed9",
1433
-                "reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9",
1432
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5",
1433
+                "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5",
1434
                 "shasum": ""
1434
                 "shasum": ""
1435
             },
1435
             },
1436
             "require": {
1436
             "require": {
1437
                 "ext-json": "*",
1437
                 "ext-json": "*",
1438
-                "guzzlehttp/promises": "^1.5",
1438
+                "guzzlehttp/promises": "^1.5.3 || ^2.0",
1439
                 "guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
1439
                 "guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
1440
                 "php": "^7.2.5 || ^8.0",
1440
                 "php": "^7.2.5 || ^8.0",
1441
                 "psr/http-client": "^1.0",
1441
                 "psr/http-client": "^1.0",
1447
             "require-dev": {
1447
             "require-dev": {
1448
                 "bamarni/composer-bin-plugin": "^1.8.1",
1448
                 "bamarni/composer-bin-plugin": "^1.8.1",
1449
                 "ext-curl": "*",
1449
                 "ext-curl": "*",
1450
-                "php-http/client-integration-tests": "^3.0",
1450
+                "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
1451
+                "php-http/message-factory": "^1.1",
1451
                 "phpunit/phpunit": "^8.5.29 || ^9.5.23",
1452
                 "phpunit/phpunit": "^8.5.29 || ^9.5.23",
1452
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
1453
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
1453
             },
1454
             },
1461
                 "bamarni-bin": {
1462
                 "bamarni-bin": {
1462
                     "bin-links": true,
1463
                     "bin-links": true,
1463
                     "forward-command": false
1464
                     "forward-command": false
1464
-                },
1465
-                "branch-alias": {
1466
-                    "dev-master": "7.5-dev"
1467
                 }
1465
                 }
1468
             },
1466
             },
1469
             "autoload": {
1467
             "autoload": {
1529
             ],
1527
             ],
1530
             "support": {
1528
             "support": {
1531
                 "issues": "https://github.com/guzzle/guzzle/issues",
1529
                 "issues": "https://github.com/guzzle/guzzle/issues",
1532
-                "source": "https://github.com/guzzle/guzzle/tree/7.5.1"
1530
+                "source": "https://github.com/guzzle/guzzle/tree/7.7.0"
1533
             },
1531
             },
1534
             "funding": [
1532
             "funding": [
1535
                 {
1533
                 {
1545
                     "type": "tidelift"
1543
                     "type": "tidelift"
1546
                 }
1544
                 }
1547
             ],
1545
             ],
1548
-            "time": "2023-04-17T16:30:08+00:00"
1546
+            "time": "2023-05-21T14:04:53+00:00"
1549
         },
1547
         },
1550
         {
1548
         {
1551
             "name": "guzzlehttp/promises",
1549
             "name": "guzzlehttp/promises",
1552
-            "version": "1.5.2",
1550
+            "version": "2.0.0",
1553
             "source": {
1551
             "source": {
1554
                 "type": "git",
1552
                 "type": "git",
1555
                 "url": "https://github.com/guzzle/promises.git",
1553
                 "url": "https://github.com/guzzle/promises.git",
1556
-                "reference": "b94b2807d85443f9719887892882d0329d1e2598"
1554
+                "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6"
1557
             },
1555
             },
1558
             "dist": {
1556
             "dist": {
1559
                 "type": "zip",
1557
                 "type": "zip",
1560
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598",
1561
-                "reference": "b94b2807d85443f9719887892882d0329d1e2598",
1558
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6",
1559
+                "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6",
1562
                 "shasum": ""
1560
                 "shasum": ""
1563
             },
1561
             },
1564
             "require": {
1562
             "require": {
1565
-                "php": ">=5.5"
1563
+                "php": "^7.2.5 || ^8.0"
1566
             },
1564
             },
1567
             "require-dev": {
1565
             "require-dev": {
1568
-                "symfony/phpunit-bridge": "^4.4 || ^5.1"
1566
+                "bamarni/composer-bin-plugin": "^1.8.1",
1567
+                "phpunit/phpunit": "^8.5.29 || ^9.5.23"
1569
             },
1568
             },
1570
             "type": "library",
1569
             "type": "library",
1571
             "extra": {
1570
             "extra": {
1572
-                "branch-alias": {
1573
-                    "dev-master": "1.5-dev"
1571
+                "bamarni-bin": {
1572
+                    "bin-links": true,
1573
+                    "forward-command": false
1574
                 }
1574
                 }
1575
             },
1575
             },
1576
             "autoload": {
1576
             "autoload": {
1577
-                "files": [
1578
-                    "src/functions_include.php"
1579
-                ],
1580
                 "psr-4": {
1577
                 "psr-4": {
1581
                     "GuzzleHttp\\Promise\\": "src/"
1578
                     "GuzzleHttp\\Promise\\": "src/"
1582
                 }
1579
                 }
1613
             ],
1610
             ],
1614
             "support": {
1611
             "support": {
1615
                 "issues": "https://github.com/guzzle/promises/issues",
1612
                 "issues": "https://github.com/guzzle/promises/issues",
1616
-                "source": "https://github.com/guzzle/promises/tree/1.5.2"
1613
+                "source": "https://github.com/guzzle/promises/tree/2.0.0"
1617
             },
1614
             },
1618
             "funding": [
1615
             "funding": [
1619
                 {
1616
                 {
1629
                     "type": "tidelift"
1626
                     "type": "tidelift"
1630
                 }
1627
                 }
1631
             ],
1628
             ],
1632
-            "time": "2022-08-28T14:55:35+00:00"
1629
+            "time": "2023-05-21T13:50:22+00:00"
1633
         },
1630
         },
1634
         {
1631
         {
1635
             "name": "guzzlehttp/psr7",
1632
             "name": "guzzlehttp/psr7",
1897
         },
1894
         },
1898
         {
1895
         {
1899
             "name": "laravel/framework",
1896
             "name": "laravel/framework",
1900
-            "version": "v10.10.0",
1897
+            "version": "v10.11.0",
1901
             "source": {
1898
             "source": {
1902
                 "type": "git",
1899
                 "type": "git",
1903
                 "url": "https://github.com/laravel/framework.git",
1900
                 "url": "https://github.com/laravel/framework.git",
1904
-                "reference": "0da22a8d179f79b49d4e71f4822f759651f35012"
1901
+                "reference": "21a5b6d9b669f32c10cc8ba776511b5f62599fea"
1905
             },
1902
             },
1906
             "dist": {
1903
             "dist": {
1907
                 "type": "zip",
1904
                 "type": "zip",
1908
-                "url": "https://api.github.com/repos/laravel/framework/zipball/0da22a8d179f79b49d4e71f4822f759651f35012",
1909
-                "reference": "0da22a8d179f79b49d4e71f4822f759651f35012",
1905
+                "url": "https://api.github.com/repos/laravel/framework/zipball/21a5b6d9b669f32c10cc8ba776511b5f62599fea",
1906
+                "reference": "21a5b6d9b669f32c10cc8ba776511b5f62599fea",
1910
                 "shasum": ""
1907
                 "shasum": ""
1911
             },
1908
             },
1912
             "require": {
1909
             "require": {
2093
                 "issues": "https://github.com/laravel/framework/issues",
2090
                 "issues": "https://github.com/laravel/framework/issues",
2094
                 "source": "https://github.com/laravel/framework"
2091
                 "source": "https://github.com/laravel/framework"
2095
             },
2092
             },
2096
-            "time": "2023-05-09T13:08:05+00:00"
2093
+            "time": "2023-05-16T13:59:23+00:00"
2097
         },
2094
         },
2098
         {
2095
         {
2099
             "name": "laravel/sanctum",
2096
             "name": "laravel/sanctum",
3583
         },
3580
         },
3584
         {
3581
         {
3585
             "name": "nikic/php-parser",
3582
             "name": "nikic/php-parser",
3586
-            "version": "v4.15.4",
3583
+            "version": "v4.15.5",
3587
             "source": {
3584
             "source": {
3588
                 "type": "git",
3585
                 "type": "git",
3589
                 "url": "https://github.com/nikic/PHP-Parser.git",
3586
                 "url": "https://github.com/nikic/PHP-Parser.git",
3590
-                "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
3587
+                "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e"
3591
             },
3588
             },
3592
             "dist": {
3589
             "dist": {
3593
                 "type": "zip",
3590
                 "type": "zip",
3594
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
3595
-                "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
3591
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e",
3592
+                "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e",
3596
                 "shasum": ""
3593
                 "shasum": ""
3597
             },
3594
             },
3598
             "require": {
3595
             "require": {
3633
             ],
3630
             ],
3634
             "support": {
3631
             "support": {
3635
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
3632
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
3636
-                "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
3633
+                "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5"
3637
             },
3634
             },
3638
-            "time": "2023-03-05T19:49:14+00:00"
3635
+            "time": "2023-05-19T20:20:00+00:00"
3639
         },
3636
         },
3640
         {
3637
         {
3641
             "name": "nunomaduro/termwind",
3638
             "name": "nunomaduro/termwind",
4283
         },
4280
         },
4284
         {
4281
         {
4285
             "name": "psy/psysh",
4282
             "name": "psy/psysh",
4286
-            "version": "v0.11.17",
4283
+            "version": "v0.11.18",
4287
             "source": {
4284
             "source": {
4288
                 "type": "git",
4285
                 "type": "git",
4289
                 "url": "https://github.com/bobthecow/psysh.git",
4286
                 "url": "https://github.com/bobthecow/psysh.git",
4290
-                "reference": "3dc5d4018dabd80bceb8fe1e3191ba8460569f0a"
4287
+                "reference": "4f00ee9e236fa6a48f4560d1300b9c961a70a7ec"
4291
             },
4288
             },
4292
             "dist": {
4289
             "dist": {
4293
                 "type": "zip",
4290
                 "type": "zip",
4294
-                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/3dc5d4018dabd80bceb8fe1e3191ba8460569f0a",
4295
-                "reference": "3dc5d4018dabd80bceb8fe1e3191ba8460569f0a",
4291
+                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/4f00ee9e236fa6a48f4560d1300b9c961a70a7ec",
4292
+                "reference": "4f00ee9e236fa6a48f4560d1300b9c961a70a7ec",
4296
                 "shasum": ""
4293
                 "shasum": ""
4297
             },
4294
             },
4298
             "require": {
4295
             "require": {
4353
             ],
4350
             ],
4354
             "support": {
4351
             "support": {
4355
                 "issues": "https://github.com/bobthecow/psysh/issues",
4352
                 "issues": "https://github.com/bobthecow/psysh/issues",
4356
-                "source": "https://github.com/bobthecow/psysh/tree/v0.11.17"
4353
+                "source": "https://github.com/bobthecow/psysh/tree/v0.11.18"
4357
             },
4354
             },
4358
-            "time": "2023-05-05T20:02:42+00:00"
4355
+            "time": "2023-05-23T02:31:11+00:00"
4359
         },
4356
         },
4360
         {
4357
         {
4361
             "name": "ralouphie/getallheaders",
4358
             "name": "ralouphie/getallheaders",
7642
         },
7639
         },
7643
         {
7640
         {
7644
             "name": "fakerphp/faker",
7641
             "name": "fakerphp/faker",
7645
-            "version": "v1.21.0",
7642
+            "version": "v1.22.0",
7646
             "source": {
7643
             "source": {
7647
                 "type": "git",
7644
                 "type": "git",
7648
                 "url": "https://github.com/FakerPHP/Faker.git",
7645
                 "url": "https://github.com/FakerPHP/Faker.git",
7649
-                "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d"
7646
+                "reference": "f85772abd508bd04e20bb4b1bbe260a68d0066d2"
7650
             },
7647
             },
7651
             "dist": {
7648
             "dist": {
7652
                 "type": "zip",
7649
                 "type": "zip",
7653
-                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/92efad6a967f0b79c499705c69b662f738cc9e4d",
7654
-                "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d",
7650
+                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/f85772abd508bd04e20bb4b1bbe260a68d0066d2",
7651
+                "reference": "f85772abd508bd04e20bb4b1bbe260a68d0066d2",
7655
                 "shasum": ""
7652
                 "shasum": ""
7656
             },
7653
             },
7657
             "require": {
7654
             "require": {
7704
             ],
7701
             ],
7705
             "support": {
7702
             "support": {
7706
                 "issues": "https://github.com/FakerPHP/Faker/issues",
7703
                 "issues": "https://github.com/FakerPHP/Faker/issues",
7707
-                "source": "https://github.com/FakerPHP/Faker/tree/v1.21.0"
7704
+                "source": "https://github.com/FakerPHP/Faker/tree/v1.22.0"
7708
             },
7705
             },
7709
-            "time": "2022-12-13T13:54:32+00:00"
7706
+            "time": "2023-05-14T12:31:37+00:00"
7710
         },
7707
         },
7711
         {
7708
         {
7712
             "name": "filp/whoops",
7709
             "name": "filp/whoops",
8301
         },
8298
         },
8302
         {
8299
         {
8303
             "name": "phpunit/php-code-coverage",
8300
             "name": "phpunit/php-code-coverage",
8304
-            "version": "10.1.1",
8301
+            "version": "10.1.2",
8305
             "source": {
8302
             "source": {
8306
                 "type": "git",
8303
                 "type": "git",
8307
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
8304
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
8308
-                "reference": "884a0da7f9f46f28b2cb69134217fd810b793974"
8305
+                "reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e"
8309
             },
8306
             },
8310
             "dist": {
8307
             "dist": {
8311
                 "type": "zip",
8308
                 "type": "zip",
8312
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/884a0da7f9f46f28b2cb69134217fd810b793974",
8313
-                "reference": "884a0da7f9f46f28b2cb69134217fd810b793974",
8309
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/db1497ec8dd382e82c962f7abbe0320e4882ee4e",
8310
+                "reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e",
8314
                 "shasum": ""
8311
                 "shasum": ""
8315
             },
8312
             },
8316
             "require": {
8313
             "require": {
8367
             "support": {
8364
             "support": {
8368
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
8365
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
8369
                 "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
8366
                 "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
8370
-                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.1"
8367
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.2"
8371
             },
8368
             },
8372
             "funding": [
8369
             "funding": [
8373
                 {
8370
                 {
8375
                     "type": "github"
8372
                     "type": "github"
8376
                 }
8373
                 }
8377
             ],
8374
             ],
8378
-            "time": "2023-04-17T12:15:40+00:00"
8375
+            "time": "2023-05-22T09:04:27+00:00"
8379
         },
8376
         },
8380
         {
8377
         {
8381
             "name": "phpunit/php-file-iterator",
8378
             "name": "phpunit/php-file-iterator",
8621
         },
8618
         },
8622
         {
8619
         {
8623
             "name": "phpunit/phpunit",
8620
             "name": "phpunit/phpunit",
8624
-            "version": "10.1.2",
8621
+            "version": "10.1.3",
8625
             "source": {
8622
             "source": {
8626
                 "type": "git",
8623
                 "type": "git",
8627
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
8624
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
8628
-                "reference": "6f0cd95be71add539f8fd2be25b2a4a29789000b"
8625
+                "reference": "2379ebafc1737e71cdc84f402acb6b7f04198b9d"
8629
             },
8626
             },
8630
             "dist": {
8627
             "dist": {
8631
                 "type": "zip",
8628
                 "type": "zip",
8632
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6f0cd95be71add539f8fd2be25b2a4a29789000b",
8633
-                "reference": "6f0cd95be71add539f8fd2be25b2a4a29789000b",
8629
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2379ebafc1737e71cdc84f402acb6b7f04198b9d",
8630
+                "reference": "2379ebafc1737e71cdc84f402acb6b7f04198b9d",
8634
                 "shasum": ""
8631
                 "shasum": ""
8635
             },
8632
             },
8636
             "require": {
8633
             "require": {
8702
             "support": {
8699
             "support": {
8703
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
8700
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
8704
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
8701
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
8705
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.1.2"
8702
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.1.3"
8706
             },
8703
             },
8707
             "funding": [
8704
             "funding": [
8708
                 {
8705
                 {
8718
                     "type": "tidelift"
8715
                     "type": "tidelift"
8719
                 }
8716
                 }
8720
             ],
8717
             ],
8721
-            "time": "2023-04-22T07:38:19+00:00"
8718
+            "time": "2023-05-11T05:16:22+00:00"
8722
         },
8719
         },
8723
         {
8720
         {
8724
             "name": "psr/cache",
8721
             "name": "psr/cache",

+ 1808
- 0
config/money.php
文件差異過大導致無法顯示
查看文件


+ 84
- 0
database/factories/AccountFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Banking\Account;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Account>
10
+ */
11
+class AccountFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = Account::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        $types = ['bank', 'card'];
28
+
29
+        return [
30
+            'type' => $this->faker->randomElement($types),
31
+            'name' => $this->faker->text(15),
32
+            'number' => (string) $this->faker->randomNumber(12, true),
33
+            'currency_code' => $this->company->currencies()->enabled()->get()->random(1)->pluck('code')->first(),
34
+            'opening_balance' => '0',
35
+            'bank_name' => $this->faker->text(15),
36
+            'bank_phone' => $this->faker->phoneNumber,
37
+            'bank_address' => $this->faker->address,
38
+            'enabled' => $this->faker->boolean,
39
+            'company_id' => $this->company->id,
40
+        ];
41
+    }
42
+
43
+    /**
44
+     * Indicate that the model is enabled.
45
+     *
46
+     * @return Factory<Account>
47
+     */
48
+    public function enabled(): Factory
49
+    {
50
+        return $this->state(function (array $attributes) {
51
+            return [
52
+                'enabled' => true,
53
+            ];
54
+        });
55
+    }
56
+
57
+    /**
58
+     * Indicate that the model is disabled.
59
+     *
60
+     * @return Factory<Account>
61
+     */
62
+    public function disabled(): Factory
63
+    {
64
+        return $this->state(function (array $attributes) {
65
+            return [
66
+                'enabled' => false,
67
+            ];
68
+        });
69
+    }
70
+
71
+    /**
72
+     * Indicate that the default currency is used.
73
+     *
74
+     * @return Factory<Account>
75
+     */
76
+    public function default_currency(): Factory
77
+    {
78
+        return $this->state(function (array $attributes) {
79
+            return [
80
+                'currency_code' => $this->default_currency(),
81
+            ];
82
+        });
83
+    }
84
+}

+ 31
- 0
database/factories/CategoryFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Setting\Category;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Category>
10
+ */
11
+class CategoryFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = Category::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        return [
28
+            //
29
+        ];
30
+    }
31
+}

+ 31
- 0
database/factories/ContactFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Contact;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Contact>
10
+ */
11
+class ContactFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = Contact::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        return [
28
+            //
29
+        ];
30
+    }
31
+}

+ 79
- 0
database/factories/CurrencyFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Setting\Currency;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Currency>
10
+ */
11
+class CurrencyFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = Currency::class;
19
+
20
+
21
+    /**
22
+     * Define the model's default state.
23
+     *
24
+     * @return array<string, mixed>
25
+     */
26
+    public function definition(): array
27
+    {
28
+        $currencies = config('money');
29
+
30
+        $existingCodes = Currency::query()->pluck('code')->toArray();
31
+
32
+        foreach ($existingCodes as $code) {
33
+            unset($currencies[$code]);
34
+        }
35
+
36
+        $randomCode = $this->faker->randomElement(array_keys($currencies));
37
+
38
+        $code = $randomCode;
39
+
40
+        $currency = $currencies[$randomCode];
41
+
42
+        return [
43
+            'name' => $currency['name'],
44
+            'code' => $code,
45
+            'rate' => $this->faker->randomFloat($currency['precision'], 1, 10),
46
+            'precision' => $currency['precision'],
47
+            'symbol' => $currency['symbol'],
48
+            'symbol_first' => $currency['symbol_first'],
49
+            'decimal_mark' => $currency['decimal_mark'],
50
+            'thousands_separator' => $currency['thousands_separator'],
51
+            'enabled' => $this->faker->boolean,
52
+            'company_id' => $this->company->id,
53
+        ];
54
+    }
55
+
56
+    /**
57
+     * Indicate that the currency is enabled.
58
+     */
59
+    public function enabled(): Factory
60
+    {
61
+        return $this->state(static function (array $attributes) {
62
+            return [
63
+                'enabled' => true,
64
+            ];
65
+        });
66
+    }
67
+
68
+    /**
69
+     * Indicate that the currency is disabled.
70
+     */
71
+    public function disabled(): Factory
72
+    {
73
+        return $this->state(static function (array $attributes) {
74
+            return [
75
+                'enabled' => false,
76
+            ];
77
+        });
78
+    }
79
+}

+ 31
- 0
database/factories/DiscountFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Setting\Discount;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Discount>
10
+ */
11
+class DiscountFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = Discount::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        return [
28
+            //
29
+        ];
30
+    }
31
+}

+ 31
- 0
database/factories/DocumentFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Document\Document;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Document>
10
+ */
11
+class DocumentFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = Document::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        return [
28
+            //
29
+        ];
30
+    }
31
+}

+ 31
- 0
database/factories/DocumentItemFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Document\DocumentItem;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<DocumentItem>
10
+ */
11
+class DocumentItemFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = DocumentItem::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        return [
28
+            //
29
+        ];
30
+    }
31
+}

+ 31
- 0
database/factories/DocumentTotalFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Document\DocumentTotal;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<DocumentTotal>
10
+ */
11
+class DocumentTotalFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = DocumentTotal::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        return [
28
+            //
29
+        ];
30
+    }
31
+}

+ 29
- 0
database/factories/ItemFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Item;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Item>
10
+ */
11
+class ItemFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     */
16
+    protected $model = Item::class;
17
+
18
+    /**
19
+     * Define the model's default state.
20
+     *
21
+     * @return array<string, mixed>
22
+     */
23
+    public function definition(): array
24
+    {
25
+        return [
26
+            //
27
+        ];
28
+    }
29
+}

+ 31
- 0
database/factories/TaxFactory.php 查看文件

1
+<?php
2
+
3
+namespace Database\Factories;
4
+
5
+use App\Models\Setting\Tax;
6
+use Illuminate\Database\Eloquent\Factories\Factory;
7
+
8
+/**
9
+ * @extends Factory<Tax>
10
+ */
11
+class TaxFactory extends Factory
12
+{
13
+    /**
14
+     * The name of the factory's corresponding model.
15
+     *
16
+     * @var string
17
+     */
18
+    protected $model = Tax::class;
19
+
20
+    /**
21
+     * Define the model's default state.
22
+     *
23
+     * @return array<string, mixed>
24
+     */
25
+    public function definition(): array
26
+    {
27
+        return [
28
+            //
29
+        ];
30
+    }
31
+}

+ 40
- 0
database/migrations/2023_05_10_040940_create_currencies_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::create('currencies', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->string('name', 100);
18
+            $table->string('code')->index();
19
+            $table->decimal('rate', 15, 8);
20
+            $table->unsignedTinyInteger('precision')->default(2);
21
+            $table->string('symbol')->default('$');
22
+            $table->boolean('symbol_first')->default(true);
23
+            $table->string('decimal_mark')->default('.');
24
+            $table->string('thousands_separator')->default(',');
25
+            $table->boolean('enabled')->default(true);
26
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
27
+            $table->timestamps();
28
+
29
+            $table->unique(['company_id', 'code']);
30
+        });
31
+    }
32
+
33
+    /**
34
+     * Reverse the migrations.
35
+     */
36
+    public function down(): void
37
+    {
38
+        Schema::dropIfExists('currencies');
39
+    }
40
+};

+ 41
- 0
database/migrations/2023_05_11_044321_create_accounts_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::create('accounts', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->string('type')->default('bank');
18
+            $table->string('name', 100);
19
+            $table->string('number', 20);
20
+            $table->string('currency_code')->default('USD');
21
+            $table->decimal('opening_balance', 15, 4)->default(0.0000);
22
+            $table->string('bank_name', 100)->nullable();
23
+            $table->string('bank_phone', 20)->nullable();
24
+            $table->text('bank_address')->nullable();
25
+            $table->boolean('enabled')->default(true);
26
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
27
+            $table->timestamps();
28
+
29
+            $table->unique(['company_id', 'number']);
30
+            $table->foreign('currency_code')->references('code')->on('currencies')->restrictOnDelete();
31
+        });
32
+    }
33
+
34
+    /**
35
+     * Reverse the migrations.
36
+     */
37
+    public function down(): void
38
+    {
39
+        Schema::dropIfExists('accounts');
40
+    }
41
+};

+ 33
- 0
database/migrations/2023_05_12_042255_create_categories_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::create('categories', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->string('name');
18
+            $table->string('type'); // expense, income, item, other
19
+            $table->string('color');
20
+            $table->boolean('enabled')->default(true);
21
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
22
+            $table->timestamps();
23
+        });
24
+    }
25
+
26
+    /**
27
+     * Reverse the migrations.
28
+     */
29
+    public function down(): void
30
+    {
31
+        Schema::dropIfExists('categories');
32
+    }
33
+};

+ 47
- 0
database/migrations/2023_05_19_042232_create_contacts_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::create('contacts', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->onDelete('cascade');
17
+            $table->string('entity')->default('company'); // company, individual (person)
18
+            $table->string('type'); // vendor, customer, employee
19
+            $table->string('name');
20
+            $table->string('email')->nullable();
21
+            $table->string('tax_number')->nullable();
22
+            $table->string('phone')->nullable();
23
+            $table->text('address')->nullable();
24
+            $table->string('city')->nullable();
25
+            $table->string('zip_code')->nullable();
26
+            $table->string('state')->nullable();
27
+            $table->string('country')->nullable();
28
+            $table->string('website')->nullable();
29
+            $table->string('currency_code')->default('USD');
30
+            $table->string('reference')->nullable();
31
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
32
+            $table->timestamps();
33
+
34
+            $table->index(['company_id', 'type']);
35
+            $table->unique(['company_id', 'type', 'email']);
36
+            $table->foreign('currency_code')->references('code')->on('currencies')->restrictOnDelete();
37
+        });
38
+    }
39
+
40
+    /**
41
+     * Reverse the migrations.
42
+     */
43
+    public function down(): void
44
+    {
45
+        Schema::dropIfExists('contacts');
46
+    }
47
+};

+ 36
- 0
database/migrations/2023_05_20_080131_create_taxes_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::create('taxes', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->string('name');
18
+            $table->text('description')->nullable();
19
+            $table->decimal('rate', 15, 4);
20
+            $table->string('computation')->default('percentage'); // percentage, fixed, compound, inclusive, withholding
21
+            $table->string('type')->default('sales'); // sales, purchases
22
+            $table->string('scope')->nullable(); // product, service, none
23
+            $table->boolean('enabled')->default(true);
24
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
25
+            $table->timestamps();
26
+        });
27
+    }
28
+
29
+    /**
30
+     * Reverse the migrations.
31
+     */
32
+    public function down(): void
33
+    {
34
+        Schema::dropIfExists('taxes');
35
+    }
36
+};

+ 35
- 0
database/migrations/2023_05_21_163808_create_discounts_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::create('discounts', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->string('name');
17
+            $table->text('description')->nullable();
18
+            $table->decimal('rate', 15, 4);
19
+            $table->string('computation')->default('percentage'); // percentage, fixed
20
+            $table->string('type')->default('sales'); // sales, purchases
21
+            $table->string('scope')->nullable(); // product, service, none
22
+            $table->boolean('enabled')->default(true);
23
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
24
+            $table->timestamps();
25
+        });
26
+    }
27
+
28
+    /**
29
+     * Reverse the migrations.
30
+     */
31
+    public function down(): void
32
+    {
33
+        Schema::dropIfExists('discounts');
34
+    }
35
+};

+ 40
- 0
database/migrations/2023_05_22_073252_create_items_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::create('items', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->string('type'); // product, service
18
+            $table->string('name');
19
+            $table->string('sku')->unique();
20
+            $table->string('description')->nullable();
21
+            $table->decimal('sale_price', 15, 4);
22
+            $table->decimal('purchase_price', 15, 4);
23
+            $table->integer('quantity')->default(1);
24
+            $table->foreignId('category_id')->default(1)->constrained()->restrictOnDelete();
25
+            $table->foreignId('tax_id')->nullable()->constrained()->nullOnDelete();
26
+            $table->foreignId('discount_id')->nullable()->constrained()->nullOnDelete();
27
+            $table->boolean('enabled')->default(true);
28
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
29
+            $table->timestamps();
30
+        });
31
+    }
32
+
33
+    /**
34
+     * Reverse the migrations.
35
+     */
36
+    public function down(): void
37
+    {
38
+        Schema::dropIfExists('items');
39
+    }
40
+};

+ 46
- 0
database/migrations/2023_05_23_141215_create_documents_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::create('documents', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->string('type'); // invoice, bill
18
+            $table->string('document_number');
19
+            $table->string('order_number')->nullable();
20
+            $table->string('status');
21
+            $table->dateTime('document_date');
22
+            $table->dateTime('due_date');
23
+            $table->dateTime('paid_date')->nullable();
24
+            $table->decimal('amount', 15, 4);
25
+            $table->foreignId('tax_id')->nullable()->constrained()->nullOnDelete();
26
+            $table->foreignId('discount_id')->nullable()->constrained()->nullOnDelete();
27
+            $table->string('reference')->nullable();
28
+            $table->string('currency_code')->default('USD');
29
+            $table->foreignId('category_id')->default(1)->constrained()->restrictOnDelete();
30
+            $table->foreignId('contact_id')->nullable()->constrained()->nullOnDelete();
31
+            $table->text('notes')->nullable();
32
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
33
+            $table->timestamps();
34
+
35
+            $table->foreign('currency_code')->references('code')->on('currencies')->restrictOnDelete();
36
+        });
37
+    }
38
+
39
+    /**
40
+     * Reverse the migrations.
41
+     */
42
+    public function down(): void
43
+    {
44
+        Schema::dropIfExists('documents');
45
+    }
46
+};

+ 39
- 0
database/migrations/2023_05_23_151550_create_document_items_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::create('document_items', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->foreignId('document_id')->constrained()->cascadeOnDelete();
18
+            $table->foreignId('item_id')->constrained()->cascadeOnDelete();
19
+            $table->string('type');
20
+            $table->string('name');
21
+            $table->text('description')->nullable();
22
+            $table->decimal('quantity', 7, 2);
23
+            $table->decimal('price', 15, 4);
24
+            $table->foreignId('tax_id')->nullable()->constrained()->nullOnDelete();
25
+            $table->foreignId('discount_id')->nullable()->constrained()->nullOnDelete();
26
+            $table->decimal('total', 15, 4);
27
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
28
+            $table->timestamps();
29
+        });
30
+    }
31
+
32
+    /**
33
+     * Reverse the migrations.
34
+     */
35
+    public function down(): void
36
+    {
37
+        Schema::dropIfExists('document_items');
38
+    }
39
+};

+ 37
- 0
database/migrations/2023_05_23_173412_create_document_totals_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::create('document_totals', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->foreignId('document_id')->constrained()->cascadeOnDelete();
18
+            $table->string('type');
19
+            $table->string('code');
20
+            $table->string('name');
21
+            $table->decimal('subtotal', 15, 4)->default(0);
22
+            $table->decimal('discount', 15, 4)->default(0);
23
+            $table->decimal('tax', 15, 4)->default(0);
24
+            $table->decimal('total', 15, 4);
25
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
26
+            $table->timestamps();
27
+        });
28
+    }
29
+
30
+    /**
31
+     * Reverse the migrations.
32
+     */
33
+    public function down(): void
34
+    {
35
+        Schema::dropIfExists('document_totals');
36
+    }
37
+};

+ 20
- 0
database/seeders/AccountSeeder.php 查看文件

1
+<?php
2
+
3
+namespace Database\Seeders;
4
+
5
+use App\Models\Banking\Account;
6
+use Illuminate\Database\Console\Seeds\WithoutModelEvents;
7
+use Illuminate\Database\Seeder;
8
+
9
+class AccountSeeder extends Seeder
10
+{
11
+    /**
12
+     * Run the database seeds.
13
+     */
14
+    public function run(): void
15
+    {
16
+        Account::factory()
17
+            ->count(5)
18
+            ->create();
19
+    }
20
+}

+ 20
- 0
database/seeders/CurrencySeeder.php 查看文件

1
+<?php
2
+
3
+namespace Database\Seeders;
4
+
5
+use App\Models\Setting\Currency;
6
+use Illuminate\Database\Console\Seeds\WithoutModelEvents;
7
+use Illuminate\Database\Seeder;
8
+
9
+class CurrencySeeder extends Seeder
10
+{
11
+    /**
12
+     * Run the database seeds.
13
+     */
14
+    public function run(): void
15
+    {
16
+        Currency::factory()
17
+            ->count(5)
18
+            ->create();
19
+    }
20
+}

+ 256
- 255
package-lock.json 查看文件

32
             }
32
             }
33
         },
33
         },
34
         "node_modules/@alpinejs/focus": {
34
         "node_modules/@alpinejs/focus": {
35
-            "version": "3.12.0",
36
-            "resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.12.0.tgz",
37
-            "integrity": "sha512-KfFS6W2Ao71e/zWMg5B51QR8Djocc2grDBhZ4VYNYFh5cUnb3TELQ3luY0kjl9phy2NToi52Gz360G889Pz1Bg==",
35
+            "version": "3.12.1",
36
+            "resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.12.1.tgz",
37
+            "integrity": "sha512-8LXkzY9yHqTqsB+aqdY1SL4fv+IbMtn2vEwGPw3YFio0+vfS+hGnZS1E4aDkm+JIUUtQvqRbV3cnK2WRZkVGnA==",
38
             "dev": true,
38
             "dev": true,
39
             "dependencies": {
39
             "dependencies": {
40
                 "focus-trap": "^6.6.1"
40
                 "focus-trap": "^6.6.1"
47
             "dev": true
47
             "dev": true
48
         },
48
         },
49
         "node_modules/@esbuild/android-arm": {
49
         "node_modules/@esbuild/android-arm": {
50
-            "version": "0.17.18",
51
-            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz",
52
-            "integrity": "sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==",
50
+            "version": "0.17.19",
51
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
52
+            "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
53
             "cpu": [
53
             "cpu": [
54
                 "arm"
54
                 "arm"
55
             ],
55
             ],
63
             }
63
             }
64
         },
64
         },
65
         "node_modules/@esbuild/android-arm64": {
65
         "node_modules/@esbuild/android-arm64": {
66
-            "version": "0.17.18",
67
-            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz",
68
-            "integrity": "sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==",
66
+            "version": "0.17.19",
67
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
68
+            "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
69
             "cpu": [
69
             "cpu": [
70
                 "arm64"
70
                 "arm64"
71
             ],
71
             ],
79
             }
79
             }
80
         },
80
         },
81
         "node_modules/@esbuild/android-x64": {
81
         "node_modules/@esbuild/android-x64": {
82
-            "version": "0.17.18",
83
-            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.18.tgz",
84
-            "integrity": "sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==",
82
+            "version": "0.17.19",
83
+            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
84
+            "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
85
             "cpu": [
85
             "cpu": [
86
                 "x64"
86
                 "x64"
87
             ],
87
             ],
95
             }
95
             }
96
         },
96
         },
97
         "node_modules/@esbuild/darwin-arm64": {
97
         "node_modules/@esbuild/darwin-arm64": {
98
-            "version": "0.17.18",
99
-            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz",
100
-            "integrity": "sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==",
98
+            "version": "0.17.19",
99
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
100
+            "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
101
             "cpu": [
101
             "cpu": [
102
                 "arm64"
102
                 "arm64"
103
             ],
103
             ],
111
             }
111
             }
112
         },
112
         },
113
         "node_modules/@esbuild/darwin-x64": {
113
         "node_modules/@esbuild/darwin-x64": {
114
-            "version": "0.17.18",
115
-            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz",
116
-            "integrity": "sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==",
114
+            "version": "0.17.19",
115
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
116
+            "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
117
             "cpu": [
117
             "cpu": [
118
                 "x64"
118
                 "x64"
119
             ],
119
             ],
127
             }
127
             }
128
         },
128
         },
129
         "node_modules/@esbuild/freebsd-arm64": {
129
         "node_modules/@esbuild/freebsd-arm64": {
130
-            "version": "0.17.18",
131
-            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz",
132
-            "integrity": "sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==",
130
+            "version": "0.17.19",
131
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
132
+            "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
133
             "cpu": [
133
             "cpu": [
134
                 "arm64"
134
                 "arm64"
135
             ],
135
             ],
143
             }
143
             }
144
         },
144
         },
145
         "node_modules/@esbuild/freebsd-x64": {
145
         "node_modules/@esbuild/freebsd-x64": {
146
-            "version": "0.17.18",
147
-            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz",
148
-            "integrity": "sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==",
146
+            "version": "0.17.19",
147
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
148
+            "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
149
             "cpu": [
149
             "cpu": [
150
                 "x64"
150
                 "x64"
151
             ],
151
             ],
159
             }
159
             }
160
         },
160
         },
161
         "node_modules/@esbuild/linux-arm": {
161
         "node_modules/@esbuild/linux-arm": {
162
-            "version": "0.17.18",
163
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz",
164
-            "integrity": "sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==",
162
+            "version": "0.17.19",
163
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
164
+            "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
165
             "cpu": [
165
             "cpu": [
166
                 "arm"
166
                 "arm"
167
             ],
167
             ],
175
             }
175
             }
176
         },
176
         },
177
         "node_modules/@esbuild/linux-arm64": {
177
         "node_modules/@esbuild/linux-arm64": {
178
-            "version": "0.17.18",
179
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz",
180
-            "integrity": "sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==",
178
+            "version": "0.17.19",
179
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
180
+            "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
181
             "cpu": [
181
             "cpu": [
182
                 "arm64"
182
                 "arm64"
183
             ],
183
             ],
191
             }
191
             }
192
         },
192
         },
193
         "node_modules/@esbuild/linux-ia32": {
193
         "node_modules/@esbuild/linux-ia32": {
194
-            "version": "0.17.18",
195
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz",
196
-            "integrity": "sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==",
194
+            "version": "0.17.19",
195
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
196
+            "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
197
             "cpu": [
197
             "cpu": [
198
                 "ia32"
198
                 "ia32"
199
             ],
199
             ],
207
             }
207
             }
208
         },
208
         },
209
         "node_modules/@esbuild/linux-loong64": {
209
         "node_modules/@esbuild/linux-loong64": {
210
-            "version": "0.17.18",
211
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz",
212
-            "integrity": "sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==",
210
+            "version": "0.17.19",
211
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
212
+            "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
213
             "cpu": [
213
             "cpu": [
214
                 "loong64"
214
                 "loong64"
215
             ],
215
             ],
223
             }
223
             }
224
         },
224
         },
225
         "node_modules/@esbuild/linux-mips64el": {
225
         "node_modules/@esbuild/linux-mips64el": {
226
-            "version": "0.17.18",
227
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz",
228
-            "integrity": "sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==",
226
+            "version": "0.17.19",
227
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
228
+            "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
229
             "cpu": [
229
             "cpu": [
230
                 "mips64el"
230
                 "mips64el"
231
             ],
231
             ],
239
             }
239
             }
240
         },
240
         },
241
         "node_modules/@esbuild/linux-ppc64": {
241
         "node_modules/@esbuild/linux-ppc64": {
242
-            "version": "0.17.18",
243
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz",
244
-            "integrity": "sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==",
242
+            "version": "0.17.19",
243
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
244
+            "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
245
             "cpu": [
245
             "cpu": [
246
                 "ppc64"
246
                 "ppc64"
247
             ],
247
             ],
255
             }
255
             }
256
         },
256
         },
257
         "node_modules/@esbuild/linux-riscv64": {
257
         "node_modules/@esbuild/linux-riscv64": {
258
-            "version": "0.17.18",
259
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz",
260
-            "integrity": "sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==",
258
+            "version": "0.17.19",
259
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
260
+            "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
261
             "cpu": [
261
             "cpu": [
262
                 "riscv64"
262
                 "riscv64"
263
             ],
263
             ],
271
             }
271
             }
272
         },
272
         },
273
         "node_modules/@esbuild/linux-s390x": {
273
         "node_modules/@esbuild/linux-s390x": {
274
-            "version": "0.17.18",
275
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz",
276
-            "integrity": "sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==",
274
+            "version": "0.17.19",
275
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
276
+            "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
277
             "cpu": [
277
             "cpu": [
278
                 "s390x"
278
                 "s390x"
279
             ],
279
             ],
287
             }
287
             }
288
         },
288
         },
289
         "node_modules/@esbuild/linux-x64": {
289
         "node_modules/@esbuild/linux-x64": {
290
-            "version": "0.17.18",
291
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz",
292
-            "integrity": "sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==",
290
+            "version": "0.17.19",
291
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
292
+            "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
293
             "cpu": [
293
             "cpu": [
294
                 "x64"
294
                 "x64"
295
             ],
295
             ],
303
             }
303
             }
304
         },
304
         },
305
         "node_modules/@esbuild/netbsd-x64": {
305
         "node_modules/@esbuild/netbsd-x64": {
306
-            "version": "0.17.18",
307
-            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz",
308
-            "integrity": "sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==",
306
+            "version": "0.17.19",
307
+            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
308
+            "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
309
             "cpu": [
309
             "cpu": [
310
                 "x64"
310
                 "x64"
311
             ],
311
             ],
319
             }
319
             }
320
         },
320
         },
321
         "node_modules/@esbuild/openbsd-x64": {
321
         "node_modules/@esbuild/openbsd-x64": {
322
-            "version": "0.17.18",
323
-            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz",
324
-            "integrity": "sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==",
322
+            "version": "0.17.19",
323
+            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
324
+            "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
325
             "cpu": [
325
             "cpu": [
326
                 "x64"
326
                 "x64"
327
             ],
327
             ],
335
             }
335
             }
336
         },
336
         },
337
         "node_modules/@esbuild/sunos-x64": {
337
         "node_modules/@esbuild/sunos-x64": {
338
-            "version": "0.17.18",
339
-            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz",
340
-            "integrity": "sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==",
338
+            "version": "0.17.19",
339
+            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
340
+            "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
341
             "cpu": [
341
             "cpu": [
342
                 "x64"
342
                 "x64"
343
             ],
343
             ],
351
             }
351
             }
352
         },
352
         },
353
         "node_modules/@esbuild/win32-arm64": {
353
         "node_modules/@esbuild/win32-arm64": {
354
-            "version": "0.17.18",
355
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz",
356
-            "integrity": "sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==",
354
+            "version": "0.17.19",
355
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
356
+            "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
357
             "cpu": [
357
             "cpu": [
358
                 "arm64"
358
                 "arm64"
359
             ],
359
             ],
367
             }
367
             }
368
         },
368
         },
369
         "node_modules/@esbuild/win32-ia32": {
369
         "node_modules/@esbuild/win32-ia32": {
370
-            "version": "0.17.18",
371
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz",
372
-            "integrity": "sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==",
370
+            "version": "0.17.19",
371
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
372
+            "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
373
             "cpu": [
373
             "cpu": [
374
                 "ia32"
374
                 "ia32"
375
             ],
375
             ],
383
             }
383
             }
384
         },
384
         },
385
         "node_modules/@esbuild/win32-x64": {
385
         "node_modules/@esbuild/win32-x64": {
386
-            "version": "0.17.18",
387
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz",
388
-            "integrity": "sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==",
386
+            "version": "0.17.19",
387
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
388
+            "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
389
             "cpu": [
389
             "cpu": [
390
                 "x64"
390
                 "x64"
391
             ],
391
             ],
540
             "dev": true
540
             "dev": true
541
         },
541
         },
542
         "node_modules/alpinejs": {
542
         "node_modules/alpinejs": {
543
-            "version": "3.12.0",
544
-            "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.12.0.tgz",
545
-            "integrity": "sha512-YENcRBA9dlwR8PsZNFMTHbmdlTNwd1BkCeivPvOzzCKHas6AfwNRsDK9UEFmE5dXTMEZjnnpCTxV8vkdpWiOCw==",
543
+            "version": "3.12.1",
544
+            "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.12.1.tgz",
545
+            "integrity": "sha512-GjEmZscHuCPv/XRbzabQLFH3I1+M3TbZqEsLDuYai/Yw+pE1IL7DK4ejRfqBSaysi4wWZ1k5IqVG2aefhWWqsQ==",
546
             "dev": true,
546
             "dev": true,
547
             "dependencies": {
547
             "dependencies": {
548
                 "@vue/reactivity": "~3.1.1"
548
                 "@vue/reactivity": "~3.1.1"
698
             }
698
             }
699
         },
699
         },
700
         "node_modules/caniuse-lite": {
700
         "node_modules/caniuse-lite": {
701
-            "version": "1.0.30001482",
702
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz",
703
-            "integrity": "sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ==",
701
+            "version": "1.0.30001489",
702
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz",
703
+            "integrity": "sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ==",
704
             "dev": true,
704
             "dev": true,
705
             "funding": [
705
             "funding": [
706
                 {
706
                 {
817
             "dev": true
817
             "dev": true
818
         },
818
         },
819
         "node_modules/electron-to-chromium": {
819
         "node_modules/electron-to-chromium": {
820
-            "version": "1.4.383",
821
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.383.tgz",
822
-            "integrity": "sha512-BQyvFauIMzCJqILViJNs0kIBEAlx1bYLS5CRLyJtlun1KAnZlhNSgyfyWifPWagQ5s8KYPY6BpNHZsEMkxZAQQ==",
820
+            "version": "1.4.405",
821
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.405.tgz",
822
+            "integrity": "sha512-JdDgnwU69FMZURoesf9gNOej2Cms1XJFfLk24y1IBtnAdhTcJY/mXnokmpmxHN59PcykBP4bgUU98vLY44Lhuw==",
823
             "dev": true
823
             "dev": true
824
         },
824
         },
825
         "node_modules/esbuild": {
825
         "node_modules/esbuild": {
826
-            "version": "0.17.18",
827
-            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz",
828
-            "integrity": "sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==",
826
+            "version": "0.17.19",
827
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
828
+            "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
829
             "dev": true,
829
             "dev": true,
830
             "hasInstallScript": true,
830
             "hasInstallScript": true,
831
             "bin": {
831
             "bin": {
835
                 "node": ">=12"
835
                 "node": ">=12"
836
             },
836
             },
837
             "optionalDependencies": {
837
             "optionalDependencies": {
838
-                "@esbuild/android-arm": "0.17.18",
839
-                "@esbuild/android-arm64": "0.17.18",
840
-                "@esbuild/android-x64": "0.17.18",
841
-                "@esbuild/darwin-arm64": "0.17.18",
842
-                "@esbuild/darwin-x64": "0.17.18",
843
-                "@esbuild/freebsd-arm64": "0.17.18",
844
-                "@esbuild/freebsd-x64": "0.17.18",
845
-                "@esbuild/linux-arm": "0.17.18",
846
-                "@esbuild/linux-arm64": "0.17.18",
847
-                "@esbuild/linux-ia32": "0.17.18",
848
-                "@esbuild/linux-loong64": "0.17.18",
849
-                "@esbuild/linux-mips64el": "0.17.18",
850
-                "@esbuild/linux-ppc64": "0.17.18",
851
-                "@esbuild/linux-riscv64": "0.17.18",
852
-                "@esbuild/linux-s390x": "0.17.18",
853
-                "@esbuild/linux-x64": "0.17.18",
854
-                "@esbuild/netbsd-x64": "0.17.18",
855
-                "@esbuild/openbsd-x64": "0.17.18",
856
-                "@esbuild/sunos-x64": "0.17.18",
857
-                "@esbuild/win32-arm64": "0.17.18",
858
-                "@esbuild/win32-ia32": "0.17.18",
859
-                "@esbuild/win32-x64": "0.17.18"
838
+                "@esbuild/android-arm": "0.17.19",
839
+                "@esbuild/android-arm64": "0.17.19",
840
+                "@esbuild/android-x64": "0.17.19",
841
+                "@esbuild/darwin-arm64": "0.17.19",
842
+                "@esbuild/darwin-x64": "0.17.19",
843
+                "@esbuild/freebsd-arm64": "0.17.19",
844
+                "@esbuild/freebsd-x64": "0.17.19",
845
+                "@esbuild/linux-arm": "0.17.19",
846
+                "@esbuild/linux-arm64": "0.17.19",
847
+                "@esbuild/linux-ia32": "0.17.19",
848
+                "@esbuild/linux-loong64": "0.17.19",
849
+                "@esbuild/linux-mips64el": "0.17.19",
850
+                "@esbuild/linux-ppc64": "0.17.19",
851
+                "@esbuild/linux-riscv64": "0.17.19",
852
+                "@esbuild/linux-s390x": "0.17.19",
853
+                "@esbuild/linux-x64": "0.17.19",
854
+                "@esbuild/netbsd-x64": "0.17.19",
855
+                "@esbuild/openbsd-x64": "0.17.19",
856
+                "@esbuild/sunos-x64": "0.17.19",
857
+                "@esbuild/win32-arm64": "0.17.19",
858
+                "@esbuild/win32-ia32": "0.17.19",
859
+                "@esbuild/win32-x64": "0.17.19"
860
             }
860
             }
861
         },
861
         },
862
         "node_modules/escalade": {
862
         "node_modules/escalade": {
1072
             }
1072
             }
1073
         },
1073
         },
1074
         "node_modules/is-core-module": {
1074
         "node_modules/is-core-module": {
1075
-            "version": "2.12.0",
1076
-            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
1077
-            "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
1075
+            "version": "2.12.1",
1076
+            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
1077
+            "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
1078
             "dev": true,
1078
             "dev": true,
1079
             "dependencies": {
1079
             "dependencies": {
1080
                 "has": "^1.0.3"
1080
                 "has": "^1.0.3"
1123
             }
1123
             }
1124
         },
1124
         },
1125
         "node_modules/laravel-vite-plugin": {
1125
         "node_modules/laravel-vite-plugin": {
1126
-            "version": "0.7.4",
1127
-            "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.7.4.tgz",
1128
-            "integrity": "sha512-NlIuXbeuI+4NZzRpWNpGHRVTwuFWessvD7QoD+o2MlyAi7qyUS4J8r4/yTlu1dl9lxcR7iKoYUmHQqZDcrw2KA==",
1126
+            "version": "0.7.7",
1127
+            "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.7.7.tgz",
1128
+            "integrity": "sha512-/KsnyNUOMylBVLvGz1VlL1ukxyQeMQUz4zmnMflYe8fAWzLvjHDXnbh6fLgIrzAmevzNjYm/TUqmD5Io0+kqhg==",
1129
             "dev": true,
1129
             "dev": true,
1130
             "dependencies": {
1130
             "dependencies": {
1131
                 "picocolors": "^1.0.0",
1131
                 "picocolors": "^1.0.0",
1265
             }
1265
             }
1266
         },
1266
         },
1267
         "node_modules/node-releases": {
1267
         "node_modules/node-releases": {
1268
-            "version": "2.0.10",
1269
-            "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
1270
-            "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
1268
+            "version": "2.0.11",
1269
+            "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.11.tgz",
1270
+            "integrity": "sha512-+M0PwXeU80kRohZ3aT4J/OnR+l9/KD2nVLNNoRgFtnf+umQVFdGBAO2N8+nCnEi0xlh/Wk3zOGC+vNNx+uM79Q==",
1271
             "dev": true
1271
             "dev": true
1272
         },
1272
         },
1273
         "node_modules/normalize-path": {
1273
         "node_modules/normalize-path": {
1479
             }
1479
             }
1480
         },
1480
         },
1481
         "node_modules/postcss-nested/node_modules/postcss-selector-parser": {
1481
         "node_modules/postcss-nested/node_modules/postcss-selector-parser": {
1482
-            "version": "6.0.12",
1483
-            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz",
1484
-            "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==",
1482
+            "version": "6.0.13",
1483
+            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
1484
+            "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
1485
             "dev": true,
1485
             "dev": true,
1486
             "dependencies": {
1486
             "dependencies": {
1487
                 "cssesc": "^3.0.0",
1487
                 "cssesc": "^3.0.0",
1585
             }
1585
             }
1586
         },
1586
         },
1587
         "node_modules/rollup": {
1587
         "node_modules/rollup": {
1588
-            "version": "3.21.5",
1589
-            "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.5.tgz",
1590
-            "integrity": "sha512-a4NTKS4u9PusbUJcfF4IMxuqjFzjm6ifj76P54a7cKnvVzJaG12BLVR+hgU2YDGHzyMMQNxLAZWuALsn8q2oQg==",
1588
+            "version": "3.23.0",
1589
+            "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz",
1590
+            "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==",
1591
             "dev": true,
1591
             "dev": true,
1592
             "bin": {
1592
             "bin": {
1593
                 "rollup": "dist/bin/rollup"
1593
                 "rollup": "dist/bin/rollup"
1711
             }
1711
             }
1712
         },
1712
         },
1713
         "node_modules/tailwindcss/node_modules/postcss-selector-parser": {
1713
         "node_modules/tailwindcss/node_modules/postcss-selector-parser": {
1714
-            "version": "6.0.12",
1715
-            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz",
1716
-            "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==",
1714
+            "version": "6.0.13",
1715
+            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
1716
+            "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
1717
             "dev": true,
1717
             "dev": true,
1718
             "dependencies": {
1718
             "dependencies": {
1719
                 "cssesc": "^3.0.0",
1719
                 "cssesc": "^3.0.0",
1808
             "dev": true
1808
             "dev": true
1809
         },
1809
         },
1810
         "node_modules/vite": {
1810
         "node_modules/vite": {
1811
-            "version": "4.3.4",
1812
-            "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz",
1813
-            "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==",
1811
+            "version": "4.3.8",
1812
+            "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz",
1813
+            "integrity": "sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==",
1814
             "dev": true,
1814
             "dev": true,
1815
             "dependencies": {
1815
             "dependencies": {
1816
                 "esbuild": "^0.17.5",
1816
                 "esbuild": "^0.17.5",
1875
             "dev": true
1875
             "dev": true
1876
         },
1876
         },
1877
         "node_modules/yaml": {
1877
         "node_modules/yaml": {
1878
-            "version": "2.2.2",
1879
-            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
1880
-            "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
1878
+            "version": "2.3.0",
1879
+            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.0.tgz",
1880
+            "integrity": "sha512-8/1wgzdKc7bc9E6my5wZjmdavHLvO/QOmLG1FBugblEvY4IXrLjlViIOmL24HthU042lWTDRO90Fz1Yp66UnMw==",
1881
             "dev": true,
1881
             "dev": true,
1882
             "engines": {
1882
             "engines": {
1883
-                "node": ">= 14"
1883
+                "node": ">= 14",
1884
+                "npm": ">= 7"
1884
             }
1885
             }
1885
         }
1886
         }
1886
     },
1887
     },
1892
             "dev": true
1893
             "dev": true
1893
         },
1894
         },
1894
         "@alpinejs/focus": {
1895
         "@alpinejs/focus": {
1895
-            "version": "3.12.0",
1896
-            "resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.12.0.tgz",
1897
-            "integrity": "sha512-KfFS6W2Ao71e/zWMg5B51QR8Djocc2grDBhZ4VYNYFh5cUnb3TELQ3luY0kjl9phy2NToi52Gz360G889Pz1Bg==",
1896
+            "version": "3.12.1",
1897
+            "resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.12.1.tgz",
1898
+            "integrity": "sha512-8LXkzY9yHqTqsB+aqdY1SL4fv+IbMtn2vEwGPw3YFio0+vfS+hGnZS1E4aDkm+JIUUtQvqRbV3cnK2WRZkVGnA==",
1898
             "dev": true,
1899
             "dev": true,
1899
             "requires": {
1900
             "requires": {
1900
                 "focus-trap": "^6.6.1"
1901
                 "focus-trap": "^6.6.1"
1907
             "dev": true
1908
             "dev": true
1908
         },
1909
         },
1909
         "@esbuild/android-arm": {
1910
         "@esbuild/android-arm": {
1910
-            "version": "0.17.18",
1911
-            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz",
1912
-            "integrity": "sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==",
1911
+            "version": "0.17.19",
1912
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
1913
+            "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
1913
             "dev": true,
1914
             "dev": true,
1914
             "optional": true
1915
             "optional": true
1915
         },
1916
         },
1916
         "@esbuild/android-arm64": {
1917
         "@esbuild/android-arm64": {
1917
-            "version": "0.17.18",
1918
-            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz",
1919
-            "integrity": "sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==",
1918
+            "version": "0.17.19",
1919
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
1920
+            "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
1920
             "dev": true,
1921
             "dev": true,
1921
             "optional": true
1922
             "optional": true
1922
         },
1923
         },
1923
         "@esbuild/android-x64": {
1924
         "@esbuild/android-x64": {
1924
-            "version": "0.17.18",
1925
-            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.18.tgz",
1926
-            "integrity": "sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==",
1925
+            "version": "0.17.19",
1926
+            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
1927
+            "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
1927
             "dev": true,
1928
             "dev": true,
1928
             "optional": true
1929
             "optional": true
1929
         },
1930
         },
1930
         "@esbuild/darwin-arm64": {
1931
         "@esbuild/darwin-arm64": {
1931
-            "version": "0.17.18",
1932
-            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz",
1933
-            "integrity": "sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==",
1932
+            "version": "0.17.19",
1933
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
1934
+            "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
1934
             "dev": true,
1935
             "dev": true,
1935
             "optional": true
1936
             "optional": true
1936
         },
1937
         },
1937
         "@esbuild/darwin-x64": {
1938
         "@esbuild/darwin-x64": {
1938
-            "version": "0.17.18",
1939
-            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz",
1940
-            "integrity": "sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==",
1939
+            "version": "0.17.19",
1940
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
1941
+            "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
1941
             "dev": true,
1942
             "dev": true,
1942
             "optional": true
1943
             "optional": true
1943
         },
1944
         },
1944
         "@esbuild/freebsd-arm64": {
1945
         "@esbuild/freebsd-arm64": {
1945
-            "version": "0.17.18",
1946
-            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz",
1947
-            "integrity": "sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==",
1946
+            "version": "0.17.19",
1947
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
1948
+            "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
1948
             "dev": true,
1949
             "dev": true,
1949
             "optional": true
1950
             "optional": true
1950
         },
1951
         },
1951
         "@esbuild/freebsd-x64": {
1952
         "@esbuild/freebsd-x64": {
1952
-            "version": "0.17.18",
1953
-            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz",
1954
-            "integrity": "sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==",
1953
+            "version": "0.17.19",
1954
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
1955
+            "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
1955
             "dev": true,
1956
             "dev": true,
1956
             "optional": true
1957
             "optional": true
1957
         },
1958
         },
1958
         "@esbuild/linux-arm": {
1959
         "@esbuild/linux-arm": {
1959
-            "version": "0.17.18",
1960
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz",
1961
-            "integrity": "sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==",
1960
+            "version": "0.17.19",
1961
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
1962
+            "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
1962
             "dev": true,
1963
             "dev": true,
1963
             "optional": true
1964
             "optional": true
1964
         },
1965
         },
1965
         "@esbuild/linux-arm64": {
1966
         "@esbuild/linux-arm64": {
1966
-            "version": "0.17.18",
1967
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz",
1968
-            "integrity": "sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==",
1967
+            "version": "0.17.19",
1968
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
1969
+            "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
1969
             "dev": true,
1970
             "dev": true,
1970
             "optional": true
1971
             "optional": true
1971
         },
1972
         },
1972
         "@esbuild/linux-ia32": {
1973
         "@esbuild/linux-ia32": {
1973
-            "version": "0.17.18",
1974
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz",
1975
-            "integrity": "sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==",
1974
+            "version": "0.17.19",
1975
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
1976
+            "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
1976
             "dev": true,
1977
             "dev": true,
1977
             "optional": true
1978
             "optional": true
1978
         },
1979
         },
1979
         "@esbuild/linux-loong64": {
1980
         "@esbuild/linux-loong64": {
1980
-            "version": "0.17.18",
1981
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz",
1982
-            "integrity": "sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==",
1981
+            "version": "0.17.19",
1982
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
1983
+            "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
1983
             "dev": true,
1984
             "dev": true,
1984
             "optional": true
1985
             "optional": true
1985
         },
1986
         },
1986
         "@esbuild/linux-mips64el": {
1987
         "@esbuild/linux-mips64el": {
1987
-            "version": "0.17.18",
1988
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz",
1989
-            "integrity": "sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==",
1988
+            "version": "0.17.19",
1989
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
1990
+            "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
1990
             "dev": true,
1991
             "dev": true,
1991
             "optional": true
1992
             "optional": true
1992
         },
1993
         },
1993
         "@esbuild/linux-ppc64": {
1994
         "@esbuild/linux-ppc64": {
1994
-            "version": "0.17.18",
1995
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz",
1996
-            "integrity": "sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==",
1995
+            "version": "0.17.19",
1996
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
1997
+            "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
1997
             "dev": true,
1998
             "dev": true,
1998
             "optional": true
1999
             "optional": true
1999
         },
2000
         },
2000
         "@esbuild/linux-riscv64": {
2001
         "@esbuild/linux-riscv64": {
2001
-            "version": "0.17.18",
2002
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz",
2003
-            "integrity": "sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==",
2002
+            "version": "0.17.19",
2003
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
2004
+            "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
2004
             "dev": true,
2005
             "dev": true,
2005
             "optional": true
2006
             "optional": true
2006
         },
2007
         },
2007
         "@esbuild/linux-s390x": {
2008
         "@esbuild/linux-s390x": {
2008
-            "version": "0.17.18",
2009
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz",
2010
-            "integrity": "sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==",
2009
+            "version": "0.17.19",
2010
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
2011
+            "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
2011
             "dev": true,
2012
             "dev": true,
2012
             "optional": true
2013
             "optional": true
2013
         },
2014
         },
2014
         "@esbuild/linux-x64": {
2015
         "@esbuild/linux-x64": {
2015
-            "version": "0.17.18",
2016
-            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz",
2017
-            "integrity": "sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==",
2016
+            "version": "0.17.19",
2017
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
2018
+            "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
2018
             "dev": true,
2019
             "dev": true,
2019
             "optional": true
2020
             "optional": true
2020
         },
2021
         },
2021
         "@esbuild/netbsd-x64": {
2022
         "@esbuild/netbsd-x64": {
2022
-            "version": "0.17.18",
2023
-            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz",
2024
-            "integrity": "sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==",
2023
+            "version": "0.17.19",
2024
+            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
2025
+            "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
2025
             "dev": true,
2026
             "dev": true,
2026
             "optional": true
2027
             "optional": true
2027
         },
2028
         },
2028
         "@esbuild/openbsd-x64": {
2029
         "@esbuild/openbsd-x64": {
2029
-            "version": "0.17.18",
2030
-            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz",
2031
-            "integrity": "sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==",
2030
+            "version": "0.17.19",
2031
+            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
2032
+            "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
2032
             "dev": true,
2033
             "dev": true,
2033
             "optional": true
2034
             "optional": true
2034
         },
2035
         },
2035
         "@esbuild/sunos-x64": {
2036
         "@esbuild/sunos-x64": {
2036
-            "version": "0.17.18",
2037
-            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz",
2038
-            "integrity": "sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==",
2037
+            "version": "0.17.19",
2038
+            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
2039
+            "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
2039
             "dev": true,
2040
             "dev": true,
2040
             "optional": true
2041
             "optional": true
2041
         },
2042
         },
2042
         "@esbuild/win32-arm64": {
2043
         "@esbuild/win32-arm64": {
2043
-            "version": "0.17.18",
2044
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz",
2045
-            "integrity": "sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==",
2044
+            "version": "0.17.19",
2045
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
2046
+            "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
2046
             "dev": true,
2047
             "dev": true,
2047
             "optional": true
2048
             "optional": true
2048
         },
2049
         },
2049
         "@esbuild/win32-ia32": {
2050
         "@esbuild/win32-ia32": {
2050
-            "version": "0.17.18",
2051
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz",
2052
-            "integrity": "sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==",
2051
+            "version": "0.17.19",
2052
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
2053
+            "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
2053
             "dev": true,
2054
             "dev": true,
2054
             "optional": true
2055
             "optional": true
2055
         },
2056
         },
2056
         "@esbuild/win32-x64": {
2057
         "@esbuild/win32-x64": {
2057
-            "version": "0.17.18",
2058
-            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz",
2059
-            "integrity": "sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==",
2058
+            "version": "0.17.19",
2059
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
2060
+            "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
2060
             "dev": true,
2061
             "dev": true,
2061
             "optional": true
2062
             "optional": true
2062
         },
2063
         },
2176
             "dev": true
2177
             "dev": true
2177
         },
2178
         },
2178
         "alpinejs": {
2179
         "alpinejs": {
2179
-            "version": "3.12.0",
2180
-            "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.12.0.tgz",
2181
-            "integrity": "sha512-YENcRBA9dlwR8PsZNFMTHbmdlTNwd1BkCeivPvOzzCKHas6AfwNRsDK9UEFmE5dXTMEZjnnpCTxV8vkdpWiOCw==",
2180
+            "version": "3.12.1",
2181
+            "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.12.1.tgz",
2182
+            "integrity": "sha512-GjEmZscHuCPv/XRbzabQLFH3I1+M3TbZqEsLDuYai/Yw+pE1IL7DK4ejRfqBSaysi4wWZ1k5IqVG2aefhWWqsQ==",
2182
             "dev": true,
2183
             "dev": true,
2183
             "requires": {
2184
             "requires": {
2184
                 "@vue/reactivity": "~3.1.1"
2185
                 "@vue/reactivity": "~3.1.1"
2287
             "dev": true
2288
             "dev": true
2288
         },
2289
         },
2289
         "caniuse-lite": {
2290
         "caniuse-lite": {
2290
-            "version": "1.0.30001482",
2291
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz",
2292
-            "integrity": "sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ==",
2291
+            "version": "1.0.30001489",
2292
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz",
2293
+            "integrity": "sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ==",
2293
             "dev": true
2294
             "dev": true
2294
         },
2295
         },
2295
         "chokidar": {
2296
         "chokidar": {
2365
             "dev": true
2366
             "dev": true
2366
         },
2367
         },
2367
         "electron-to-chromium": {
2368
         "electron-to-chromium": {
2368
-            "version": "1.4.383",
2369
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.383.tgz",
2370
-            "integrity": "sha512-BQyvFauIMzCJqILViJNs0kIBEAlx1bYLS5CRLyJtlun1KAnZlhNSgyfyWifPWagQ5s8KYPY6BpNHZsEMkxZAQQ==",
2369
+            "version": "1.4.405",
2370
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.405.tgz",
2371
+            "integrity": "sha512-JdDgnwU69FMZURoesf9gNOej2Cms1XJFfLk24y1IBtnAdhTcJY/mXnokmpmxHN59PcykBP4bgUU98vLY44Lhuw==",
2371
             "dev": true
2372
             "dev": true
2372
         },
2373
         },
2373
         "esbuild": {
2374
         "esbuild": {
2374
-            "version": "0.17.18",
2375
-            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz",
2376
-            "integrity": "sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==",
2375
+            "version": "0.17.19",
2376
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
2377
+            "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
2377
             "dev": true,
2378
             "dev": true,
2378
             "requires": {
2379
             "requires": {
2379
-                "@esbuild/android-arm": "0.17.18",
2380
-                "@esbuild/android-arm64": "0.17.18",
2381
-                "@esbuild/android-x64": "0.17.18",
2382
-                "@esbuild/darwin-arm64": "0.17.18",
2383
-                "@esbuild/darwin-x64": "0.17.18",
2384
-                "@esbuild/freebsd-arm64": "0.17.18",
2385
-                "@esbuild/freebsd-x64": "0.17.18",
2386
-                "@esbuild/linux-arm": "0.17.18",
2387
-                "@esbuild/linux-arm64": "0.17.18",
2388
-                "@esbuild/linux-ia32": "0.17.18",
2389
-                "@esbuild/linux-loong64": "0.17.18",
2390
-                "@esbuild/linux-mips64el": "0.17.18",
2391
-                "@esbuild/linux-ppc64": "0.17.18",
2392
-                "@esbuild/linux-riscv64": "0.17.18",
2393
-                "@esbuild/linux-s390x": "0.17.18",
2394
-                "@esbuild/linux-x64": "0.17.18",
2395
-                "@esbuild/netbsd-x64": "0.17.18",
2396
-                "@esbuild/openbsd-x64": "0.17.18",
2397
-                "@esbuild/sunos-x64": "0.17.18",
2398
-                "@esbuild/win32-arm64": "0.17.18",
2399
-                "@esbuild/win32-ia32": "0.17.18",
2400
-                "@esbuild/win32-x64": "0.17.18"
2380
+                "@esbuild/android-arm": "0.17.19",
2381
+                "@esbuild/android-arm64": "0.17.19",
2382
+                "@esbuild/android-x64": "0.17.19",
2383
+                "@esbuild/darwin-arm64": "0.17.19",
2384
+                "@esbuild/darwin-x64": "0.17.19",
2385
+                "@esbuild/freebsd-arm64": "0.17.19",
2386
+                "@esbuild/freebsd-x64": "0.17.19",
2387
+                "@esbuild/linux-arm": "0.17.19",
2388
+                "@esbuild/linux-arm64": "0.17.19",
2389
+                "@esbuild/linux-ia32": "0.17.19",
2390
+                "@esbuild/linux-loong64": "0.17.19",
2391
+                "@esbuild/linux-mips64el": "0.17.19",
2392
+                "@esbuild/linux-ppc64": "0.17.19",
2393
+                "@esbuild/linux-riscv64": "0.17.19",
2394
+                "@esbuild/linux-s390x": "0.17.19",
2395
+                "@esbuild/linux-x64": "0.17.19",
2396
+                "@esbuild/netbsd-x64": "0.17.19",
2397
+                "@esbuild/openbsd-x64": "0.17.19",
2398
+                "@esbuild/sunos-x64": "0.17.19",
2399
+                "@esbuild/win32-arm64": "0.17.19",
2400
+                "@esbuild/win32-ia32": "0.17.19",
2401
+                "@esbuild/win32-x64": "0.17.19"
2401
             }
2402
             }
2402
         },
2403
         },
2403
         "escalade": {
2404
         "escalade": {
2557
             }
2558
             }
2558
         },
2559
         },
2559
         "is-core-module": {
2560
         "is-core-module": {
2560
-            "version": "2.12.0",
2561
-            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
2562
-            "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
2561
+            "version": "2.12.1",
2562
+            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
2563
+            "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
2563
             "dev": true,
2564
             "dev": true,
2564
             "requires": {
2565
             "requires": {
2565
                 "has": "^1.0.3"
2566
                 "has": "^1.0.3"
2593
             "dev": true
2594
             "dev": true
2594
         },
2595
         },
2595
         "laravel-vite-plugin": {
2596
         "laravel-vite-plugin": {
2596
-            "version": "0.7.4",
2597
-            "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.7.4.tgz",
2598
-            "integrity": "sha512-NlIuXbeuI+4NZzRpWNpGHRVTwuFWessvD7QoD+o2MlyAi7qyUS4J8r4/yTlu1dl9lxcR7iKoYUmHQqZDcrw2KA==",
2597
+            "version": "0.7.7",
2598
+            "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.7.7.tgz",
2599
+            "integrity": "sha512-/KsnyNUOMylBVLvGz1VlL1ukxyQeMQUz4zmnMflYe8fAWzLvjHDXnbh6fLgIrzAmevzNjYm/TUqmD5Io0+kqhg==",
2599
             "dev": true,
2600
             "dev": true,
2600
             "requires": {
2601
             "requires": {
2601
                 "picocolors": "^1.0.0",
2602
                 "picocolors": "^1.0.0",
2696
             "dev": true
2697
             "dev": true
2697
         },
2698
         },
2698
         "node-releases": {
2699
         "node-releases": {
2699
-            "version": "2.0.10",
2700
-            "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
2701
-            "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
2700
+            "version": "2.0.11",
2701
+            "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.11.tgz",
2702
+            "integrity": "sha512-+M0PwXeU80kRohZ3aT4J/OnR+l9/KD2nVLNNoRgFtnf+umQVFdGBAO2N8+nCnEi0xlh/Wk3zOGC+vNNx+uM79Q==",
2702
             "dev": true
2703
             "dev": true
2703
         },
2704
         },
2704
         "normalize-path": {
2705
         "normalize-path": {
2821
             },
2822
             },
2822
             "dependencies": {
2823
             "dependencies": {
2823
                 "postcss-selector-parser": {
2824
                 "postcss-selector-parser": {
2824
-                    "version": "6.0.12",
2825
-                    "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz",
2826
-                    "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==",
2825
+                    "version": "6.0.13",
2826
+                    "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
2827
+                    "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
2827
                     "dev": true,
2828
                     "dev": true,
2828
                     "requires": {
2829
                     "requires": {
2829
                         "cssesc": "^3.0.0",
2830
                         "cssesc": "^3.0.0",
2896
             "dev": true
2897
             "dev": true
2897
         },
2898
         },
2898
         "rollup": {
2899
         "rollup": {
2899
-            "version": "3.21.5",
2900
-            "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.5.tgz",
2901
-            "integrity": "sha512-a4NTKS4u9PusbUJcfF4IMxuqjFzjm6ifj76P54a7cKnvVzJaG12BLVR+hgU2YDGHzyMMQNxLAZWuALsn8q2oQg==",
2900
+            "version": "3.23.0",
2901
+            "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz",
2902
+            "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==",
2902
             "dev": true,
2903
             "dev": true,
2903
             "requires": {
2904
             "requires": {
2904
                 "fsevents": "~2.3.2"
2905
                 "fsevents": "~2.3.2"
2978
             },
2979
             },
2979
             "dependencies": {
2980
             "dependencies": {
2980
                 "postcss-selector-parser": {
2981
                 "postcss-selector-parser": {
2981
-                    "version": "6.0.12",
2982
-                    "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz",
2983
-                    "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==",
2982
+                    "version": "6.0.13",
2983
+                    "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
2984
+                    "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
2984
                     "dev": true,
2985
                     "dev": true,
2985
                     "requires": {
2986
                     "requires": {
2986
                         "cssesc": "^3.0.0",
2987
                         "cssesc": "^3.0.0",
3048
             "dev": true
3049
             "dev": true
3049
         },
3050
         },
3050
         "vite": {
3051
         "vite": {
3051
-            "version": "4.3.4",
3052
-            "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz",
3053
-            "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==",
3052
+            "version": "4.3.8",
3053
+            "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz",
3054
+            "integrity": "sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==",
3054
             "dev": true,
3055
             "dev": true,
3055
             "requires": {
3056
             "requires": {
3056
                 "esbuild": "^0.17.5",
3057
                 "esbuild": "^0.17.5",
3076
             "dev": true
3077
             "dev": true
3077
         },
3078
         },
3078
         "yaml": {
3079
         "yaml": {
3079
-            "version": "2.2.2",
3080
-            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
3081
-            "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
3080
+            "version": "2.3.0",
3081
+            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.0.tgz",
3082
+            "integrity": "sha512-8/1wgzdKc7bc9E6my5wZjmdavHLvO/QOmLG1FBugblEvY4IXrLjlViIOmL24HthU042lWTDRO90Fz1Yp66UnMw==",
3082
             "dev": true
3083
             "dev": true
3083
         }
3084
         }
3084
     }
3085
     }

Loading…
取消
儲存