|
@@ -8,7 +8,6 @@ use App\Enums\Accounting\AdjustmentType;
|
8
|
8
|
use App\Enums\Accounting\DocumentDiscountMethod;
|
9
|
9
|
use App\Enums\Accounting\DocumentType;
|
10
|
10
|
use App\Enums\Accounting\InvoiceStatus;
|
11
|
|
-use App\Enums\Accounting\PaymentMethod;
|
12
|
11
|
use App\Enums\Setting\PaymentTerms;
|
13
|
12
|
use App\Filament\Company\Resources\Sales\ClientResource\RelationManagers\InvoicesRelationManager;
|
14
|
13
|
use App\Filament\Company\Resources\Sales\InvoiceResource\Pages;
|
|
@@ -27,14 +26,12 @@ use App\Filament\Tables\Filters\DateRangeFilter;
|
27
|
26
|
use App\Models\Accounting\Adjustment;
|
28
|
27
|
use App\Models\Accounting\DocumentLineItem;
|
29
|
28
|
use App\Models\Accounting\Invoice;
|
30
|
|
-use App\Models\Banking\BankAccount;
|
31
|
29
|
use App\Models\Common\Client;
|
32
|
30
|
use App\Models\Common\Offering;
|
33
|
31
|
use App\Utilities\Currency\CurrencyAccessor;
|
34
|
32
|
use App\Utilities\Currency\CurrencyConverter;
|
35
|
33
|
use App\Utilities\RateCalculator;
|
36
|
34
|
use Awcodes\TableRepeater\Header;
|
37
|
|
-use Closure;
|
38
|
35
|
use Filament\Forms;
|
39
|
36
|
use Filament\Forms\Form;
|
40
|
37
|
use Filament\Notifications\Notification;
|
|
@@ -489,161 +486,20 @@ class InvoiceResource extends Resource
|
489
|
486
|
Invoice::getReplicateAction(Tables\Actions\ReplicateAction::class),
|
490
|
487
|
Invoice::getApproveDraftAction(Tables\Actions\Action::class),
|
491
|
488
|
Invoice::getMarkAsSentAction(Tables\Actions\Action::class),
|
492
|
|
- Tables\Actions\Action::make('recordPaymentBulk')
|
|
489
|
+ Tables\Actions\Action::make('recordPayment')
|
493
|
490
|
->label('Record Payment')
|
494
|
491
|
->icon('heroicon-m-credit-card')
|
|
492
|
+ ->visible(function (Invoice $record) {
|
|
493
|
+ return $record->canRecordPayment();
|
|
494
|
+ })
|
495
|
495
|
->url(fn (Invoice $record) => Pages\RecordPayments::getUrl([
|
496
|
|
- 'tableFilters' => ['client_id' => ['value' => $record->client_id]],
|
|
496
|
+ 'tableFilters' => [
|
|
497
|
+ 'client_id' => ['value' => $record->client_id],
|
|
498
|
+ 'currency_code' => ['value' => $record->currency_code],
|
|
499
|
+ ],
|
497
|
500
|
'invoice_id' => $record->id,
|
498
|
501
|
]))
|
499
|
502
|
->openUrlInNewTab(false),
|
500
|
|
- Tables\Actions\Action::make('recordPayment')
|
501
|
|
- ->label(fn (Invoice $record) => $record->status === InvoiceStatus::Overpaid ? 'Refund Overpayment' : 'Record Payment')
|
502
|
|
- ->slideOver()
|
503
|
|
- ->modalWidth(MaxWidth::TwoExtraLarge)
|
504
|
|
- ->icon('heroicon-m-credit-card')
|
505
|
|
- ->visible(function (Invoice $record) {
|
506
|
|
- return $record->canRecordPayment();
|
507
|
|
- })
|
508
|
|
- ->mountUsing(function (Invoice $record, Form $form) {
|
509
|
|
- $form->fill([
|
510
|
|
- 'posted_at' => now(),
|
511
|
|
- 'amount' => abs($record->amount_due),
|
512
|
|
- ]);
|
513
|
|
- })
|
514
|
|
- ->databaseTransaction()
|
515
|
|
- ->successNotificationTitle('Payment recorded')
|
516
|
|
- ->form([
|
517
|
|
- Forms\Components\DatePicker::make('posted_at')
|
518
|
|
- ->label('Date'),
|
519
|
|
- Forms\Components\Grid::make()
|
520
|
|
- ->schema([
|
521
|
|
- Forms\Components\Select::make('bank_account_id')
|
522
|
|
- ->label('Account')
|
523
|
|
- ->required()
|
524
|
|
- ->live()
|
525
|
|
- ->options(function () {
|
526
|
|
- return BankAccount::query()
|
527
|
|
- ->join('accounts', 'bank_accounts.account_id', '=', 'accounts.id')
|
528
|
|
- ->select(['bank_accounts.id', 'accounts.name', 'accounts.currency_code'])
|
529
|
|
- ->get()
|
530
|
|
- ->mapWithKeys(function ($account) {
|
531
|
|
- $label = $account->name;
|
532
|
|
- if ($account->currency_code) {
|
533
|
|
- $label .= " ({$account->currency_code})";
|
534
|
|
- }
|
535
|
|
-
|
536
|
|
- return [$account->id => $label];
|
537
|
|
- })
|
538
|
|
- ->toArray();
|
539
|
|
- })
|
540
|
|
- ->searchable(),
|
541
|
|
- Forms\Components\TextInput::make('amount')
|
542
|
|
- ->label('Amount')
|
543
|
|
- ->required()
|
544
|
|
- ->money(fn (Invoice $record) => $record->currency_code)
|
545
|
|
- ->live(onBlur: true)
|
546
|
|
- ->helperText(function (Invoice $record, $state) {
|
547
|
|
- $invoiceCurrency = $record->currency_code;
|
548
|
|
-
|
549
|
|
- if (! CurrencyConverter::isValidAmount($state, 'USD')) {
|
550
|
|
- return null;
|
551
|
|
- }
|
552
|
|
-
|
553
|
|
- $amountDue = $record->amount_due;
|
554
|
|
-
|
555
|
|
- $amount = CurrencyConverter::convertToCents($state, 'USD');
|
556
|
|
-
|
557
|
|
- if ($amount <= 0) {
|
558
|
|
- return 'Please enter a valid positive amount';
|
559
|
|
- }
|
560
|
|
-
|
561
|
|
- if ($record->status === InvoiceStatus::Overpaid) {
|
562
|
|
- $newAmountDue = $amountDue + $amount;
|
563
|
|
- } else {
|
564
|
|
- $newAmountDue = $amountDue - $amount;
|
565
|
|
- }
|
566
|
|
-
|
567
|
|
- return match (true) {
|
568
|
|
- $newAmountDue > 0 => 'Amount due after payment will be ' . CurrencyConverter::formatCentsToMoney($newAmountDue, $invoiceCurrency),
|
569
|
|
- $newAmountDue === 0 => 'Invoice will be fully paid',
|
570
|
|
- default => 'Invoice will be overpaid by ' . CurrencyConverter::formatCentsToMoney(abs($newAmountDue), $invoiceCurrency),
|
571
|
|
- };
|
572
|
|
- })
|
573
|
|
- ->rules([
|
574
|
|
- static fn (): Closure => static function (string $attribute, $value, Closure $fail) {
|
575
|
|
- if (! CurrencyConverter::isValidAmount($value, 'USD')) {
|
576
|
|
- $fail('Please enter a valid amount');
|
577
|
|
- }
|
578
|
|
- },
|
579
|
|
- ]),
|
580
|
|
- ])->columns(2),
|
581
|
|
- Forms\Components\Placeholder::make('currency_conversion')
|
582
|
|
- ->label('Currency Conversion')
|
583
|
|
- ->content(function (Forms\Get $get, Invoice $record) {
|
584
|
|
- $amount = $get('amount');
|
585
|
|
- $bankAccountId = $get('bank_account_id');
|
586
|
|
-
|
587
|
|
- $invoiceCurrency = $record->currency_code;
|
588
|
|
-
|
589
|
|
- if (empty($amount) || empty($bankAccountId) || ! CurrencyConverter::isValidAmount($amount, 'USD')) {
|
590
|
|
- return null;
|
591
|
|
- }
|
592
|
|
-
|
593
|
|
- $bankAccount = BankAccount::with('account')->find($bankAccountId);
|
594
|
|
- if (! $bankAccount) {
|
595
|
|
- return null;
|
596
|
|
- }
|
597
|
|
-
|
598
|
|
- $bankCurrency = $bankAccount->account->currency_code ?? CurrencyAccessor::getDefaultCurrency();
|
599
|
|
-
|
600
|
|
- // If currencies are the same, no conversion needed
|
601
|
|
- if ($invoiceCurrency === $bankCurrency) {
|
602
|
|
- return null;
|
603
|
|
- }
|
604
|
|
-
|
605
|
|
- // Convert amount from invoice currency to bank currency
|
606
|
|
- $amountInInvoiceCurrencyCents = CurrencyConverter::convertToCents($amount, 'USD');
|
607
|
|
- $amountInBankCurrencyCents = CurrencyConverter::convertBalance(
|
608
|
|
- $amountInInvoiceCurrencyCents,
|
609
|
|
- $invoiceCurrency,
|
610
|
|
- $bankCurrency
|
611
|
|
- );
|
612
|
|
-
|
613
|
|
- $formattedBankAmount = CurrencyConverter::formatCentsToMoney($amountInBankCurrencyCents, $bankCurrency);
|
614
|
|
-
|
615
|
|
- return "Payment will be recorded as {$formattedBankAmount} in the bank account's currency ({$bankCurrency}).";
|
616
|
|
- })
|
617
|
|
- ->hidden(function (Forms\Get $get, Invoice $record) {
|
618
|
|
- $bankAccountId = $get('bank_account_id');
|
619
|
|
- if (empty($bankAccountId)) {
|
620
|
|
- return true;
|
621
|
|
- }
|
622
|
|
-
|
623
|
|
- $invoiceCurrency = $record->currency_code;
|
624
|
|
-
|
625
|
|
- $bankAccount = BankAccount::with('account')->find($bankAccountId);
|
626
|
|
- if (! $bankAccount) {
|
627
|
|
- return true;
|
628
|
|
- }
|
629
|
|
-
|
630
|
|
- $bankCurrency = $bankAccount->account->currency_code ?? CurrencyAccessor::getDefaultCurrency();
|
631
|
|
-
|
632
|
|
- // Hide if currencies are the same
|
633
|
|
- return $invoiceCurrency === $bankCurrency;
|
634
|
|
- }),
|
635
|
|
- Forms\Components\Select::make('payment_method')
|
636
|
|
- ->label('Payment method')
|
637
|
|
- ->required()
|
638
|
|
- ->options(PaymentMethod::class),
|
639
|
|
- Forms\Components\Textarea::make('notes')
|
640
|
|
- ->label('Notes'),
|
641
|
|
- ])
|
642
|
|
- ->action(function (Invoice $record, Tables\Actions\Action $action, array $data) {
|
643
|
|
- $record->recordPayment($data);
|
644
|
|
-
|
645
|
|
- $action->success();
|
646
|
|
- }),
|
647
|
503
|
])->dropdown(false),
|
648
|
504
|
Tables\Actions\DeleteAction::make(),
|
649
|
505
|
]),
|