Pārlūkot izejas kodu

wip: Accounting Module

3.x
wallo 2 gadus atpakaļ
vecāks
revīzija
df54a41330
34 mainītis faili ar 496 papildinājumiem un 234 dzēšanām
  1. 3
    6
      app/Filament/Resources/AccountResource.php
  2. 47
    31
      app/Filament/Resources/CurrencyResource.php
  3. 4
    8
      app/Filament/Resources/CustomerResource.php
  4. 2
    1
      app/Filament/Resources/InvoiceResource.php
  5. 17
    1
      app/Http/Livewire/DefaultSetting.php
  6. 0
    16
      app/Models/Banking/Account.php
  7. 9
    0
      app/Models/Setting/Currency.php
  8. 48
    0
      app/Models/Setting/DefaultSetting.php
  9. 0
    67
      app/Observers/AccountObserver.php
  10. 67
    0
      app/Policies/CurrencyPolicy.php
  11. 0
    11
      app/Providers/EventServiceProvider.php
  12. 55
    0
      app/Services/CurrencyService.php
  13. 6
    6
      composer.lock
  14. 11
    48
      database/factories/CurrencyFactory.php
  15. 2
    1
      database/factories/DefaultSettingFactory.php
  16. 9
    1
      database/factories/DiscountFactory.php
  17. 1
    0
      database/factories/TaxFactory.php
  18. 1
    1
      database/migrations/2023_05_10_040940_create_currencies_table.php
  19. 1
    1
      database/migrations/2023_05_11_044321_create_accounts_table.php
  20. 1
    1
      database/migrations/2023_05_12_042255_create_categories_table.php
  21. 2
    2
      database/migrations/2023_05_19_042232_create_contacts_table.php
  22. 4
    4
      database/migrations/2023_05_20_080131_create_taxes_table.php
  23. 4
    4
      database/migrations/2023_05_21_163808_create_discounts_table.php
  24. 4
    4
      database/migrations/2023_05_22_073252_create_items_table.php
  25. 4
    4
      database/migrations/2023_05_23_141215_create_documents_table.php
  26. 3
    3
      database/migrations/2023_05_23_151550_create_document_items_table.php
  27. 4
    4
      database/migrations/2023_05_23_173412_create_document_totals_table.php
  28. 2
    0
      database/migrations/2023_07_03_054805_create_default_settings_table.php
  29. 0
    1
      database/seeders/AccountSeeder.php
  30. 0
    1
      database/seeders/CategorySeeder.php
  31. 9
    4
      database/seeders/CurrencySeeder.php
  32. 111
    0
      database/seeders/DatabaseSeeder.php
  33. 65
    0
      database/seeders/DiscountSeeder.php
  34. 0
    3
      database/seeders/TaxSeeder.php

+ 3
- 6
app/Filament/Resources/AccountResource.php Parādīt failu

@@ -2,12 +2,11 @@
2 2
 
3 3
 namespace App\Filament\Resources;
4 4
 
5
-use Akaunting\Money\Currency;
6
-use Akaunting\Money\Money;
7 5
 use App\Actions\Banking\CreateCurrencyFromAccount;
8 6
 use App\Filament\Resources\AccountResource\Pages;
9 7
 use App\Filament\Resources\AccountResource\RelationManagers;
10 8
 use App\Models\Banking\Account;
9
+use App\Models\Setting\Currency;
11 10
 use Closure;
12 11
 use Exception;
13 12
 use Filament\Forms;
@@ -18,8 +17,6 @@ use Filament\Resources\Resource;
18 17
 use Filament\Resources\Table;
19 18
 use Filament\Tables;
20 19
 use Illuminate\Database\Eloquent\Builder;
21
-use Illuminate\Database\Eloquent\Model;
22
-use Illuminate\Database\Eloquent\SoftDeletingScope;
23 20
 use Illuminate\Support\Collection;
24 21
 use Illuminate\Support\Facades\Auth;
25 22
 use Illuminate\Support\Facades\DB;
@@ -81,7 +78,7 @@ class AccountResource extends Resource
81 78
                                     ->label('Currency')
82 79
                                     ->relationship('currency', 'name', static fn (Builder $query) => $query->where('company_id', Auth::user()->currentCompany->id))
83 80
                                     ->preload()
84
-                                    ->default(Account::getDefaultCurrencyCode())
81
+                                    ->default(Currency::getDefaultCurrency())
85 82
                                     ->searchable()
86 83
                                     ->reactive()
87 84
                                     ->required()
@@ -89,7 +86,7 @@ class AccountResource extends Resource
89 86
                                         Forms\Components\Select::make('currency.code')
90 87
                                             ->label('Code')
91 88
                                             ->searchable()
92
-                                            ->options(Account::getCurrencyCodes())
89
+                                            ->options(Currency::getCurrencyCodes())
93 90
                                             ->reactive()
94 91
                                             ->afterStateUpdated(static function (callable $set, $state) {
95 92
                                                 $code = $state;

+ 47
- 31
app/Filament/Resources/CurrencyResource.php Parādīt failu

@@ -6,6 +6,7 @@ use App\Filament\Resources\CurrencyResource\Pages;
6 6
 use App\Filament\Resources\CurrencyResource\RelationManagers;
7 7
 use App\Models\Banking\Account;
8 8
 use App\Models\Setting\Currency;
9
+use App\Services\CurrencyService;
9 10
 use Closure;
10 11
 use Exception;
11 12
 use Filament\Forms;
@@ -15,12 +16,9 @@ use Filament\Resources\Resource;
15 16
 use Filament\Resources\Table;
16 17
 use Filament\Tables;
17 18
 use Illuminate\Database\Eloquent\Builder;
18
-use Illuminate\Database\Eloquent\Model;
19
-use Illuminate\Database\Eloquent\SoftDeletingScope;
20 19
 use Illuminate\Support\Collection;
21 20
 use Illuminate\Support\Facades\Auth;
22
-use Illuminate\Support\Facades\Blade;
23
-use Illuminate\Support\HtmlString;
21
+use Illuminate\Support\Facades\Cache;
24 22
 use Wallo\FilamentSelectify\Components\ToggleButton;
25 23
 
26 24
 class CurrencyResource extends Resource
@@ -41,7 +39,7 @@ class CurrencyResource extends Resource
41 39
         return $form
42 40
             ->schema([
43 41
                 Forms\Components\Section::make('General')
44
-                    ->description('The default currency is used for all transactions and reports and cannot be deleted. Currency precision determines the number of decimal places to display when formatting currency amounts. The currency rate is set to 1 for the default currency and is utilized as the basis for setting exchange rates for all other currencies.')
42
+                    ->description('Upon selecting a currency code, the corresponding values based on real-world currencies will auto-populate. The default currency is used for all transactions and reports and cannot be deleted. Currency precision determines the number of decimal places to display when formatting currency amounts. The currency rate is set to 1 for the default currency and is utilized as the basis for setting exchange rates for all other currencies. Alterations to default values are allowed but manage such changes wisely as any confusion or discrepancies are your responsibility.')
45 43
                     ->schema([
46 44
                         Forms\Components\Select::make('code')
47 45
                             ->label('Code')
@@ -49,42 +47,48 @@ class CurrencyResource extends Resource
49 47
                             ->searchable()
50 48
                             ->placeholder('Select a currency code...')
51 49
                             ->reactive()
50
+                            ->hidden(static fn (Closure $get): bool => $get('enabled'))
52 51
                             ->afterStateUpdated(static function (Closure $set, $state) {
52
+                                if ($state === null) {
53
+                                    return;
54
+                                }
55
+
53 56
                                 $code = $state;
54
-                                $name = config("money.{$code}.name");
55
-                                $precision = config("money.{$code}.precision");
56
-                                $symbol = config("money.{$code}.symbol");
57
-                                $symbol_first = config("money.{$code}.symbol_first");
58
-                                $decimal_mark = config("money.{$code}.decimal_mark");
59
-                                $thousands_separator = config("money.{$code}.thousands_separator");
60
-
61
-                                $set('name', $name);
62
-                                $set('precision', $precision);
63
-                                $set('symbol', $symbol);
64
-                                $set('symbol_first', $symbol_first);
65
-                                $set('decimal_mark', $decimal_mark);
66
-                                $set('thousands_separator', $thousands_separator);
57
+                                $currencyConfig = config("money.{$code}", []);
58
+                                $currencyService = app(CurrencyService::class);
59
+
60
+                                $defaultCurrency = Currency::getDefaultCurrency();
61
+
62
+                                $rate = 1;
63
+
64
+                                if ($defaultCurrency !== null) {
65
+                                   $rate = $currencyService->getCachedExchangeRate($defaultCurrency, $code);
66
+                                }
67
+
68
+                                $set('name', $currencyConfig['name'] ?? '');
69
+                                $set('rate', $rate);
70
+                                $set('precision', $currencyConfig['precision'] ?? '');
71
+                                $set('symbol', $currencyConfig['symbol'] ?? '');
72
+                                $set('symbol_first', $currencyConfig['symbol_first'] ?? '');
73
+                                $set('decimal_mark', $currencyConfig['decimal_mark'] ?? '');
74
+                                $set('thousands_separator', $currencyConfig['thousands_separator'] ?? '');
67 75
                             })
68 76
                             ->required(),
77
+                        Forms\Components\TextInput::make('code')
78
+                            ->label('Code')
79
+                            ->hidden(static fn (Closure $get): bool => !$get('enabled'))
80
+                            ->disabled(static fn (Closure $get): bool => $get('enabled'))
81
+                            ->required(),
69 82
                         Forms\Components\TextInput::make('name')
70 83
                             ->translateLabel()
71 84
                             ->maxLength(100)
72 85
                             ->required(),
73 86
                         Forms\Components\TextInput::make('rate')
74 87
                             ->label('Rate')
75
-                            ->dehydrateStateUsing(static fn (Closure $get, $state): bool => $get('enabled') === true ? '1' : $state) // rate is 1 when enabled is true
88
+                            ->dehydrateStateUsing(static fn (Closure $get, $state) => $get('enabled') ? '1' : $state)
76 89
                             ->numeric()
77 90
                             ->reactive()
78
-                            ->disabled(static fn (Closure $get): bool => $get('enabled') === true) // disabled is true when enabled is true
79
-                            ->mask(static fn (Forms\Components\TextInput\Mask $mask) => $mask
80
-                                ->numeric()
81
-                                ->decimalPlaces(4)
82
-                                ->signed(false)
83
-                                ->padFractionalZeros(false)
84
-                                ->normalizeZeros(false)
85
-                                ->minValue(0.0001)
86
-                                ->maxValue(999999.9999)
87
-                                ->lazyPlaceholder(false))
91
+                            ->disabled(static fn (Closure $get): bool => $get('enabled'))
88 92
                             ->required(),
89 93
                         Forms\Components\Select::make('precision')
90 94
                             ->label('Precision')
@@ -114,7 +118,20 @@ class CurrencyResource extends Resource
114 118
                             ->reactive()
115 119
                             ->offColor('danger')
116 120
                             ->onColor('primary')
117
-                            ->afterStateUpdated(static fn (Closure $set, $state) => $state ? $set('rate', '1') : null),
121
+                            ->afterStateUpdated(static function (Closure $set, Closure $get, $state) {
122
+                                $enabled = $state;
123
+                                $code = $get('code');
124
+                                $currencyService = app(CurrencyService::class);
125
+
126
+                                if ($enabled) {
127
+                                    $rate = 1;
128
+                                } else {
129
+                                    $defaultCurrency = Currency::getDefaultCurrency();
130
+                                    $rate = $defaultCurrency ? $currencyService->getCachedExchangeRate($defaultCurrency, $code) : 1;
131
+                                }
132
+
133
+                                $set('rate', $rate);
134
+                            }),
118 135
                     ])->columns(),
119 136
             ]);
120 137
     }
@@ -144,7 +161,6 @@ class CurrencyResource extends Resource
144 161
                     ->sortable(),
145 162
                 Tables\Columns\TextColumn::make('rate')
146 163
                     ->label('Rate')
147
-                    ->formatStateUsing(static fn ($state) => str_contains($state, '.') ? rtrim(rtrim($state, '0'), '.') : null)
148 164
                     ->searchable()
149 165
                     ->sortable(),
150 166
             ])

+ 4
- 8
app/Filament/Resources/CustomerResource.php Parādīt failu

@@ -5,8 +5,8 @@ namespace App\Filament\Resources;
5 5
 use App\Actions\Banking\CreateCurrencyFromAccount;
6 6
 use App\Filament\Resources\CustomerResource\Pages;
7 7
 use App\Filament\Resources\CustomerResource\RelationManagers;
8
+use App\Models\Setting\Currency;
8 9
 use Wallo\FilamentSelectify\Components\ButtonGroup;
9
-use App\Models\Banking\Account;
10 10
 use App\Models\Contact;
11 11
 use Filament\Forms;
12 12
 use Filament\Resources\Form;
@@ -14,11 +14,8 @@ use Filament\Resources\Resource;
14 14
 use Filament\Resources\Table;
15 15
 use Filament\Tables;
16 16
 use Illuminate\Database\Eloquent\Builder;
17
-use Illuminate\Database\Eloquent\SoftDeletingScope;
18 17
 use Illuminate\Support\Facades\Auth;
19 18
 use Illuminate\Support\Facades\DB;
20
-use Squire\Models\Country;
21
-use Squire\Models\Region;
22 19
 
23 20
 class CustomerResource extends Resource
24 21
 {
@@ -55,8 +52,7 @@ class CustomerResource extends Resource
55 52
                                     ])
56 53
                                     ->gridDirection('column')
57 54
                                     ->default('individual')
58
-                                    ->columnSpan(1)
59
-                                    ->required(),
55
+                                    ->columnSpan(1),
60 56
                                 Forms\Components\Grid::make()
61 57
                                     ->schema([
62 58
                                         Forms\Components\TextInput::make('name')
@@ -94,7 +90,7 @@ class CustomerResource extends Resource
94 90
                             ->label('Currency')
95 91
                             ->relationship('currency', 'name', static fn (Builder $query) => $query->where('company_id', Auth::user()->currentCompany->id))
96 92
                             ->preload()
97
-                            ->default(Account::getDefaultCurrencyCode())
93
+                            ->default(Currency::getDefaultCurrency())
98 94
                             ->searchable()
99 95
                             ->reactive()
100 96
                             ->required()
@@ -102,7 +98,7 @@ class CustomerResource extends Resource
102 98
                                 Forms\Components\Select::make('currency.code')
103 99
                                     ->label('Code')
104 100
                                     ->searchable()
105
-                                    ->options(Account::getCurrencyCodes())
101
+                                    ->options(Currency::getCurrencyCodes())
106 102
                                     ->reactive()
107 103
                                     ->afterStateUpdated(static function (callable $set, $state) {
108 104
                                         $code = $state;

+ 2
- 1
app/Filament/Resources/InvoiceResource.php Parādīt failu

@@ -4,6 +4,7 @@ namespace App\Filament\Resources;
4 4
 
5 5
 use App\Filament\Resources\InvoiceResource\Pages;
6 6
 use App\Filament\Resources\InvoiceResource\RelationManagers;
7
+use App\Models\Setting\Currency;
7 8
 use Wallo\FilamentSelectify\Components\ButtonGroup;
8 9
 use App\Models\Banking\Account;
9 10
 use App\Models\Document\Document;
@@ -75,7 +76,7 @@ class InvoiceResource extends Resource
75 76
                                             ->label('Currency')
76 77
                                             ->relationship('currency', 'name', static fn (Builder $query) => $query->where('company_id', Auth::user()->currentCompany->id))
77 78
                                             ->preload()
78
-                                            ->default(Account::getDefaultCurrencyCode())
79
+                                            ->default(Currency::getDefaultCurrency())
79 80
                                             ->searchable()
80 81
                                             ->reactive()
81 82
                                             ->required(),

+ 17
- 1
app/Http/Livewire/DefaultSetting.php Parādīt failu

@@ -56,7 +56,7 @@ class DefaultSetting extends Component implements HasForms
56 56
                         ->validationAttribute('Currency')
57 57
                         ->required(),
58 58
                 ])->columns(),
59
-            Section::make('Taxes')
59
+            Section::make('Taxes & Discounts')
60 60
                 ->schema([
61 61
                     Select::make('sales_tax_id')
62 62
                         ->label('Sales Tax')
@@ -72,6 +72,20 @@ class DefaultSetting extends Component implements HasForms
72 72
                         ->searchable()
73 73
                         ->validationAttribute('Purchase Tax')
74 74
                         ->required(),
75
+                    Select::make('sales_discount_id')
76
+                        ->label('Sales Discount')
77
+                        ->options(Defaults::getSalesDiscounts())
78
+                        ->default(Defaults::getDefaultSalesDiscount())
79
+                        ->searchable()
80
+                        ->validationAttribute('Sales Discount')
81
+                        ->required(),
82
+                    Select::make('purchase_discount_id')
83
+                        ->label('Purchase Discount')
84
+                        ->options(Defaults::getPurchaseDiscounts())
85
+                        ->default(Defaults::getDefaultPurchaseDiscount())
86
+                        ->searchable()
87
+                        ->validationAttribute('Purchase Discount')
88
+                        ->required(),
75 89
                 ])->columns(),
76 90
             Section::make('Categories')
77 91
                 ->schema([
@@ -121,6 +135,8 @@ class DefaultSetting extends Component implements HasForms
121 135
             'currency_code' => [Currency::class, 'code'],
122 136
             'sales_tax_id' => [Tax::class, 'id', 'sales'],
123 137
             'purchase_tax_id' => [Tax::class, 'id', 'purchase'],
138
+            'sales_discount_id' => [Tax::class, 'id', 'sales'],
139
+            'purchase_discount_id' => [Tax::class, 'id', 'purchase'],
124 140
             'income_category_id' => [Category::class, 'id', 'income'],
125 141
             'expense_category_id' => [Category::class, 'id', 'expense'],
126 142
         ];

+ 0
- 16
app/Models/Banking/Account.php Parādīt failu

@@ -101,22 +101,6 @@ class Account extends Model
101 101
         ];
102 102
     }
103 103
 
104
-    public static function getCurrencyCodes(): array
105
-    {
106
-        $codes = array_keys(Config::get('money'));
107
-
108
-        return array_combine($codes, $codes);
109
-    }
110
-
111
-    public static function getDefaultCurrencyCode(): ?string
112
-    {
113
-        $defaultCurrency = Currency::where('enabled', true)
114
-            ->where('company_id', Auth::user()->currentCompany->id)
115
-            ->first();
116
-
117
-        return $defaultCurrency?->code;
118
-    }
119
-
120 104
     protected static function newFactory(): Factory
121 105
     {
122 106
         return AccountFactory::new();

+ 9
- 0
app/Models/Setting/Currency.php Parādīt failu

@@ -63,6 +63,15 @@ class Currency extends Model
63 63
         return array_combine($codes, $codes);
64 64
     }
65 65
 
66
+    public static function getDefaultCurrency(): ?string
67
+    {
68
+        $defaultCurrency = self::where('enabled', true)
69
+            ->where('company_id', Auth::user()->currentCompany->id)
70
+            ->first();
71
+
72
+        return $defaultCurrency->code ?? null;
73
+    }
74
+
66 75
     protected static function newFactory(): Factory
67 76
     {
68 77
         return CurrencyFactory::new();

+ 48
- 0
app/Models/Setting/DefaultSetting.php Parādīt failu

@@ -21,6 +21,8 @@ class DefaultSetting extends Model
21 21
         'currency_code',
22 22
         'sales_tax_id',
23 23
         'purchase_tax_id',
24
+        'sales_discount_id',
25
+        'purchase_discount_id',
24 26
         'income_category_id',
25 27
         'expense_category_id',
26 28
         'updated_by',
@@ -51,6 +53,16 @@ class DefaultSetting extends Model
51 53
         return $this->belongsTo(Tax::class,'purchase_tax_id', 'id');
52 54
     }
53 55
 
56
+    public function salesDiscount(): BelongsTo
57
+    {
58
+        return $this->belongsTo(Discount::class,'sales_discount_id', 'id');
59
+    }
60
+
61
+    public function purchaseDiscount(): BelongsTo
62
+    {
63
+        return $this->belongsTo(Discount::class,'purchase_discount_id', 'id');
64
+    }
65
+
54 66
     public function incomeCategory(): BelongsTo
55 67
     {
56 68
         return $this->belongsTo(Category::class,'income_category_id', 'id');
@@ -96,6 +108,22 @@ class DefaultSetting extends Model
96 108
             ->toArray();
97 109
     }
98 110
 
111
+    public static function getSalesDiscounts(): array
112
+    {
113
+        return Discount::where('company_id', Auth::user()->currentCompany->id)
114
+            ->where('type', 'sales')
115
+            ->pluck('name', 'id')
116
+            ->toArray();
117
+    }
118
+
119
+    public static function getPurchaseDiscounts(): array
120
+    {
121
+        return Discount::where('company_id', Auth::user()->currentCompany->id)
122
+            ->where('type', 'purchase')
123
+            ->pluck('name', 'id')
124
+            ->toArray();
125
+    }
126
+
99 127
     public static function getIncomeCategories(): array
100 128
     {
101 129
         return Category::where('company_id', Auth::user()->currentCompany->id)
@@ -150,6 +178,26 @@ class DefaultSetting extends Model
150 178
         return $defaultPurchaseTax->id ?? null;
151 179
     }
152 180
 
181
+    public static function getDefaultSalesDiscount()
182
+    {
183
+        $defaultSalesDiscount = Discount::where('enabled', true)
184
+            ->where('company_id', Auth::user()->currentCompany->id)
185
+            ->where('type', 'sales')
186
+            ->first();
187
+
188
+        return $defaultSalesDiscount->id ?? null;
189
+    }
190
+
191
+    public static function getDefaultPurchaseDiscount()
192
+    {
193
+        $defaultPurchaseDiscount = Discount::where('enabled', true)
194
+            ->where('company_id', Auth::user()->currentCompany->id)
195
+            ->where('type', 'purchase')
196
+            ->first();
197
+
198
+        return $defaultPurchaseDiscount->id ?? null;
199
+    }
200
+
153 201
     public static function getDefaultIncomeCategory()
154 202
     {
155 203
         $defaultIncomeCategory = Category::where('enabled', true)

+ 0
- 67
app/Observers/AccountObserver.php Parādīt failu

@@ -1,67 +0,0 @@
1
-<?php
2
-
3
-namespace App\Observers;
4
-
5
-use App\Models\Banking\Account;
6
-use Illuminate\Support\Facades\Auth;
7
-
8
-class AccountObserver
9
-{
10
-    /**
11
-     * Handle the account "creating" event.
12
-     */
13
-    public function creating(Account $account): void
14
-    {
15
-        $account->company()->associate(Auth::user()->currentCompany->id);
16
-        $account->company_id = Auth::user()->currentCompany->id;
17
-        $account->created_by = Auth::id();
18
-    }
19
-
20
-    /**
21
-     * Handle the Account "created" event.
22
-     */
23
-    public function created(Account $account): void
24
-    {
25
-        //
26
-    }
27
-
28
-    /**
29
-     * Handle the Account "updating" event.
30
-     */
31
-    public function updating(Account $account): void
32
-    {
33
-        $account->updated_by = Auth::id();
34
-    }
35
-
36
-    /**
37
-     * Handle the Account "updated" event.
38
-     */
39
-    public function updated(Account $account): void
40
-    {
41
-        //
42
-    }
43
-
44
-    /**
45
-     * Handle the Account "deleted" event.
46
-     */
47
-    public function deleted(Account $account): void
48
-    {
49
-        //
50
-    }
51
-
52
-    /**
53
-     * Handle the Account "restored" event.
54
-     */
55
-    public function restored(Account $account): void
56
-    {
57
-        //
58
-    }
59
-
60
-    /**
61
-     * Handle the Account "force deleted" event.
62
-     */
63
-    public function forceDeleted(Account $account): void
64
-    {
65
-        //
66
-    }
67
-}

+ 67
- 0
app/Policies/CurrencyPolicy.php Parādīt failu

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

+ 0
- 11
app/Providers/EventServiceProvider.php Parādīt failu

@@ -2,8 +2,6 @@
2 2
 
3 3
 namespace App\Providers;
4 4
 
5
-use App\Models\Banking\Account;
6
-use App\Observers\AccountObserver;
7 5
 use Illuminate\Auth\Events\Registered;
8 6
 use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
9 7
 use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
@@ -37,13 +35,4 @@ class EventServiceProvider extends ServiceProvider
37 35
     {
38 36
         return false;
39 37
     }
40
-
41
-    /**
42
-     * The model observers for the application.
43
-     *
44
-     * @var array
45
-     */
46
-    protected $observers = [
47
-        Account::class => [AccountObserver::class],
48
-    ];
49 38
 }

+ 55
- 0
app/Services/CurrencyService.php Parādīt failu

@@ -0,0 +1,55 @@
1
+<?php
2
+
3
+namespace App\Services;
4
+
5
+use Illuminate\Support\Carbon;
6
+use Illuminate\Support\Facades\Cache;
7
+use Illuminate\Support\Facades\Http;
8
+
9
+class CurrencyService
10
+{
11
+    public function getExchangeRate($from, $to)
12
+    {
13
+        $date = Carbon::today()->format('Y-m-d');
14
+
15
+        $req_url = 'https://api.exchangerate.host/convert?from=' . $from . '&to=' . $to . '&date=' . $date;
16
+
17
+        $response = Http::get($req_url);
18
+
19
+        if ($response->successful()) {
20
+            $responseData = $response->json();
21
+            if ($responseData['success'] === true) {
22
+                return $responseData['info']['rate'];
23
+            }
24
+        }
25
+
26
+        return null;
27
+    }
28
+
29
+    public function getCachedExchangeRate(string $defaultCurrencyCode, string $code): ?float
30
+    {
31
+        // Include both the default currency code and the target currency code in the cache key
32
+        $cacheKey = 'currency_data_' . $defaultCurrencyCode . '_' . $code;
33
+
34
+        // Attempt to retrieve the cached exchange rate
35
+        $cachedData = Cache::get($cacheKey);
36
+
37
+        // If the cached exchange rate exists, return it
38
+        if ($cachedData !== null) {
39
+            return $cachedData['rate'];
40
+        }
41
+
42
+        // If the cached exchange rate does not exist, retrieve it from the API
43
+        $rate = $this->getExchangeRate($defaultCurrencyCode, $code);
44
+
45
+        // If the API call was successful, cache the exchange rate
46
+        if ($rate !== null) {
47
+            // Store the exchange rate in the cache for 24 hours
48
+            $dataToCache = compact('rate');
49
+            $expirationTimeInSeconds = 60 * 60 * 24; // 24 hours
50
+            Cache::put($cacheKey, $dataToCache, $expirationTimeInSeconds);
51
+        }
52
+
53
+        return $rate;
54
+    }
55
+}

+ 6
- 6
composer.lock Parādīt failu

@@ -9373,16 +9373,16 @@
9373 9373
         },
9374 9374
         {
9375 9375
             "name": "phpunit/phpunit",
9376
-            "version": "10.2.3",
9376
+            "version": "10.2.4",
9377 9377
             "source": {
9378 9378
                 "type": "git",
9379 9379
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
9380
-                "reference": "35c8cac1734ede2ae354a6644f7088356ff5b08e"
9380
+                "reference": "68484779b5a2ed711fbdeba6ca01910d87acdff2"
9381 9381
             },
9382 9382
             "dist": {
9383 9383
                 "type": "zip",
9384
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/35c8cac1734ede2ae354a6644f7088356ff5b08e",
9385
-                "reference": "35c8cac1734ede2ae354a6644f7088356ff5b08e",
9384
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/68484779b5a2ed711fbdeba6ca01910d87acdff2",
9385
+                "reference": "68484779b5a2ed711fbdeba6ca01910d87acdff2",
9386 9386
                 "shasum": ""
9387 9387
             },
9388 9388
             "require": {
@@ -9454,7 +9454,7 @@
9454 9454
             "support": {
9455 9455
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
9456 9456
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
9457
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.2.3"
9457
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.2.4"
9458 9458
             },
9459 9459
             "funding": [
9460 9460
                 {
@@ -9470,7 +9470,7 @@
9470 9470
                     "type": "tidelift"
9471 9471
                 }
9472 9472
             ],
9473
-            "time": "2023-06-30T06:17:38+00:00"
9473
+            "time": "2023-07-10T04:06:08+00:00"
9474 9474
         },
9475 9475
         {
9476 9476
             "name": "psr/cache",

+ 11
- 48
database/factories/CurrencyFactory.php Parādīt failu

@@ -3,6 +3,7 @@
3 3
 namespace Database\Factories;
4 4
 
5 5
 use App\Models\Setting\Currency;
6
+use Config;
6 7
 use Illuminate\Database\Eloquent\Factories\Factory;
7 8
 
8 9
 /**
@@ -17,7 +18,6 @@ class CurrencyFactory extends Factory
17 18
      */
18 19
     protected $model = Currency::class;
19 20
 
20
-
21 21
     /**
22 22
      * Define the model's default state.
23 23
      *
@@ -25,55 +25,18 @@ class CurrencyFactory extends Factory
25 25
      */
26 26
     public function definition(): array
27 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];
28
+        $defaultCurrency = Config::get('money.USD');
41 29
 
42 30
         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,
31
+            'name' => $defaultCurrency['name'],
32
+            'code' => 'USD',
33
+            'rate' => 1,
34
+            'precision' => $defaultCurrency['precision'],
35
+            'symbol' => $defaultCurrency['symbol'],
36
+            'symbol_first' => $defaultCurrency['symbol_first'],
37
+            'decimal_mark' => $defaultCurrency['decimal_mark'],
38
+            'thousands_separator' => $defaultCurrency['thousands_separator'],
39
+            'enabled' => true,
53 40
         ];
54 41
     }
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 42
 }

+ 2
- 1
database/factories/DefaultSettingFactory.php Parādīt failu

@@ -2,10 +2,11 @@
2 2
 
3 3
 namespace Database\Factories;
4 4
 
5
+use App\Models\Setting\DefaultSetting;
5 6
 use Illuminate\Database\Eloquent\Factories\Factory;
6 7
 
7 8
 /**
8
- * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\DefaultSetting>
9
+ * @extends Factory<DefaultSetting>
9 10
  */
10 11
 class DefaultSettingFactory extends Factory
11 12
 {

+ 9
- 1
database/factories/DiscountFactory.php Parādīt failu

@@ -24,8 +24,16 @@ class DiscountFactory extends Factory
24 24
      */
25 25
     public function definition(): array
26 26
     {
27
+        $startDate = $this->faker->dateTimeBetween('now', '+1 year');
28
+        $endDate = $this->faker->dateTimeBetween($startDate, strtotime('+1 year'));
29
+
27 30
         return [
28
-            //
31
+            'description' => $this->faker->sentence,
32
+            'rate' => $this->faker->randomFloat(4, 0, 20),
33
+            'computation' => $this->faker->randomElement(Discount::getComputationTypes()),
34
+            'scope' => $this->faker->randomElement(Discount::getDiscountScopes()),
35
+            'start_date' => $startDate,
36
+            'end_date' => $endDate,
29 37
         ];
30 38
     }
31 39
 }

+ 1
- 0
database/factories/TaxFactory.php Parādīt failu

@@ -25,6 +25,7 @@ class TaxFactory extends Factory
25 25
     public function definition(): array
26 26
     {
27 27
         return [
28
+            'description' => $this->faker->sentence,
28 29
             'rate' => $this->faker->randomFloat(4, 0, 20),
29 30
             'computation' => $this->faker->randomElement(Tax::getComputationTypes()),
30 31
             'scope' => $this->faker->randomElement(Tax::getTaxScopes()),

+ 1
- 1
database/migrations/2023_05_10_040940_create_currencies_table.php Parādīt failu

@@ -16,7 +16,7 @@ return new class extends Migration
16 16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17 17
             $table->string('name', 100);
18 18
             $table->string('code')->index();
19
-            $table->decimal('rate', 15, 8);
19
+            $table->double('rate', 15, 8);
20 20
             $table->unsignedTinyInteger('precision')->default(2);
21 21
             $table->string('symbol')->default('$');
22 22
             $table->boolean('symbol_first')->default(true);

+ 1
- 1
database/migrations/2023_05_11_044321_create_accounts_table.php Parādīt failu

@@ -18,7 +18,7 @@ return new class extends Migration
18 18
             $table->string('name', 100)->index();
19 19
             $table->string('number', 20);
20 20
             $table->string('currency_code')->default('USD');
21
-            $table->double('opening_balance', 15, 4)->default(0.00);
21
+            $table->double('opening_balance', 15, 4)->default(0.0000);
22 22
             $table->string('description')->nullable();
23 23
             $table->text('notes')->nullable();
24 24
             $table->string('status')->default('open');

+ 1
- 1
database/migrations/2023_05_12_042255_create_categories_table.php Parādīt failu

@@ -15,7 +15,7 @@ return new class extends Migration
15 15
             $table->id();
16 16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17 17
             $table->string('name')->index();
18
-            $table->string('type'); // expense, income, item, other
18
+            $table->string('type');
19 19
             $table->string('color');
20 20
             $table->boolean('enabled')->default(true);
21 21
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();

+ 2
- 2
database/migrations/2023_05_19_042232_create_contacts_table.php Parādīt failu

@@ -14,8 +14,8 @@ return new class extends Migration
14 14
         Schema::create('contacts', function (Blueprint $table) {
15 15
             $table->id();
16 16
             $table->foreignId('company_id')->constrained()->onDelete('cascade');
17
-            $table->string('entity')->default('company'); // company, individual (person)
18
-            $table->string('type'); // vendor, customer, employee
17
+            $table->string('entity')->default('individual');
18
+            $table->string('type');
19 19
             $table->string('name');
20 20
             $table->string('email')->nullable();
21 21
             $table->string('tax_number')->nullable();

+ 4
- 4
database/migrations/2023_05_20_080131_create_taxes_table.php Parādīt failu

@@ -16,10 +16,10 @@ return new class extends Migration
16 16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17 17
             $table->string('name');
18 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
19
+            $table->double('rate', 15, 4);
20
+            $table->string('computation')->default('percentage');
21
+            $table->string('type')->default('sales');
22
+            $table->string('scope')->nullable();
23 23
             $table->boolean('enabled')->default(true);
24 24
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
25 25
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();

+ 4
- 4
database/migrations/2023_05_21_163808_create_discounts_table.php Parādīt failu

@@ -16,10 +16,10 @@ return new class extends Migration
16 16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17 17
             $table->string('name');
18 18
             $table->text('description')->nullable();
19
-            $table->decimal('rate', 15, 4);
20
-            $table->string('computation')->default('percentage'); // percentage, fixed
21
-            $table->string('type')->default('sales'); // sales, purchases
22
-            $table->string('scope')->nullable(); // product, service, none
19
+            $table->double('rate', 15, 4);
20
+            $table->string('computation')->default('percentage');
21
+            $table->string('type')->default('sales');
22
+            $table->string('scope')->nullable();
23 23
             $table->dateTime('start_date')->nullable();
24 24
             $table->dateTime('end_date')->nullable();
25 25
             $table->boolean('enabled')->default(true);

+ 4
- 4
database/migrations/2023_05_22_073252_create_items_table.php Parādīt failu

@@ -14,14 +14,14 @@ return new class extends Migration
14 14
         Schema::create('items', function (Blueprint $table) {
15 15
             $table->id();
16 16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
-            $table->string('type'); // product, service
17
+            $table->string('type');
18 18
             $table->string('name');
19 19
             $table->string('sku')->unique();
20 20
             $table->string('description')->nullable();
21
-            $table->decimal('sale_price', 15, 4);
22
-            $table->decimal('purchase_price', 15, 4);
21
+            $table->double('sale_price', 15, 4);
22
+            $table->double('purchase_price', 15, 4);
23 23
             $table->integer('quantity')->default(1);
24
-            $table->foreignId('category_id')->default(1)->constrained()->restrictOnDelete();
24
+            $table->foreignId('category_id')->nullable()->constrained()->nullOnDelete();
25 25
             $table->foreignId('tax_id')->nullable()->constrained()->nullOnDelete();
26 26
             $table->foreignId('discount_id')->nullable()->constrained()->nullOnDelete();
27 27
             $table->boolean('enabled')->default(true);

+ 4
- 4
database/migrations/2023_05_23_141215_create_documents_table.php Parādīt failu

@@ -14,19 +14,19 @@ return new class extends Migration
14 14
         Schema::create('documents', function (Blueprint $table) {
15 15
             $table->id();
16 16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
-            $table->string('type'); // invoice, bill
17
+            $table->string('type');
18 18
             $table->string('document_number');
19 19
             $table->string('order_number')->nullable();
20
-            $table->string('status'); // draft, sent, paid, cancelled, approved
20
+            $table->string('status');
21 21
             $table->dateTime('document_date');
22 22
             $table->dateTime('due_date');
23 23
             $table->dateTime('paid_date')->nullable();
24
-            $table->decimal('amount', 15, 4);
24
+            $table->double('amount', 15, 4);
25 25
             $table->foreignId('tax_id')->nullable()->constrained()->nullOnDelete();
26 26
             $table->foreignId('discount_id')->nullable()->constrained()->nullOnDelete();
27 27
             $table->string('reference')->nullable();
28 28
             $table->string('currency_code')->default('USD');
29
-            $table->foreignId('category_id')->default(1)->constrained()->restrictOnDelete();
29
+            $table->foreignId('category_id')->nullable()->constrained()->nullOnDelete();
30 30
             $table->foreignId('contact_id')->nullable()->constrained()->nullOnDelete();
31 31
             $table->text('notes')->nullable();
32 32
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();

+ 3
- 3
database/migrations/2023_05_23_151550_create_document_items_table.php Parādīt failu

@@ -19,11 +19,11 @@ return new class extends Migration
19 19
             $table->string('type');
20 20
             $table->string('name');
21 21
             $table->text('description')->nullable();
22
-            $table->decimal('quantity', 7, 2);
23
-            $table->decimal('price', 15, 4);
22
+            $table->double('quantity', 7, 2);
23
+            $table->double('price', 15, 4);
24 24
             $table->foreignId('tax_id')->nullable()->constrained()->nullOnDelete();
25 25
             $table->foreignId('discount_id')->nullable()->constrained()->nullOnDelete();
26
-            $table->decimal('total', 15, 4);
26
+            $table->double('total', 15, 4);
27 27
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
28 28
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
29 29
             $table->timestamps();

+ 4
- 4
database/migrations/2023_05_23_173412_create_document_totals_table.php Parādīt failu

@@ -18,10 +18,10 @@ return new class extends Migration
18 18
             $table->string('type');
19 19
             $table->string('code');
20 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);
21
+            $table->double('subtotal', 15, 4)->default(0);
22
+            $table->double('discount', 15, 4)->default(0);
23
+            $table->double('tax', 15, 4)->default(0);
24
+            $table->double('total', 15, 4);
25 25
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
26 26
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
27 27
             $table->timestamps();

+ 2
- 0
database/migrations/2023_07_03_054805_create_default_settings_table.php Parādīt failu

@@ -18,6 +18,8 @@ return new class extends Migration
18 18
             $table->string('currency_code')->default('USD');
19 19
             $table->foreignId('sales_tax_id')->constrained('taxes')->restrictOnDelete();
20 20
             $table->foreignId('purchase_tax_id')->constrained('taxes')->restrictOnDelete();
21
+            $table->foreignId('sales_discount_id')->constrained('discounts')->restrictOnDelete();
22
+            $table->foreignId('purchase_discount_id')->constrained('discounts')->restrictOnDelete();
21 23
             $table->foreignId('income_category_id')->constrained('categories')->restrictOnDelete();
22 24
             $table->foreignId('expense_category_id')->constrained('categories')->restrictOnDelete();
23 25
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();

+ 0
- 1
database/seeders/AccountSeeder.php Parādīt failu

@@ -3,7 +3,6 @@
3 3
 namespace Database\Seeders;
4 4
 
5 5
 use App\Models\Banking\Account;
6
-use Illuminate\Database\Console\Seeds\WithoutModelEvents;
7 6
 use Illuminate\Database\Seeder;
8 7
 
9 8
 class AccountSeeder extends Seeder

+ 0
- 1
database/seeders/CategorySeeder.php Parādīt failu

@@ -3,7 +3,6 @@
3 3
 namespace Database\Seeders;
4 4
 
5 5
 use App\Models\Setting\Category;
6
-use Illuminate\Database\Console\Seeds\WithoutModelEvents;
7 6
 use Illuminate\Database\Seeder;
8 7
 use Illuminate\Support\Facades\DB;
9 8
 

+ 9
- 4
database/seeders/CurrencySeeder.php Parādīt failu

@@ -3,8 +3,8 @@
3 3
 namespace Database\Seeders;
4 4
 
5 5
 use App\Models\Setting\Currency;
6
-use Illuminate\Database\Console\Seeds\WithoutModelEvents;
7 6
 use Illuminate\Database\Seeder;
7
+use Illuminate\Support\Facades\DB;
8 8
 
9 9
 class CurrencySeeder extends Seeder
10 10
 {
@@ -13,8 +13,13 @@ class CurrencySeeder extends Seeder
13 13
      */
14 14
     public function run(): void
15 15
     {
16
-        Currency::factory()
17
-            ->count(5)
18
-            ->create();
16
+        $companyId = DB::table('companies')->first()->id;
17
+        $userId = DB::table('users')->first()->id;
18
+
19
+        Currency::factory()->create([
20
+            'company_id' => $companyId,
21
+            'created_by' => $userId,
22
+            'updated_by' => $userId,
23
+        ]);
19 24
     }
20 25
 }

+ 111
- 0
database/seeders/DatabaseSeeder.php Parādīt failu

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

+ 65
- 0
database/seeders/DiscountSeeder.php Parādīt failu

@@ -0,0 +1,65 @@
1
+<?php
2
+
3
+namespace Database\Seeders;
4
+
5
+use App\Models\Setting\Discount;
6
+use Illuminate\Database\Seeder;
7
+use Illuminate\Support\Facades\DB;
8
+
9
+class DiscountSeeder extends Seeder
10
+{
11
+    /**
12
+     * Run the database seeds.
13
+     */
14
+    public function run(): void
15
+    {
16
+        $companyId = DB::table('companies')->first()->id;
17
+        $userId = DB::table('users')->first()->id;
18
+
19
+        $salesDiscounts = [
20
+            '4th of July Sale',
21
+            'End of Year Sale',
22
+            'Black Friday Sale',
23
+            'Cyber Monday Sale',
24
+            'Christmas Sale',
25
+        ];
26
+
27
+        $purchaseDiscounts = [
28
+            'Bulk Purchase Bargain',
29
+            'Early Payment Discount',
30
+            'First Time Buyer Special',
31
+            'Recurring Purchase Reward',
32
+            'Referral Program Discount',
33
+        ];
34
+
35
+        $shuffledDiscounts = [
36
+            ...array_map(static fn($name) => ['name' => $name, 'type' => 'sales'], $salesDiscounts),
37
+            ...array_map(static fn($name) => ['name' => $name, 'type' => 'purchase'], $purchaseDiscounts)
38
+        ];
39
+
40
+        shuffle($shuffledDiscounts);
41
+
42
+        $allDiscounts = $shuffledDiscounts;
43
+
44
+        foreach ($allDiscounts as $discount) {
45
+            Discount::factory()->create([
46
+                'company_id' => $companyId,
47
+                'name' => $discount['name'],
48
+                'type' => $discount['type'],
49
+                'enabled' => false,
50
+                'created_by' => $userId,
51
+                'updated_by' => $userId,
52
+            ]);
53
+        }
54
+
55
+        Discount::where('type', 'sales')
56
+            ->where('company_id', $companyId)
57
+            ->first()
58
+            ->update(['enabled' => true]);
59
+
60
+        Discount::where('type', 'purchase')
61
+            ->where('company_id', $companyId)
62
+            ->first()
63
+            ->update(['enabled' => true]);
64
+    }
65
+}

+ 0
- 3
database/seeders/TaxSeeder.php Parādīt failu

@@ -32,7 +32,6 @@ class TaxSeeder extends Seeder
32 32
             'Environmental Tax',
33 33
         ];
34 34
 
35
-        // Merge and shuffle the sales and purchase taxes
36 35
         $shuffledTaxes = [
37 36
             ...array_map(static fn($name) => ['name' => $name, 'type' => 'sales'], $salesTaxes),
38 37
             ...array_map(static fn($name) => ['name' => $name, 'type' => 'purchase'], $purchaseTaxes)
@@ -53,13 +52,11 @@ class TaxSeeder extends Seeder
53 52
             ]);
54 53
         }
55 54
 
56
-        // Set the first sales tax as enabled
57 55
         Tax::where('type', 'sales')
58 56
             ->where('company_id', $companyId)
59 57
             ->first()
60 58
             ->update(['enabled' => true]);
61 59
 
62
-        // Set the first purchase tax as enabled
63 60
         Tax::where('type', 'purchase')
64 61
             ->where('company_id', $companyId)
65 62
             ->first()

Notiek ielāde…
Atcelt
Saglabāt