Andrew Wallo 9 months ago
parent
commit
8acaeab07b

+ 8
- 7
app/Filament/Company/Resources/Purchases/BillResource.php View File

324
                             Forms\Components\TextInput::make('amount')
324
                             Forms\Components\TextInput::make('amount')
325
                                 ->label('Amount')
325
                                 ->label('Amount')
326
                                 ->required()
326
                                 ->required()
327
-                                ->money()
327
+                                ->money(fn (Bill $record) => $record->currency_code)
328
                                 ->live(onBlur: true)
328
                                 ->live(onBlur: true)
329
                                 ->helperText(function (Bill $record, $state) {
329
                                 ->helperText(function (Bill $record, $state) {
330
-                                    if (! CurrencyConverter::isValidAmount($state)) {
330
+                                    $billCurrency = $record->currency_code;
331
+                                    if (! CurrencyConverter::isValidAmount($state, $billCurrency)) {
331
                                         return null;
332
                                         return null;
332
                                     }
333
                                     }
333
 
334
 
334
                                     $amountDue = $record->getRawOriginal('amount_due');
335
                                     $amountDue = $record->getRawOriginal('amount_due');
335
-                                    $amount = CurrencyConverter::convertToCents($state);
336
+                                    $amount = CurrencyConverter::convertToCents($state, $billCurrency);
336
 
337
 
337
                                     if ($amount <= 0) {
338
                                     if ($amount <= 0) {
338
                                         return 'Please enter a valid positive amount';
339
                                         return 'Please enter a valid positive amount';
341
                                     $newAmountDue = $amountDue - $amount;
342
                                     $newAmountDue = $amountDue - $amount;
342
 
343
 
343
                                     return match (true) {
344
                                     return match (true) {
344
-                                        $newAmountDue > 0 => 'Amount due after payment will be ' . CurrencyConverter::formatCentsToMoney($newAmountDue),
345
+                                        $newAmountDue > 0 => 'Amount due after payment will be ' . CurrencyConverter::formatCentsToMoney($newAmountDue, $billCurrency),
345
                                         $newAmountDue === 0 => 'Bill will be fully paid',
346
                                         $newAmountDue === 0 => 'Bill will be fully paid',
346
-                                        default => 'Amount exceeds bill total by ' . CurrencyConverter::formatCentsToMoney(abs($newAmountDue)),
347
+                                        default => 'Amount exceeds bill total by ' . CurrencyConverter::formatCentsToMoney(abs($newAmountDue), $billCurrency),
347
                                     };
348
                                     };
348
                                 })
349
                                 })
349
                                 ->rules([
350
                                 ->rules([
350
-                                    static fn (): Closure => static function (string $attribute, $value, Closure $fail) {
351
-                                        if (! CurrencyConverter::isValidAmount($value)) {
351
+                                    static fn (Bill $record): Closure => static function (string $attribute, $value, Closure $fail) use ($record) {
352
+                                        if (! CurrencyConverter::isValidAmount($value, $record->currency_code)) {
352
                                             $fail('Please enter a valid amount');
353
                                             $fail('Please enter a valid amount');
353
                                         }
354
                                         }
354
                                     },
355
                                     },

+ 61
- 12
app/Models/Accounting/Bill.php View File

12
 use App\Enums\Accounting\JournalEntryType;
12
 use App\Enums\Accounting\JournalEntryType;
13
 use App\Enums\Accounting\TransactionType;
13
 use App\Enums\Accounting\TransactionType;
14
 use App\Filament\Company\Resources\Purchases\BillResource;
14
 use App\Filament\Company\Resources\Purchases\BillResource;
15
+use App\Models\Banking\BankAccount;
15
 use App\Models\Common\Vendor;
16
 use App\Models\Common\Vendor;
16
 use App\Models\Setting\Currency;
17
 use App\Models\Setting\Currency;
17
 use App\Observers\BillObserver;
18
 use App\Observers\BillObserver;
19
+use App\Utilities\Currency\CurrencyAccessor;
18
 use App\Utilities\Currency\CurrencyConverter;
20
 use App\Utilities\Currency\CurrencyConverter;
19
 use Filament\Actions\MountableAction;
21
 use Filament\Actions\MountableAction;
20
 use Filament\Actions\ReplicateAction;
22
 use Filament\Actions\ReplicateAction;
194
         $transactionType = TransactionType::Withdrawal;
196
         $transactionType = TransactionType::Withdrawal;
195
         $transactionDescription = "Bill #{$this->bill_number}: Payment to {$this->vendor->name}";
197
         $transactionDescription = "Bill #{$this->bill_number}: Payment to {$this->vendor->name}";
196
 
198
 
197
-        // Create transaction
199
+        // Add multi-currency handling
200
+        $bankAccount = BankAccount::findOrFail($data['bank_account_id']);
201
+        $bankAccountCurrency = $bankAccount->account->currency_code ?? CurrencyAccessor::getDefaultCurrency();
202
+
203
+        $billCurrency = $this->currency_code;
204
+        $requiresConversion = $billCurrency !== $bankAccountCurrency;
205
+
206
+        if ($requiresConversion) {
207
+            $amountInBillCurrencyCents = CurrencyConverter::convertToCents($data['amount'], $billCurrency);
208
+            $amountInBankCurrencyCents = CurrencyConverter::convertBalance(
209
+                $amountInBillCurrencyCents,
210
+                $billCurrency,
211
+                $bankAccountCurrency
212
+            );
213
+            $formattedAmountForBankCurrency = CurrencyConverter::convertCentsToFormatSimple(
214
+                $amountInBankCurrencyCents,
215
+                $bankAccountCurrency
216
+            );
217
+        } else {
218
+            $formattedAmountForBankCurrency = $data['amount']; // Already in simple format
219
+        }
220
+
221
+        // Create transaction with converted amount
198
         $this->transactions()->create([
222
         $this->transactions()->create([
199
             'company_id' => $this->company_id,
223
             'company_id' => $this->company_id,
200
             'type' => $transactionType,
224
             'type' => $transactionType,
201
             'is_payment' => true,
225
             'is_payment' => true,
202
             'posted_at' => $data['posted_at'],
226
             'posted_at' => $data['posted_at'],
203
-            'amount' => $data['amount'],
227
+            'amount' => $formattedAmountForBankCurrency,
204
             'payment_method' => $data['payment_method'],
228
             'payment_method' => $data['payment_method'],
205
             'bank_account_id' => $data['bank_account_id'],
229
             'bank_account_id' => $data['bank_account_id'],
206
             'account_id' => Account::getAccountsPayableAccount()->id,
230
             'account_id' => Account::getAccountsPayableAccount()->id,
213
     {
237
     {
214
         $postedAt ??= $this->date;
238
         $postedAt ??= $this->date;
215
 
239
 
240
+        $total = $this->formatAmountToDefaultCurrency($this->getRawOriginal('total'));
241
+
216
         $transaction = $this->transactions()->create([
242
         $transaction = $this->transactions()->create([
217
             'company_id' => $this->company_id,
243
             'company_id' => $this->company_id,
218
             'type' => TransactionType::Journal,
244
             'type' => TransactionType::Journal,
219
             'posted_at' => $postedAt,
245
             'posted_at' => $postedAt,
220
-            'amount' => $this->total,
246
+            'amount' => $total,
221
             'description' => 'Bill Creation for Bill #' . $this->bill_number,
247
             'description' => 'Bill Creation for Bill #' . $this->bill_number,
222
         ]);
248
         ]);
223
 
249
 
227
             'company_id' => $this->company_id,
253
             'company_id' => $this->company_id,
228
             'type' => JournalEntryType::Credit,
254
             'type' => JournalEntryType::Credit,
229
             'account_id' => Account::getAccountsPayableAccount()->id,
255
             'account_id' => Account::getAccountsPayableAccount()->id,
230
-            'amount' => $this->total,
256
+            'amount' => $total,
231
             'description' => $baseDescription,
257
             'description' => $baseDescription,
232
         ]);
258
         ]);
233
 
259
 
234
-        $totalLineItemSubtotal = (int) $this->lineItems()->sum('subtotal');
235
-        $billDiscountTotalCents = (int) $this->getRawOriginal('discount_total');
260
+        $totalLineItemSubtotalCents = $this->convertAmountToDefaultCurrency((int) $this->lineItems()->sum('subtotal'));
261
+        $billDiscountTotalCents = $this->convertAmountToDefaultCurrency((int) $this->getRawOriginal('discount_total'));
236
         $remainingDiscountCents = $billDiscountTotalCents;
262
         $remainingDiscountCents = $billDiscountTotalCents;
237
 
263
 
238
         foreach ($this->lineItems as $index => $lineItem) {
264
         foreach ($this->lineItems as $index => $lineItem) {
239
             $lineItemDescription = "{$baseDescription} › {$lineItem->offering->name}";
265
             $lineItemDescription = "{$baseDescription} › {$lineItem->offering->name}";
240
 
266
 
267
+            $lineItemSubtotal = $this->formatAmountToDefaultCurrency($lineItem->getRawOriginal('subtotal'));
268
+
241
             $transaction->journalEntries()->create([
269
             $transaction->journalEntries()->create([
242
                 'company_id' => $this->company_id,
270
                 'company_id' => $this->company_id,
243
                 'type' => JournalEntryType::Debit,
271
                 'type' => JournalEntryType::Debit,
244
                 'account_id' => $lineItem->offering->expense_account_id,
272
                 'account_id' => $lineItem->offering->expense_account_id,
245
-                'amount' => $lineItem->subtotal,
273
+                'amount' => $lineItemSubtotal,
246
                 'description' => $lineItemDescription,
274
                 'description' => $lineItemDescription,
247
             ]);
275
             ]);
248
 
276
 
249
             foreach ($lineItem->adjustments as $adjustment) {
277
             foreach ($lineItem->adjustments as $adjustment) {
278
+                $adjustmentAmount = $this->formatAmountToDefaultCurrency($lineItem->calculateAdjustmentTotalAmount($adjustment));
279
+
250
                 if ($adjustment->isNonRecoverablePurchaseTax()) {
280
                 if ($adjustment->isNonRecoverablePurchaseTax()) {
251
                     $transaction->journalEntries()->create([
281
                     $transaction->journalEntries()->create([
252
                         'company_id' => $this->company_id,
282
                         'company_id' => $this->company_id,
253
                         'type' => JournalEntryType::Debit,
283
                         'type' => JournalEntryType::Debit,
254
                         'account_id' => $lineItem->offering->expense_account_id,
284
                         'account_id' => $lineItem->offering->expense_account_id,
255
-                        'amount' => $lineItem->calculateAdjustmentTotal($adjustment)->getAmount(),
285
+                        'amount' => $adjustmentAmount,
256
                         'description' => "{$lineItemDescription} ({$adjustment->name})",
286
                         'description' => "{$lineItemDescription} ({$adjustment->name})",
257
                     ]);
287
                     ]);
258
                 } elseif ($adjustment->account_id) {
288
                 } elseif ($adjustment->account_id) {
260
                         'company_id' => $this->company_id,
290
                         'company_id' => $this->company_id,
261
                         'type' => $adjustment->category->isDiscount() ? JournalEntryType::Credit : JournalEntryType::Debit,
291
                         'type' => $adjustment->category->isDiscount() ? JournalEntryType::Credit : JournalEntryType::Debit,
262
                         'account_id' => $adjustment->account_id,
292
                         'account_id' => $adjustment->account_id,
263
-                        'amount' => $lineItem->calculateAdjustmentTotal($adjustment)->getAmount(),
293
+                        'amount' => $adjustmentAmount,
264
                         'description' => $lineItemDescription,
294
                         'description' => $lineItemDescription,
265
                     ]);
295
                     ]);
266
                 }
296
                 }
267
             }
297
             }
268
 
298
 
269
-            if ($this->discount_method->isPerDocument() && $totalLineItemSubtotal > 0) {
270
-                $lineItemSubtotalCents = (int) $lineItem->getRawOriginal('subtotal');
299
+            if ($this->discount_method->isPerDocument() && $totalLineItemSubtotalCents > 0) {
300
+                $lineItemSubtotalCents = $this->convertAmountToDefaultCurrency((int) $lineItem->getRawOriginal('subtotal'));
271
 
301
 
272
                 if ($index === $this->lineItems->count() - 1) {
302
                 if ($index === $this->lineItems->count() - 1) {
273
                     $lineItemDiscount = $remainingDiscountCents;
303
                     $lineItemDiscount = $remainingDiscountCents;
274
                 } else {
304
                 } else {
275
                     $lineItemDiscount = (int) round(
305
                     $lineItemDiscount = (int) round(
276
-                        ($lineItemSubtotalCents / $totalLineItemSubtotal) * $billDiscountTotalCents
306
+                        ($lineItemSubtotalCents / $totalLineItemSubtotalCents) * $billDiscountTotalCents
277
                     );
307
                     );
278
                     $remainingDiscountCents -= $lineItemDiscount;
308
                     $remainingDiscountCents -= $lineItemDiscount;
279
                 }
309
                 }
302
         $this->createInitialTransaction();
332
         $this->createInitialTransaction();
303
     }
333
     }
304
 
334
 
335
+    public function convertAmountToDefaultCurrency(int $amountCents): int
336
+    {
337
+        $defaultCurrency = CurrencyAccessor::getDefaultCurrency();
338
+        $needsConversion = $this->currency_code !== $defaultCurrency;
339
+
340
+        if ($needsConversion) {
341
+            return CurrencyConverter::convertBalance($amountCents, $this->currency_code, $defaultCurrency);
342
+        }
343
+
344
+        return $amountCents;
345
+    }
346
+
347
+    public function formatAmountToDefaultCurrency(int $amountCents): string
348
+    {
349
+        $convertedCents = $this->convertAmountToDefaultCurrency($amountCents);
350
+
351
+        return CurrencyConverter::convertCentsToFormatSimple($convertedCents);
352
+    }
353
+
305
     public static function getReplicateAction(string $action = ReplicateAction::class): MountableAction
354
     public static function getReplicateAction(string $action = ReplicateAction::class): MountableAction
306
     {
355
     {
307
         return $action::make()
356
         return $action::make()

Loading…
Cancel
Save