Browse Source

refactor

3.x
Andrew Wallo 1 year ago
parent
commit
c697fc2fe0
44 changed files with 924 additions and 604 deletions
  1. 13
    0
      app/Enums/Accounting/AdjustmentCategory.php
  2. 13
    0
      app/Enums/Accounting/AdjustmentType.php
  3. 16
    0
      app/Enums/Common/OfferingType.php
  4. 130
    0
      app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource.php
  5. 11
    0
      app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource/Pages/CreateAdjustment.php
  6. 18
    0
      app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource/Pages/EditAdjustment.php
  7. 4
    4
      app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource/Pages/ListAdjustments.php
  8. 0
    189
      app/Filament/Company/Clusters/Settings/Resources/DiscountResource.php
  9. 0
    16
      app/Filament/Company/Clusters/Settings/Resources/DiscountResource/Pages/CreateDiscount.php
  10. 0
    24
      app/Filament/Company/Clusters/Settings/Resources/DiscountResource/Pages/EditDiscount.php
  11. 0
    25
      app/Filament/Company/Clusters/Settings/Resources/DiscountResource/Pages/ListDiscounts.php
  12. 0
    158
      app/Filament/Company/Clusters/Settings/Resources/TaxResource.php
  13. 0
    16
      app/Filament/Company/Clusters/Settings/Resources/TaxResource/Pages/CreateTax.php
  14. 0
    24
      app/Filament/Company/Clusters/Settings/Resources/TaxResource/Pages/EditTax.php
  15. 2
    0
      app/Filament/Company/Pages/Accounting/AccountChart.php
  16. 131
    0
      app/Filament/Company/Resources/Common/OfferingResource.php
  17. 11
    0
      app/Filament/Company/Resources/Common/OfferingResource/Pages/CreateOffering.php
  18. 19
    0
      app/Filament/Company/Resources/Common/OfferingResource/Pages/EditOffering.php
  19. 19
    0
      app/Filament/Company/Resources/Common/OfferingResource/Pages/ListOfferings.php
  20. 50
    0
      app/Filament/Company/Resources/Purchases/BuyableOfferingResource.php
  21. 21
    0
      app/Filament/Company/Resources/Purchases/BuyableOfferingResource/Pages/CreateBuyableOffering.php
  22. 29
    0
      app/Filament/Company/Resources/Purchases/BuyableOfferingResource/Pages/EditBuyableOffering.php
  23. 25
    0
      app/Filament/Company/Resources/Purchases/BuyableOfferingResource/Pages/ListBuyableOfferings.php
  24. 50
    0
      app/Filament/Company/Resources/Sales/SellableOfferingResource.php
  25. 21
    0
      app/Filament/Company/Resources/Sales/SellableOfferingResource/Pages/CreateSellableOffering.php
  26. 29
    0
      app/Filament/Company/Resources/Sales/SellableOfferingResource/Pages/EditSellableOffering.php
  27. 25
    0
      app/Filament/Company/Resources/Sales/SellableOfferingResource/Pages/ListSellableOfferings.php
  28. 36
    7
      app/Models/Accounting/Adjustment.php
  29. 33
    8
      app/Models/Common/Offering.php
  30. 6
    0
      app/Models/Company.php
  31. 40
    0
      app/Observers/AdjustmentObserver.php
  32. 10
    0
      app/Providers/FilamentCompaniesServiceProvider.php
  33. 24
    14
      app/Services/ChartOfAccountsService.php
  34. 17
    17
      composer.lock
  35. 17
    13
      config/chart-of-accounts.php
  36. 1
    1
      database/factories/Accounting/AccountFactory.php
  37. 0
    1
      database/factories/Accounting/AdjustmentFactory.php
  38. 2
    0
      database/migrations/2024_11_13_214149_create_offerings_table.php
  39. 3
    1
      database/migrations/2024_11_14_230753_create_adjustments_table.php
  40. 2
    6
      database/migrations/2024_11_15_225714_create_adjustmentables_table.php
  41. 78
    78
      package-lock.json
  42. 9
    1
      resources/data/lang/en.json
  43. 8
    0
      resources/views/filament/company/components/tables/columns/offering-status.blade.php
  44. 1
    1
      resources/views/filament/company/pages/accounting/chart.blade.php

+ 13
- 0
app/Enums/Accounting/AdjustmentCategory.php View File

2
 
2
 
3
 namespace App\Enums\Accounting;
3
 namespace App\Enums\Accounting;
4
 
4
 
5
+use App\Enums\Concerns\ParsesEnum;
5
 use Filament\Support\Contracts\HasLabel;
6
 use Filament\Support\Contracts\HasLabel;
6
 
7
 
7
 enum AdjustmentCategory: string implements HasLabel
8
 enum AdjustmentCategory: string implements HasLabel
8
 {
9
 {
10
+    use ParsesEnum;
11
+
9
     case Tax = 'tax';
12
     case Tax = 'tax';
10
     case Discount = 'discount';
13
     case Discount = 'discount';
11
 
14
 
13
     {
16
     {
14
         return $this->name;
17
         return $this->name;
15
     }
18
     }
19
+
20
+    public function isTax(): bool
21
+    {
22
+        return $this === self::Tax;
23
+    }
24
+
25
+    public function isDiscount(): bool
26
+    {
27
+        return $this === self::Discount;
28
+    }
16
 }
29
 }

+ 13
- 0
app/Enums/Accounting/AdjustmentType.php View File

2
 
2
 
3
 namespace App\Enums\Accounting;
3
 namespace App\Enums\Accounting;
4
 
4
 
5
+use App\Enums\Concerns\ParsesEnum;
5
 use Filament\Support\Contracts\HasColor;
6
 use Filament\Support\Contracts\HasColor;
6
 use Filament\Support\Contracts\HasIcon;
7
 use Filament\Support\Contracts\HasIcon;
7
 use Filament\Support\Contracts\HasLabel;
8
 use Filament\Support\Contracts\HasLabel;
8
 
9
 
9
 enum AdjustmentType: string implements HasColor, HasIcon, HasLabel
10
 enum AdjustmentType: string implements HasColor, HasIcon, HasLabel
10
 {
11
 {
12
+    use ParsesEnum;
13
+
11
     case Sales = 'sales';
14
     case Sales = 'sales';
12
     case Purchase = 'purchase';
15
     case Purchase = 'purchase';
13
 
16
 
31
             self::Purchase => 'heroicon-o-shopping-bag',
34
             self::Purchase => 'heroicon-o-shopping-bag',
32
         };
35
         };
33
     }
36
     }
37
+
38
+    public function isSales(): bool
39
+    {
40
+        return $this === self::Sales;
41
+    }
42
+
43
+    public function isPurchase(): bool
44
+    {
45
+        return $this === self::Purchase;
46
+    }
34
 }
47
 }

+ 16
- 0
app/Enums/Common/OfferingType.php View File

1
+<?php
2
+
3
+namespace App\Enums\Common;
4
+
5
+use Filament\Support\Contracts\HasLabel;
6
+
7
+enum OfferingType: string implements HasLabel
8
+{
9
+    case Product = 'product';
10
+    case Service = 'service';
11
+
12
+    public function getLabel(): string
13
+    {
14
+        return $this->name;
15
+    }
16
+}

+ 130
- 0
app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Clusters\Settings\Resources;
4
+
5
+use App\Enums\Accounting\AdjustmentCategory;
6
+use App\Enums\Accounting\AdjustmentComputation;
7
+use App\Enums\Accounting\AdjustmentScope;
8
+use App\Enums\Accounting\AdjustmentType;
9
+use App\Filament\Company\Clusters\Settings;
10
+use App\Filament\Company\Clusters\Settings\Resources\AdjustmentResource\Pages;
11
+use App\Models\Accounting\Adjustment;
12
+use Filament\Forms;
13
+use Filament\Forms\Form;
14
+use Filament\Resources\Resource;
15
+use Filament\Tables;
16
+use Filament\Tables\Table;
17
+use Wallo\FilamentSelectify\Components\ToggleButton;
18
+
19
+class AdjustmentResource extends Resource
20
+{
21
+    protected static ?string $model = Adjustment::class;
22
+
23
+    protected static ?string $cluster = Settings::class;
24
+
25
+    public static function form(Form $form): Form
26
+    {
27
+        return $form
28
+            ->schema([
29
+                Forms\Components\Section::make('General')
30
+                    ->schema([
31
+                        Forms\Components\TextInput::make('name')
32
+                            ->autofocus()
33
+                            ->required()
34
+                            ->maxLength(255),
35
+                        Forms\Components\Textarea::make('description')
36
+                            ->label('Description')
37
+                            ->autosize(),
38
+                    ]),
39
+                Forms\Components\Section::make('Configuration')
40
+                    ->schema([
41
+                        Forms\Components\Select::make('category')
42
+                            ->localizeLabel()
43
+                            ->options(AdjustmentCategory::class)
44
+                            ->default(AdjustmentCategory::Tax)
45
+                            ->live()
46
+                            ->required(),
47
+                        Forms\Components\Select::make('type')
48
+                            ->localizeLabel()
49
+                            ->options(AdjustmentType::class)
50
+                            ->default(AdjustmentType::Sales)
51
+                            ->live()
52
+                            ->required(),
53
+                        ToggleButton::make('recoverable')
54
+                            ->label('Recoverable')
55
+                            ->default(false)
56
+                            ->visible(fn (Forms\Get $get) => AdjustmentCategory::parse($get('category')) === AdjustmentCategory::Tax && AdjustmentType::parse($get('type')) === AdjustmentType::Purchase),
57
+                    ])
58
+                    ->columns()
59
+                    ->visibleOn('create'),
60
+                Forms\Components\Section::make('Adjustment Details')
61
+                    ->schema([
62
+                        Forms\Components\Select::make('computation')
63
+                            ->localizeLabel()
64
+                            ->options(AdjustmentComputation::class)
65
+                            ->default(AdjustmentComputation::Percentage)
66
+                            ->live()
67
+                            ->required(),
68
+                        Forms\Components\TextInput::make('rate')
69
+                            ->localizeLabel()
70
+                            ->rate(static fn (Forms\Get $get) => $get('computation'))
71
+                            ->required(),
72
+                        Forms\Components\Select::make('scope')
73
+                            ->localizeLabel()
74
+                            ->options(AdjustmentScope::class),
75
+                    ])
76
+                    ->columns(),
77
+                Forms\Components\Section::make('Dates')
78
+                    ->schema([
79
+                        Forms\Components\DateTimePicker::make('start_date'),
80
+                        Forms\Components\DateTimePicker::make('end_date'),
81
+                    ])
82
+                    ->columns()
83
+                    ->visible(fn (Forms\Get $get) => AdjustmentCategory::parse($get('category')) === AdjustmentCategory::Discount),
84
+            ]);
85
+    }
86
+
87
+    public static function table(Table $table): Table
88
+    {
89
+        return $table
90
+            ->columns([
91
+                Tables\Columns\TextColumn::make('name')
92
+                    ->label('Name')
93
+                    ->sortable(),
94
+                Tables\Columns\TextColumn::make('category')
95
+                    ->searchable(),
96
+                Tables\Columns\TextColumn::make('type')
97
+                    ->searchable(),
98
+                Tables\Columns\TextColumn::make('rate')
99
+                    ->localizeLabel()
100
+                    ->rate(static fn (Adjustment $record) => $record->computation->value)
101
+                    ->searchable()
102
+                    ->sortable(),
103
+            ])
104
+            ->filters([
105
+                //
106
+            ])
107
+            ->actions([
108
+                Tables\Actions\EditAction::make(),
109
+            ])
110
+            ->bulkActions([
111
+                //
112
+            ]);
113
+    }
114
+
115
+    public static function getRelations(): array
116
+    {
117
+        return [
118
+            //
119
+        ];
120
+    }
121
+
122
+    public static function getPages(): array
123
+    {
124
+        return [
125
+            'index' => Pages\ListAdjustments::route('/'),
126
+            'create' => Pages\CreateAdjustment::route('/create'),
127
+            'edit' => Pages\EditAdjustment::route('/{record}/edit'),
128
+        ];
129
+    }
130
+}

+ 11
- 0
app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource/Pages/CreateAdjustment.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Clusters\Settings\Resources\AdjustmentResource\Pages;
4
+
5
+use App\Filament\Company\Clusters\Settings\Resources\AdjustmentResource;
6
+use Filament\Resources\Pages\CreateRecord;
7
+
8
+class CreateAdjustment extends CreateRecord
9
+{
10
+    protected static string $resource = AdjustmentResource::class;
11
+}

+ 18
- 0
app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource/Pages/EditAdjustment.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Clusters\Settings\Resources\AdjustmentResource\Pages;
4
+
5
+use App\Filament\Company\Clusters\Settings\Resources\AdjustmentResource;
6
+use Filament\Resources\Pages\EditRecord;
7
+
8
+class EditAdjustment extends EditRecord
9
+{
10
+    protected static string $resource = AdjustmentResource::class;
11
+
12
+    protected function getHeaderActions(): array
13
+    {
14
+        return [
15
+            //
16
+        ];
17
+    }
18
+}

app/Filament/Company/Clusters/Settings/Resources/TaxResource/Pages/ListTaxes.php → app/Filament/Company/Clusters/Settings/Resources/AdjustmentResource/Pages/ListAdjustments.php View File

1
 <?php
1
 <?php
2
 
2
 
3
-namespace App\Filament\Company\Clusters\Settings\Resources\TaxResource\Pages;
3
+namespace App\Filament\Company\Clusters\Settings\Resources\AdjustmentResource\Pages;
4
 
4
 
5
-use App\Filament\Company\Clusters\Settings\Resources\TaxResource;
5
+use App\Filament\Company\Clusters\Settings\Resources\AdjustmentResource;
6
 use Filament\Actions;
6
 use Filament\Actions;
7
 use Filament\Resources\Pages\ListRecords;
7
 use Filament\Resources\Pages\ListRecords;
8
 use Filament\Support\Enums\MaxWidth;
8
 use Filament\Support\Enums\MaxWidth;
9
 
9
 
10
-class ListTaxes extends ListRecords
10
+class ListAdjustments extends ListRecords
11
 {
11
 {
12
-    protected static string $resource = TaxResource::class;
12
+    protected static string $resource = AdjustmentResource::class;
13
 
13
 
14
     protected function getHeaderActions(): array
14
     protected function getHeaderActions(): array
15
     {
15
     {

+ 0
- 189
app/Filament/Company/Clusters/Settings/Resources/DiscountResource.php View File

1
-<?php
2
-
3
-namespace App\Filament\Company\Clusters\Settings\Resources;
4
-
5
-use App\Concerns\NotifiesOnDelete;
6
-use App\Enums\Setting\DateFormat;
7
-use App\Enums\Setting\DiscountComputation;
8
-use App\Enums\Setting\DiscountScope;
9
-use App\Enums\Setting\DiscountType;
10
-use App\Enums\Setting\TimeFormat;
11
-use App\Filament\Company\Clusters\Settings;
12
-use App\Filament\Company\Clusters\Settings\Resources\DiscountResource\Pages;
13
-use App\Models\Setting\Discount;
14
-use App\Models\Setting\Localization;
15
-use Closure;
16
-use Filament\Forms;
17
-use Filament\Forms\Form;
18
-use Filament\Resources\Resource;
19
-use Filament\Support\Enums\FontWeight;
20
-use Filament\Tables;
21
-use Filament\Tables\Table;
22
-use Wallo\FilamentSelectify\Components\ToggleButton;
23
-
24
-class DiscountResource extends Resource
25
-{
26
-    use NotifiesOnDelete;
27
-
28
-    protected static ?string $model = Discount::class;
29
-
30
-    protected static ?string $modelLabel = 'Discount';
31
-
32
-    protected static ?string $cluster = Settings::class;
33
-
34
-    public static function getModelLabel(): string
35
-    {
36
-        $modelLabel = static::$modelLabel;
37
-
38
-        return translate($modelLabel);
39
-    }
40
-
41
-    public static function form(Form $form): Form
42
-    {
43
-        return $form
44
-            ->schema([
45
-                Forms\Components\Section::make('General')
46
-                    ->schema([
47
-                        Forms\Components\TextInput::make('name')
48
-                            ->autofocus()
49
-                            ->required()
50
-                            ->localizeLabel()
51
-                            ->maxLength(255)
52
-                            ->rule(static function (Forms\Get $get, Forms\Components\Component $component): Closure {
53
-                                return static function (string $attribute, $value, Closure $fail) use ($component, $get) {
54
-                                    $existingDiscount = Discount::where('name', $value)
55
-                                        ->whereKeyNot($component->getRecord()?->getKey())
56
-                                        ->where('type', $get('type'))
57
-                                        ->first();
58
-
59
-                                    if ($existingDiscount) {
60
-                                        $message = translate('The :Type :record ":name" already exists.', [
61
-                                            'Type' => $existingDiscount->type->getLabel(),
62
-                                            'record' => strtolower(static::getModelLabel()),
63
-                                            'name' => $value,
64
-                                        ]);
65
-
66
-                                        $fail($message);
67
-                                    }
68
-                                };
69
-                            }),
70
-                        Forms\Components\TextInput::make('description')
71
-                            ->localizeLabel(),
72
-                        Forms\Components\Select::make('computation')
73
-                            ->localizeLabel()
74
-                            ->options(DiscountComputation::class)
75
-                            ->default(DiscountComputation::Percentage)
76
-                            ->live()
77
-                            ->required(),
78
-                        Forms\Components\TextInput::make('rate')
79
-                            ->localizeLabel()
80
-                            ->rate(static fn (Forms\Get $get) => $get('computation'))
81
-                            ->required(),
82
-                        Forms\Components\Select::make('type')
83
-                            ->localizeLabel()
84
-                            ->options(DiscountType::class)
85
-                            ->default(DiscountType::Sales)
86
-                            ->required(),
87
-                        Forms\Components\Select::make('scope')
88
-                            ->localizeLabel()
89
-                            ->options(DiscountScope::class)
90
-                            ->nullable(),
91
-                        Forms\Components\DateTimePicker::make('start_date')
92
-                            ->localizeLabel()
93
-                            ->beforeOrEqual('end_date')
94
-                            ->seconds(false)
95
-                            ->disabled(static fn (string $operation, ?Discount $record = null) => $operation === 'edit' && $record?->start_date?->isPast() ?? false)
96
-                            ->helperText(static fn (Forms\Components\DateTimePicker $component) => $component->isDisabled() ? 'Start date cannot be changed after the discount has begun.' : null),
97
-                        Forms\Components\DateTimePicker::make('end_date')
98
-                            ->localizeLabel()
99
-                            ->afterOrEqual('start_date')
100
-                            ->seconds(false),
101
-                        ToggleButton::make('enabled')
102
-                            ->localizeLabel('Default')
103
-                            ->onLabel(Discount::enabledLabel())
104
-                            ->offLabel(Discount::disabledLabel()),
105
-                    ])->columns(),
106
-            ]);
107
-    }
108
-
109
-    public static function table(Table $table): Table
110
-    {
111
-        return $table
112
-            ->columns([
113
-                Tables\Columns\TextColumn::make('name')
114
-                    ->localizeLabel()
115
-                    ->weight(FontWeight::Medium)
116
-                    ->icon(static fn (Discount $record) => $record->isEnabled() ? 'heroicon-o-lock-closed' : null)
117
-                    ->tooltip(static function (Discount $record) {
118
-                        if ($record->isDisabled()) {
119
-                            return null;
120
-                        }
121
-
122
-                        return translate('Default :Type :Record', [
123
-                            'Type' => $record->type->getLabel(),
124
-                            'Record' => static::getModelLabel(),
125
-                        ]);
126
-                    })
127
-                    ->iconPosition('after')
128
-                    ->searchable()
129
-                    ->sortable(),
130
-                Tables\Columns\TextColumn::make('rate')
131
-                    ->localizeLabel()
132
-                    ->rate(static fn (Discount $record) => $record->computation->value)
133
-                    ->searchable()
134
-                    ->sortable(),
135
-                Tables\Columns\TextColumn::make('type')
136
-                    ->localizeLabel()
137
-                    ->badge()
138
-                    ->searchable()
139
-                    ->sortable(),
140
-                Tables\Columns\TextColumn::make('start_date')
141
-                    ->localizeLabel()
142
-                    ->formatStateUsing(static function (Discount $record) {
143
-                        $dateFormat = Localization::firstOrFail()->date_format->value ?? DateFormat::DEFAULT;
144
-                        $timeFormat = Localization::firstOrFail()->time_format->value ?? TimeFormat::DEFAULT;
145
-
146
-                        return $record->start_date ? $record->start_date->format("{$dateFormat} {$timeFormat}") : 'N/A';
147
-                    })
148
-                    ->searchable()
149
-                    ->sortable(),
150
-                Tables\Columns\TextColumn::make('end_date')
151
-                    ->localizeLabel()
152
-                    ->formatStateUsing(static function (Discount $record) {
153
-                        $dateFormat = Localization::firstOrFail()->date_format->value ?? DateFormat::DEFAULT;
154
-                        $timeFormat = Localization::firstOrFail()->time_format->value ?? TimeFormat::DEFAULT;
155
-
156
-                        return $record->end_date ? $record->end_date->format("{$dateFormat} {$timeFormat}") : 'N/A';
157
-                    })
158
-                    ->color(static fn (Discount $record) => $record->end_date?->isPast() ? 'danger' : null)
159
-                    ->searchable()
160
-                    ->sortable(),
161
-            ])
162
-            ->filters([
163
-                //
164
-            ])
165
-            ->actions([
166
-                Tables\Actions\EditAction::make(),
167
-            ])
168
-            ->bulkActions([
169
-                Tables\Actions\BulkActionGroup::make([
170
-                    Tables\Actions\DeleteBulkAction::make(),
171
-                ]),
172
-            ])
173
-            ->checkIfRecordIsSelectableUsing(static function (Discount $record) {
174
-                return $record->isDisabled();
175
-            })
176
-            ->emptyStateActions([
177
-                Tables\Actions\CreateAction::make(),
178
-            ]);
179
-    }
180
-
181
-    public static function getPages(): array
182
-    {
183
-        return [
184
-            'index' => Pages\ListDiscounts::route('/'),
185
-            'create' => Pages\CreateDiscount::route('/create'),
186
-            'edit' => Pages\EditDiscount::route('/{record}/edit'),
187
-        ];
188
-    }
189
-}

+ 0
- 16
app/Filament/Company/Clusters/Settings/Resources/DiscountResource/Pages/CreateDiscount.php View File

1
-<?php
2
-
3
-namespace App\Filament\Company\Clusters\Settings\Resources\DiscountResource\Pages;
4
-
5
-use App\Filament\Company\Clusters\Settings\Resources\DiscountResource;
6
-use Filament\Resources\Pages\CreateRecord;
7
-
8
-class CreateDiscount extends CreateRecord
9
-{
10
-    protected static string $resource = DiscountResource::class;
11
-
12
-    protected function getRedirectUrl(): string
13
-    {
14
-        return $this->getResource()::getUrl('index');
15
-    }
16
-}

+ 0
- 24
app/Filament/Company/Clusters/Settings/Resources/DiscountResource/Pages/EditDiscount.php View File

1
-<?php
2
-
3
-namespace App\Filament\Company\Clusters\Settings\Resources\DiscountResource\Pages;
4
-
5
-use App\Filament\Company\Clusters\Settings\Resources\DiscountResource;
6
-use Filament\Actions;
7
-use Filament\Resources\Pages\EditRecord;
8
-
9
-class EditDiscount extends EditRecord
10
-{
11
-    protected static string $resource = DiscountResource::class;
12
-
13
-    protected function getHeaderActions(): array
14
-    {
15
-        return [
16
-            Actions\DeleteAction::make(),
17
-        ];
18
-    }
19
-
20
-    protected function getRedirectUrl(): string
21
-    {
22
-        return $this->getResource()::getUrl('index');
23
-    }
24
-}

+ 0
- 25
app/Filament/Company/Clusters/Settings/Resources/DiscountResource/Pages/ListDiscounts.php View File

1
-<?php
2
-
3
-namespace App\Filament\Company\Clusters\Settings\Resources\DiscountResource\Pages;
4
-
5
-use App\Filament\Company\Clusters\Settings\Resources\DiscountResource;
6
-use Filament\Actions;
7
-use Filament\Resources\Pages\ListRecords;
8
-use Filament\Support\Enums\MaxWidth;
9
-
10
-class ListDiscounts extends ListRecords
11
-{
12
-    protected static string $resource = DiscountResource::class;
13
-
14
-    protected function getHeaderActions(): array
15
-    {
16
-        return [
17
-            Actions\CreateAction::make(),
18
-        ];
19
-    }
20
-
21
-    public function getMaxContentWidth(): MaxWidth | string | null
22
-    {
23
-        return MaxWidth::ScreenTwoExtraLarge;
24
-    }
25
-}

+ 0
- 158
app/Filament/Company/Clusters/Settings/Resources/TaxResource.php View File

1
-<?php
2
-
3
-namespace App\Filament\Company\Clusters\Settings\Resources;
4
-
5
-use App\Concerns\NotifiesOnDelete;
6
-use App\Enums\Setting\TaxComputation;
7
-use App\Enums\Setting\TaxScope;
8
-use App\Enums\Setting\TaxType;
9
-use App\Filament\Company\Clusters\Settings;
10
-use App\Filament\Company\Clusters\Settings\Resources\TaxResource\Pages;
11
-use App\Models\Setting\Tax;
12
-use Closure;
13
-use Filament\Forms;
14
-use Filament\Forms\Form;
15
-use Filament\Resources\Resource;
16
-use Filament\Support\Enums\FontWeight;
17
-use Filament\Tables;
18
-use Filament\Tables\Table;
19
-use Wallo\FilamentSelectify\Components\ToggleButton;
20
-
21
-class TaxResource extends Resource
22
-{
23
-    use NotifiesOnDelete;
24
-
25
-    protected static ?string $model = Tax::class;
26
-
27
-    protected static ?string $modelLabel = 'Tax';
28
-
29
-    protected static ?string $cluster = Settings::class;
30
-
31
-    public static function getModelLabel(): string
32
-    {
33
-        $modelLabel = static::$modelLabel;
34
-
35
-        return translate($modelLabel);
36
-    }
37
-
38
-    public static function form(Form $form): Form
39
-    {
40
-        return $form
41
-            ->schema([
42
-                Forms\Components\Section::make('General')
43
-                    ->schema([
44
-                        Forms\Components\TextInput::make('name')
45
-                            ->autofocus()
46
-                            ->required()
47
-                            ->localizeLabel()
48
-                            ->maxLength(255)
49
-                            ->rule(static function (Forms\Get $get, Forms\Components\Component $component): Closure {
50
-                                return static function (string $attribute, $value, Closure $fail) use ($component, $get) {
51
-                                    $existingTax = Tax::where('name', $value)
52
-                                        ->whereKeyNot($component->getRecord()?->getKey())
53
-                                        ->where('type', $get('type'))
54
-                                        ->first();
55
-
56
-                                    if ($existingTax) {
57
-                                        $message = translate('The :Type :record ":name" already exists.', [
58
-                                            'Type' => $existingTax->type->getLabel(),
59
-                                            'record' => strtolower(static::getModelLabel()),
60
-                                            'name' => $value,
61
-                                        ]);
62
-
63
-                                        $fail($message);
64
-                                    }
65
-                                };
66
-                            }),
67
-                        Forms\Components\TextInput::make('description'),
68
-                        Forms\Components\Select::make('computation')
69
-                            ->localizeLabel()
70
-                            ->options(TaxComputation::class)
71
-                            ->default(TaxComputation::Percentage)
72
-                            ->live()
73
-                            ->required(),
74
-                        Forms\Components\TextInput::make('rate')
75
-                            ->localizeLabel()
76
-                            ->rate(static fn (Forms\Get $get) => $get('computation'))
77
-                            ->required(),
78
-                        Forms\Components\Select::make('type')
79
-                            ->localizeLabel()
80
-                            ->options(TaxType::class)
81
-                            ->default(TaxType::Sales)
82
-                            ->required(),
83
-                        Forms\Components\Select::make('scope')
84
-                            ->localizeLabel()
85
-                            ->options(TaxScope::class),
86
-                        ToggleButton::make('enabled')
87
-                            ->localizeLabel('Default')
88
-                            ->onLabel(Tax::enabledLabel())
89
-                            ->offLabel(Tax::disabledLabel()),
90
-                    ])->columns(),
91
-            ]);
92
-    }
93
-
94
-    public static function table(Table $table): Table
95
-    {
96
-        return $table
97
-            ->columns([
98
-                Tables\Columns\TextColumn::make('name')
99
-                    ->localizeLabel()
100
-                    ->weight(FontWeight::Medium)
101
-                    ->icon(static fn (Tax $record) => $record->isEnabled() ? 'heroicon-o-lock-closed' : null)
102
-                    ->tooltip(static function (Tax $record) {
103
-                        if ($record->isDisabled()) {
104
-                            return null;
105
-                        }
106
-
107
-                        return translate('Default :Type :Record', [
108
-                            'Type' => $record->type->getLabel(),
109
-                            'Record' => static::getModelLabel(),
110
-                        ]);
111
-                    })
112
-                    ->iconPosition('after')
113
-                    ->searchable()
114
-                    ->sortable(),
115
-                Tables\Columns\TextColumn::make('computation')
116
-                    ->localizeLabel()
117
-                    ->searchable()
118
-                    ->sortable(),
119
-                Tables\Columns\TextColumn::make('rate')
120
-                    ->localizeLabel()
121
-                    ->rate(static fn (Tax $record) => $record->computation->value)
122
-                    ->searchable()
123
-                    ->sortable(),
124
-                Tables\Columns\TextColumn::make('type')
125
-                    ->localizeLabel()
126
-                    ->badge()
127
-                    ->searchable()
128
-                    ->sortable(),
129
-            ])
130
-            ->filters([
131
-                //
132
-            ])
133
-            ->actions([
134
-                Tables\Actions\EditAction::make(),
135
-                Tables\Actions\DeleteAction::make(),
136
-            ])
137
-            ->bulkActions([
138
-                Tables\Actions\BulkActionGroup::make([
139
-                    Tables\Actions\DeleteBulkAction::make(),
140
-                ]),
141
-            ])
142
-            ->checkIfRecordIsSelectableUsing(static function (Tax $record) {
143
-                return $record->isDisabled();
144
-            })
145
-            ->emptyStateActions([
146
-                Tables\Actions\CreateAction::make(),
147
-            ]);
148
-    }
149
-
150
-    public static function getPages(): array
151
-    {
152
-        return [
153
-            'index' => Pages\ListTaxes::route('/'),
154
-            'create' => Pages\CreateTax::route('/create'),
155
-            'edit' => Pages\EditTax::route('/{record}/edit'),
156
-        ];
157
-    }
158
-}

+ 0
- 16
app/Filament/Company/Clusters/Settings/Resources/TaxResource/Pages/CreateTax.php View File

1
-<?php
2
-
3
-namespace App\Filament\Company\Clusters\Settings\Resources\TaxResource\Pages;
4
-
5
-use App\Filament\Company\Clusters\Settings\Resources\TaxResource;
6
-use Filament\Resources\Pages\CreateRecord;
7
-
8
-class CreateTax extends CreateRecord
9
-{
10
-    protected static string $resource = TaxResource::class;
11
-
12
-    protected function getRedirectUrl(): string
13
-    {
14
-        return $this->getResource()::getUrl('index');
15
-    }
16
-}

+ 0
- 24
app/Filament/Company/Clusters/Settings/Resources/TaxResource/Pages/EditTax.php View File

1
-<?php
2
-
3
-namespace App\Filament\Company\Clusters\Settings\Resources\TaxResource\Pages;
4
-
5
-use App\Filament\Company\Clusters\Settings\Resources\TaxResource;
6
-use Filament\Actions;
7
-use Filament\Resources\Pages\EditRecord;
8
-
9
-class EditTax extends EditRecord
10
-{
11
-    protected static string $resource = TaxResource::class;
12
-
13
-    protected function getHeaderActions(): array
14
-    {
15
-        return [
16
-            Actions\DeleteAction::make(),
17
-        ];
18
-    }
19
-
20
-    protected function getRedirectUrl(): string
21
-    {
22
-        return $this->getResource()::getUrl('index');
23
-    }
24
-}

+ 2
- 0
app/Filament/Company/Pages/Accounting/AccountChart.php View File

46
     public function categories(): Collection
46
     public function categories(): Collection
47
     {
47
     {
48
         return AccountSubtype::withCount('accounts')
48
         return AccountSubtype::withCount('accounts')
49
+            ->with('accounts')
50
+            ->with('accounts.adjustment')
49
             ->get()
51
             ->get()
50
             ->groupBy('category');
52
             ->groupBy('category');
51
     }
53
     }

+ 131
- 0
app/Filament/Company/Resources/Common/OfferingResource.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Common;
4
+
5
+use App\Enums\Common\OfferingType;
6
+use App\Filament\Company\Resources\Common\OfferingResource\Pages;
7
+use App\Models\Common\Offering;
8
+use App\Utilities\Currency\CurrencyAccessor;
9
+use Filament\Forms;
10
+use Filament\Forms\Form;
11
+use Filament\Resources\Resource;
12
+use Filament\Tables;
13
+use Filament\Tables\Table;
14
+
15
+class OfferingResource extends Resource
16
+{
17
+    protected static ?string $model = Offering::class;
18
+
19
+    public static function form(Form $form): Form
20
+    {
21
+        return $form
22
+            ->schema([
23
+                Forms\Components\Section::make('General')
24
+                    ->schema([
25
+                        Forms\Components\TextInput::make('name')
26
+                            ->autofocus()
27
+                            ->required()
28
+                            ->maxLength(255),
29
+                        Forms\Components\Textarea::make('description')
30
+                            ->label('Description')
31
+                            ->autosize(),
32
+                        Forms\Components\Select::make('type')
33
+                            ->options(OfferingType::class)
34
+                            ->searchable()
35
+                            ->required(),
36
+                        Forms\Components\TextInput::make('price')
37
+                            ->required()
38
+                            ->money(CurrencyAccessor::getDefaultCurrency()),
39
+                        Forms\Components\Checkbox::make('sellable')
40
+                            ->label('Sellable')
41
+                            ->live()
42
+                            ->dehydrated(false)
43
+                            ->default(false),
44
+                        Forms\Components\Checkbox::make('purchasable')
45
+                            ->label('Purchasable')
46
+                            ->live()
47
+                            ->dehydrated(false)
48
+                            ->default(false),
49
+                    ]),
50
+                // Sellable Section
51
+                Forms\Components\Section::make('Sellable Configuration')
52
+                    ->schema([
53
+                        Forms\Components\Select::make('income_account_id')
54
+                            ->relationship('incomeAccount', 'name')
55
+                            ->searchable()
56
+                            ->preload(),
57
+                        Forms\Components\Select::make('sales_taxes')
58
+                            ->relationship('salesTaxes', 'name')
59
+                            ->preload()
60
+                            ->multiple(),
61
+                        Forms\Components\Select::make('sales_discounts')
62
+                            ->relationship('salesDiscounts', 'name')
63
+                            ->preload()
64
+                            ->multiple(),
65
+                    ])
66
+                    ->columns(2)
67
+                    ->visible(fn (Forms\Get $get) => $get('sellable')),
68
+
69
+                // Purchasable Section
70
+                Forms\Components\Section::make('Purchasable Configuration')
71
+                    ->schema([
72
+                        Forms\Components\Select::make('expense_account_id')
73
+                            ->relationship('expenseAccount', 'name')
74
+                            ->searchable()
75
+                            ->preload(),
76
+                        Forms\Components\Select::make('purchase_taxes')
77
+                            ->relationship('purchaseTaxes', 'name')
78
+                            ->preload()
79
+                            ->multiple(),
80
+                        Forms\Components\Select::make('purchase_discounts')
81
+                            ->relationship('purchaseDiscounts', 'name')
82
+                            ->preload()
83
+                            ->multiple(),
84
+                    ])
85
+                    ->columns(2)
86
+                    ->visible(fn (Forms\Get $get) => $get('purchasable')),
87
+            ])->columns(1);
88
+    }
89
+
90
+    public static function table(Table $table): Table
91
+    {
92
+        return $table
93
+            ->columns([
94
+                Tables\Columns\ViewColumn::make('name')
95
+                    ->label('Name')
96
+                    ->view('filament.company.components.tables.columns.offering-status'),
97
+                Tables\Columns\TextColumn::make('type')
98
+                    ->searchable(),
99
+                Tables\Columns\TextColumn::make('price')
100
+                    ->money()
101
+                    ->sortable(),
102
+            ])
103
+            ->filters([
104
+                //
105
+            ])
106
+            ->actions([
107
+                Tables\Actions\EditAction::make(),
108
+            ])
109
+            ->bulkActions([
110
+                Tables\Actions\BulkActionGroup::make([
111
+                    Tables\Actions\DeleteBulkAction::make(),
112
+                ]),
113
+            ]);
114
+    }
115
+
116
+    public static function getRelations(): array
117
+    {
118
+        return [
119
+            //
120
+        ];
121
+    }
122
+
123
+    public static function getPages(): array
124
+    {
125
+        return [
126
+            'index' => Pages\ListOfferings::route('/'),
127
+            'create' => Pages\CreateOffering::route('/create'),
128
+            'edit' => Pages\EditOffering::route('/{record}/edit'),
129
+        ];
130
+    }
131
+}

+ 11
- 0
app/Filament/Company/Resources/Common/OfferingResource/Pages/CreateOffering.php View File

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

+ 19
- 0
app/Filament/Company/Resources/Common/OfferingResource/Pages/EditOffering.php View File

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

+ 19
- 0
app/Filament/Company/Resources/Common/OfferingResource/Pages/ListOfferings.php View File

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

+ 50
- 0
app/Filament/Company/Resources/Purchases/BuyableOfferingResource.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Purchases;
4
+
5
+use App\Filament\Company\Resources\Common\OfferingResource;
6
+use App\Filament\Company\Resources\Purchases\BuyableOfferingResource\Pages;
7
+use App\Models\Common\Offering;
8
+use Filament\Forms\Form;
9
+use Filament\Resources\Resource;
10
+use Filament\Tables\Table;
11
+use Illuminate\Database\Eloquent\Builder;
12
+
13
+class BuyableOfferingResource extends Resource
14
+{
15
+    protected static ?string $model = Offering::class;
16
+
17
+    protected static ?string $pluralModelLabel = 'Products & Services';
18
+
19
+    public static function getEloquentQuery(): Builder
20
+    {
21
+        return parent::getEloquentQuery()
22
+            ->whereNotNull('expense_account_id');
23
+    }
24
+
25
+    public static function form(Form $form): Form
26
+    {
27
+        return OfferingResource::form($form);
28
+    }
29
+
30
+    public static function table(Table $table): Table
31
+    {
32
+        return OfferingResource::table($table);
33
+    }
34
+
35
+    public static function getRelations(): array
36
+    {
37
+        return [
38
+            //
39
+        ];
40
+    }
41
+
42
+    public static function getPages(): array
43
+    {
44
+        return [
45
+            'index' => Pages\ListBuyableOfferings::route('/'),
46
+            'create' => Pages\CreateBuyableOffering::route('/create'),
47
+            'edit' => Pages\EditBuyableOffering::route('/{record}/edit'),
48
+        ];
49
+    }
50
+}

+ 21
- 0
app/Filament/Company/Resources/Purchases/BuyableOfferingResource/Pages/CreateBuyableOffering.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Purchases\BuyableOfferingResource\Pages;
4
+
5
+use App\Filament\Company\Resources\Purchases\BuyableOfferingResource;
6
+use App\Filament\Company\Resources\Sales\SellableOfferingResource;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateBuyableOffering extends CreateRecord
10
+{
11
+    protected static string $resource = BuyableOfferingResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        if ($this->record->income_account_id && ! $this->record->expense_account_id) {
16
+            return SellableOfferingResource::getUrl();
17
+        } else {
18
+            return $this->getResource()::getUrl('index');
19
+        }
20
+    }
21
+}

+ 29
- 0
app/Filament/Company/Resources/Purchases/BuyableOfferingResource/Pages/EditBuyableOffering.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Purchases\BuyableOfferingResource\Pages;
4
+
5
+use App\Filament\Company\Resources\Purchases\BuyableOfferingResource;
6
+use App\Filament\Company\Resources\Sales\SellableOfferingResource;
7
+use Filament\Actions;
8
+use Filament\Resources\Pages\EditRecord;
9
+
10
+class EditBuyableOffering extends EditRecord
11
+{
12
+    protected static string $resource = BuyableOfferingResource::class;
13
+
14
+    protected function getHeaderActions(): array
15
+    {
16
+        return [
17
+            Actions\DeleteAction::make(),
18
+        ];
19
+    }
20
+
21
+    protected function getRedirectUrl(): string
22
+    {
23
+        if ($this->record->income_account_id && ! $this->record->expense_account_id) {
24
+            return SellableOfferingResource::getUrl();
25
+        } else {
26
+            return $this->getResource()::getUrl('index');
27
+        }
28
+    }
29
+}

+ 25
- 0
app/Filament/Company/Resources/Purchases/BuyableOfferingResource/Pages/ListBuyableOfferings.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Purchases\BuyableOfferingResource\Pages;
4
+
5
+use App\Filament\Company\Resources\Purchases\BuyableOfferingResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+use Illuminate\Contracts\Support\Htmlable;
9
+
10
+class ListBuyableOfferings extends ListRecords
11
+{
12
+    protected static string $resource = BuyableOfferingResource::class;
13
+
14
+    protected function getHeaderActions(): array
15
+    {
16
+        return [
17
+            Actions\CreateAction::make(),
18
+        ];
19
+    }
20
+
21
+    public function getHeading(): string | Htmlable
22
+    {
23
+        return 'Products & Services (Purchases)';
24
+    }
25
+}

+ 50
- 0
app/Filament/Company/Resources/Sales/SellableOfferingResource.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Sales;
4
+
5
+use App\Filament\Company\Resources\Common\OfferingResource;
6
+use App\Filament\Company\Resources\Sales\SellableOfferingResource\Pages;
7
+use App\Models\Common\Offering;
8
+use Filament\Forms\Form;
9
+use Filament\Resources\Resource;
10
+use Filament\Tables\Table;
11
+use Illuminate\Database\Eloquent\Builder;
12
+
13
+class SellableOfferingResource extends Resource
14
+{
15
+    protected static ?string $model = Offering::class;
16
+
17
+    protected static ?string $pluralModelLabel = 'Products & Services';
18
+
19
+    public static function getEloquentQuery(): Builder
20
+    {
21
+        return parent::getEloquentQuery()
22
+            ->whereNotNull('income_account_id');
23
+    }
24
+
25
+    public static function form(Form $form): Form
26
+    {
27
+        return OfferingResource::form($form);
28
+    }
29
+
30
+    public static function table(Table $table): Table
31
+    {
32
+        return OfferingResource::table($table);
33
+    }
34
+
35
+    public static function getRelations(): array
36
+    {
37
+        return [
38
+            //
39
+        ];
40
+    }
41
+
42
+    public static function getPages(): array
43
+    {
44
+        return [
45
+            'index' => Pages\ListSellableOfferings::route('/'),
46
+            'create' => Pages\CreateSellableOffering::route('/create'),
47
+            'edit' => Pages\EditSellableOffering::route('/{record}/edit'),
48
+        ];
49
+    }
50
+}

+ 21
- 0
app/Filament/Company/Resources/Sales/SellableOfferingResource/Pages/CreateSellableOffering.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Sales\SellableOfferingResource\Pages;
4
+
5
+use App\Filament\Company\Resources\Purchases\BuyableOfferingResource;
6
+use App\Filament\Company\Resources\Sales\SellableOfferingResource;
7
+use Filament\Resources\Pages\CreateRecord;
8
+
9
+class CreateSellableOffering extends CreateRecord
10
+{
11
+    protected static string $resource = SellableOfferingResource::class;
12
+
13
+    protected function getRedirectUrl(): string
14
+    {
15
+        if ($this->record->expense_account_id && ! $this->record->income_account_id) {
16
+            return BuyableOfferingResource::getUrl();
17
+        } else {
18
+            return $this->getResource()::getUrl('index');
19
+        }
20
+    }
21
+}

+ 29
- 0
app/Filament/Company/Resources/Sales/SellableOfferingResource/Pages/EditSellableOffering.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Sales\SellableOfferingResource\Pages;
4
+
5
+use App\Filament\Company\Resources\Purchases\BuyableOfferingResource;
6
+use App\Filament\Company\Resources\Sales\SellableOfferingResource;
7
+use Filament\Actions;
8
+use Filament\Resources\Pages\EditRecord;
9
+
10
+class EditSellableOffering extends EditRecord
11
+{
12
+    protected static string $resource = SellableOfferingResource::class;
13
+
14
+    protected function getHeaderActions(): array
15
+    {
16
+        return [
17
+            Actions\DeleteAction::make(),
18
+        ];
19
+    }
20
+
21
+    protected function getRedirectUrl(): string
22
+    {
23
+        if ($this->record->expense_account_id && ! $this->record->income_account_id) {
24
+            return BuyableOfferingResource::getUrl();
25
+        } else {
26
+            return $this->getResource()::getUrl('index');
27
+        }
28
+    }
29
+}

+ 25
- 0
app/Filament/Company/Resources/Sales/SellableOfferingResource/Pages/ListSellableOfferings.php View File

1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Sales\SellableOfferingResource\Pages;
4
+
5
+use App\Filament\Company\Resources\Sales\SellableOfferingResource;
6
+use Filament\Actions;
7
+use Filament\Resources\Pages\ListRecords;
8
+use Illuminate\Contracts\Support\Htmlable;
9
+
10
+class ListSellableOfferings extends ListRecords
11
+{
12
+    protected static string $resource = SellableOfferingResource::class;
13
+
14
+    protected function getHeaderActions(): array
15
+    {
16
+        return [
17
+            Actions\CreateAction::make(),
18
+        ];
19
+    }
20
+
21
+    public function getHeading(): string | Htmlable
22
+    {
23
+        return 'Products & Services (Sales)';
24
+    }
25
+}

+ 36
- 7
app/Models/Accounting/Adjustment.php View File

5
 use App\Casts\RateCast;
5
 use App\Casts\RateCast;
6
 use App\Concerns\Blamable;
6
 use App\Concerns\Blamable;
7
 use App\Concerns\CompanyOwned;
7
 use App\Concerns\CompanyOwned;
8
-use App\Concerns\HasDefault;
9
 use App\Enums\Accounting\AdjustmentCategory;
8
 use App\Enums\Accounting\AdjustmentCategory;
10
 use App\Enums\Accounting\AdjustmentComputation;
9
 use App\Enums\Accounting\AdjustmentComputation;
11
 use App\Enums\Accounting\AdjustmentScope;
10
 use App\Enums\Accounting\AdjustmentScope;
12
 use App\Enums\Accounting\AdjustmentType;
11
 use App\Enums\Accounting\AdjustmentType;
12
+use App\Models\Common\Offering;
13
+use App\Observers\AdjustmentObserver;
13
 use Database\Factories\Accounting\AdjustmentFactory;
14
 use Database\Factories\Accounting\AdjustmentFactory;
15
+use Illuminate\Database\Eloquent\Attributes\ObservedBy;
14
 use Illuminate\Database\Eloquent\Factories\Factory;
16
 use Illuminate\Database\Eloquent\Factories\Factory;
15
 use Illuminate\Database\Eloquent\Factories\HasFactory;
17
 use Illuminate\Database\Eloquent\Factories\HasFactory;
16
 use Illuminate\Database\Eloquent\Model;
18
 use Illuminate\Database\Eloquent\Model;
17
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
19
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
18
-use Illuminate\Database\Eloquent\Relations\MorphTo;
20
+use Illuminate\Database\Eloquent\Relations\MorphToMany;
19
 
21
 
22
+#[ObservedBy(AdjustmentObserver::class)]
20
 class Adjustment extends Model
23
 class Adjustment extends Model
21
 {
24
 {
22
     use Blamable;
25
     use Blamable;
23
     use CompanyOwned;
26
     use CompanyOwned;
24
-    use HasDefault;
25
     use HasFactory;
27
     use HasFactory;
26
 
28
 
27
     protected $table = 'adjustments';
29
     protected $table = 'adjustments';
29
     protected $fillable = [
31
     protected $fillable = [
30
         'company_id',
32
         'company_id',
31
         'account_id',
33
         'account_id',
34
+        'name',
35
+        'description',
32
         'category',
36
         'category',
33
         'type',
37
         'type',
38
+        'recoverable',
34
         'rate',
39
         'rate',
35
         'computation',
40
         'computation',
36
         'scope',
41
         'scope',
37
         'start_date',
42
         'start_date',
38
         'end_date',
43
         'end_date',
39
-        'enabled',
40
         'created_by',
44
         'created_by',
41
         'updated_by',
45
         'updated_by',
42
     ];
46
     ];
44
     protected $casts = [
48
     protected $casts = [
45
         'category' => AdjustmentCategory::class,
49
         'category' => AdjustmentCategory::class,
46
         'type' => AdjustmentType::class,
50
         'type' => AdjustmentType::class,
51
+        'recoverable' => 'boolean',
47
         'rate' => RateCast::class,
52
         'rate' => RateCast::class,
48
         'computation' => AdjustmentComputation::class,
53
         'computation' => AdjustmentComputation::class,
49
         'scope' => AdjustmentScope::class,
54
         'scope' => AdjustmentScope::class,
50
         'start_date' => 'datetime',
55
         'start_date' => 'datetime',
51
         'end_date' => 'datetime',
56
         'end_date' => 'datetime',
52
-        'enabled' => 'boolean',
53
     ];
57
     ];
54
 
58
 
55
     public function account(): BelongsTo
59
     public function account(): BelongsTo
57
         return $this->belongsTo(Account::class, 'account_id');
61
         return $this->belongsTo(Account::class, 'account_id');
58
     }
62
     }
59
 
63
 
60
-    public function adjustmentables(): MorphTo
64
+    public function offerings(): MorphToMany
61
     {
65
     {
62
-        return $this->morphTo();
66
+        return $this->morphedByMany(Offering::class, 'adjustmentable', 'adjustmentables');
67
+    }
68
+
69
+    public function isSalesTax(): bool
70
+    {
71
+        return $this->category->isTax() && $this->type->isSales();
72
+    }
73
+
74
+    public function isNonRecoverablePurchaseTax(): bool
75
+    {
76
+        return $this->category->isTax() && $this->type->isPurchase() && $this->recoverable === false;
77
+    }
78
+
79
+    public function isRecoverablePurchaseTax(): bool
80
+    {
81
+        return $this->category->isTax() && $this->type->isPurchase() && $this->recoverable === true;
82
+    }
83
+
84
+    public function isSalesDiscount(): bool
85
+    {
86
+        return $this->category->isDiscount() && $this->type->isSales();
87
+    }
88
+
89
+    public function isPurchaseDiscount(): bool
90
+    {
91
+        return $this->category->isDiscount() && $this->type->isPurchase();
63
     }
92
     }
64
 
93
 
65
     protected static function newFactory(): Factory
94
     protected static function newFactory(): Factory

+ 33
- 8
app/Models/Common/Offering.php View File

2
 
2
 
3
 namespace App\Models\Common;
3
 namespace App\Models\Common;
4
 
4
 
5
+use App\Casts\MoneyCast;
6
+use App\Concerns\Blamable;
5
 use App\Concerns\CompanyOwned;
7
 use App\Concerns\CompanyOwned;
8
+use App\Enums\Accounting\AdjustmentCategory;
9
+use App\Enums\Accounting\AdjustmentType;
10
+use App\Enums\Common\OfferingType;
6
 use App\Models\Accounting\Account;
11
 use App\Models\Accounting\Account;
7
-use App\Models\Setting\Discount;
8
-use App\Models\Setting\Tax;
12
+use App\Models\Accounting\Adjustment;
9
 use Illuminate\Database\Eloquent\Factories\HasFactory;
13
 use Illuminate\Database\Eloquent\Factories\HasFactory;
10
 use Illuminate\Database\Eloquent\Model;
14
 use Illuminate\Database\Eloquent\Model;
11
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
15
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
13
 
17
 
14
 class Offering extends Model
18
 class Offering extends Model
15
 {
19
 {
20
+    use Blamable;
16
     use CompanyOwned;
21
     use CompanyOwned;
17
     use HasFactory;
22
     use HasFactory;
18
 
23
 
24
         'price',
29
         'price',
25
         'income_account_id',
30
         'income_account_id',
26
         'expense_account_id',
31
         'expense_account_id',
32
+        'created_by',
33
+        'updated_by',
34
+    ];
35
+
36
+    protected $casts = [
37
+        'type' => OfferingType::class,
38
+        'price' => MoneyCast::class,
27
     ];
39
     ];
28
 
40
 
29
     public function incomeAccount(): BelongsTo
41
     public function incomeAccount(): BelongsTo
36
         return $this->belongsTo(Account::class, 'expense_account_id');
48
         return $this->belongsTo(Account::class, 'expense_account_id');
37
     }
49
     }
38
 
50
 
39
-    public function taxes(): MorphToMany
51
+    public function adjustments(): MorphToMany
52
+    {
53
+        return $this->morphToMany(Adjustment::class, 'adjustmentable', 'adjustmentables');
54
+    }
55
+
56
+    public function salesTaxes(): MorphToMany
57
+    {
58
+        return $this->adjustments()->where('category', AdjustmentCategory::Tax)->where('type', AdjustmentType::Sales);
59
+    }
60
+
61
+    public function purchaseTaxes(): MorphToMany
62
+    {
63
+        return $this->adjustments()->where('category', AdjustmentCategory::Tax)->where('type', AdjustmentType::Purchase);
64
+    }
65
+
66
+    public function salesDiscounts(): MorphToMany
40
     {
67
     {
41
-        return $this->morphToMany(Tax::class, 'adjustmentable', 'adjustmentables')
42
-            ->wherePivot('adjustment_type', Tax::class);
68
+        return $this->adjustments()->where('category', AdjustmentCategory::Discount)->where('type', AdjustmentType::Sales);
43
     }
69
     }
44
 
70
 
45
-    public function discounts(): MorphToMany
71
+    public function purchaseDiscounts(): MorphToMany
46
     {
72
     {
47
-        return $this->morphToMany(Discount::class, 'adjustmentable', 'adjustmentables')
48
-            ->wherePivot('adjustment_type', Discount::class);
73
+        return $this->adjustments()->where('category', AdjustmentCategory::Discount)->where('type', AdjustmentType::Purchase);
49
     }
74
     }
50
 }
75
 }

+ 6
- 0
app/Models/Company.php View File

7
 use App\Models\Banking\BankAccount;
7
 use App\Models\Banking\BankAccount;
8
 use App\Models\Banking\ConnectedBankAccount;
8
 use App\Models\Banking\ConnectedBankAccount;
9
 use App\Models\Common\Contact;
9
 use App\Models\Common\Contact;
10
+use App\Models\Common\Offering;
10
 use App\Models\Core\Department;
11
 use App\Models\Core\Department;
11
 use App\Models\Setting\Appearance;
12
 use App\Models\Setting\Appearance;
12
 use App\Models\Setting\CompanyDefault;
13
 use App\Models\Setting\CompanyDefault;
139
     {
140
     {
140
         return $this->hasMany(Accounting\Transaction::class, 'company_id');
141
         return $this->hasMany(Accounting\Transaction::class, 'company_id');
141
     }
142
     }
143
+
144
+    public function offerings(): HasMany
145
+    {
146
+        return $this->hasMany(Offering::class, 'company_id');
147
+    }
142
 }
148
 }

+ 40
- 0
app/Observers/AdjustmentObserver.php View File

1
+<?php
2
+
3
+namespace App\Observers;
4
+
5
+use App\Models\Accounting\Account;
6
+use App\Models\Accounting\Adjustment;
7
+
8
+class AdjustmentObserver
9
+{
10
+    public function creating(Adjustment $adjustment): void
11
+    {
12
+        if ($adjustment->account_id === null && ! $adjustment->isNonRecoverablePurchaseTax()) {
13
+            $account = null;
14
+
15
+            if ($adjustment->isSalesTax()) {
16
+                $account = Account::factory()->forSalesTax($adjustment->name, $adjustment->description)->create();
17
+            } elseif ($adjustment->isRecoverablePurchaseTax()) {
18
+                $account = Account::factory()->forPurchaseTax($adjustment->name, $adjustment->description)->create();
19
+            } elseif ($adjustment->isSalesDiscount()) {
20
+                $account = Account::factory()->forSalesDiscount($adjustment->name, $adjustment->description)->create();
21
+            } elseif ($adjustment->isPurchaseDiscount()) {
22
+                $account = Account::factory()->forPurchaseDiscount($adjustment->name, $adjustment->description)->create();
23
+            }
24
+
25
+            if ($account) {
26
+                $adjustment->account()->associate($account);
27
+            }
28
+        }
29
+    }
30
+
31
+    public function updating(Adjustment $adjustment): void
32
+    {
33
+        if ($adjustment->account) {
34
+            $adjustment->account->update([
35
+                'name' => $adjustment->name,
36
+                'description' => $adjustment->description,
37
+            ]);
38
+        }
39
+    }
40
+}

+ 10
- 0
app/Providers/FilamentCompaniesServiceProvider.php View File

27
 use App\Filament\Company\Pages\Service\LiveCurrency;
27
 use App\Filament\Company\Pages\Service\LiveCurrency;
28
 use App\Filament\Company\Resources\Banking\AccountResource;
28
 use App\Filament\Company\Resources\Banking\AccountResource;
29
 use App\Filament\Company\Resources\Core\DepartmentResource;
29
 use App\Filament\Company\Resources\Core\DepartmentResource;
30
+use App\Filament\Company\Resources\Purchases\BuyableOfferingResource;
31
+use App\Filament\Company\Resources\Sales\SellableOfferingResource;
30
 use App\Filament\Components\PanelShiftDropdown;
32
 use App\Filament\Components\PanelShiftDropdown;
31
 use App\Filament\User\Clusters\Account;
33
 use App\Filament\User\Clusters\Account;
32
 use App\Http\Middleware\ConfigureCurrentCompany;
34
 use App\Http\Middleware\ConfigureCurrentCompany;
121
                         ...Settings::getNavigationItems(),
123
                         ...Settings::getNavigationItems(),
122
                     ])
124
                     ])
123
                     ->groups([
125
                     ->groups([
126
+                        NavigationGroup::make('Sales & Payments')
127
+                            ->label('Sales & Payments')
128
+                            ->icon('heroicon-o-currency-dollar')
129
+                            ->items(SellableOfferingResource::getNavigationItems()),
130
+                        NavigationGroup::make('Purchases')
131
+                            ->label('Purchases')
132
+                            ->icon('heroicon-o-shopping-cart')
133
+                            ->items(BuyableOfferingResource::getNavigationItems()),
124
                         NavigationGroup::make('Accounting')
134
                         NavigationGroup::make('Accounting')
125
                             ->localizeLabel()
135
                             ->localizeLabel()
126
                             ->icon('heroicon-o-clipboard-document-list')
136
                             ->icon('heroicon-o-clipboard-document-list')

+ 24
- 14
app/Services/ChartOfAccountsService.php View File

4
 
4
 
5
 use App\Enums\Accounting\AccountType;
5
 use App\Enums\Accounting\AccountType;
6
 use App\Enums\Banking\BankAccountType;
6
 use App\Enums\Banking\BankAccountType;
7
+use App\Models\Accounting\Account;
7
 use App\Models\Accounting\AccountSubtype;
8
 use App\Models\Accounting\AccountSubtype;
8
 use App\Models\Accounting\Adjustment;
9
 use App\Models\Accounting\Adjustment;
9
 use App\Models\Banking\BankAccount;
10
 use App\Models\Banking\BankAccount;
17
     {
18
     {
18
         $chartOfAccounts = config('chart-of-accounts.default');
19
         $chartOfAccounts = config('chart-of-accounts.default');
19
 
20
 
21
+        // Always create a non-recoverable "Purchase Tax" adjustment, even without an account
22
+        $this->createAdjustmentForAccount($company, 'tax', 'purchase', false);
23
+
20
         foreach ($chartOfAccounts as $type => $subtypes) {
24
         foreach ($chartOfAccounts as $type => $subtypes) {
21
             foreach ($subtypes as $subtypeName => $subtypeConfig) {
25
             foreach ($subtypes as $subtypeName => $subtypeConfig) {
22
                 $subtype = $company->accountSubtypes()
26
                 $subtype = $company->accountSubtypes()
57
 
61
 
58
             foreach ($subtypeConfig['accounts'] as $accountName => $accountDetails) {
62
             foreach ($subtypeConfig['accounts'] as $accountName => $accountDetails) {
59
                 // Create the Account without directly setting bank_account_id
63
                 // Create the Account without directly setting bank_account_id
64
+                /** @var Account $account */
60
                 $account = $company->accounts()->createQuietly([
65
                 $account = $company->accounts()->createQuietly([
61
                     'subtype_id' => $subtype->id,
66
                     'subtype_id' => $subtype->id,
62
                     'category' => $subtype->type->getCategory()->value,
67
                     'category' => $subtype->type->getCategory()->value,
79
                     $bankAccount->saveQuietly();
84
                     $bankAccount->saveQuietly();
80
                 }
85
                 }
81
 
86
 
82
-                if (isset($subtypeConfig['adjustment_category'], $subtypeConfig['adjustment_type'])) {
83
-                    $adjustment = $this->createAdjustmentForAccount($company, $subtypeConfig['adjustment_category'], $subtypeConfig['adjustment_type']);
87
+                if (isset($subtypeConfig['adjustment_category'], $subtypeConfig['adjustment_type'], $subtypeConfig['adjustment_recoverable'])) {
88
+                    $adjustment = $this->createAdjustmentForAccount($company, $subtypeConfig['adjustment_category'], $subtypeConfig['adjustment_type'], $subtypeConfig['adjustment_recoverable']);
84
 
89
 
85
                     // Associate the Adjustment with the Account
90
                     // Associate the Adjustment with the Account
86
                     $adjustment->account()->associate($account);
91
                     $adjustment->account()->associate($account);
92
+
93
+                    $adjustment->name = $account->name;
94
+
95
+                    $adjustment->description = $account->description;
96
+
87
                     $adjustment->saveQuietly();
97
                     $adjustment->saveQuietly();
88
                 }
98
                 }
89
             }
99
             }
102
         ]);
112
         ]);
103
     }
113
     }
104
 
114
 
105
-    private function createAdjustmentForAccount(Company $company, string $category, string $type): Adjustment
115
+    private function createAdjustmentForAccount(Company $company, string $category, string $type, bool $recoverable): Adjustment
106
     {
116
     {
107
-        $noDefaultAdjustmentType = $company->adjustments()->where('category', $category)
108
-            ->where('type', $type)
109
-            ->where('enabled', true)
110
-            ->doesntExist();
111
-
112
         $defaultRate = match ([$category, $type]) {
117
         $defaultRate = match ([$category, $type]) {
113
-            ['tax', 'sales'] => 8,          // Default 8% for Sales Tax
114
-            ['tax', 'purchase'] => 8,       // Default 8% for Purchase Tax
115
-            ['discount', 'sales'] => 5,     // Default 5% for Sales Discount
116
-            ['discount', 'purchase'] => 5,  // Default 5% for Purchase Discount
117
-            default => 0,                   // Default to 0 if unspecified
118
+            ['tax', 'sales'], ['tax', 'purchase'] => '8',
119
+            ['discount', 'sales'], ['discount', 'purchase'] => '5',
120
+            default => '0',
118
         };
121
         };
119
 
122
 
123
+        if ($category === 'tax' && $type === 'purchase' && $recoverable === false) {
124
+            $name = 'Purchase Tax';
125
+            $description = 'This tax is non-recoverable and is included as part of the total cost of the purchase. The tax amount is embedded into the associated expense or asset account based on the type of purchase.';
126
+        }
127
+
120
         return $company->adjustments()->createQuietly([
128
         return $company->adjustments()->createQuietly([
129
+            'name' => $name ?? null,
130
+            'description' => $description ?? null,
121
             'category' => $category,
131
             'category' => $category,
122
             'type' => $type,
132
             'type' => $type,
133
+            'recoverable' => $recoverable,
123
             'rate' => $defaultRate,
134
             'rate' => $defaultRate,
124
             'computation' => 'percentage',
135
             'computation' => 'percentage',
125
-            'enabled' => $noDefaultAdjustmentType,
126
             'created_by' => $company->owner->id,
136
             'created_by' => $company->owner->id,
127
             'updated_by' => $company->owner->id,
137
             'updated_by' => $company->owner->id,
128
         ]);
138
         ]);

+ 17
- 17
composer.lock View File

302
         },
302
         },
303
         {
303
         {
304
             "name": "anourvalar/eloquent-serialize",
304
             "name": "anourvalar/eloquent-serialize",
305
-            "version": "1.2.25",
305
+            "version": "1.2.26",
306
             "source": {
306
             "source": {
307
                 "type": "git",
307
                 "type": "git",
308
                 "url": "https://github.com/AnourValar/eloquent-serialize.git",
308
                 "url": "https://github.com/AnourValar/eloquent-serialize.git",
309
-                "reference": "6d7a868ae4218b9d7796334ff9a17e1539bad48a"
309
+                "reference": "756c1232ff0d02321fd90f4fe3c221d6a7b8d697"
310
             },
310
             },
311
             "dist": {
311
             "dist": {
312
                 "type": "zip",
312
                 "type": "zip",
313
-                "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/6d7a868ae4218b9d7796334ff9a17e1539bad48a",
314
-                "reference": "6d7a868ae4218b9d7796334ff9a17e1539bad48a",
313
+                "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/756c1232ff0d02321fd90f4fe3c221d6a7b8d697",
314
+                "reference": "756c1232ff0d02321fd90f4fe3c221d6a7b8d697",
315
                 "shasum": ""
315
                 "shasum": ""
316
             },
316
             },
317
             "require": {
317
             "require": {
362
             ],
362
             ],
363
             "support": {
363
             "support": {
364
                 "issues": "https://github.com/AnourValar/eloquent-serialize/issues",
364
                 "issues": "https://github.com/AnourValar/eloquent-serialize/issues",
365
-                "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.2.25"
365
+                "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.2.26"
366
             },
366
             },
367
-            "time": "2024-09-16T12:59:37+00:00"
367
+            "time": "2024-11-16T12:29:47+00:00"
368
         },
368
         },
369
         {
369
         {
370
             "name": "awcodes/filament-table-repeater",
370
             "name": "awcodes/filament-table-repeater",
497
         },
497
         },
498
         {
498
         {
499
             "name": "aws/aws-sdk-php",
499
             "name": "aws/aws-sdk-php",
500
-            "version": "3.327.0",
500
+            "version": "3.328.0",
501
             "source": {
501
             "source": {
502
                 "type": "git",
502
                 "type": "git",
503
                 "url": "https://github.com/aws/aws-sdk-php.git",
503
                 "url": "https://github.com/aws/aws-sdk-php.git",
504
-                "reference": "ba4a7ac2544de61b33f693c461f8b09c0353298f"
504
+                "reference": "a99b58e166ae367f2b067937afb04e843e900745"
505
             },
505
             },
506
             "dist": {
506
             "dist": {
507
                 "type": "zip",
507
                 "type": "zip",
508
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ba4a7ac2544de61b33f693c461f8b09c0353298f",
509
-                "reference": "ba4a7ac2544de61b33f693c461f8b09c0353298f",
508
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a99b58e166ae367f2b067937afb04e843e900745",
509
+                "reference": "a99b58e166ae367f2b067937afb04e843e900745",
510
                 "shasum": ""
510
                 "shasum": ""
511
             },
511
             },
512
             "require": {
512
             "require": {
589
             "support": {
589
             "support": {
590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
592
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.327.0"
592
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.328.0"
593
             },
593
             },
594
-            "time": "2024-11-14T19:06:19+00:00"
594
+            "time": "2024-11-15T19:06:57+00:00"
595
         },
595
         },
596
         {
596
         {
597
             "name": "aws/aws-sdk-php-laravel",
597
             "name": "aws/aws-sdk-php-laravel",
2908
         },
2908
         },
2909
         {
2909
         {
2910
             "name": "laravel/framework",
2910
             "name": "laravel/framework",
2911
-            "version": "v11.31.0",
2911
+            "version": "v11.32.0",
2912
             "source": {
2912
             "source": {
2913
                 "type": "git",
2913
                 "type": "git",
2914
                 "url": "https://github.com/laravel/framework.git",
2914
                 "url": "https://github.com/laravel/framework.git",
2915
-                "reference": "365090ed2c68244e3141cdb5e247cdf3dfba2c40"
2915
+                "reference": "bc2aad63f83ee5089be7b21cf29d645ccf31e927"
2916
             },
2916
             },
2917
             "dist": {
2917
             "dist": {
2918
                 "type": "zip",
2918
                 "type": "zip",
2919
-                "url": "https://api.github.com/repos/laravel/framework/zipball/365090ed2c68244e3141cdb5e247cdf3dfba2c40",
2920
-                "reference": "365090ed2c68244e3141cdb5e247cdf3dfba2c40",
2919
+                "url": "https://api.github.com/repos/laravel/framework/zipball/bc2aad63f83ee5089be7b21cf29d645ccf31e927",
2920
+                "reference": "bc2aad63f83ee5089be7b21cf29d645ccf31e927",
2921
                 "shasum": ""
2921
                 "shasum": ""
2922
             },
2922
             },
2923
             "require": {
2923
             "require": {
3113
                 "issues": "https://github.com/laravel/framework/issues",
3113
                 "issues": "https://github.com/laravel/framework/issues",
3114
                 "source": "https://github.com/laravel/framework"
3114
                 "source": "https://github.com/laravel/framework"
3115
             },
3115
             },
3116
-            "time": "2024-11-12T15:36:15+00:00"
3116
+            "time": "2024-11-15T17:04:33+00:00"
3117
         },
3117
         },
3118
         {
3118
         {
3119
             "name": "laravel/prompts",
3119
             "name": "laravel/prompts",

+ 17
- 13
config/chart-of-accounts.php View File

26
                     ],
26
                     ],
27
                 ],
27
                 ],
28
             ],
28
             ],
29
+            'Input Tax Recoverable' => [
30
+                'description' => 'The amount of sales tax paid on purchases that can be recovered from the government.',
31
+                'multi_currency' => false,
32
+                'base_code' => '1150',
33
+                'inverse_cash_flow' => true,
34
+                'adjustment_category' => 'tax',
35
+                'adjustment_type' => 'purchase',
36
+                'adjustment_recoverable' => true,
37
+                'accounts' => [
38
+                    'Input Tax' => [
39
+                        'description' => null,
40
+                    ],
41
+                ],
42
+            ],
29
             'Inventory' => [
43
             'Inventory' => [
30
                 'description' => 'The raw materials, work-in-progress goods and completely finished goods that are considered to be the portion of a business\'s assets that are ready or will be ready for sale.',
44
                 'description' => 'The raw materials, work-in-progress goods and completely finished goods that are considered to be the portion of a business\'s assets that are ready or will be ready for sale.',
31
                 'multi_currency' => true,
45
                 'multi_currency' => true,
126
                 'inverse_cash_flow' => false,
140
                 'inverse_cash_flow' => false,
127
                 'adjustment_category' => 'tax',
141
                 'adjustment_category' => 'tax',
128
                 'adjustment_type' => 'sales',
142
                 'adjustment_type' => 'sales',
143
+                'adjustment_recoverable' => false,
129
                 'accounts' => [
144
                 'accounts' => [
130
                     'Sales Tax' => [
145
                     'Sales Tax' => [
131
                         'description' => null,
146
                         'description' => null,
288
                 'inverse_cash_flow' => false,
303
                 'inverse_cash_flow' => false,
289
                 'adjustment_category' => 'discount',
304
                 'adjustment_category' => 'discount',
290
                 'adjustment_type' => 'sales',
305
                 'adjustment_type' => 'sales',
306
+                'adjustment_recoverable' => false,
291
                 'accounts' => [
307
                 'accounts' => [
292
                     'Sales Discount' => [
308
                     'Sales Discount' => [
293
                         'description' => null,
309
                         'description' => null,
430
                 'base_code' => '5600',
446
                 'base_code' => '5600',
431
                 'inverse_cash_flow' => true,
447
                 'inverse_cash_flow' => true,
432
             ],
448
             ],
433
-            'Purchase Taxes' => [
434
-                'description' => 'Taxes paid on purchases of goods or services, such as value-added tax (VAT), goods and services tax (GST), or customs duties.',
435
-                'multi_currency' => false,
436
-                'base_code' => '5650',
437
-                'inverse_cash_flow' => true,
438
-                'adjustment_category' => 'tax',
439
-                'adjustment_type' => 'purchase',
440
-                'accounts' => [
441
-                    'Purchase Tax' => [
442
-                        'description' => null,
443
-                    ],
444
-                ],
445
-            ],
446
             'Other Non-Operating Expense' => [
449
             'Other Non-Operating Expense' => [
447
                 'description' => 'Expenses not related to primary business activities, like losses from asset disposals, legal settlements, restructuring costs, or foreign exchange losses.',
450
                 'description' => 'Expenses not related to primary business activities, like losses from asset disposals, legal settlements, restructuring costs, or foreign exchange losses.',
448
                 'multi_currency' => false,
451
                 'multi_currency' => false,
474
                 'inverse_cash_flow' => true,
477
                 'inverse_cash_flow' => true,
475
                 'adjustment_category' => 'discount',
478
                 'adjustment_category' => 'discount',
476
                 'adjustment_type' => 'purchase',
479
                 'adjustment_type' => 'purchase',
480
+                'adjustment_recoverable' => false,
477
                 'accounts' => [
481
                 'accounts' => [
478
                     'Purchase Discount' => [
482
                     'Purchase Discount' => [
479
                         'description' => null,
483
                         'description' => null,

+ 1
- 1
database/factories/Accounting/AccountFactory.php View File

92
 
92
 
93
     public function forPurchaseTax(?string $name = null, ?string $description = null): static
93
     public function forPurchaseTax(?string $name = null, ?string $description = null): static
94
     {
94
     {
95
-        $accountSubtype = AccountSubtype::where('name', 'Purchase Taxes')->first();
95
+        $accountSubtype = AccountSubtype::where('name', 'Input Tax Recoverable')->first();
96
 
96
 
97
         return $this->state([
97
         return $this->state([
98
             'name' => $name,
98
             'name' => $name,

+ 0
- 1
database/factories/Accounting/AdjustmentFactory.php View File

44
             'scope' => $this->faker->randomElement(AdjustmentScope::class),
44
             'scope' => $this->faker->randomElement(AdjustmentScope::class),
45
             'start_date' => $startDate,
45
             'start_date' => $startDate,
46
             'end_date' => $endDate,
46
             'end_date' => $endDate,
47
-            'enabled' => false,
48
         ];
47
         ];
49
     }
48
     }
50
 
49
 

+ 2
- 0
database/migrations/2024_11_13_214149_create_offerings_table.php View File

20
             $table->integer('price')->default(0);
20
             $table->integer('price')->default(0);
21
             $table->foreignId('income_account_id')->nullable()->constrained('accounts')->nullOnDelete(); // income account e.g. sales/invoice
21
             $table->foreignId('income_account_id')->nullable()->constrained('accounts')->nullOnDelete(); // income account e.g. sales/invoice
22
             $table->foreignId('expense_account_id')->nullable()->constrained('accounts')->nullOnDelete(); // expense account e.g. purchase/bill
22
             $table->foreignId('expense_account_id')->nullable()->constrained('accounts')->nullOnDelete(); // expense account e.g. purchase/bill
23
+            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
24
+            $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
23
             $table->timestamps();
25
             $table->timestamps();
24
         });
26
         });
25
     }
27
     }

+ 3
- 1
database/migrations/2024_11_14_230753_create_adjustments_table.php View File

15
             $table->id();
15
             $table->id();
16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
             $table->foreignId('account_id')->nullable()->constrained('accounts')->nullOnDelete();
17
             $table->foreignId('account_id')->nullable()->constrained('accounts')->nullOnDelete();
18
+            $table->string('name')->nullable();
19
+            $table->text('description')->nullable();
18
             $table->string('category')->default('tax');
20
             $table->string('category')->default('tax');
19
             $table->string('type')->default('sales');
21
             $table->string('type')->default('sales');
22
+            $table->boolean('recoverable')->default(false);
20
             $table->integer('rate')->default(0);
23
             $table->integer('rate')->default(0);
21
             $table->string('computation')->default('percentage');
24
             $table->string('computation')->default('percentage');
22
             $table->string('scope')->nullable();
25
             $table->string('scope')->nullable();
23
             $table->dateTime('start_date')->nullable();
26
             $table->dateTime('start_date')->nullable();
24
             $table->dateTime('end_date')->nullable();
27
             $table->dateTime('end_date')->nullable();
25
-            $table->boolean('enabled')->default(true);
26
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
28
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
27
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
29
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
28
             $table->timestamps();
30
             $table->timestamps();

database/migrations/2024_11_13_225714_create_adjustmentables_table.php → database/migrations/2024_11_15_225714_create_adjustmentables_table.php View File

13
     {
13
     {
14
         Schema::create('adjustmentables', function (Blueprint $table) {
14
         Schema::create('adjustmentables', function (Blueprint $table) {
15
             $table->id();
15
             $table->id();
16
-            $table->unsignedBigInteger('adjustment_id');   // No foreign key constraint due to polymorphism
17
-            $table->string('adjustment_type');             // Type of adjustment (e.g., "App\Models\Tax" or "App\Models\Discount")
18
-            $table->morphs('adjustmentable');              // Creates adjustmentable_id and adjustmentable_type
19
-            $table->timestamps();
16
+            $table->foreignId('adjustment_id')->constrained()->cascadeOnDelete();
17
+            $table->morphs('adjustmentable');
20
 
18
 
21
-            // Optional indexes for efficient querying
22
-            $table->index(['adjustment_id', 'adjustment_type']);
23
             $table->index(['adjustmentable_id', 'adjustmentable_type']);
19
             $table->index(['adjustmentable_id', 'adjustmentable_type']);
24
         });
20
         });
25
     }
21
     }

+ 78
- 78
package-lock.json View File

541
             }
541
             }
542
         },
542
         },
543
         "node_modules/@rollup/rollup-android-arm-eabi": {
543
         "node_modules/@rollup/rollup-android-arm-eabi": {
544
-            "version": "4.26.0",
545
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.26.0.tgz",
546
-            "integrity": "sha512-gJNwtPDGEaOEgejbaseY6xMFu+CPltsc8/T+diUTTbOQLqD+bnrJq9ulH6WD69TqwqWmrfRAtUv30cCFZlbGTQ==",
544
+            "version": "4.27.2",
545
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.2.tgz",
546
+            "integrity": "sha512-Tj+j7Pyzd15wAdSJswvs5CJzJNV+qqSUcr/aCD+jpQSBtXvGnV0pnrjoc8zFTe9fcKCatkpFpOO7yAzpO998HA==",
547
             "cpu": [
547
             "cpu": [
548
                 "arm"
548
                 "arm"
549
             ],
549
             ],
555
             ]
555
             ]
556
         },
556
         },
557
         "node_modules/@rollup/rollup-android-arm64": {
557
         "node_modules/@rollup/rollup-android-arm64": {
558
-            "version": "4.26.0",
559
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.26.0.tgz",
560
-            "integrity": "sha512-YJa5Gy8mEZgz5JquFruhJODMq3lTHWLm1fOy+HIANquLzfIOzE9RA5ie3JjCdVb9r46qfAQY/l947V0zfGJ0OQ==",
558
+            "version": "4.27.2",
559
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.2.tgz",
560
+            "integrity": "sha512-xsPeJgh2ThBpUqlLgRfiVYBEf/P1nWlWvReG+aBWfNv3XEBpa6ZCmxSVnxJgLgkNz4IbxpLy64h2gCmAAQLneQ==",
561
             "cpu": [
561
             "cpu": [
562
                 "arm64"
562
                 "arm64"
563
             ],
563
             ],
569
             ]
569
             ]
570
         },
570
         },
571
         "node_modules/@rollup/rollup-darwin-arm64": {
571
         "node_modules/@rollup/rollup-darwin-arm64": {
572
-            "version": "4.26.0",
573
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.26.0.tgz",
574
-            "integrity": "sha512-ErTASs8YKbqTBoPLp/kA1B1Um5YSom8QAc4rKhg7b9tyyVqDBlQxy7Bf2wW7yIlPGPg2UODDQcbkTlruPzDosw==",
572
+            "version": "4.27.2",
573
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.2.tgz",
574
+            "integrity": "sha512-KnXU4m9MywuZFedL35Z3PuwiTSn/yqRIhrEA9j+7OSkji39NzVkgxuxTYg5F8ryGysq4iFADaU5osSizMXhU2A==",
575
             "cpu": [
575
             "cpu": [
576
                 "arm64"
576
                 "arm64"
577
             ],
577
             ],
583
             ]
583
             ]
584
         },
584
         },
585
         "node_modules/@rollup/rollup-darwin-x64": {
585
         "node_modules/@rollup/rollup-darwin-x64": {
586
-            "version": "4.26.0",
587
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.26.0.tgz",
588
-            "integrity": "sha512-wbgkYDHcdWW+NqP2mnf2NOuEbOLzDblalrOWcPyY6+BRbVhliavon15UploG7PpBRQ2bZJnbmh8o3yLoBvDIHA==",
586
+            "version": "4.27.2",
587
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.2.tgz",
588
+            "integrity": "sha512-Hj77A3yTvUeCIx/Vi+4d4IbYhyTwtHj07lVzUgpUq9YpJSEiGJj4vXMKwzJ3w5zp5v3PFvpJNgc/J31smZey6g==",
589
             "cpu": [
589
             "cpu": [
590
                 "x64"
590
                 "x64"
591
             ],
591
             ],
597
             ]
597
             ]
598
         },
598
         },
599
         "node_modules/@rollup/rollup-freebsd-arm64": {
599
         "node_modules/@rollup/rollup-freebsd-arm64": {
600
-            "version": "4.26.0",
601
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.26.0.tgz",
602
-            "integrity": "sha512-Y9vpjfp9CDkAG4q/uwuhZk96LP11fBz/bYdyg9oaHYhtGZp7NrbkQrj/66DYMMP2Yo/QPAsVHkV891KyO52fhg==",
600
+            "version": "4.27.2",
601
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.2.tgz",
602
+            "integrity": "sha512-RjgKf5C3xbn8gxvCm5VgKZ4nn0pRAIe90J0/fdHUsgztd3+Zesb2lm2+r6uX4prV2eUByuxJNdt647/1KPRq5g==",
603
             "cpu": [
603
             "cpu": [
604
                 "arm64"
604
                 "arm64"
605
             ],
605
             ],
611
             ]
611
             ]
612
         },
612
         },
613
         "node_modules/@rollup/rollup-freebsd-x64": {
613
         "node_modules/@rollup/rollup-freebsd-x64": {
614
-            "version": "4.26.0",
615
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.26.0.tgz",
616
-            "integrity": "sha512-A/jvfCZ55EYPsqeaAt/yDAG4q5tt1ZboWMHEvKAH9Zl92DWvMIbnZe/f/eOXze65aJaaKbL+YeM0Hz4kLQvdwg==",
614
+            "version": "4.27.2",
615
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.2.tgz",
616
+            "integrity": "sha512-duq21FoXwQtuws+V9H6UZ+eCBc7fxSpMK1GQINKn3fAyd9DFYKPJNcUhdIKOrMFjLEJgQskoMoiuizMt+dl20g==",
617
             "cpu": [
617
             "cpu": [
618
                 "x64"
618
                 "x64"
619
             ],
619
             ],
625
             ]
625
             ]
626
         },
626
         },
627
         "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
627
         "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
628
-            "version": "4.26.0",
629
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.26.0.tgz",
630
-            "integrity": "sha512-paHF1bMXKDuizaMODm2bBTjRiHxESWiIyIdMugKeLnjuS1TCS54MF5+Y5Dx8Ui/1RBPVRE09i5OUlaLnv8OGnA==",
628
+            "version": "4.27.2",
629
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.2.tgz",
630
+            "integrity": "sha512-6npqOKEPRZkLrMcvyC/32OzJ2srdPzCylJjiTJT2c0bwwSGm7nz2F9mNQ1WrAqCBZROcQn91Fno+khFhVijmFA==",
631
             "cpu": [
631
             "cpu": [
632
                 "arm"
632
                 "arm"
633
             ],
633
             ],
639
             ]
639
             ]
640
         },
640
         },
641
         "node_modules/@rollup/rollup-linux-arm-musleabihf": {
641
         "node_modules/@rollup/rollup-linux-arm-musleabihf": {
642
-            "version": "4.26.0",
643
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.26.0.tgz",
644
-            "integrity": "sha512-cwxiHZU1GAs+TMxvgPfUDtVZjdBdTsQwVnNlzRXC5QzIJ6nhfB4I1ahKoe9yPmoaA/Vhf7m9dB1chGPpDRdGXg==",
642
+            "version": "4.27.2",
643
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.2.tgz",
644
+            "integrity": "sha512-V9Xg6eXtgBtHq2jnuQwM/jr2mwe2EycnopO8cbOvpzFuySCGtKlPCI3Hj9xup/pJK5Q0388qfZZy2DqV2J8ftw==",
645
             "cpu": [
645
             "cpu": [
646
                 "arm"
646
                 "arm"
647
             ],
647
             ],
653
             ]
653
             ]
654
         },
654
         },
655
         "node_modules/@rollup/rollup-linux-arm64-gnu": {
655
         "node_modules/@rollup/rollup-linux-arm64-gnu": {
656
-            "version": "4.26.0",
657
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.26.0.tgz",
658
-            "integrity": "sha512-4daeEUQutGRCW/9zEo8JtdAgtJ1q2g5oHaoQaZbMSKaIWKDQwQ3Yx0/3jJNmpzrsScIPtx/V+1AfibLisb3AMQ==",
656
+            "version": "4.27.2",
657
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.2.tgz",
658
+            "integrity": "sha512-uCFX9gtZJoQl2xDTpRdseYuNqyKkuMDtH6zSrBTA28yTfKyjN9hQ2B04N5ynR8ILCoSDOrG/Eg+J2TtJ1e/CSA==",
659
             "cpu": [
659
             "cpu": [
660
                 "arm64"
660
                 "arm64"
661
             ],
661
             ],
667
             ]
667
             ]
668
         },
668
         },
669
         "node_modules/@rollup/rollup-linux-arm64-musl": {
669
         "node_modules/@rollup/rollup-linux-arm64-musl": {
670
-            "version": "4.26.0",
671
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.26.0.tgz",
672
-            "integrity": "sha512-eGkX7zzkNxvvS05ROzJ/cO/AKqNvR/7t1jA3VZDi2vRniLKwAWxUr85fH3NsvtxU5vnUUKFHKh8flIBdlo2b3Q==",
670
+            "version": "4.27.2",
671
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.2.tgz",
672
+            "integrity": "sha512-/PU9P+7Rkz8JFYDHIi+xzHabOu9qEWR07L5nWLIUsvserrxegZExKCi2jhMZRd0ATdboKylu/K5yAXbp7fYFvA==",
673
             "cpu": [
673
             "cpu": [
674
                 "arm64"
674
                 "arm64"
675
             ],
675
             ],
681
             ]
681
             ]
682
         },
682
         },
683
         "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
683
         "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
684
-            "version": "4.26.0",
685
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.26.0.tgz",
686
-            "integrity": "sha512-Odp/lgHbW/mAqw/pU21goo5ruWsytP7/HCC/liOt0zcGG0llYWKrd10k9Fj0pdj3prQ63N5yQLCLiE7HTX+MYw==",
684
+            "version": "4.27.2",
685
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.2.tgz",
686
+            "integrity": "sha512-eCHmol/dT5odMYi/N0R0HC8V8QE40rEpkyje/ZAXJYNNoSfrObOvG/Mn+s1F/FJyB7co7UQZZf6FuWnN6a7f4g==",
687
             "cpu": [
687
             "cpu": [
688
                 "ppc64"
688
                 "ppc64"
689
             ],
689
             ],
695
             ]
695
             ]
696
         },
696
         },
697
         "node_modules/@rollup/rollup-linux-riscv64-gnu": {
697
         "node_modules/@rollup/rollup-linux-riscv64-gnu": {
698
-            "version": "4.26.0",
699
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.26.0.tgz",
700
-            "integrity": "sha512-MBR2ZhCTzUgVD0OJdTzNeF4+zsVogIR1U/FsyuFerwcqjZGvg2nYe24SAHp8O5sN8ZkRVbHwlYeHqcSQ8tcYew==",
698
+            "version": "4.27.2",
699
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.2.tgz",
700
+            "integrity": "sha512-DEP3Njr9/ADDln3kNi76PXonLMSSMiCir0VHXxmGSHxCxDfQ70oWjHcJGfiBugzaqmYdTC7Y+8Int6qbnxPBIQ==",
701
             "cpu": [
701
             "cpu": [
702
                 "riscv64"
702
                 "riscv64"
703
             ],
703
             ],
709
             ]
709
             ]
710
         },
710
         },
711
         "node_modules/@rollup/rollup-linux-s390x-gnu": {
711
         "node_modules/@rollup/rollup-linux-s390x-gnu": {
712
-            "version": "4.26.0",
713
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.26.0.tgz",
714
-            "integrity": "sha512-YYcg8MkbN17fMbRMZuxwmxWqsmQufh3ZJFxFGoHjrE7bv0X+T6l3glcdzd7IKLiwhT+PZOJCblpnNlz1/C3kGQ==",
712
+            "version": "4.27.2",
713
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.2.tgz",
714
+            "integrity": "sha512-NHGo5i6IE/PtEPh5m0yw5OmPMpesFnzMIS/lzvN5vknnC1sXM5Z/id5VgcNPgpD+wHmIcuYYgW+Q53v+9s96lQ==",
715
             "cpu": [
715
             "cpu": [
716
                 "s390x"
716
                 "s390x"
717
             ],
717
             ],
723
             ]
723
             ]
724
         },
724
         },
725
         "node_modules/@rollup/rollup-linux-x64-gnu": {
725
         "node_modules/@rollup/rollup-linux-x64-gnu": {
726
-            "version": "4.26.0",
727
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.26.0.tgz",
728
-            "integrity": "sha512-ZuwpfjCwjPkAOxpjAEjabg6LRSfL7cAJb6gSQGZYjGhadlzKKywDkCUnJ+KEfrNY1jH5EEoSIKLCb572jSiglA==",
726
+            "version": "4.27.2",
727
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.2.tgz",
728
+            "integrity": "sha512-PaW2DY5Tan+IFvNJGHDmUrORadbe/Ceh8tQxi8cmdQVCCYsLoQo2cuaSj+AU+YRX8M4ivS2vJ9UGaxfuNN7gmg==",
729
             "cpu": [
729
             "cpu": [
730
                 "x64"
730
                 "x64"
731
             ],
731
             ],
737
             ]
737
             ]
738
         },
738
         },
739
         "node_modules/@rollup/rollup-linux-x64-musl": {
739
         "node_modules/@rollup/rollup-linux-x64-musl": {
740
-            "version": "4.26.0",
741
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.26.0.tgz",
742
-            "integrity": "sha512-+HJD2lFS86qkeF8kNu0kALtifMpPCZU80HvwztIKnYwym3KnA1os6nsX4BGSTLtS2QVAGG1P3guRgsYyMA0Yhg==",
740
+            "version": "4.27.2",
741
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.2.tgz",
742
+            "integrity": "sha512-dOlWEMg2gI91Qx5I/HYqOD6iqlJspxLcS4Zlg3vjk1srE67z5T2Uz91yg/qA8sY0XcwQrFzWWiZhMNERylLrpQ==",
743
             "cpu": [
743
             "cpu": [
744
                 "x64"
744
                 "x64"
745
             ],
745
             ],
751
             ]
751
             ]
752
         },
752
         },
753
         "node_modules/@rollup/rollup-win32-arm64-msvc": {
753
         "node_modules/@rollup/rollup-win32-arm64-msvc": {
754
-            "version": "4.26.0",
755
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.26.0.tgz",
756
-            "integrity": "sha512-WUQzVFWPSw2uJzX4j6YEbMAiLbs0BUysgysh8s817doAYhR5ybqTI1wtKARQKo6cGop3pHnrUJPFCsXdoFaimQ==",
754
+            "version": "4.27.2",
755
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.2.tgz",
756
+            "integrity": "sha512-euMIv/4x5Y2/ImlbGl88mwKNXDsvzbWUlT7DFky76z2keajCtcbAsN9LUdmk31hAoVmJJYSThgdA0EsPeTr1+w==",
757
             "cpu": [
757
             "cpu": [
758
                 "arm64"
758
                 "arm64"
759
             ],
759
             ],
765
             ]
765
             ]
766
         },
766
         },
767
         "node_modules/@rollup/rollup-win32-ia32-msvc": {
767
         "node_modules/@rollup/rollup-win32-ia32-msvc": {
768
-            "version": "4.26.0",
769
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.26.0.tgz",
770
-            "integrity": "sha512-D4CxkazFKBfN1akAIY6ieyOqzoOoBV1OICxgUblWxff/pSjCA2khXlASUx7mK6W1oP4McqhgcCsu6QaLj3WMWg==",
768
+            "version": "4.27.2",
769
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.2.tgz",
770
+            "integrity": "sha512-RsnE6LQkUHlkC10RKngtHNLxb7scFykEbEwOFDjr3CeCMG+Rr+cKqlkKc2/wJ1u4u990urRHCbjz31x84PBrSQ==",
771
             "cpu": [
771
             "cpu": [
772
                 "ia32"
772
                 "ia32"
773
             ],
773
             ],
779
             ]
779
             ]
780
         },
780
         },
781
         "node_modules/@rollup/rollup-win32-x64-msvc": {
781
         "node_modules/@rollup/rollup-win32-x64-msvc": {
782
-            "version": "4.26.0",
783
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.26.0.tgz",
784
-            "integrity": "sha512-2x8MO1rm4PGEP0xWbubJW5RtbNLk3puzAMaLQd3B3JHVw4KcHlmXcO+Wewx9zCoo7EUFiMlu/aZbCJ7VjMzAag==",
782
+            "version": "4.27.2",
783
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.2.tgz",
784
+            "integrity": "sha512-foJM5vv+z2KQmn7emYdDLyTbkoO5bkHZE1oth2tWbQNGW7mX32d46Hz6T0MqXdWS2vBZhaEtHqdy9WYwGfiliA==",
785
             "cpu": [
785
             "cpu": [
786
                 "x64"
786
                 "x64"
787
             ],
787
             ],
1187
             "license": "MIT"
1187
             "license": "MIT"
1188
         },
1188
         },
1189
         "node_modules/electron-to-chromium": {
1189
         "node_modules/electron-to-chromium": {
1190
-            "version": "1.5.59",
1191
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.59.tgz",
1192
-            "integrity": "sha512-faAXB6+gEbC8FsiRdpOXgOe4snP49YwjiXynEB8Mp7sUx80W5eN+BnnBHJ/F7eIeLzs+QBfDD40bJMm97oEFcw==",
1190
+            "version": "1.5.62",
1191
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz",
1192
+            "integrity": "sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg==",
1193
             "dev": true,
1193
             "dev": true,
1194
             "license": "ISC"
1194
             "license": "ISC"
1195
         },
1195
         },
2199
             }
2199
             }
2200
         },
2200
         },
2201
         "node_modules/rollup": {
2201
         "node_modules/rollup": {
2202
-            "version": "4.26.0",
2203
-            "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.26.0.tgz",
2204
-            "integrity": "sha512-ilcl12hnWonG8f+NxU6BlgysVA0gvY2l8N0R84S1HcINbW20bvwuCngJkkInV6LXhwRpucsW5k1ovDwEdBVrNg==",
2202
+            "version": "4.27.2",
2203
+            "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.2.tgz",
2204
+            "integrity": "sha512-KreA+PzWmk2yaFmZVwe6GB2uBD86nXl86OsDkt1bJS9p3vqWuEQ6HnJJ+j/mZi/q0920P99/MVRlB4L3crpF5w==",
2205
             "dev": true,
2205
             "dev": true,
2206
             "license": "MIT",
2206
             "license": "MIT",
2207
             "dependencies": {
2207
             "dependencies": {
2215
                 "npm": ">=8.0.0"
2215
                 "npm": ">=8.0.0"
2216
             },
2216
             },
2217
             "optionalDependencies": {
2217
             "optionalDependencies": {
2218
-                "@rollup/rollup-android-arm-eabi": "4.26.0",
2219
-                "@rollup/rollup-android-arm64": "4.26.0",
2220
-                "@rollup/rollup-darwin-arm64": "4.26.0",
2221
-                "@rollup/rollup-darwin-x64": "4.26.0",
2222
-                "@rollup/rollup-freebsd-arm64": "4.26.0",
2223
-                "@rollup/rollup-freebsd-x64": "4.26.0",
2224
-                "@rollup/rollup-linux-arm-gnueabihf": "4.26.0",
2225
-                "@rollup/rollup-linux-arm-musleabihf": "4.26.0",
2226
-                "@rollup/rollup-linux-arm64-gnu": "4.26.0",
2227
-                "@rollup/rollup-linux-arm64-musl": "4.26.0",
2228
-                "@rollup/rollup-linux-powerpc64le-gnu": "4.26.0",
2229
-                "@rollup/rollup-linux-riscv64-gnu": "4.26.0",
2230
-                "@rollup/rollup-linux-s390x-gnu": "4.26.0",
2231
-                "@rollup/rollup-linux-x64-gnu": "4.26.0",
2232
-                "@rollup/rollup-linux-x64-musl": "4.26.0",
2233
-                "@rollup/rollup-win32-arm64-msvc": "4.26.0",
2234
-                "@rollup/rollup-win32-ia32-msvc": "4.26.0",
2235
-                "@rollup/rollup-win32-x64-msvc": "4.26.0",
2218
+                "@rollup/rollup-android-arm-eabi": "4.27.2",
2219
+                "@rollup/rollup-android-arm64": "4.27.2",
2220
+                "@rollup/rollup-darwin-arm64": "4.27.2",
2221
+                "@rollup/rollup-darwin-x64": "4.27.2",
2222
+                "@rollup/rollup-freebsd-arm64": "4.27.2",
2223
+                "@rollup/rollup-freebsd-x64": "4.27.2",
2224
+                "@rollup/rollup-linux-arm-gnueabihf": "4.27.2",
2225
+                "@rollup/rollup-linux-arm-musleabihf": "4.27.2",
2226
+                "@rollup/rollup-linux-arm64-gnu": "4.27.2",
2227
+                "@rollup/rollup-linux-arm64-musl": "4.27.2",
2228
+                "@rollup/rollup-linux-powerpc64le-gnu": "4.27.2",
2229
+                "@rollup/rollup-linux-riscv64-gnu": "4.27.2",
2230
+                "@rollup/rollup-linux-s390x-gnu": "4.27.2",
2231
+                "@rollup/rollup-linux-x64-gnu": "4.27.2",
2232
+                "@rollup/rollup-linux-x64-musl": "4.27.2",
2233
+                "@rollup/rollup-win32-arm64-msvc": "4.27.2",
2234
+                "@rollup/rollup-win32-ia32-msvc": "4.27.2",
2235
+                "@rollup/rollup-win32-x64-msvc": "4.27.2",
2236
                 "fsevents": "~2.3.2"
2236
                 "fsevents": "~2.3.2"
2237
             }
2237
             }
2238
         },
2238
         },

+ 9
- 1
resources/data/lang/en.json View File

189
     "Edit": "Edit",
189
     "Edit": "Edit",
190
     "Notes": "Notes",
190
     "Notes": "Notes",
191
     "Terms": "Terms",
191
     "Terms": "Terms",
192
-    "Ending Balance": "Ending Balance"
192
+    "Ending Balance": "Ending Balance",
193
+    "Default :Type :Category": "Default :Type :Category",
194
+    "Category": "Category",
195
+    "Configuration": "Configuration",
196
+    "Dates": "Dates",
197
+    "Adjustment Details": "Adjustment Details",
198
+    "Adjustments": "Adjustments",
199
+    "Sellable Configuration": "Sellable Configuration",
200
+    "Purchasable Configuration": "Purchasable Configuration"
193
 }
201
 }

+ 8
- 0
resources/views/filament/company/components/tables/columns/offering-status.blade.php View File

1
+<div class="flex items-center space-x-2 text-sm leading-6">
2
+    <span>{{ $getState() }}</span>
3
+    @if ($getRecord()->income_account_id && $getRecord()->expense_account_id)
4
+        <x-filament::badge>
5
+            Sell & Buy
6
+        </x-filament::badge>
7
+    @endif
8
+</div>

+ 1
- 1
resources/views/filament/company/pages/accounting/chart.blade.php View File

76
                                         </td>
76
                                         </td>
77
                                         <td colspan="1" class="es-table__cell px-4 py-4">
77
                                         <td colspan="1" class="es-table__cell px-4 py-4">
78
                                             <div>
78
                                             <div>
79
-                                                @if($account->default === false)
79
+                                                @if($account->default === false && !$account->adjustment)
80
                                                     {{ ($this->editChartAction)(['chart' => $account->id]) }}
80
                                                     {{ ($this->editChartAction)(['chart' => $account->id]) }}
81
                                                 @endif
81
                                                 @endif
82
                                             </div>
82
                                             </div>

Loading…
Cancel
Save