Procházet zdrojové kódy

wip multi-currency

3.x
Andrew Wallo před 10 měsíci
rodič
revize
692993ae6e

+ 8
- 7
app/Filament/Company/Resources/Sales/InvoiceResource.php Zobrazit soubor

@@ -385,16 +385,17 @@ class InvoiceResource extends Resource
385 385
                             Forms\Components\TextInput::make('amount')
386 386
                                 ->label('Amount')
387 387
                                 ->required()
388
-                                ->money()
388
+                                ->money(fn (Invoice $record) => $record->currency_code)
389 389
                                 ->live(onBlur: true)
390 390
                                 ->helperText(function (Invoice $record, $state) {
391
-                                    if (! CurrencyConverter::isValidAmount($state)) {
391
+                                    $invoiceCurrency = $record->currency_code;
392
+                                    if (! CurrencyConverter::isValidAmount($state, $invoiceCurrency)) {
392 393
                                         return null;
393 394
                                     }
394 395
 
395 396
                                     $amountDue = $record->getRawOriginal('amount_due');
396 397
 
397
-                                    $amount = CurrencyConverter::convertToCents($state);
398
+                                    $amount = CurrencyConverter::convertToCents($state, $invoiceCurrency);
398 399
 
399 400
                                     if ($amount <= 0) {
400 401
                                         return 'Please enter a valid positive amount';
@@ -407,14 +408,14 @@ class InvoiceResource extends Resource
407 408
                                     }
408 409
 
409 410
                                     return match (true) {
410
-                                        $newAmountDue > 0 => 'Amount due after payment will be ' . CurrencyConverter::formatCentsToMoney($newAmountDue),
411
+                                        $newAmountDue > 0 => 'Amount due after payment will be ' . CurrencyConverter::formatCentsToMoney($newAmountDue, $invoiceCurrency),
411 412
                                         $newAmountDue === 0 => 'Invoice will be fully paid',
412
-                                        default => 'Invoice will be overpaid by ' . CurrencyConverter::formatCentsToMoney(abs($newAmountDue)),
413
+                                        default => 'Invoice will be overpaid by ' . CurrencyConverter::formatCentsToMoney(abs($newAmountDue), $invoiceCurrency),
413 414
                                     };
414 415
                                 })
415 416
                                 ->rules([
416
-                                    static fn (): Closure => static function (string $attribute, $value, Closure $fail) {
417
-                                        if (! CurrencyConverter::isValidAmount($value)) {
417
+                                    static fn (Invoice $record): Closure => static function (string $attribute, $value, Closure $fail) use ($record) {
418
+                                        if (! CurrencyConverter::isValidAmount($value, $record->currency_code)) {
418 419
                                             $fail('Please enter a valid amount');
419 420
                                         }
420 421
                                     },

+ 23
- 1
app/Models/Accounting/Invoice.php Zobrazit soubor

@@ -13,6 +13,7 @@ use App\Enums\Accounting\InvoiceStatus;
13 13
 use App\Enums\Accounting\JournalEntryType;
14 14
 use App\Enums\Accounting\TransactionType;
15 15
 use App\Filament\Company\Resources\Sales\InvoiceResource;
16
+use App\Models\Banking\BankAccount;
16 17
 use App\Models\Common\Client;
17 18
 use App\Models\Setting\Currency;
18 19
 use App\Observers\InvoiceObserver;
@@ -226,13 +227,34 @@ class Invoice extends Model
226 227
             $transactionDescription = "Invoice #{$this->invoice_number}: Payment from {$this->client->name}";
227 228
         }
228 229
 
230
+        $bankAccount = BankAccount::findOrFail($data['bank_account_id']);
231
+        $bankAccountCurrency = $bankAccount->account->currency_code ?? CurrencyAccessor::getDefaultCurrency();
232
+
233
+        $invoiceCurrency = $this->currency_code;
234
+        $requiresConversion = $invoiceCurrency !== $bankAccountCurrency;
235
+
236
+        if ($requiresConversion) {
237
+            $amountInInvoiceCurrencyCents = CurrencyConverter::convertToCents($data['amount'], $invoiceCurrency);
238
+            $amountInBankCurrencyCents = CurrencyConverter::convertBalance(
239
+                $amountInInvoiceCurrencyCents,
240
+                $invoiceCurrency,
241
+                $bankAccountCurrency
242
+            );
243
+            $formattedAmountForBankCurrency = CurrencyConverter::convertCentsToFormatSimple(
244
+                $amountInBankCurrencyCents,
245
+                $bankAccountCurrency
246
+            );
247
+        } else {
248
+            $formattedAmountForBankCurrency = $data['amount']; // Already in simple format
249
+        }
250
+
229 251
         // Create transaction
230 252
         $this->transactions()->create([
231 253
             'company_id' => $this->company_id,
232 254
             'type' => $transactionType,
233 255
             'is_payment' => true,
234 256
             'posted_at' => $data['posted_at'],
235
-            'amount' => $data['amount'],
257
+            'amount' => $formattedAmountForBankCurrency,
236 258
             'payment_method' => $data['payment_method'],
237 259
             'bank_account_id' => $data['bank_account_id'],
238 260
             'account_id' => Account::getAccountsReceivableAccount()->id,

+ 38
- 15
app/Observers/TransactionObserver.php Zobrazit soubor

@@ -107,21 +107,35 @@ class TransactionObserver
107 107
             return;
108 108
         }
109 109
 
110
-        $depositTotal = (int) $invoice->deposits()
110
+        $invoiceCurrency = $invoice->currency_code;
111
+
112
+        $depositTotalInInvoiceCurrencyCents = (int) $invoice->deposits()
111 113
             ->when($excludedTransaction, fn (Builder $query) => $query->whereKeyNot($excludedTransaction->getKey()))
112
-            ->sum('amount');
114
+            ->get()
115
+            ->sum(function (Transaction $transaction) use ($invoiceCurrency) {
116
+                $bankAccountCurrency = $transaction->bankAccount->account->currency_code;
117
+                $amountCents = (int) $transaction->getRawOriginal('amount');
118
+
119
+                return CurrencyConverter::convertBalance($amountCents, $bankAccountCurrency, $invoiceCurrency);
120
+            });
113 121
 
114
-        $withdrawalTotal = (int) $invoice->withdrawals()
122
+        $withdrawalTotalInInvoiceCurrencyCents = (int) $invoice->withdrawals()
115 123
             ->when($excludedTransaction, fn (Builder $query) => $query->whereKeyNot($excludedTransaction->getKey()))
116
-            ->sum('amount');
124
+            ->get()
125
+            ->sum(function (Transaction $transaction) use ($invoiceCurrency) {
126
+                $bankAccountCurrency = $transaction->bankAccount->account->currency_code;
127
+                $amountCents = (int) $transaction->getRawOriginal('amount');
128
+
129
+                return CurrencyConverter::convertBalance($amountCents, $bankAccountCurrency, $invoiceCurrency);
130
+            });
117 131
 
118
-        $totalPaid = $depositTotal - $withdrawalTotal;
132
+        $totalPaidInInvoiceCurrencyCents = $depositTotalInInvoiceCurrencyCents - $withdrawalTotalInInvoiceCurrencyCents;
119 133
 
120
-        $invoiceTotal = (int) $invoice->getRawOriginal('total');
134
+        $invoiceTotalInInvoiceCurrencyCents = (int) $invoice->getRawOriginal('total');
121 135
 
122 136
         $newStatus = match (true) {
123
-            $totalPaid > $invoiceTotal => InvoiceStatus::Overpaid,
124
-            $totalPaid === $invoiceTotal => InvoiceStatus::Paid,
137
+            $totalPaidInInvoiceCurrencyCents > $invoiceTotalInInvoiceCurrencyCents => InvoiceStatus::Overpaid,
138
+            $totalPaidInInvoiceCurrencyCents === $invoiceTotalInInvoiceCurrencyCents => InvoiceStatus::Paid,
125 139
             default => InvoiceStatus::Partial,
126 140
         };
127 141
 
@@ -134,7 +148,7 @@ class TransactionObserver
134 148
         }
135 149
 
136 150
         $invoice->update([
137
-            'amount_paid' => CurrencyConverter::convertCentsToFloat($totalPaid),
151
+            'amount_paid' => CurrencyConverter::convertCentsToFormatSimple($totalPaidInInvoiceCurrencyCents, $invoiceCurrency),
138 152
             'status' => $newStatus,
139 153
             'paid_at' => $paidAt,
140 154
         ]);
@@ -146,15 +160,24 @@ class TransactionObserver
146 160
             return;
147 161
         }
148 162
 
149
-        $withdrawalTotal = (int) $bill->withdrawals()
163
+        $billCurrency = $bill->currency_code;
164
+
165
+        $withdrawalTotalInBillCurrencyCents = (int) $bill->withdrawals()
150 166
             ->when($excludedTransaction, fn (Builder $query) => $query->whereKeyNot($excludedTransaction->getKey()))
151
-            ->sum('amount');
167
+            ->get()
168
+            ->sum(function (Transaction $transaction) use ($billCurrency) {
169
+                $bankAccountCurrency = $transaction->bankAccount->account->currency_code;
170
+                $amountCents = (int) $transaction->getRawOriginal('amount');
171
+
172
+                return CurrencyConverter::convertBalance($amountCents, $bankAccountCurrency, $billCurrency);
173
+            });
174
+
175
+        $totalPaidInBillCurrencyCents = $withdrawalTotalInBillCurrencyCents;
152 176
 
153
-        $totalPaid = $withdrawalTotal;
154
-        $billTotal = (int) $bill->getRawOriginal('total');
177
+        $billTotalInBillCurrencyCents = (int) $bill->getRawOriginal('total');
155 178
 
156 179
         $newStatus = match (true) {
157
-            $totalPaid >= $billTotal => BillStatus::Paid,
180
+            $totalPaidInBillCurrencyCents >= $billTotalInBillCurrencyCents => BillStatus::Paid,
158 181
             default => BillStatus::Partial,
159 182
         };
160 183
 
@@ -167,7 +190,7 @@ class TransactionObserver
167 190
         }
168 191
 
169 192
         $bill->update([
170
-            'amount_paid' => CurrencyConverter::convertCentsToFloat($totalPaid),
193
+            'amount_paid' => CurrencyConverter::convertCentsToFormatSimple($totalPaidInBillCurrencyCents, $billCurrency),
171 194
             'status' => $newStatus,
172 195
             'paid_at' => $paidAt,
173 196
         ]);

Načítá se…
Zrušit
Uložit