Browse Source

wip: Accounting Module

3.x
wallo 2 years ago
parent
commit
c72d4afbc0
38 changed files with 478 additions and 253 deletions
  1. 0
    4
      app/Actions/OptionAction/CreateCurrency.php
  2. 11
    3
      app/Filament/Resources/AccountResource/Pages/CreateAccount.php
  3. 11
    6
      app/Filament/Resources/AccountResource/Pages/EditAccount.php
  4. 11
    3
      app/Filament/Resources/CategoryResource/Pages/CreateCategory.php
  5. 11
    3
      app/Filament/Resources/CategoryResource/Pages/EditCategory.php
  6. 11
    3
      app/Filament/Resources/CurrencyResource/Pages/CreateCurrency.php
  7. 11
    6
      app/Filament/Resources/CurrencyResource/Pages/EditCurrency.php
  8. 0
    2
      app/Filament/Resources/CustomerResource/Pages/CreateCustomer.php
  9. 1
    10
      app/Filament/Resources/CustomerResource/Pages/EditCustomer.php
  10. 4
    4
      app/Filament/Resources/DiscountResource.php
  11. 11
    3
      app/Filament/Resources/DiscountResource/Pages/CreateDiscount.php
  12. 19
    1
      app/Filament/Resources/DiscountResource/Pages/EditDiscount.php
  13. 0
    2
      app/Filament/Resources/InvoiceResource/Pages/CreateInvoice.php
  14. 0
    9
      app/Filament/Resources/InvoiceResource/Pages/EditInvoice.php
  15. 11
    3
      app/Filament/Resources/TaxResource/Pages/CreateTax.php
  16. 11
    5
      app/Filament/Resources/TaxResource/Pages/EditTax.php
  17. 3
    22
      app/Http/Livewire/DefaultSetting.php
  18. 3
    4
      app/Models/Banking/Account.php
  19. 3
    1
      app/Models/Contact.php
  20. 3
    1
      app/Models/Document/Document.php
  21. 3
    1
      app/Models/Document/DocumentItem.php
  22. 3
    1
      app/Models/Document/DocumentTotal.php
  23. 3
    1
      app/Models/Item.php
  24. 3
    1
      app/Models/Setting/Category.php
  25. 13
    1
      app/Models/Setting/Currency.php
  26. 9
    1
      app/Models/Setting/DefaultSetting.php
  27. 3
    1
      app/Models/Setting/Discount.php
  28. 15
    1
      app/Models/Setting/DocumentDefault.php
  29. 3
    1
      app/Models/Setting/Tax.php
  30. 3
    67
      app/Observers/CompanyObserver.php
  31. 141
    0
      app/Services/DefaultSettingService.php
  32. 20
    0
      app/Traits/Blamable.php
  33. 25
    0
      app/Traits/CompanyOwned.php
  34. 12
    18
      app/Traits/HandlesDefaultSettingRecordUpdate.php
  35. 31
    18
      app/Traits/HandlesResourceRecordCreation.php
  36. 53
    46
      app/Traits/HandlesResourceRecordUpdate.php
  37. 2
    0
      database/migrations/2023_05_22_000100_create_document_defaults_table.php
  38. 1
    0
      database/migrations/2023_07_03_054805_create_default_settings_table.php

+ 0
- 4
app/Actions/OptionAction/CreateCurrency.php View File

@@ -3,14 +3,11 @@
3 3
 namespace App\Actions\OptionAction;
4 4
 
5 5
 use App\Models\Setting\Currency;
6
-use Illuminate\Support\Facades\Auth;
7 6
 
8 7
 class CreateCurrency
9 8
 {
10 9
     public function create(string $code, string $name, string $rate): Currency
11 10
     {
12
-        $companyId = Auth::user()->currentCompany->id;
13
-
14 11
         $defaultCurrency = Currency::getDefaultCurrency();
15 12
 
16 13
         $hasDefaultCurrency = $defaultCurrency !== null;
@@ -25,7 +22,6 @@ class CreateCurrency
25 22
             'decimal_mark' => config("money.{$code}.decimal_mark"),
26 23
             'thousands_separator' => config("money.{$code}.thousands_separator"),
27 24
             'enabled' => !$hasDefaultCurrency,
28
-            'company_id' => $companyId,
29 25
         ]);
30 26
     }
31 27
 }

+ 11
- 3
app/Filament/Resources/AccountResource/Pages/CreateAccount.php View File

@@ -6,6 +6,7 @@ use App\Filament\Resources\AccountResource;
6 6
 use App\Models\Banking\Account;
7 7
 use App\Traits\HandlesResourceRecordCreation;
8 8
 use Filament\Resources\Pages\CreateRecord;
9
+use Filament\Support\Exceptions\Halt;
9 10
 use Illuminate\Database\Eloquent\Model;
10 11
 use Illuminate\Support\Facades\Auth;
11 12
 
@@ -22,15 +23,22 @@ class CreateAccount extends CreateRecord
22 23
 
23 24
     protected function mutateFormDataBeforeCreate(array $data): array
24 25
     {
25
-        $data['company_id'] = Auth::user()->currentCompany->id;
26 26
         $data['enabled'] = (bool)$data['enabled'];
27
-        $data['created_by'] = Auth::id();
28 27
 
29 28
         return $data;
30 29
     }
31 30
 
31
+    /**
32
+     * @throws Halt
33
+     */
32 34
     protected function handleRecordCreation(array $data): Model
33 35
     {
34
-        return $this->handleRecordCreationWithUniqueField($data, new Account());
36
+        $user = Auth::user();
37
+
38
+        if (!$user) {
39
+            throw new Halt('No authenticated user found.');
40
+        }
41
+
42
+        return $this->handleRecordCreationWithUniqueField($data, new Account(), $user);
35 43
     }
36 44
 }

+ 11
- 6
app/Filament/Resources/AccountResource/Pages/EditAccount.php View File

@@ -3,14 +3,12 @@
3 3
 namespace App\Filament\Resources\AccountResource\Pages;
4 4
 
5 5
 use App\Filament\Resources\AccountResource;
6
-use App\Models\Banking\Account;
7 6
 use App\Traits\HandlesResourceRecordUpdate;
8
-use Filament\Notifications\Notification;
9 7
 use Filament\Pages\Actions;
10 8
 use Filament\Resources\Pages\EditRecord;
9
+use Filament\Support\Exceptions\Halt;
11 10
 use Illuminate\Database\Eloquent\Model;
12 11
 use Illuminate\Support\Facades\Auth;
13
-use Illuminate\Support\Facades\DB;
14 12
 
15 13
 class EditAccount extends EditRecord
16 14
 {
@@ -32,15 +30,22 @@ class EditAccount extends EditRecord
32 30
 
33 31
     protected function mutateFormDataBeforeSave(array $data): array
34 32
     {
35
-        $data['company_id'] = Auth::user()->currentCompany->id;
36 33
         $data['enabled'] = (bool)$data['enabled'];
37
-        $data['updated_by'] = Auth::id();
38 34
 
39 35
         return $data;
40 36
     }
41 37
 
38
+    /**
39
+     * @throws Halt
40
+     */
42 41
     protected function handleRecordUpdate(Model $record, array $data): Model
43 42
     {
44
-        return $this->handleRecordUpdateWithUniqueField($record, $data);
43
+        $user = Auth::user();
44
+
45
+        if (!$user) {
46
+            throw new Halt('No authenticated user found.');
47
+        }
48
+
49
+        return $this->handleRecordUpdateWithUniqueField($record, $data, $user);
45 50
     }
46 51
 }

+ 11
- 3
app/Filament/Resources/CategoryResource/Pages/CreateCategory.php View File

@@ -6,6 +6,7 @@ use App\Filament\Resources\CategoryResource;
6 6
 use App\Models\Setting\Category;
7 7
 use App\Traits\HandlesResourceRecordCreation;
8 8
 use Filament\Resources\Pages\CreateRecord;
9
+use Filament\Support\Exceptions\Halt;
9 10
 use Illuminate\Database\Eloquent\Model;
10 11
 use Illuminate\Support\Facades\Auth;
11 12
 
@@ -22,15 +23,22 @@ class CreateCategory extends CreateRecord
22 23
 
23 24
     protected function mutateFormDataBeforeCreate(array $data): array
24 25
     {
25
-        $data['company_id'] = Auth::user()->currentCompany->id;
26 26
         $data['enabled'] = (bool)$data['enabled'];
27
-        $data['created_by'] = Auth::id();
28 27
 
29 28
         return $data;
30 29
     }
31 30
 
31
+    /**
32
+     * @throws Halt
33
+     */
32 34
     protected function handleRecordCreation(array $data): Model
33 35
     {
34
-        return $this->handleRecordCreationWithUniqueField($data, new Category(), 'type');
36
+        $user = Auth::user();
37
+
38
+        if (!$user) {
39
+            throw new Halt('No authenticated user found.');
40
+        }
41
+
42
+        return $this->handleRecordCreationWithUniqueField($data, new Category(), $user, 'type');
35 43
     }
36 44
 }

+ 11
- 3
app/Filament/Resources/CategoryResource/Pages/EditCategory.php View File

@@ -6,6 +6,7 @@ use App\Filament\Resources\CategoryResource;
6 6
 use App\Traits\HandlesResourceRecordUpdate;
7 7
 use Filament\Pages\Actions;
8 8
 use Filament\Resources\Pages\EditRecord;
9
+use Filament\Support\Exceptions\Halt;
9 10
 use Illuminate\Database\Eloquent\Model;
10 11
 use Illuminate\Support\Facades\Auth;
11 12
 
@@ -29,15 +30,22 @@ class EditCategory extends EditRecord
29 30
 
30 31
     protected function mutateFormDataBeforeSave(array $data): array
31 32
     {
32
-        $data['company_id'] = Auth::user()->currentCompany->id;
33 33
         $data['enabled'] = (bool)$data['enabled'];
34
-        $data['updated_by'] = Auth::id();
35 34
 
36 35
         return $data;
37 36
     }
38 37
 
38
+    /**
39
+     * @throws Halt
40
+     */
39 41
     protected function handleRecordUpdate(Model $record, array $data): Model
40 42
     {
41
-        return $this->handleRecordUpdateWithUniqueField($record, $data, 'type');
43
+        $user = Auth::user();
44
+
45
+        if (!$user) {
46
+            throw new Halt('No authenticated user found.');
47
+        }
48
+
49
+        return $this->handleRecordUpdateWithUniqueField($record, $data, $user, 'type');
42 50
     }
43 51
 }

+ 11
- 3
app/Filament/Resources/CurrencyResource/Pages/CreateCurrency.php View File

@@ -7,6 +7,7 @@ use App\Models\Setting\Currency;
7 7
 use App\Traits\HandlesResourceRecordCreation;
8 8
 use Filament\Pages\Actions;
9 9
 use Filament\Resources\Pages\CreateRecord;
10
+use Filament\Support\Exceptions\Halt;
10 11
 use Illuminate\Database\Eloquent\Model;
11 12
 use Illuminate\Support\Facades\Auth;
12 13
 use Illuminate\Support\Facades\DB;
@@ -24,15 +25,22 @@ class CreateCurrency extends CreateRecord
24 25
 
25 26
     protected function mutateFormDataBeforeCreate(array $data): array
26 27
     {
27
-        $data['company_id'] = Auth::user()->currentCompany->id;
28 28
         $data['enabled'] = (bool)$data['enabled'];
29
-        $data['created_by'] = Auth::id();
30 29
 
31 30
         return $data;
32 31
     }
33 32
 
33
+    /**
34
+     * @throws Halt
35
+     */
34 36
     protected function handleRecordCreation(array $data): Model
35 37
     {
36
-        return $this->handleRecordCreationWithUniqueField($data, new Currency());
38
+        $user = Auth::user();
39
+
40
+        if (!$user) {
41
+            throw new Halt('No authenticated user found.');
42
+        }
43
+
44
+        return $this->handleRecordCreationWithUniqueField($data, new Currency(), $user);
37 45
     }
38 46
 }

+ 11
- 6
app/Filament/Resources/CurrencyResource/Pages/EditCurrency.php View File

@@ -3,14 +3,12 @@
3 3
 namespace App\Filament\Resources\CurrencyResource\Pages;
4 4
 
5 5
 use App\Filament\Resources\CurrencyResource;
6
-use App\Models\Banking\Account;
7
-use App\Models\Setting\Currency;
8 6
 use App\Traits\HandlesResourceRecordUpdate;
9 7
 use Filament\Pages\Actions;
10 8
 use Filament\Resources\Pages\EditRecord;
9
+use Filament\Support\Exceptions\Halt;
11 10
 use Illuminate\Database\Eloquent\Model;
12 11
 use Illuminate\Support\Facades\Auth;
13
-use Illuminate\Support\Facades\DB;
14 12
 
15 13
 class EditCurrency extends EditRecord
16 14
 {
@@ -32,16 +30,23 @@ class EditCurrency extends EditRecord
32 30
 
33 31
     protected function mutateFormDataBeforeSave(array $data): array
34 32
     {
35
-        $data['company_id'] = Auth::user()->currentCompany->id;
36 33
         $data['enabled'] = (bool)$data['enabled'];
37
-        $data['updated_by'] = Auth::id();
38 34
 
39 35
         return $data;
40 36
     }
41 37
 
38
+    /**
39
+     * @throws Halt
40
+     */
42 41
     protected function handleRecordUpdate(Model $record, array $data): Model
43 42
     {
44
-        return $this->handleRecordUpdateWithUniqueField($record, $data);
43
+        $user = Auth::user();
44
+
45
+        if (!$user) {
46
+            throw new Halt('No authenticated user found.');
47
+        }
48
+
49
+        return $this->handleRecordUpdateWithUniqueField($record, $data, $user);
45 50
     }
46 51
 
47 52
 }

+ 0
- 2
app/Filament/Resources/CustomerResource/Pages/CreateCustomer.php View File

@@ -19,9 +19,7 @@ class CreateCustomer extends CreateRecord
19 19
 
20 20
     protected function mutateFormDataBeforeCreate(array $data): array
21 21
     {
22
-        $data['company_id'] = Auth::user()->currentCompany->id;
23 22
         $data['type'] = 'customer';
24
-        $data['created_by'] = Auth::id();
25 23
 
26 24
         return $data;
27 25
     }

+ 1
- 10
app/Filament/Resources/CustomerResource/Pages/EditCustomer.php View File

@@ -5,7 +5,6 @@ namespace App\Filament\Resources\CustomerResource\Pages;
5 5
 use App\Filament\Resources\CustomerResource;
6 6
 use Filament\Pages\Actions;
7 7
 use Filament\Resources\Pages\EditRecord;
8
-use Illuminate\Support\Facades\Auth;
9 8
 
10 9
 class EditCustomer extends EditRecord
11 10
 {
@@ -20,14 +19,6 @@ class EditCustomer extends EditRecord
20 19
 
21 20
     protected function getRedirectUrl(): string
22 21
     {
23
-        return $this->getResource()::getUrl('index');
24
-    }
25
-
26
-    protected function mutateFormDataBeforeSave(array $data): array
27
-    {
28
-        $data['company_id'] = Auth::user()->currentCompany->id;
29
-        $data['updated_by'] = Auth::id();
30
-
31
-        return $data;
22
+        return $this->previousUrl;
32 23
     }
33 24
 }

+ 4
- 4
app/Filament/Resources/DiscountResource.php View File

@@ -72,7 +72,7 @@ class DiscountResource extends Resource
72 72
                                 return today()->addDay();
73 73
                             }
74 74
 
75
-                            return $record?->start_date->isFuture() ? today()->addDay() : $record?->start_date;
75
+                            return $record?->start_date?->isFuture() ? today()->addDay() : $record?->start_date;
76 76
                         })
77 77
                         ->maxDate(static function (callable $get, Discount|null $record = null) {
78 78
                             $end_date = $get('end_date') ?? $record?->end_date;
@@ -83,7 +83,7 @@ class DiscountResource extends Resource
83 83
                         ->displayFormat('F d, Y H:i')
84 84
                         ->withoutSeconds()
85 85
                         ->reactive()
86
-                        ->disabled(static fn ($context, Discount|null $record = null) => $context === 'edit' && $record?->start_date->isPast())
86
+                        ->disabled(static fn ($context, Discount|null $record = null) => $context === 'edit' && $record?->start_date?->isPast() ?? false)
87 87
                         ->helperText(static fn (Forms\Components\DateTimePicker $component) => $component->isDisabled() ? 'Start date cannot be changed after the discount has begun.' : null),
88 88
                     Forms\Components\DateTimePicker::make('end_date')
89 89
                         ->label('End Date')
@@ -148,12 +148,12 @@ class DiscountResource extends Resource
148 148
                     ->sortable(),
149 149
                 Tables\Columns\TextColumn::make('start_date')
150 150
                 ->label('Start Date')
151
-                ->formatStateUsing(static fn (Discount $record) => $record->start_date ? $record->start_date->format('F d, Y H:i') : null)
151
+                ->formatStateUsing(static fn (Discount $record) => $record->start_date ? $record->start_date->format('F d, Y H:i') : 'N/A')
152 152
                 ->searchable()
153 153
                 ->sortable(),
154 154
                 Tables\Columns\TextColumn::make('end_date')
155 155
                 ->label('End Date')
156
-                ->formatStateUsing(static fn (Discount $record) => $record->end_date ? $record->end_date->format('F d, Y H:i') : null)
156
+                ->formatStateUsing(static fn (Discount $record) => $record->end_date ? $record->end_date->format('F d, Y H:i') : 'N/A')
157 157
                 ->color(static fn(Discount $record) => $record->end_date?->isPast() ? 'danger' : null)
158 158
                 ->searchable()
159 159
                 ->sortable(),

+ 11
- 3
app/Filament/Resources/DiscountResource/Pages/CreateDiscount.php View File

@@ -6,6 +6,7 @@ use App\Filament\Resources\DiscountResource;
6 6
 use App\Models\Setting\Discount;
7 7
 use App\Traits\HandlesResourceRecordCreation;
8 8
 use Filament\Resources\Pages\CreateRecord;
9
+use Filament\Support\Exceptions\Halt;
9 10
 use Illuminate\Database\Eloquent\Model;
10 11
 use Illuminate\Support\Facades\Auth;
11 12
 
@@ -22,15 +23,22 @@ class CreateDiscount extends CreateRecord
22 23
 
23 24
     protected function mutateFormDataBeforeCreate(array $data): array
24 25
     {
25
-        $data['company_id'] = Auth::user()->currentCompany->id;
26 26
         $data['enabled'] = (bool)($data['enabled']);
27
-        $data['created_by'] = Auth::id();
28 27
 
29 28
         return $data;
30 29
     }
31 30
 
31
+    /**
32
+     * @throws Halt
33
+     */
32 34
     protected function handleRecordCreation(array $data): Model
33 35
     {
34
-        return $this->handleRecordCreationWithUniqueField($data, new Discount(), 'type');
36
+        $user = Auth::user();
37
+
38
+        if (!$user) {
39
+            throw new Halt('No authenticated user found.');
40
+        }
41
+
42
+        return $this->handleRecordCreationWithUniqueField($data, new Discount(), $user, 'type');
35 43
     }
36 44
 }

+ 19
- 1
app/Filament/Resources/DiscountResource/Pages/EditDiscount.php View File

@@ -6,7 +6,9 @@ use App\Filament\Resources\DiscountResource;
6 6
 use App\Traits\HandlesResourceRecordUpdate;
7 7
 use Filament\Pages\Actions;
8 8
 use Filament\Resources\Pages\EditRecord;
9
+use Filament\Support\Exceptions\Halt;
9 10
 use Illuminate\Database\Eloquent\Model;
11
+use Illuminate\Support\Facades\Auth;
10 12
 
11 13
 class EditDiscount extends EditRecord
12 14
 {
@@ -26,8 +28,24 @@ class EditDiscount extends EditRecord
26 28
         return $this->previousUrl;
27 29
     }
28 30
 
31
+    protected function mutateFormDataBeforeSave(array $data): array
32
+    {
33
+        $data['enabled'] = (bool)$data['enabled'];
34
+
35
+        return $data;
36
+    }
37
+
38
+    /**
39
+     * @throws Halt
40
+     */
29 41
     protected function handleRecordUpdate(Model $record, array $data): Model
30 42
     {
31
-        return $this->handleRecordUpdateWithUniqueField($record, $data, 'type');
43
+        $user = Auth::user();
44
+
45
+        if (!$user) {
46
+            throw new Halt('No authenticated user found.');
47
+        }
48
+
49
+        return $this->handleRecordUpdateWithUniqueField($record, $data, $user, 'type');
32 50
     }
33 51
 }

+ 0
- 2
app/Filament/Resources/InvoiceResource/Pages/CreateInvoice.php View File

@@ -18,11 +18,9 @@ class CreateInvoice extends CreateRecord
18 18
 
19 19
     protected function mutateFormDataBeforeCreate(array $data): array
20 20
     {
21
-        $data['company_id'] = Auth::user()->currentCompany->id;
22 21
         $data['type'] = 'invoice';
23 22
         $data['status'] = 'draft';
24 23
         $data['amount'] = 0;
25
-        $data['created_by'] = Auth::id();
26 24
 
27 25
         return $data;
28 26
     }

+ 0
- 9
app/Filament/Resources/InvoiceResource/Pages/EditInvoice.php View File

@@ -5,7 +5,6 @@ namespace App\Filament\Resources\InvoiceResource\Pages;
5 5
 use App\Filament\Resources\InvoiceResource;
6 6
 use Filament\Pages\Actions;
7 7
 use Filament\Resources\Pages\EditRecord;
8
-use Illuminate\Support\Facades\Auth;
9 8
 
10 9
 class EditInvoice extends EditRecord
11 10
 {
@@ -22,12 +21,4 @@ class EditInvoice extends EditRecord
22 21
     {
23 22
         return $this->previousUrl;
24 23
     }
25
-
26
-    protected function mutateFormDataBeforeSave(array $data): array
27
-    {
28
-        $data['company_id'] = Auth::user()->currentCompany->id;
29
-        $data['updated_by'] = Auth::id();
30
-
31
-        return $data;
32
-    }
33 24
 }

+ 11
- 3
app/Filament/Resources/TaxResource/Pages/CreateTax.php View File

@@ -6,6 +6,7 @@ use App\Filament\Resources\TaxResource;
6 6
 use App\Models\Setting\Tax;
7 7
 use App\Traits\HandlesResourceRecordCreation;
8 8
 use Filament\Resources\Pages\CreateRecord;
9
+use Filament\Support\Exceptions\Halt;
9 10
 use Illuminate\Database\Eloquent\Model;
10 11
 use Illuminate\Support\Facades\Auth;
11 12
 
@@ -22,15 +23,22 @@ class CreateTax extends CreateRecord
22 23
 
23 24
     protected function mutateFormDataBeforeCreate(array $data): array
24 25
     {
25
-        $data['company_id'] = Auth::user()->currentCompany->id;
26 26
         $data['enabled'] = (bool)$data['enabled'];
27
-        $data['created_by'] = Auth::id();
28 27
 
29 28
         return $data;
30 29
     }
31 30
 
31
+    /**
32
+     * @throws Halt
33
+     */
32 34
     protected function handleRecordCreation(array $data): Model
33 35
     {
34
-        return $this->handleRecordCreationWithUniqueField($data, new Tax(), 'type');
36
+        $user = Auth::user();
37
+
38
+        if (!$user) {
39
+            throw new Halt('No authenticated user found.');
40
+        }
41
+
42
+        return $this->handleRecordCreationWithUniqueField($data, new Tax(), $user, 'type');
35 43
     }
36 44
 }

+ 11
- 5
app/Filament/Resources/TaxResource/Pages/EditTax.php View File

@@ -3,13 +3,12 @@
3 3
 namespace App\Filament\Resources\TaxResource\Pages;
4 4
 
5 5
 use App\Filament\Resources\TaxResource;
6
-use App\Models\Setting\Tax;
7 6
 use App\Traits\HandlesResourceRecordUpdate;
8 7
 use Filament\Pages\Actions;
9 8
 use Filament\Resources\Pages\EditRecord;
9
+use Filament\Support\Exceptions\Halt;
10 10
 use Illuminate\Database\Eloquent\Model;
11 11
 use Illuminate\Support\Facades\Auth;
12
-use Illuminate\Support\Facades\DB;
13 12
 
14 13
 class EditTax extends EditRecord
15 14
 {
@@ -31,15 +30,22 @@ class EditTax extends EditRecord
31 30
 
32 31
     protected function mutateFormDataBeforeUpdate(array $data): array
33 32
     {
34
-        $data['company_id'] = Auth::user()->currentCompany->id;
35 33
         $data['enabled'] = (bool)$data['enabled'];
36
-        $data['updated_by'] = Auth::id();
37 34
 
38 35
         return $data;
39 36
     }
40 37
 
38
+    /**
39
+     * @throws Halt
40
+     */
41 41
     protected function handleRecordUpdate(Model $record, array $data): Model
42 42
     {
43
-        return $this->handleRecordUpdateWithUniqueField($record, $data, 'type');
43
+        $user = Auth::user();
44
+
45
+        if (!$user) {
46
+            throw new Halt('No authenticated user found.');
47
+        }
48
+
49
+        return $this->handleRecordUpdateWithUniqueField($record, $data, $user, 'type');
44 50
     }
45 51
 }

+ 3
- 22
app/Http/Livewire/DefaultSetting.php View File

@@ -7,7 +7,7 @@ use App\Models\Setting\Category;
7 7
 use App\Models\Setting\Currency;
8 8
 use App\Models\Setting\DefaultSetting as Defaults;
9 9
 use App\Models\Setting\Tax;
10
-use App\Traits\HandlesDefaultSettingRecordCreation;
10
+use App\Traits\HandlesDefaultSettingRecordUpdate;
11 11
 use Filament\Forms\ComponentContainer;
12 12
 use Filament\Forms\Components\Section;
13 13
 use Filament\Forms\Components\Select;
@@ -15,7 +15,6 @@ use Filament\Forms\Concerns\InteractsWithForms;
15 15
 use Filament\Forms\Contracts\HasForms;
16 16
 use Filament\Notifications\Notification;
17 17
 use Illuminate\Contracts\View\View;
18
-use Illuminate\Support\Facades\Auth;
19 18
 use Livewire\Component;
20 19
 
21 20
 /**
@@ -23,7 +22,7 @@ use Livewire\Component;
23 22
  */
24 23
 class DefaultSetting extends Component implements HasForms
25 24
 {
26
-    use InteractsWithForms, HandlesDefaultSettingRecordCreation;
25
+    use InteractsWithForms, HandlesDefaultSettingRecordUpdate;
27 26
 
28 27
     public Defaults $defaultSetting;
29 28
 
@@ -55,14 +54,12 @@ class DefaultSetting extends Component implements HasForms
55 54
                     Select::make('account_id')
56 55
                         ->label('Account')
57 56
                         ->options(Defaults::getAccounts())
58
-                        ->default(Defaults::getDefaultAccount())
59 57
                         ->searchable()
60 58
                         ->validationAttribute('Account')
61 59
                         ->nullable(),
62 60
                     Select::make('currency_code')
63 61
                         ->label('Currency')
64 62
                         ->options(Defaults::getCurrencies())
65
-                        ->default(Defaults::getDefaultCurrency())
66 63
                         ->searchable()
67 64
                         ->validationAttribute('Currency')
68 65
                         ->nullable(),
@@ -72,28 +69,24 @@ class DefaultSetting extends Component implements HasForms
72 69
                     Select::make('sales_tax_id')
73 70
                         ->label('Sales Tax')
74 71
                         ->options(Defaults::getSalesTaxes())
75
-                        ->default(Defaults::getDefaultSalesTax())
76 72
                         ->searchable()
77 73
                         ->validationAttribute('Sales Tax')
78 74
                         ->nullable(),
79 75
                     Select::make('purchase_tax_id')
80 76
                         ->label('Purchase Tax')
81 77
                         ->options(Defaults::getPurchaseTaxes())
82
-                        ->default(Defaults::getDefaultPurchaseTax())
83 78
                         ->searchable()
84 79
                         ->validationAttribute('Purchase Tax')
85 80
                         ->nullable(),
86 81
                     Select::make('sales_discount_id')
87 82
                         ->label('Sales Discount')
88 83
                         ->options(Defaults::getSalesDiscounts())
89
-                        ->default(Defaults::getDefaultSalesDiscount())
90 84
                         ->searchable()
91 85
                         ->validationAttribute('Sales Discount')
92 86
                         ->nullable(),
93 87
                     Select::make('purchase_discount_id')
94 88
                         ->label('Purchase Discount')
95 89
                         ->options(Defaults::getPurchaseDiscounts())
96
-                        ->default(Defaults::getDefaultPurchaseDiscount())
97 90
                         ->searchable()
98 91
                         ->validationAttribute('Purchase Discount')
99 92
                         ->nullable(),
@@ -103,14 +96,12 @@ class DefaultSetting extends Component implements HasForms
103 96
                     Select::make('income_category_id')
104 97
                         ->label('Income Category')
105 98
                         ->options(Defaults::getIncomeCategories())
106
-                        ->default(Defaults::getDefaultIncomeCategory())
107 99
                         ->searchable()
108 100
                         ->validationAttribute('Income Category')
109 101
                         ->nullable(),
110 102
                     Select::make('expense_category_id')
111 103
                         ->label('Expense Category')
112 104
                         ->options(Defaults::getExpenseCategories())
113
-                        ->default(Defaults::getDefaultExpenseCategory())
114 105
                         ->searchable()
115 106
                         ->validationAttribute('Expense Category')
116 107
                         ->nullable(),
@@ -122,23 +113,13 @@ class DefaultSetting extends Component implements HasForms
122 113
     {
123 114
         $data = $this->form->getState();
124 115
 
125
-        $data = $this->mutateFormDataBeforeCreate($data);
126
-
127
-        $this->record = $this->handleRecordCreation($data);
116
+        $this->record = $this->handleRecordUpdate($data);
128 117
 
129 118
         $this->form->model($this->record)->saveRelationships();
130 119
 
131 120
         $this->getSavedNotification()?->send();
132 121
     }
133 122
 
134
-    protected function mutateFormDataBeforeCreate(array $data): array
135
-    {
136
-        $data['company_id'] = Auth::user()->currentCompany->id;
137
-        $data['updated_by'] = Auth::id();
138
-
139
-        return $data;
140
-    }
141
-
142 123
     protected function getRelatedEntities(): array
143 124
     {
144 125
         return [

+ 3
- 4
app/Models/Banking/Account.php View File

@@ -5,6 +5,8 @@ namespace App\Models\Banking;
5 5
 use App\Scopes\CurrentCompanyScope;
6 6
 use App\Models\Setting\Currency;
7 7
 use App\Models\Setting\DefaultSetting;
8
+use App\Traits\Blamable;
9
+use App\Traits\CompanyOwned;
8 10
 use Database\Factories\AccountFactory;
9 11
 use Illuminate\Database\Eloquent\Factories\Factory;
10 12
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -12,15 +14,12 @@ use Illuminate\Database\Eloquent\Model;
12 14
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
13 15
 use Illuminate\Database\Eloquent\Relations\HasMany;
14 16
 use Illuminate\Database\Eloquent\Relations\HasOne;
15
-use Illuminate\Support\Facades\Auth;
16
-use Illuminate\Support\Facades\Config;
17 17
 use Spatie\Tags\HasTags;
18 18
 use Wallo\FilamentCompanies\FilamentCompanies;
19 19
 
20 20
 class Account extends Model
21 21
 {
22
-    use HasFactory;
23
-    use HasTags;
22
+    use Blamable, CompanyOwned, HasFactory, HasTags;
24 23
 
25 24
     protected $table = 'accounts';
26 25
 

+ 3
- 1
app/Models/Contact.php View File

@@ -5,6 +5,8 @@ namespace App\Models;
5 5
 use App\Models\Document\Document;
6 6
 use App\Models\Setting\Currency;
7 7
 use App\Scopes\CurrentCompanyScope;
8
+use App\Traits\Blamable;
9
+use App\Traits\CompanyOwned;
8 10
 use Illuminate\Database\Eloquent\Factories\HasFactory;
9 11
 use Illuminate\Database\Eloquent\Model;
10 12
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -15,7 +17,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
15 17
 
16 18
 class Contact extends Model
17 19
 {
18
-    use HasFactory;
20
+    use Blamable, CompanyOwned, HasFactory;
19 21
 
20 22
     protected $table = 'contacts';
21 23
 

+ 3
- 1
app/Models/Document/Document.php View File

@@ -8,6 +8,8 @@ use App\Models\Setting\Currency;
8 8
 use App\Models\Setting\Discount;
9 9
 use App\Models\Setting\DocumentDefault;
10 10
 use App\Models\Setting\Tax;
11
+use App\Traits\Blamable;
12
+use App\Traits\CompanyOwned;
11 13
 use Database\Factories\DocumentFactory;
12 14
 use Illuminate\Database\Eloquent\Factories\Factory;
13 15
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -19,7 +21,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
19 21
 
20 22
 class Document extends Model
21 23
 {
22
-    use HasFactory;
24
+    use Blamable, CompanyOwned, HasFactory;
23 25
 
24 26
     protected $table = 'documents';
25 27
 

+ 3
- 1
app/Models/Document/DocumentItem.php View File

@@ -5,6 +5,8 @@ namespace App\Models\Document;
5 5
 use App\Models\Item;
6 6
 use App\Models\Setting\Discount;
7 7
 use App\Models\Setting\Tax;
8
+use App\Traits\Blamable;
9
+use App\Traits\CompanyOwned;
8 10
 use Database\Factories\DocumentItemFactory;
9 11
 use Illuminate\Database\Eloquent\Factories\Factory;
10 12
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -14,7 +16,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
14 16
 
15 17
 class DocumentItem extends Model
16 18
 {
17
-    use HasFactory;
19
+    use Blamable, CompanyOwned, HasFactory;
18 20
 
19 21
     protected $table = 'document_items';
20 22
 

+ 3
- 1
app/Models/Document/DocumentTotal.php View File

@@ -2,6 +2,8 @@
2 2
 
3 3
 namespace App\Models\Document;
4 4
 
5
+use App\Traits\Blamable;
6
+use App\Traits\CompanyOwned;
5 7
 use Database\Factories\DocumentTotalFactory;
6 8
 use Illuminate\Database\Eloquent\Factories\Factory;
7 9
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -11,7 +13,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
11 13
 
12 14
 class DocumentTotal extends Model
13 15
 {
14
-    use HasFactory;
16
+    use Blamable, CompanyOwned, HasFactory;
15 17
 
16 18
     protected $table = 'document_totals';
17 19
 

+ 3
- 1
app/Models/Item.php View File

@@ -6,6 +6,8 @@ use App\Models\Document\DocumentItem;
6 6
 use App\Models\Setting\Category;
7 7
 use App\Models\Setting\Discount;
8 8
 use App\Models\Setting\Tax;
9
+use App\Traits\Blamable;
10
+use App\Traits\CompanyOwned;
9 11
 use Illuminate\Database\Eloquent\Factories\HasFactory;
10 12
 use Illuminate\Database\Eloquent\Model;
11 13
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -14,7 +16,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
14 16
 
15 17
 class Item extends Model
16 18
 {
17
-    use HasFactory;
19
+    use Blamable, CompanyOwned, HasFactory;
18 20
 
19 21
     protected $table = 'items';
20 22
 

+ 3
- 1
app/Models/Setting/Category.php View File

@@ -5,6 +5,8 @@ namespace App\Models\Setting;
5 5
 use App\Models\Document\Document;
6 6
 use App\Models\Item;
7 7
 use App\Scopes\CurrentCompanyScope;
8
+use App\Traits\Blamable;
9
+use App\Traits\CompanyOwned;
8 10
 use Database\Factories\CategoryFactory;
9 11
 use Illuminate\Database\Eloquent\Factories\Factory;
10 12
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -16,7 +18,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
16 18
 
17 19
 class Category extends Model
18 20
 {
19
-    use HasFactory;
21
+    use Blamable, CompanyOwned, HasFactory;
20 22
 
21 23
     protected $table = 'categories';
22 24
 

+ 13
- 1
app/Models/Setting/Currency.php View File

@@ -4,6 +4,8 @@ namespace App\Models\Setting;
4 4
 
5 5
 use App\Models\Banking\Account;
6 6
 use App\Scopes\CurrentCompanyScope;
7
+use App\Traits\Blamable;
8
+use App\Traits\CompanyOwned;
7 9
 use Database\Factories\CurrencyFactory;
8 10
 use Illuminate\Database\Eloquent\Factories\Factory;
9 11
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -16,7 +18,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
16 18
 
17 19
 class Currency extends Model
18 20
 {
19
-    use HasFactory;
21
+    use Blamable, CompanyOwned, HasFactory;
20 22
 
21 23
     protected $table = 'currencies';
22 24
 
@@ -60,6 +62,16 @@ class Currency extends Model
60 62
         return $this->hasMany(Account::class, 'currency_code', 'code');
61 63
     }
62 64
 
65
+    public function createdBy(): BelongsTo
66
+    {
67
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
68
+    }
69
+
70
+    public function updatedBy(): BelongsTo
71
+    {
72
+        return $this->belongsTo(FilamentCompanies::userModel(), 'updated_by');
73
+    }
74
+
63 75
     public static function getCurrencyCodes(): array
64 76
     {
65 77
         $allCodes = array_keys(Config::get('money'));

+ 9
- 1
app/Models/Setting/DefaultSetting.php View File

@@ -4,6 +4,8 @@ namespace App\Models\Setting;
4 4
 
5 5
 use App\Models\Banking\Account;
6 6
 use App\Scopes\CurrentCompanyScope;
7
+use App\Traits\Blamable;
8
+use App\Traits\CompanyOwned;
7 9
 use Illuminate\Database\Eloquent\Factories\HasFactory;
8 10
 use Illuminate\Database\Eloquent\Model;
9 11
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -11,7 +13,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
11 13
 
12 14
 class DefaultSetting extends Model
13 15
 {
14
-    use HasFactory;
16
+    use Blamable, CompanyOwned, HasFactory;
15 17
 
16 18
     protected $table = 'default_settings';
17 19
 
@@ -25,6 +27,7 @@ class DefaultSetting extends Model
25 27
         'purchase_discount_id',
26 28
         'income_category_id',
27 29
         'expense_category_id',
30
+        'created_by',
28 31
         'updated_by',
29 32
     ];
30 33
 
@@ -84,6 +87,11 @@ class DefaultSetting extends Model
84 87
             ->where('type', 'expense');
85 88
     }
86 89
 
90
+    public function createdBy(): BelongsTo
91
+    {
92
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
93
+    }
94
+
87 95
     public function updatedBy(): BelongsTo
88 96
     {
89 97
         return $this->belongsTo(FilamentCompanies::userModel(), 'updated_by');

+ 3
- 1
app/Models/Setting/Discount.php View File

@@ -5,6 +5,8 @@ namespace App\Models\Setting;
5 5
 use App\Models\Document\DocumentItem;
6 6
 use App\Models\Item;
7 7
 use App\Scopes\CurrentCompanyScope;
8
+use App\Traits\Blamable;
9
+use App\Traits\CompanyOwned;
8 10
 use Database\Factories\DiscountFactory;
9 11
 use Illuminate\Database\Eloquent\Factories\Factory;
10 12
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -16,7 +18,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
16 18
 
17 19
 class Discount extends Model
18 20
 {
19
-    use HasFactory;
21
+    use Blamable, CompanyOwned, HasFactory;
20 22
 
21 23
     protected $table = 'discounts';
22 24
 

+ 15
- 1
app/Models/Setting/DocumentDefault.php View File

@@ -4,6 +4,8 @@ namespace App\Models\Setting;
4 4
 
5 5
 use App\Models\Document\Document;
6 6
 use App\Scopes\CurrentCompanyScope;
7
+use App\Traits\Blamable;
8
+use App\Traits\CompanyOwned;
7 9
 use Database\Factories\DocumentDefaultFactory;
8 10
 use Illuminate\Database\Eloquent\Factories\Factory;
9 11
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -14,7 +16,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
14 16
 
15 17
 class DocumentDefault extends Model
16 18
 {
17
-    use HasFactory;
19
+    use Blamable, CompanyOwned, HasFactory;
18 20
 
19 21
     protected $table = 'document_defaults';
20 22
 
@@ -31,6 +33,8 @@ class DocumentDefault extends Model
31 33
         'notes',
32 34
         'terms',
33 35
         'footer',
36
+        'created_by',
37
+        'updated_by',
34 38
     ];
35 39
 
36 40
     protected static function booted(): void
@@ -48,6 +52,16 @@ class DocumentDefault extends Model
48 52
         return $this->hasMany(Document::class);
49 53
     }
50 54
 
55
+    public function createdBy(): BelongsTo
56
+    {
57
+        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
58
+    }
59
+
60
+    public function updatedBy(): BelongsTo
61
+    {
62
+        return $this->belongsTo(FilamentCompanies::userModel(), 'updated_by');
63
+    }
64
+
51 65
     public static function getDocumentNumberDigits(): array
52 66
     {
53 67
         return array_combine(range(1, 20), range(1, 20));

+ 3
- 1
app/Models/Setting/Tax.php View File

@@ -6,6 +6,8 @@ use App\Models\Company;
6 6
 use App\Models\Document\DocumentItem;
7 7
 use App\Models\Item;
8 8
 use App\Scopes\CurrentCompanyScope;
9
+use App\Traits\Blamable;
10
+use App\Traits\CompanyOwned;
9 11
 use Database\Factories\TaxFactory;
10 12
 use Illuminate\Database\Eloquent\Factories\Factory;
11 13
 use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -17,7 +19,7 @@ use Wallo\FilamentCompanies\FilamentCompanies;
17 19
 
18 20
 class Tax extends Model
19 21
 {
20
-    use HasFactory;
22
+    use Blamable, CompanyOwned, HasFactory;
21 23
 
22 24
     protected $table = 'taxes';
23 25
 

+ 3
- 67
app/Observers/CompanyObserver.php View File

@@ -3,11 +3,7 @@
3 3
 namespace App\Observers;
4 4
 
5 5
 use App\Models\Company;
6
-use App\Models\Setting\Category;
7
-use App\Models\Setting\Currency;
8
-use App\Models\Setting\Discount;
9
-use App\Models\Setting\DocumentDefault;
10
-use App\Models\Setting\Tax;
6
+use App\Services\DefaultSettingService;
11 7
 
12 8
 class CompanyObserver
13 9
 {
@@ -16,68 +12,8 @@ class CompanyObserver
16 12
      */
17 13
     public function created(Company $company): void
18 14
     {
19
-        $incomeCategories = ['Salary', 'Bonus', 'Interest', 'Dividends', 'Rentals'];
20
-        $expenseCategories = ['Rent', 'Utilities', 'Food', 'Transportation', 'Entertainment'];
21
-
22
-        $shuffledCategories = [
23
-            ...array_map(static fn ($name) => ['name' => $name, 'type' => 'income'], $incomeCategories),
24
-            ...array_map(static fn ($name) => ['name' => $name, 'type' => 'expense'], $expenseCategories),
25
-        ];
26
-
27
-        shuffle($shuffledCategories);
28
-
29
-        $incomeEnabled = $expenseEnabled = false;
30
-
31
-        foreach ($shuffledCategories as $category) {
32
-            $enabled = false;
33
-            if (!$incomeEnabled && $category['type'] === 'income') {
34
-                $enabled = $incomeEnabled = true;
35
-            } elseif (!$expenseEnabled && $category['type'] === 'expense') {
36
-                $enabled = $expenseEnabled = true;
37
-            }
38
-
39
-            Category::factory()->create([
40
-                'company_id' => $company->id,
41
-                'name' => $category['name'],
42
-                'type' => $category['type'],
43
-                'enabled' => $enabled,
44
-                'created_by' => $company->user_id,
45
-            ]);
46
-        }
47
-
48
-
49
-        DocumentDefault::factory()->invoice()->create([
50
-            'company_id' => $company->id,
51
-        ]);
52
-
53
-        DocumentDefault::factory()->bill()->create([
54
-            'company_id' => $company->id,
55
-        ]);
56
-
57
-        Currency::factory()->create([
58
-            'company_id' => $company->id,
59
-            'created_by' => $company->user_id,
60
-        ]);
61
-
62
-        Tax::factory()->salesTax()->create([
63
-            'company_id' => $company->id,
64
-            'created_by' => $company->user_id,
65
-        ]);
66
-
67
-        Tax::factory()->purchaseTax()->create([
68
-            'company_id' => $company->id,
69
-            'created_by' => $company->user_id,
70
-        ]);
71
-
72
-        Discount::factory()->salesDiscount()->create([
73
-            'company_id' => $company->id,
74
-            'created_by' => $company->user_id,
75
-        ]);
76
-
77
-        Discount::factory()->purchaseDiscount()->create([
78
-            'company_id' => $company->id,
79
-            'created_by' => $company->user_id,
80
-        ]);
15
+        $defaultSettingService = new DefaultSettingService();
16
+        $defaultSettingService->createDefaultSettings($company);
81 17
     }
82 18
 
83 19
     /**

+ 141
- 0
app/Services/DefaultSettingService.php View File

@@ -0,0 +1,141 @@
1
+<?php
2
+
3
+namespace App\Services;
4
+
5
+use App\Models\Company;
6
+use App\Models\Setting\Category;
7
+use App\Models\Setting\Currency;
8
+use App\Models\Setting\DefaultSetting;
9
+use App\Models\Setting\Discount;
10
+use App\Models\Setting\DocumentDefault;
11
+use App\Models\Setting\Tax;
12
+use Illuminate\Support\Facades\Auth;
13
+
14
+class DefaultSettingService
15
+{
16
+    public function createDefaultSettings(Company $company): void
17
+    {
18
+        $categories = $this->createDefaultCategories($company);
19
+        $currency = $this->createDefaultCurrency($company);
20
+        $salesTax = $this->createDefaultSalesTax($company);
21
+        $purchaseTax = $this->createDefaultPurchaseTax($company);
22
+        $salesDiscount = $this->createDefaultSalesDiscount($company);
23
+        $purchaseDiscount = $this->createDefaultPurchaseDiscount($company);
24
+
25
+        $defaultSettings = [
26
+            'company_id' => $company->id,
27
+            'income_category_id' => $categories['income_category_id'],
28
+            'expense_category_id' => $categories['expense_category_id'],
29
+            'currency_code' => $currency->code,
30
+            'sales_tax_id' => $salesTax->id,
31
+            'purchase_tax_id' => $purchaseTax->id,
32
+            'sales_discount_id' => $salesDiscount->id,
33
+            'purchase_discount_id' => $purchaseDiscount->id,
34
+            'created_by' => $company->owner->id,
35
+            'updated_by' => $company->owner->id,
36
+        ];
37
+
38
+        DefaultSetting::create($defaultSettings);
39
+
40
+        $this->createDefaultDocuments($company);
41
+    }
42
+
43
+    private function createDefaultCategories(Company $company): array
44
+    {
45
+        $incomeCategories = ['Salary', 'Bonus', 'Interest', 'Dividends', 'Rentals'];
46
+        $expenseCategories = ['Rent', 'Utilities', 'Food', 'Transportation', 'Entertainment'];
47
+
48
+        $shuffledCategories = [
49
+            ...array_map(static fn ($name) => ['name' => $name, 'type' => 'income'], $incomeCategories),
50
+            ...array_map(static fn ($name) => ['name' => $name, 'type' => 'expense'], $expenseCategories),
51
+        ];
52
+
53
+        shuffle($shuffledCategories);
54
+
55
+        $incomeEnabled = $expenseEnabled = false;
56
+
57
+        $defaultSettings = [];
58
+
59
+        foreach ($shuffledCategories as $category) {
60
+            $enabled = false;
61
+            if (!$incomeEnabled && $category['type'] === 'income') {
62
+                $enabled = $incomeEnabled = true;
63
+            } elseif (!$expenseEnabled && $category['type'] === 'expense') {
64
+                $enabled = $expenseEnabled = true;
65
+            }
66
+
67
+            $categoryModel = Category::factory()->create([
68
+                'company_id' => $company->id,
69
+                'name' => $category['name'],
70
+                'type' => $category['type'],
71
+                'enabled' => $enabled,
72
+                'created_by' => Auth::id(),
73
+                'updated_by' => Auth::id(),
74
+            ]);
75
+
76
+            $defaultSettings[$category['type'] . '_category_id'] = $categoryModel->id;
77
+        }
78
+
79
+        return $defaultSettings;
80
+    }
81
+
82
+    private function createDefaultDocuments(Company $company): void
83
+    {
84
+        DocumentDefault::factory()->invoice()->create([
85
+            'company_id' => $company->id,
86
+            'created_by' => Auth::id(),
87
+            'updated_by' => Auth::id(),
88
+        ]);
89
+
90
+        DocumentDefault::factory()->bill()->create([
91
+            'company_id' => $company->id,
92
+            'created_by' => Auth::id(),
93
+            'updated_by' => Auth::id(),
94
+        ]);
95
+    }
96
+
97
+    private function createDefaultCurrency(Company $company): Currency
98
+    {
99
+        return Currency::factory()->create([
100
+            'company_id' => $company->id,
101
+            'created_by' => Auth::id(),
102
+            'updated_by' => Auth::id(),
103
+        ]);
104
+    }
105
+
106
+    private function createDefaultSalesTax(Company $company): Tax
107
+    {
108
+        return Tax::factory()->salesTax()->create([
109
+            'company_id' => $company->id,
110
+            'created_by' => Auth::id(),
111
+            'updated_by' => Auth::id(),
112
+        ]);
113
+    }
114
+
115
+    private function createDefaultPurchaseTax(Company $company): Tax
116
+    {
117
+        return Tax::factory()->purchaseTax()->create([
118
+            'company_id' => $company->id,
119
+            'created_by' => Auth::id(),
120
+            'updated_by' => Auth::id(),
121
+        ]);
122
+    }
123
+
124
+    private function createDefaultSalesDiscount(Company $company): Discount
125
+    {
126
+        return Discount::factory()->salesDiscount()->create([
127
+            'company_id' => $company->id,
128
+            'created_by' => Auth::id(),
129
+            'updated_by' => Auth::id(),
130
+        ]);
131
+    }
132
+
133
+    private function createDefaultPurchaseDiscount(Company $company): Discount
134
+    {
135
+        return Discount::factory()->purchaseDiscount()->create([
136
+            'company_id' => $company->id,
137
+            'created_by' => Auth::id(),
138
+            'updated_by' => Auth::id(),
139
+        ]);
140
+    }
141
+}

+ 20
- 0
app/Traits/Blamable.php View File

@@ -0,0 +1,20 @@
1
+<?php
2
+
3
+namespace App\Traits;
4
+
5
+use Illuminate\Support\Facades\Auth;
6
+
7
+trait Blamable
8
+{
9
+    public static function bootBlamable(): void
10
+    {
11
+        static::created(static function ($model) {
12
+            $model->created_by = Auth::check() ? Auth::id() : null;
13
+            $model->updated_by = Auth::check() ? Auth::id() : null;
14
+        });
15
+
16
+        static::updated(static function ($model) {
17
+            $model->updated_by = Auth::check() ? Auth::id() : null;
18
+        });
19
+    }
20
+}

+ 25
- 0
app/Traits/CompanyOwned.php View File

@@ -0,0 +1,25 @@
1
+<?php
2
+
3
+namespace App\Traits;
4
+
5
+use Filament\Notifications\Notification;
6
+use Illuminate\Support\Facades\Auth;
7
+
8
+trait CompanyOwned
9
+{
10
+    public static function bootCompanyOwned(): void
11
+    {
12
+        static::created(static function ($model) {
13
+            if (Auth::check() && Auth::user()->currentCompany) {
14
+                $model->company_id = Auth::user()->currentCompany->id;
15
+            } else {
16
+                Notification::make()
17
+                    ->danger()
18
+                    ->title('Oops! Unable to Assign Company')
19
+                    ->body('We encountered an issue while creating the record. Please ensure you are logged in and have a valid company associated with your account.')
20
+                    ->persistent()
21
+                    ->send();
22
+            }
23
+        });
24
+    }
25
+}

app/Traits/HandlesDefaultSettingRecordCreation.php → app/Traits/HandlesDefaultSettingRecordUpdate.php View File

@@ -5,45 +5,42 @@ namespace App\Traits;
5 5
 use Illuminate\Database\Eloquent\Model;
6 6
 use Illuminate\Support\Facades\Auth;
7 7
 
8
-trait HandlesDefaultSettingRecordCreation
8
+trait HandlesDefaultSettingRecordUpdate
9 9
 {
10 10
     abstract protected function getRelatedEntities(): array;
11 11
     abstract protected function getFormModel(): string;
12 12
 
13
-    protected function handleRecordCreation(array $data): Model
13
+    protected function handleRecordUpdate(array $data): Model
14 14
     {
15 15
         $relatedEntities = $this->getRelatedEntities();
16
-
17 16
         $model = $this->getFormModel();
18 17
 
19 18
         $existingRecord = $model::where('company_id', Auth::user()->currentCompany->id)
20 19
             ->latest()
21 20
             ->first();
22 21
 
23
-        $newData = [
24
-            'company_id' => Auth::user()->currentCompany->id,
25
-            'updated_by' => Auth::id(),
26
-        ];
27
-
28 22
         foreach ($relatedEntities as $field => $params) {
29 23
             [$class, $key, $type] = array_pad($params, 3, null);
30 24
 
31 25
             if ($existingRecord === null || !isset($existingRecord->{$field})) {
32
-                $newData[$field] = $data[$field];
33 26
                 continue;
34 27
             }
35 28
 
36 29
             if (isset($data[$field]) && $data[$field] !== $existingRecord->{$field}) {
37 30
                 $this->updateEnabledRecord($class, $key, $existingRecord->{$field}, $type, false);
38 31
                 $this->updateEnabledRecord($class, $key, $data[$field], $type, true);
39
-
40
-                $newData[$field] = $data[$field];
41
-            } else {
42
-                $newData[$field] = $existingRecord->{$field};
43 32
             }
44 33
         }
45 34
 
46
-        return $model::create($newData);
35
+        $defaults = $model::where('company_id', Auth::user()->currentCompany->id)->first();
36
+
37
+        if ($defaults === null) {
38
+            $defaults = $model::create($data);
39
+        } else {
40
+            $defaults->update($data);
41
+        }
42
+
43
+        return $defaults;
47 44
     }
48 45
 
49 46
     protected function updateEnabledRecord($class, $key, $value, $type = null, $enabled = true): void
@@ -56,10 +53,7 @@ trait HandlesDefaultSettingRecordCreation
56 53
         }
57 54
 
58 55
         $query->where($key, $value)
59
-            ->update([
60
-                'enabled' => $enabled,
61
-                'updated_by' => Auth::id(),
62
-            ]);
56
+            ->update(compact('enabled'));
63 57
     }
64 58
 }
65 59
 

+ 31
- 18
app/Traits/HandlesResourceRecordCreation.php View File

@@ -2,34 +2,47 @@
2 2
 
3 3
 namespace App\Traits;
4 4
 
5
+use App\Models\User;
6
+use Filament\Support\Exceptions\Halt;
7
+use Illuminate\Auth\Access\AuthorizationException;
5 8
 use Illuminate\Database\Eloquent\Model;
6
-use Illuminate\Support\Facades\Auth;
7 9
 use Illuminate\Support\Facades\DB;
10
+use Illuminate\Validation\ValidationException;
11
+use Throwable;
8 12
 
9 13
 trait HandlesResourceRecordCreation
10 14
 {
11
-    protected function handleRecordCreationWithUniqueField(array $data, Model $model, string|null $uniqueField = null): Model
15
+    /**
16
+     * @throws Halt
17
+     */
18
+    protected function handleRecordCreationWithUniqueField(array $data, Model $model, User $user, string|null $uniqueField = null, ?string $uniqueFieldValue = null): Model
12 19
     {
13
-        return DB::transaction(function () use ($data, $uniqueField, $model) {
14
-            $currentCompanyId = Auth::user()->currentCompany->id;
15
-            $uniqueFieldValue = $data[$uniqueField] ?? null;
16
-            $enabled = (bool)($data['enabled'] ?? false);
20
+        try {
21
+            return DB::transaction(function () use ($data, $user, $model, $uniqueField, $uniqueFieldValue) {
22
+                $enabled = (bool)($data['enabled'] ?? false);
17 23
 
18
-            if ($enabled === true) {
19
-                $this->disableExistingRecord($currentCompanyId, $model, $uniqueField, $uniqueFieldValue);
20
-            } else {
21
-                $this->ensureAtLeastOneEnabled($currentCompanyId, $model, $enabled, $uniqueField, $uniqueFieldValue);
22
-            }
24
+                if ($enabled === true) {
25
+                    $this->disableExistingRecord($user->currentCompany->id, $model, $uniqueField, $uniqueFieldValue);
26
+                } else {
27
+                    $this->ensureAtLeastOneEnabled($user->currentCompany->id, $model, $enabled, $uniqueField, $uniqueFieldValue);
28
+                }
23 29
 
24
-            $data['enabled'] = $enabled;
30
+                $data['enabled'] = $enabled;
25 31
 
26
-            return $model::create($data);
27
-        });
32
+                return tap($model)->create($data);
33
+            });
34
+        } catch (ValidationException) {
35
+            throw new Halt('Invalid data provided. Please check the form and try again.');
36
+        } catch (AuthorizationException) {
37
+            throw new Halt('You are not authorized to perform this action.');
38
+        } catch (Throwable) {
39
+            throw new Halt('An unexpected error occurred. Please try again.');
40
+        }
28 41
     }
29 42
 
30 43
     protected function disableExistingRecord(int $companyId, Model $model, string|null $uniqueField = null, string|null $uniqueFieldValue = null): void
31 44
     {
32
-        $query = $model::where('company_id', $companyId)
45
+        $query = $model::query()->where('company_id', $companyId)
33 46
             ->where('enabled', true);
34 47
 
35 48
         if($uniqueField && $uniqueFieldValue){
@@ -46,16 +59,16 @@ trait HandlesResourceRecordCreation
46 59
 
47 60
     protected function ensureAtLeastOneEnabled(int $companyId, Model $model, bool &$enabled, string|null $uniqueField = null, string|null $uniqueFieldValue = null): void
48 61
     {
49
-        $query = $model::where('company_id', $companyId)
62
+        $query = $model::query()->where('company_id', $companyId)
50 63
             ->where('enabled', true);
51 64
 
52 65
         if($uniqueField && $uniqueFieldValue){
53 66
             $query->where($uniqueField, $uniqueFieldValue);
54 67
         }
55 68
 
56
-        $otherEnabledRecords = $query->count();
69
+        $otherEnabledRecord = $query->first();
57 70
 
58
-        if ($otherEnabledRecords === 0) {
71
+        if ($otherEnabledRecord === null) {
59 72
             $enabled = true;
60 73
         }
61 74
     }

+ 53
- 46
app/Traits/HandlesResourceRecordUpdate.php View File

@@ -2,77 +2,84 @@
2 2
 
3 3
 namespace App\Traits;
4 4
 
5
+use App\Models\User;
6
+use Filament\Support\Exceptions\Halt;
7
+use Illuminate\Auth\Access\AuthorizationException;
8
+use Illuminate\Database\Eloquent\Builder;
5 9
 use Illuminate\Database\Eloquent\Model;
6
-use Illuminate\Support\Facades\Auth;
7 10
 use Illuminate\Support\Facades\DB;
11
+use Illuminate\Validation\ValidationException;
12
+use Throwable;
8 13
 
9 14
 trait HandlesResourceRecordUpdate
10 15
 {
11
-    protected function handleRecordUpdateWithUniqueField(Model $record, array $data, string|null $uniqueField = null): Model
16
+    /**
17
+     * @throws Halt
18
+     */
19
+    protected function handleRecordUpdateWithUniqueField(Model $record, array $data, User $user, string|null $uniqueField = null): Model
12 20
     {
13
-        return DB::transaction(function () use ($uniqueField, $record, $data) {
14
-            $companyId = Auth::user()->currentCompany->id;
15
-            $oldValue = $uniqueField ? $record->{$uniqueField} : null;
16
-            $newValue = $uniqueField ? $data[$uniqueField] : null;
17
-            $enabled = (bool)($data['enabled'] ?? false);
18
-
19
-            if ($oldValue !== $newValue && $record->enabled) {
20
-                $this->enableAnotherOfSameValue($companyId, $record, $uniqueField, $oldValue);
21
-            }
22
-
23
-            if ($enabled === true) {
24
-                $this->disableOthersOfSameValue($companyId, $record, $uniqueField, $newValue);
25
-            } elseif ($enabled === false) {
26
-                $this->ensureAtLeastOneEnabled($companyId, $record, $uniqueField, $newValue, $enabled);
27
-            }
28
-
29
-            $data['enabled'] = $enabled;
30
-
31
-            return tap($record)->update($data);
32
-        });
21
+        try {
22
+            return DB::transaction(function () use ($user, $uniqueField, $record, $data) {
23
+                $companyId = $user->currentCompany->id;
24
+                $oldValue = $uniqueField ? $record->{$uniqueField} : null;
25
+                $newValue = $uniqueField ? $data[$uniqueField] : null;
26
+                $enabled = (bool)($data['enabled'] ?? false);
27
+
28
+                if ($oldValue !== $newValue && $record->enabled) {
29
+                    $this->toggleRecord($companyId, $record, $uniqueField, $oldValue, false, true);
30
+                }
31
+
32
+                if ($enabled === true) {
33
+                    $this->toggleRecord($companyId, $record, $uniqueField, $newValue, true, false);
34
+                } elseif ($enabled === false) {
35
+                    $this->ensureAtLeastOneEnabled($companyId, $record, $uniqueField, $newValue, $enabled);
36
+                }
37
+
38
+                $data['enabled'] = $enabled;
39
+
40
+                return tap($record)->update($data);
41
+            });
42
+        } catch (ValidationException) {
43
+            throw new Halt('Invalid data provided. Please check the form and try again.');
44
+        } catch (AuthorizationException) {
45
+            throw new Halt('You are not authorized to perform this action.');
46
+        } catch (Throwable) {
47
+            throw new Halt('An unexpected error occurred. Please try again.');
48
+        }
33 49
     }
34 50
 
35
-    protected function enableAnotherOfSameValue(int $companyId, Model $record, ?string $uniqueField, $value): void
51
+    protected function toggleRecord(int $companyId, Model $record, ?string $uniqueField, $value, bool $enabled, bool $newStatus): void
36 52
     {
37
-        $query = $record::where('company_id', $companyId)
38
-            ->where('id', '!=', $record->id)
39
-            ->where('enabled', false);
53
+        $query = $this->buildQuery($companyId, $record, $uniqueField, $value, $enabled);
40 54
 
41
-        if($uniqueField){
42
-            $query->where($uniqueField, $value);
43
-        }
44
-
45
-        $otherRecord = $query->first();
55
+        if ($newStatus) {
56
+            $otherRecord = $query->first();
46 57
 
47
-        if ($otherRecord) {
48
-            $otherRecord->enabled = true;
49
-            $otherRecord->save();
58
+            if ($otherRecord) {
59
+                $otherRecord->enabled = true;
60
+                $otherRecord->save();
61
+            }
62
+        } else {
63
+            $query->update(['enabled' => false]);
50 64
         }
51 65
     }
52 66
 
53
-    protected function disableOthersOfSameValue(int $companyId, Model $record, ?string $uniqueField, $value): void
67
+    protected function buildQuery(int $companyId, Model $record, ?string $uniqueField, $value, bool $enabled): Builder
54 68
     {
55
-        $query = $record::where('company_id', $companyId)
69
+        $query = $record::query()->where('company_id', $companyId)
56 70
             ->where('id', '!=', $record->id)
57
-            ->where('enabled', true);
71
+            ->where('enabled', $enabled);
58 72
 
59 73
         if($uniqueField){
60 74
             $query->where($uniqueField, $value);
61 75
         }
62 76
 
63
-        $query->update(['enabled' => false]);
77
+        return $query;
64 78
     }
65 79
 
66 80
     protected function ensureAtLeastOneEnabled(int $companyId, Model $record, ?string $uniqueField, $value, bool &$enabled): void
67 81
     {
68
-        $query = $record::where('company_id', $companyId)
69
-            ->where('id', '!=', $record->id)
70
-            ->where('enabled', true);
71
-
72
-        if($uniqueField){
73
-            $query->where($uniqueField, $value);
74
-        }
75
-
82
+        $query = $this->buildQuery($companyId, $record, $uniqueField, $value, true);
76 83
         $enabledCount = $query->count();
77 84
 
78 85
         if ($enabledCount === 0) {

+ 2
- 0
database/migrations/2023_05_22_000100_create_document_defaults_table.php View File

@@ -25,6 +25,8 @@ return new class extends Migration
25 25
             $table->text('notes')->nullable();
26 26
             $table->text('terms')->nullable();
27 27
             $table->string('footer')->nullable();
28
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
29
+            $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
28 30
             $table->timestamps();
29 31
         });
30 32
     }

+ 1
- 0
database/migrations/2023_07_03_054805_create_default_settings_table.php View File

@@ -22,6 +22,7 @@ return new class extends Migration
22 22
             $table->foreignId('purchase_discount_id')->nullable()->constrained('discounts')->nullOnDelete();
23 23
             $table->foreignId('income_category_id')->nullable()->constrained('categories')->nullOnDelete();
24 24
             $table->foreignId('expense_category_id')->nullable()->constrained('categories')->nullOnDelete();
25
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
25 26
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
26 27
             $table->timestamps();
27 28
 

Loading…
Cancel
Save