Browse Source

wip refactor

3.x
Andrew Wallo 9 months ago
parent
commit
458dd5f5f8

+ 12
- 5
app/Filament/Company/Resources/Purchases/BillResource.php View File

@@ -129,6 +129,7 @@ class BillResource extends Resource
129 129
                             })
130 130
                             ->schema([
131 131
                                 Forms\Components\Select::make('offering_id')
132
+                                    ->label('Item')
132 133
                                     ->relationship('purchasableOffering', 'name')
133 134
                                     ->preload()
134 135
                                     ->searchable()
@@ -156,11 +157,13 @@ class BillResource extends Resource
156 157
                                     ->live()
157 158
                                     ->default(1),
158 159
                                 Forms\Components\TextInput::make('unit_price')
160
+                                    ->label('Price')
159 161
                                     ->hiddenLabel()
160 162
                                     ->numeric()
161 163
                                     ->live()
162 164
                                     ->default(0),
163 165
                                 Forms\Components\Select::make('purchaseTaxes')
166
+                                    ->label('Taxes')
164 167
                                     ->relationship('purchaseTaxes', 'name')
165 168
                                     ->saveRelationshipsUsing(null)
166 169
                                     ->dehydrated(true)
@@ -169,6 +172,7 @@ class BillResource extends Resource
169 172
                                     ->live()
170 173
                                     ->searchable(),
171 174
                                 Forms\Components\Select::make('purchaseDiscounts')
175
+                                    ->label('Discounts')
172 176
                                     ->relationship('purchaseDiscounts', 'name')
173 177
                                     ->saveRelationshipsUsing(null)
174 178
                                     ->dehydrated(true)
@@ -183,6 +187,7 @@ class BillResource extends Resource
183 187
                                     ->searchable(),
184 188
                                 Forms\Components\Placeholder::make('total')
185 189
                                     ->hiddenLabel()
190
+                                    ->extraAttributes(['class' => 'text-left sm:text-right'])
186 191
                                     ->content(function (Forms\Get $get) {
187 192
                                         $quantity = max((float) ($get('quantity') ?? 0), 0);
188 193
                                         $unitPrice = max((float) ($get('unit_price') ?? 0), 0);
@@ -253,15 +258,17 @@ class BillResource extends Resource
253 258
                 Tables\Columns\TextColumn::make('vendor.name')
254 259
                     ->sortable(),
255 260
                 Tables\Columns\TextColumn::make('total')
256
-                    ->currency()
257
-                    ->sortable(),
261
+                    ->currencyWithConversion(static fn (Bill $record) => $record->currency_code)
262
+                    ->sortable()
263
+                    ->toggleable(),
258 264
                 Tables\Columns\TextColumn::make('amount_paid')
259 265
                     ->label('Amount Paid')
260
-                    ->currency()
261
-                    ->sortable(),
266
+                    ->currencyWithConversion(static fn (Bill $record) => $record->currency_code)
267
+                    ->sortable()
268
+                    ->toggleable(),
262 269
                 Tables\Columns\TextColumn::make('amount_due')
263 270
                     ->label('Amount Due')
264
-                    ->currency()
271
+                    ->currencyWithConversion(static fn (Bill $record) => $record->currency_code)
265 272
                     ->sortable(),
266 273
             ])
267 274
             ->filters([

+ 1
- 0
app/Filament/Company/Resources/Sales/InvoiceResource.php View File

@@ -240,6 +240,7 @@ class InvoiceResource extends Resource
240 240
                                     ->searchable(),
241 241
                                 Forms\Components\Placeholder::make('total')
242 242
                                     ->hiddenLabel()
243
+                                    ->extraAttributes(['class' => 'text-left sm:text-right'])
243 244
                                     ->content(function (Forms\Get $get) {
244 245
                                         $quantity = max((float) ($get('quantity') ?? 0), 0);
245 246
                                         $unitPrice = max((float) ($get('unit_price') ?? 0), 0);

+ 10
- 9
app/Filament/Forms/Components/DocumentTotals.php View File

@@ -20,21 +20,22 @@ class DocumentTotals extends Grid
20 20
         parent::setUp();
21 21
 
22 22
         $this->schema([
23
-            TextInput::make('discount_rate')
24
-                ->label('Discount Rate')
25
-                ->hiddenLabel()
26
-                ->live()
27
-                ->rate(computation: static fn (Get $get) => $get('discount_computation'), showAffix: false),
28 23
             Select::make('discount_computation')
29 24
                 ->label('Discount Computation')
30 25
                 ->hiddenLabel()
31
-                ->options([
32
-                    'percentage' => '%',
33
-                    'fixed' => '$',
34
-                ])
26
+                ->options(AdjustmentComputation::class)
35 27
                 ->default(AdjustmentComputation::Percentage)
36 28
                 ->selectablePlaceholder(false)
37 29
                 ->live(),
30
+            TextInput::make('discount_rate')
31
+                ->label('Discount Rate')
32
+                ->hiddenLabel()
33
+                ->live()
34
+                ->extraInputAttributes(['class' => 'text-right'])
35
+                ->rate(
36
+                    computation: static fn (Get $get) => $get('discount_computation'),
37
+                    currency: static fn (Get $get) => $get('currency_code'),
38
+                ),
38 39
         ]);
39 40
     }
40 41
 

+ 29
- 35
app/Helpers/format.php View File

@@ -1,5 +1,6 @@
1 1
 <?php
2 2
 
3
+use App\Enums\Accounting\AdjustmentComputation;
3 4
 use App\Enums\Setting\NumberFormat;
4 5
 use App\Models\Setting\Localization;
5 6
 use Filament\Support\RawJs;
@@ -44,18 +45,15 @@ if (! function_exists('percentMask')) {
44 45
 if (! function_exists('ratePrefix')) {
45 46
     function ratePrefix($computation, ?string $currency = null): ?string
46 47
     {
47
-        if ($computation instanceof BackedEnum) {
48
-            $computation = $computation->value;
49
-        }
48
+        $computationEnum = AdjustmentComputation::parse($computation);
49
+        $localization = Localization::firstOrFail();
50 50
 
51
-        if ($computation === 'fixed') {
52
-            return currency($currency)->getCodePrefix();
51
+        if ($computationEnum->isFixed() && currency($currency)->isSymbolFirst()) {
52
+            return currency($currency)->getPrefix();
53 53
         }
54 54
 
55
-        if ($computation === 'percentage' || $computation === 'compound') {
56
-            $percent_first = Localization::firstOrFail()->percent_first;
57
-
58
-            return $percent_first ? '%' : null;
55
+        if ($computationEnum->isPercentage() && $localization->percent_first) {
56
+            return '%';
59 57
         }
60 58
 
61 59
         return null;
@@ -65,18 +63,15 @@ if (! function_exists('ratePrefix')) {
65 63
 if (! function_exists('rateSuffix')) {
66 64
     function rateSuffix($computation, ?string $currency = null): ?string
67 65
     {
68
-        if ($computation instanceof BackedEnum) {
69
-            $computation = $computation->value;
70
-        }
71
-
72
-        if ($computation === 'percentage' || $computation === 'compound') {
73
-            $percent_first = Localization::firstOrFail()->percent_first;
66
+        $computationEnum = AdjustmentComputation::parse($computation);
67
+        $localization = Localization::firstOrFail();
74 68
 
75
-            return $percent_first ? null : '%';
69
+        if ($computationEnum->isFixed() && ! currency($currency)->isSymbolFirst()) {
70
+            return currency($currency)->getSuffix();
76 71
         }
77 72
 
78
-        if ($computation === 'fixed') {
79
-            return currency($currency)->getCodeSuffix();
73
+        if ($computationEnum->isPercentage() && ! $localization->percent_first) {
74
+            return '%';
80 75
         }
81 76
 
82 77
         return null;
@@ -84,19 +79,21 @@ if (! function_exists('rateSuffix')) {
84 79
 }
85 80
 
86 81
 if (! function_exists('rateMask')) {
87
-    function rateMask($computation, ?string $currency = null): RawJs
82
+    function rateMask($computation, ?string $currency = null): ?RawJs
88 83
     {
89
-        if ($computation instanceof BackedEnum) {
90
-            $computation = $computation->value;
91
-        }
84
+        $computationEnum = AdjustmentComputation::parse($computation);
92 85
 
93
-        if ($computation === 'percentage' || $computation === 'compound') {
86
+        if ($computationEnum->isPercentage()) {
94 87
             return percentMask(4);
95 88
         }
96 89
 
97
-        $precision = currency($currency)->getPrecision();
90
+        if ($computationEnum->isFixed()) {
91
+            $precision = currency($currency)->getPrecision();
98 92
 
99
-        return RawJs::make(generateJsCode($precision, $currency));
93
+            return RawJs::make(generateJsCode($precision, $currency));
94
+        }
95
+
96
+        return null;
100 97
     }
101 98
 }
102 99
 
@@ -107,21 +104,18 @@ if (! function_exists('rateFormat')) {
107 104
             return null;
108 105
         }
109 106
 
110
-        if ($computation instanceof BackedEnum) {
111
-            $computation = $computation->value;
112
-        }
113
-
114
-        if ($computation === 'percentage' || $computation === 'compound') {
115
-            $percent_first = Localization::firstOrFail()->percent_first;
107
+        $computationEnum = AdjustmentComputation::parse($computation);
108
+        $localization = Localization::firstOrFail();
116 109
 
117
-            if ($percent_first) {
118
-                return '%' . $state;
119
-            }
110
+        if ($computationEnum->isPercentage() && $localization->percent_first) {
111
+            return '%' . $state;
112
+        }
120 113
 
114
+        if ($computationEnum->isPercentage() && ! $localization->percent_first) {
121 115
             return $state . '%';
122 116
         }
123 117
 
124
-        if ($computation === 'fixed') {
118
+        if ($computationEnum->isFixed()) {
125 119
             return money($state, $currency, true)->formatWithCode();
126 120
         }
127 121
 

+ 51
- 43
app/Providers/MacroServiceProvider.php View File

@@ -4,6 +4,7 @@ namespace App\Providers;
4 4
 
5 5
 use Akaunting\Money\Currency;
6 6
 use Akaunting\Money\Money;
7
+use App\Enums\Accounting\AdjustmentComputation;
7 8
 use App\Enums\Setting\DateFormat;
8 9
 use App\Models\Accounting\AccountSubtype;
9 10
 use App\Models\Setting\Localization;
@@ -62,6 +63,56 @@ class MacroServiceProvider extends ServiceProvider
62 63
             return $this;
63 64
         });
64 65
 
66
+        TextInput::macro('rate', function (string | Closure | null $computation = null, string | Closure | null $currency = null, bool $showAffix = true): static {
67
+            return $this
68
+                ->when(
69
+                    $showAffix,
70
+                    fn (TextInput $component) => $component
71
+                        ->prefix(function (TextInput $component) use ($computation, $currency) {
72
+                            $evaluatedComputation = $component->evaluate($computation);
73
+                            $evaluatedCurrency = $component->evaluate($currency);
74
+
75
+                            return ratePrefix($evaluatedComputation, $evaluatedCurrency);
76
+                        })
77
+                        ->suffix(function (TextInput $component) use ($computation, $currency) {
78
+                            $evaluatedComputation = $component->evaluate($computation);
79
+                            $evaluatedCurrency = $component->evaluate($currency);
80
+
81
+                            return rateSuffix($evaluatedComputation, $evaluatedCurrency);
82
+                        })
83
+                )
84
+                ->mask(static function (TextInput $component) use ($computation, $currency) {
85
+                    $computation = $component->evaluate($computation);
86
+                    $currency = $component->evaluate($currency);
87
+
88
+                    $computationEnum = AdjustmentComputation::parse($computation);
89
+
90
+                    if ($computationEnum->isPercentage()) {
91
+                        return rateMask(computation: $computation);
92
+                    }
93
+
94
+                    return moneyMask($currency);
95
+                })
96
+                ->rule(static function (TextInput $component) use ($computation) {
97
+                    return static function (string $attribute, $value, Closure $fail) use ($computation, $component) {
98
+                        $computation = $component->evaluate($computation);
99
+                        $numericValue = (float) $value;
100
+
101
+                        if ($computation instanceof BackedEnum) {
102
+                            $computation = $computation->value;
103
+                        }
104
+
105
+                        if ($computation === 'percentage' || $computation === 'compound') {
106
+                            if ($numericValue < 0 || $numericValue > 100) {
107
+                                $fail(translate('The rate must be between 0 and 100.'));
108
+                            }
109
+                        } elseif ($computation === 'fixed' && $numericValue < 0) {
110
+                            $fail(translate('The rate must be greater than 0.'));
111
+                        }
112
+                    };
113
+                });
114
+        });
115
+
65 116
         TextColumn::macro('defaultDateFormat', function (): static {
66 117
             $localization = Localization::firstOrFail();
67 118
 
@@ -190,49 +241,6 @@ class MacroServiceProvider extends ServiceProvider
190 241
             return $this;
191 242
         });
192 243
 
193
-        TextInput::macro('rate', function (string | Closure | null $computation = null, bool $showAffix = true): static {
194
-            $this
195
-                ->when(
196
-                    $showAffix,
197
-                    fn (TextInput $component) => $component
198
-                        ->prefix(static function (TextInput $component) use ($computation) {
199
-                            $computation = $component->evaluate($computation);
200
-
201
-                            return ratePrefix(computation: $computation);
202
-                        })
203
-                        ->suffix(static function (TextInput $component) use ($computation) {
204
-                            $computation = $component->evaluate($computation);
205
-
206
-                            return rateSuffix(computation: $computation);
207
-                        })
208
-                )
209
-                ->mask(static function (TextInput $component) use ($computation) {
210
-                    $computation = $component->evaluate($computation);
211
-
212
-                    return rateMask(computation: $computation);
213
-                })
214
-                ->rule(static function (TextInput $component) use ($computation) {
215
-                    return static function (string $attribute, $value, Closure $fail) use ($computation, $component) {
216
-                        $computation = $component->evaluate($computation);
217
-                        $numericValue = (float) $value;
218
-
219
-                        if ($computation instanceof BackedEnum) {
220
-                            $computation = $computation->value;
221
-                        }
222
-
223
-                        if ($computation === 'percentage' || $computation === 'compound') {
224
-                            if ($numericValue < 0 || $numericValue > 100) {
225
-                                $fail(translate('The rate must be between 0 and 100.'));
226
-                            }
227
-                        } elseif ($computation === 'fixed' && $numericValue < 0) {
228
-                            $fail(translate('The rate must be greater than 0.'));
229
-                        }
230
-                    };
231
-                });
232
-
233
-            return $this;
234
-        });
235
-
236 244
         Field::macro('validateAccountCode', function (string | Closure | null $subtype = null): static {
237 245
             $this
238 246
                 ->rules([

+ 5
- 1
app/View/Models/DocumentTotalViewModel.php View File

@@ -86,7 +86,7 @@ class DocumentTotalViewModel
86 86
         }
87 87
 
88 88
         $discountComputation = AdjustmentComputation::parse($this->data['discount_computation']) ?? AdjustmentComputation::Percentage;
89
-        $discountRate = $this->data['discount_rate'] ?? '0';
89
+        $discountRate = blank($this->data['discount_rate']) ? '0' : $this->data['discount_rate'];
90 90
 
91 91
         if ($discountComputation->isPercentage()) {
92 92
             $scaledDiscountRate = RateCalculator::parseLocalizedRate($discountRate);
@@ -94,6 +94,10 @@ class DocumentTotalViewModel
94 94
             return RateCalculator::calculatePercentage($subtotalInCents, $scaledDiscountRate);
95 95
         }
96 96
 
97
+        if (! CurrencyConverter::isValidAmount($discountRate)) {
98
+            $discountRate = '0';
99
+        }
100
+
97 101
         return CurrencyConverter::convertToCents($discountRate, $currencyCode);
98 102
     }
99 103
 

+ 43
- 5
resources/views/filament/forms/components/document-totals.blade.php View File

@@ -12,8 +12,8 @@
12 12
     $isPerDocumentDiscount = $discountMethod->isPerDocument();
13 13
 @endphp
14 14
 
15
-<div class="totals-summary w-full pr-14">
16
-    <table class="w-full text-right table-fixed">
15
+<div class="totals-summary w-full sm:pr-14">
16
+    <table class="w-full text-right table-fixed hidden sm:table">
17 17
         <colgroup>
18 18
             <col class="w-[20%]"> {{-- Items --}}
19 19
             <col class="w-[30%]"> {{-- Description --}}
@@ -35,11 +35,11 @@
35 35
             </tr>
36 36
             @if($isPerDocumentDiscount)
37 37
                 <tr>
38
-                    <td colspan="4" class="text-sm px-4 py-2 font-medium leading-6 text-gray-950 dark:text-white text-right">Discount:</td>
39
-                    <td class="text-sm px-4 py-2">
38
+                    <td colspan="3" class="text-sm px-4 py-2 font-medium leading-6 text-gray-950 dark:text-white text-right">Discount:</td>
39
+                    <td colspan="2" class="text-sm px-4 py-2">
40 40
                         <div class="flex justify-between space-x-2">
41 41
                             @foreach($getChildComponentContainer()->getComponents() as $component)
42
-                                <div class="flex-1">{{ $component }}</div>
42
+                                <div class="flex-1 text-left">{{ $component }}</div>
43 43
                             @endforeach
44 44
                         </div>
45 45
                     </td>
@@ -66,4 +66,42 @@
66 66
             @endif
67 67
         </tbody>
68 68
     </table>
69
+
70
+    <!-- Mobile View -->
71
+    <div class="block sm:hidden p-5">
72
+        <div class="flex flex-col space-y-6">
73
+            <div class="flex justify-between items-center">
74
+                <span class="text-sm font-medium text-gray-950 dark:text-white">Subtotal:</span>
75
+                <span class="text-sm text-gray-950 dark:text-white">{{ $subtotal }}</span>
76
+            </div>
77
+            <div class="flex justify-between items-center">
78
+                <span class="text-sm font-medium text-gray-950 dark:text-white">Taxes:</span>
79
+                <span class="text-sm text-gray-950 dark:text-white">{{ $taxTotal }}</span>
80
+            </div>
81
+            @if($isPerDocumentDiscount)
82
+                <div class="flex flex-col space-y-2">
83
+                    <span class="text-sm font-medium text-gray-950 dark:text-white">Discount:</span>
84
+                    <div class="flex justify-between space-x-2">
85
+                        @foreach($getChildComponentContainer()->getComponents() as $component)
86
+                            <div class="w-1/2">{{ $component }}</div>
87
+                        @endforeach
88
+                    </div>
89
+                </div>
90
+            @else
91
+                <div class="flex justify-between items-center">
92
+                    <span class="text-sm font-medium text-gray-950 dark:text-white">Discounts:</span>
93
+                    <span class="text-sm text-gray-950 dark:text-white">({{ $discountTotal }})</span>
94
+                </div>
95
+            @endif
96
+            <div class="flex justify-between items-center font-semibold">
97
+                <span class="text-sm font-medium text-gray-950 dark:text-white">Total:</span>
98
+                <span class="text-sm text-gray-950 dark:text-white">{{ $grandTotal }}</span>
99
+            </div>
100
+            @if($conversionMessage)
101
+                <div class="text-sm text-gray-600">
102
+                    {{ $conversionMessage }}
103
+                </div>
104
+            @endif
105
+        </div>
106
+    </div>
69 107
 </div>

Loading…
Cancel
Save