Andrew Wallo 5 månader sedan
förälder
incheckning
d1cf66bdb4

+ 95
- 80
app/Filament/Company/Resources/Common/OfferingResource.php Visa fil

@@ -56,92 +56,107 @@ class OfferingResource extends Resource
56 56
 
57 57
                         return new HtmlString($output);
58 58
                     }),
59
-                Forms\Components\Section::make('General')
60
-                    ->schema([
61
-                        RadioDeck::make('type')
62
-                            ->options(OfferingType::class)
63
-                            ->default(OfferingType::Product)
64
-                            ->icons(OfferingType::class)
65
-                            ->color('primary')
66
-                            ->columns()
67
-                            ->required(),
68
-                        Forms\Components\TextInput::make('name')
69
-                            ->autofocus()
70
-                            ->required()
71
-                            ->columnStart(1)
72
-                            ->maxLength(255),
73
-                        Forms\Components\TextInput::make('price')
74
-                            ->required()
75
-                            ->money(),
76
-                        Forms\Components\Textarea::make('description')
77
-                            ->label('Description')
78
-                            ->columnSpan(2)
79
-                            ->rows(3),
80
-                        Forms\Components\CheckboxList::make('attributes')
81
-                            ->options([
82
-                                'Sellable' => 'Sellable',
83
-                                'Purchasable' => 'Purchasable',
84
-                            ])
85
-                            ->hiddenLabel()
86
-                            ->required()
87
-                            ->live()
88
-                            ->bulkToggleable()
89
-                            ->validationMessages([
90
-                                'required' => 'The offering must be either sellable or purchasable.',
91
-                            ]),
92
-                    ])->columns(),
59
+                static::getGeneralSection(),
93 60
                 // Sellable Section
94
-                Forms\Components\Section::make('Sale Information')
95
-                    ->schema([
96
-                        CreateAccountSelect::make('income_account_id')
97
-                            ->label('Income account')
98
-                            ->category(AccountCategory::Revenue)
99
-                            ->type(AccountType::OperatingRevenue)
100
-                            ->required()
101
-                            ->validationMessages([
102
-                                'required' => 'The income account is required for sellable offerings.',
103
-                            ]),
104
-                        CreateAdjustmentSelect::make('salesTaxes')
105
-                            ->label('Sales tax')
106
-                            ->category(AdjustmentCategory::Tax)
107
-                            ->type(AdjustmentType::Sales)
108
-                            ->multiple(),
109
-                        CreateAdjustmentSelect::make('salesDiscounts')
110
-                            ->label('Sales discount')
111
-                            ->category(AdjustmentCategory::Discount)
112
-                            ->type(AdjustmentType::Sales)
113
-                            ->multiple(),
114
-                    ])
115
-                    ->columns()
116
-                    ->visible(static fn (Forms\Get $get) => in_array('Sellable', $get('attributes') ?? [])),
117
-
61
+                static::getSellableSection(),
118 62
                 // Purchasable Section
119
-                Forms\Components\Section::make('Purchase Information')
120
-                    ->schema([
121
-                        CreateAccountSelect::make('expense_account_id')
122
-                            ->label('Expense account')
123
-                            ->category(AccountCategory::Expense)
124
-                            ->type(AccountType::OperatingExpense)
125
-                            ->required()
126
-                            ->validationMessages([
127
-                                'required' => 'The expense account is required for purchasable offerings.',
128
-                            ]),
129
-                        CreateAdjustmentSelect::make('purchaseTaxes')
130
-                            ->label('Purchase tax')
131
-                            ->category(AdjustmentCategory::Tax)
132
-                            ->type(AdjustmentType::Purchase)
133
-                            ->multiple(),
134
-                        CreateAdjustmentSelect::make('purchaseDiscounts')
135
-                            ->label('Purchase discount')
136
-                            ->category(AdjustmentCategory::Discount)
137
-                            ->type(AdjustmentType::Purchase)
138
-                            ->multiple(),
139
-                    ])
63
+                static::getPurchasableSection(),
64
+            ])->columns();
65
+    }
66
+
67
+    public static function getGeneralSection(bool $hasAttributeChoices = true): Forms\Components\Section
68
+    {
69
+        return Forms\Components\Section::make('General')
70
+            ->schema([
71
+                RadioDeck::make('type')
72
+                    ->options(OfferingType::class)
73
+                    ->default(OfferingType::Product)
74
+                    ->icons(OfferingType::class)
75
+                    ->color('primary')
140 76
                     ->columns()
141
-                    ->visible(static fn (Forms\Get $get) => in_array('Purchasable', $get('attributes') ?? [])),
77
+                    ->required(),
78
+                Forms\Components\TextInput::make('name')
79
+                    ->autofocus()
80
+                    ->required()
81
+                    ->columnStart(1)
82
+                    ->maxLength(255),
83
+                Forms\Components\TextInput::make('price')
84
+                    ->required()
85
+                    ->money(),
86
+                Forms\Components\Textarea::make('description')
87
+                    ->label('Description')
88
+                    ->columnSpan(2)
89
+                    ->rows(3),
90
+                Forms\Components\CheckboxList::make('attributes')
91
+                    ->options([
92
+                        'Sellable' => 'Sellable',
93
+                        'Purchasable' => 'Purchasable',
94
+                    ])
95
+                    ->visible($hasAttributeChoices)
96
+                    ->hiddenLabel()
97
+                    ->required()
98
+                    ->live()
99
+                    ->bulkToggleable()
100
+                    ->validationMessages([
101
+                        'required' => 'The offering must be either sellable or purchasable.',
102
+                    ]),
142 103
             ])->columns();
143 104
     }
144 105
 
106
+    public static function getSellableSection(bool $showByDefault = false): Forms\Components\Section
107
+    {
108
+        return Forms\Components\Section::make('Sale Information')
109
+            ->schema([
110
+                CreateAccountSelect::make('income_account_id')
111
+                    ->label('Income account')
112
+                    ->category(AccountCategory::Revenue)
113
+                    ->type(AccountType::OperatingRevenue)
114
+                    ->required()
115
+                    ->validationMessages([
116
+                        'required' => 'The income account is required for sellable offerings.',
117
+                    ]),
118
+                CreateAdjustmentSelect::make('salesTaxes')
119
+                    ->label('Sales tax')
120
+                    ->category(AdjustmentCategory::Tax)
121
+                    ->type(AdjustmentType::Sales)
122
+                    ->multiple(),
123
+                CreateAdjustmentSelect::make('salesDiscounts')
124
+                    ->label('Sales discount')
125
+                    ->category(AdjustmentCategory::Discount)
126
+                    ->type(AdjustmentType::Sales)
127
+                    ->multiple(),
128
+            ])
129
+            ->columns()
130
+            ->visible(static fn (Forms\Get $get) => in_array('Sellable', $get('attributes') ?? []));
131
+    }
132
+
133
+    public static function getPurchasableSection(): Forms\Components\Section
134
+    {
135
+        return Forms\Components\Section::make('Purchase Information')
136
+            ->schema([
137
+                CreateAccountSelect::make('expense_account_id')
138
+                    ->label('Expense account')
139
+                    ->category(AccountCategory::Expense)
140
+                    ->type(AccountType::OperatingExpense)
141
+                    ->required()
142
+                    ->validationMessages([
143
+                        'required' => 'The expense account is required for purchasable offerings.',
144
+                    ]),
145
+                CreateAdjustmentSelect::make('purchaseTaxes')
146
+                    ->label('Purchase tax')
147
+                    ->category(AdjustmentCategory::Tax)
148
+                    ->type(AdjustmentType::Purchase)
149
+                    ->multiple(),
150
+                CreateAdjustmentSelect::make('purchaseDiscounts')
151
+                    ->label('Purchase discount')
152
+                    ->category(AdjustmentCategory::Discount)
153
+                    ->type(AdjustmentType::Purchase)
154
+                    ->multiple(),
155
+            ])
156
+            ->columns()
157
+            ->visible(static fn (Forms\Get $get) => in_array('Purchasable', $get('attributes') ?? []));
158
+    }
159
+
145 160
     public static function table(Table $table): Table
146 161
     {
147 162
         return $table

+ 3
- 4
app/Filament/Company/Resources/Purchases/BillResource.php Visa fil

@@ -14,6 +14,7 @@ use App\Filament\Company\Resources\Purchases\BillResource\Pages;
14 14
 use App\Filament\Company\Resources\Purchases\VendorResource\RelationManagers\BillsRelationManager;
15 15
 use App\Filament\Forms\Components\CreateAdjustmentSelect;
16 16
 use App\Filament\Forms\Components\CreateCurrencySelect;
17
+use App\Filament\Forms\Components\CreateOfferingSelect;
17 18
 use App\Filament\Forms\Components\CreateVendorSelect;
18 19
 use App\Filament\Forms\Components\DocumentTotals;
19 20
 use App\Filament\Tables\Actions\ReplicateBulkAction;
@@ -208,13 +209,11 @@ class BillResource extends Resource
208 209
                                 return $headers;
209 210
                             })
210 211
                             ->schema([
211
-                                Forms\Components\Select::make('offering_id')
212
+                                CreateOfferingSelect::make('offering_id')
212 213
                                     ->label('Item')
213
-                                    ->relationship('purchasableOffering', 'name')
214
-                                    ->preload()
215
-                                    ->searchable()
216 214
                                     ->required()
217 215
                                     ->live()
216
+                                    ->purchasable()
218 217
                                     ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state, ?DocumentLineItem $record) {
219 218
                                         $offeringId = $state;
220 219
                                         $discountMethod = DocumentDiscountMethod::parse($get('../../discount_method'));

+ 4
- 4
app/Filament/Company/Resources/Sales/EstimateResource.php Visa fil

@@ -15,6 +15,7 @@ use App\Filament\Company\Resources\Sales\EstimateResource\Widgets;
15 15
 use App\Filament\Forms\Components\CreateAdjustmentSelect;
16 16
 use App\Filament\Forms\Components\CreateClientSelect;
17 17
 use App\Filament\Forms\Components\CreateCurrencySelect;
18
+use App\Filament\Forms\Components\CreateOfferingSelect;
18 19
 use App\Filament\Forms\Components\DocumentFooterSection;
19 20
 use App\Filament\Forms\Components\DocumentHeaderSection;
20 21
 use App\Filament\Forms\Components\DocumentTotals;
@@ -206,12 +207,11 @@ class EstimateResource extends Resource
206 207
                                 return $headers;
207 208
                             })
208 209
                             ->schema([
209
-                                Forms\Components\Select::make('offering_id')
210
-                                    ->relationship('sellableOffering', 'name')
211
-                                    ->preload()
212
-                                    ->searchable()
210
+                                CreateOfferingSelect::make('offering_id')
211
+                                    ->label('Item')
213 212
                                     ->required()
214 213
                                     ->live()
214
+                                    ->sellable()
215 215
                                     ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state, ?DocumentLineItem $record) {
216 216
                                         $offeringId = $state;
217 217
                                         $discountMethod = DocumentDiscountMethod::parse($get('../../discount_method'));

+ 4
- 4
app/Filament/Company/Resources/Sales/InvoiceResource.php Visa fil

@@ -17,6 +17,7 @@ use App\Filament\Company\Resources\Sales\InvoiceResource\Widgets;
17 17
 use App\Filament\Forms\Components\CreateAdjustmentSelect;
18 18
 use App\Filament\Forms\Components\CreateClientSelect;
19 19
 use App\Filament\Forms\Components\CreateCurrencySelect;
20
+use App\Filament\Forms\Components\CreateOfferingSelect;
20 21
 use App\Filament\Forms\Components\DocumentFooterSection;
21 22
 use App\Filament\Forms\Components\DocumentHeaderSection;
22 23
 use App\Filament\Forms\Components\DocumentTotals;
@@ -219,12 +220,11 @@ class InvoiceResource extends Resource
219 220
                                 return $headers;
220 221
                             })
221 222
                             ->schema([
222
-                                Forms\Components\Select::make('offering_id')
223
-                                    ->relationship('sellableOffering', 'name')
224
-                                    ->preload()
225
-                                    ->searchable()
223
+                                CreateOfferingSelect::make('offering_id')
224
+                                    ->label('Item')
226 225
                                     ->required()
227 226
                                     ->live()
227
+                                    ->sellable()
228 228
                                     ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state, ?DocumentLineItem $record) {
229 229
                                         $offeringId = $state;
230 230
                                         $discountMethod = DocumentDiscountMethod::parse($get('../../discount_method'));

+ 4
- 4
app/Filament/Company/Resources/Sales/RecurringInvoiceResource.php Visa fil

@@ -14,6 +14,7 @@ use App\Filament\Company\Resources\Sales\RecurringInvoiceResource\Pages;
14 14
 use App\Filament\Forms\Components\CreateAdjustmentSelect;
15 15
 use App\Filament\Forms\Components\CreateClientSelect;
16 16
 use App\Filament\Forms\Components\CreateCurrencySelect;
17
+use App\Filament\Forms\Components\CreateOfferingSelect;
17 18
 use App\Filament\Forms\Components\DocumentFooterSection;
18 19
 use App\Filament\Forms\Components\DocumentHeaderSection;
19 20
 use App\Filament\Forms\Components\DocumentTotals;
@@ -132,12 +133,11 @@ class RecurringInvoiceResource extends Resource
132 133
                                 return $headers;
133 134
                             })
134 135
                             ->schema([
135
-                                Forms\Components\Select::make('offering_id')
136
-                                    ->relationship('sellableOffering', 'name')
137
-                                    ->preload()
138
-                                    ->searchable()
136
+                                CreateOfferingSelect::make('offering_id')
137
+                                    ->label('Item')
139 138
                                     ->required()
140 139
                                     ->live()
140
+                                    ->sellable()
141 141
                                     ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state, ?DocumentLineItem $record) {
142 142
                                         $offeringId = $state;
143 143
                                         $discountMethod = DocumentDiscountMethod::parse($get('../../discount_method'));

+ 107
- 0
app/Filament/Forms/Components/CreateOfferingSelect.php Visa fil

@@ -0,0 +1,107 @@
1
+<?php
2
+
3
+namespace App\Filament\Forms\Components;
4
+
5
+use App\Filament\Company\Resources\Common\OfferingResource;
6
+use App\Models\Common\Offering;
7
+use Filament\Forms\Components\Actions\Action;
8
+use Filament\Forms\Components\Select;
9
+use Filament\Forms\Form;
10
+use Filament\Forms\Get;
11
+use Filament\Support\Enums\MaxWidth;
12
+
13
+class CreateOfferingSelect extends Select
14
+{
15
+    protected bool $isPurchasable = true;
16
+
17
+    protected bool $isSellable = true;
18
+
19
+    public function purchasable(bool $condition = true): static
20
+    {
21
+        $this->isPurchasable = $condition;
22
+        $this->isSellable = false;
23
+
24
+        return $this;
25
+    }
26
+
27
+    public function sellable(bool $condition = true): static
28
+    {
29
+        $this->isSellable = $condition;
30
+        $this->isPurchasable = false;
31
+
32
+        return $this;
33
+    }
34
+
35
+    protected function setUp(): void
36
+    {
37
+        parent::setUp();
38
+
39
+        $this
40
+            ->searchable()
41
+            ->preload()
42
+            ->createOptionForm(fn (Form $form) => $this->createOfferingForm($form))
43
+            ->createOptionAction(fn (Action $action) => $this->createOfferingAction($action));
44
+
45
+        $this->relationship(
46
+            $this->isPurchasable() && ! $this->isSellable() ? 'purchasableOffering' :
47
+            ($this->isSellable() && ! $this->isPurchasable() ? 'sellableOffering' : 'offering'),
48
+            'name'
49
+        );
50
+
51
+        $this->createOptionUsing(function (array $data) {
52
+            if ($this->isSellableAndPurchasable()) {
53
+                $data['sellable'] = isset($data['attributes']) && in_array('Sellable', $data['attributes'], true);
54
+                $data['purchasable'] = isset($data['attributes']) && in_array('Purchasable', $data['attributes'], true);
55
+            } else {
56
+                $data['sellable'] = $this->isSellable;
57
+                $data['purchasable'] = $this->isPurchasable;
58
+            }
59
+
60
+            unset($data['attributes']);
61
+
62
+            $offering = Offering::create($data);
63
+
64
+            return $offering->getKey();
65
+        });
66
+    }
67
+
68
+    protected function createOfferingForm(Form $form): Form
69
+    {
70
+        return $form->schema([
71
+            OfferingResource::getGeneralSection($this->isSellableAndPurchasable()),
72
+            OfferingResource::getSellableSection()->visible(
73
+                fn (Get $get) => $this->isSellableAndPurchasable()
74
+                    ? in_array('Sellable', $get('attributes') ?? [])
75
+                    : $this->isSellable()
76
+            ),
77
+            OfferingResource::getPurchasableSection()->visible(
78
+                fn (Get $get) => $this->isSellableAndPurchasable()
79
+                    ? in_array('Purchasable', $get('attributes') ?? [])
80
+                    : $this->isPurchasable()
81
+            ),
82
+        ]);
83
+    }
84
+
85
+    protected function createOfferingAction(Action $action): Action
86
+    {
87
+        return $action
88
+            ->label('Add offering')
89
+            ->slideOver()
90
+            ->modalWidth(MaxWidth::ThreeExtraLarge);
91
+    }
92
+
93
+    public function isSellable(): bool
94
+    {
95
+        return $this->isSellable;
96
+    }
97
+
98
+    public function isPurchasable(): bool
99
+    {
100
+        return $this->isPurchasable;
101
+    }
102
+
103
+    public function isSellableAndPurchasable(): bool
104
+    {
105
+        return $this->isSellable && $this->isPurchasable;
106
+    }
107
+}

Laddar…
Avbryt
Spara