Revision 665741c4
Von Jan Büren vor fast 6 Jahren hinzugefügt
SL/Controller/BankTransaction.pm | ||
---|---|---|
558 | 558 |
|
559 | 559 |
my $bank_transaction = $data{bank_transaction}; |
560 | 560 |
|
561 |
# see pod |
|
562 |
if (@{ $bank_transaction->linked_invoices } || $bank_transaction->invoice_amount != 0) { |
|
563 |
return { |
|
564 |
%data, |
|
565 |
result => 'error', |
|
566 |
message => $::locale->text("Bank transaction with id #1 has already been linked to one or more record and/or some amount is already assigned.", $bank_transaction->id), |
|
567 |
}; |
|
568 |
} |
|
569 | 561 |
my (@warnings); |
570 | 562 |
|
571 | 563 |
my $worker = sub { |
572 | 564 |
my $bt_id = $data{bank_transaction_id}; |
573 | 565 |
my $sign = $bank_transaction->amount < 0 ? -1 : 1; |
574 | 566 |
my $amount_of_transaction = $sign * $bank_transaction->amount; |
567 |
my $assigned_amount = $sign * $bank_transaction->invoice_amount; |
|
568 |
my $not_assigned_amount = $amount_of_transaction - $assigned_amount; |
|
575 | 569 |
my $payment_received = $bank_transaction->amount > 0; |
576 | 570 |
my $payment_sent = $bank_transaction->amount < 0; |
577 | 571 |
|
572 |
croak("No amount left to assign") if ($not_assigned_amount <= 0); |
|
578 | 573 |
|
579 | 574 |
foreach my $invoice_id (@{ $params{invoice_ids} }) { |
580 | 575 |
my $invoice = SL::DB::Manager::Invoice->find_by(id => $invoice_id) || SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id); |
... | ... | |
634 | 629 |
} else { |
635 | 630 |
$payment_type = 'without_skonto'; |
636 | 631 |
}; |
637 |
|
|
638 |
|
|
639 |
# pay invoice or go to the next bank transaction if the amount is not sufficiently high |
|
640 |
if ($invoice->open_amount <= $amount_of_transaction && $n_invoices < $max_invoices) { |
|
641 |
my $open_amount = ($payment_type eq 'with_skonto_pt'?$invoice->amount_less_skonto:$invoice->open_amount); |
|
642 |
# first calculate new bank transaction amount ... |
|
643 |
if ($invoice->is_sales) { |
|
644 |
$amount_of_transaction -= $sign * $open_amount; |
|
645 |
$bank_transaction->invoice_amount($bank_transaction->invoice_amount + $open_amount); |
|
646 |
} else { |
|
647 |
$amount_of_transaction += $sign * $open_amount; |
|
648 |
$bank_transaction->invoice_amount($bank_transaction->invoice_amount - $open_amount); |
|
649 |
} |
|
650 |
# ... and then pay the invoice |
|
651 |
my @acc_ids = $invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id, |
|
652 |
trans_id => $invoice->id, |
|
653 |
amount => $open_amount, |
|
654 |
payment_type => $payment_type, |
|
655 |
source => $source, |
|
656 |
memo => $memo, |
|
657 |
transdate => $bank_transaction->transdate->to_kivitendo); |
|
658 |
# ... and record the origin via BankTransactionAccTrans |
|
659 |
if (scalar(@acc_ids) != 2) { |
|
660 |
return { |
|
661 |
%data, |
|
662 |
result => 'error', |
|
663 |
message => $::locale->text("Unable to book transactions for bank purpose #1", $bank_transaction->purpose), |
|
664 |
}; |
|
665 |
} |
|
666 |
foreach my $acc_trans_id (@acc_ids) { |
|
667 |
my $id_type = $invoice->is_sales ? 'ar' : 'ap'; |
|
668 |
my %props_acc = ( |
|
669 |
acc_trans_id => $acc_trans_id, |
|
670 |
bank_transaction_id => $bank_transaction->id, |
|
671 |
$id_type => $invoice->id, |
|
672 |
); |
|
673 |
SL::DB::BankTransactionAccTrans->new(%props_acc)->save; |
|
674 |
} |
|
675 |
|
|
676 |
|
|
677 |
} else { |
|
678 |
# use the whole amount of the bank transaction for the invoice, overpay the invoice if necessary |
|
679 |
|
|
680 |
# $invoice->open_amount is negative for credit_notes |
|
681 |
# $bank_transaction->amount is negative for outgoing transactions |
|
682 |
# so $amount_of_transaction is negative but needs positive |
|
683 |
# $invoice->open_amount may be negative for ap_transaction but may be positiv for negative ap_transaction |
|
684 |
# if $invoice->open_amount is negative $bank_transaction->amount is positve |
|
685 |
# if $invoice->open_amount is positive $bank_transaction->amount is negative |
|
686 |
# but amount of transaction is for both positive |
|
687 |
|
|
688 |
$amount_of_transaction *= -1 if ($invoice->amount < 0); |
|
689 |
|
|
690 |
# if we have a skonto case - the last invoice needs skonto |
|
691 |
$amount_of_transaction = $invoice->amount_less_skonto if ($payment_type eq 'with_skonto_pt'); |
|
692 |
|
|
693 |
|
|
694 |
my $overpaid_amount = $amount_of_transaction - $invoice->open_amount; |
|
695 |
$invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id, |
|
696 |
trans_id => $invoice->id, |
|
697 |
amount => $amount_of_transaction, |
|
698 |
payment_type => $payment_type, |
|
699 |
source => $source, |
|
700 |
memo => $memo, |
|
701 |
transdate => $bank_transaction->transdate->to_kivitendo); |
|
702 |
$bank_transaction->invoice_amount($bank_transaction->amount); |
|
703 |
$amount_of_transaction = 0; |
|
704 |
|
|
705 |
if ($overpaid_amount >= 0.01) { |
|
706 |
push @warnings, { |
|
707 |
%data, |
|
708 |
result => 'warning', |
|
709 |
message => $::locale->text('Invoice #1 was overpaid by #2.', $invoice->invnumber, $::form->format_amount(\%::myconfig, $overpaid_amount, 2)), |
|
710 |
}; |
|
711 |
} |
|
712 |
} |
|
632 |
# pay invoice |
|
633 |
# TODO rewrite this: really booked amount should be a return value of Payment.pm |
|
634 |
# also this controller shouldnt care about how to calc skonto. we simply delegate the |
|
635 |
# payment_type to the helper and get the corresponding bank_transaction values back |
|
636 |
|
|
637 |
my $open_amount = ($payment_type eq 'with_skonto_pt' ? $invoice->amount_less_skonto : $invoice->open_amount); |
|
638 |
my $amount_for_booking = abs(($open_amount < $not_assigned_amount) ? $open_amount : $not_assigned_amount); |
|
639 |
$amount_for_booking *= $sign; |
|
640 |
$bank_transaction->invoice_amount($bank_transaction->invoice_amount + $amount_for_booking); |
|
641 |
|
|
642 |
# ... and then pay the invoice |
|
643 |
my @acc_ids = $invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id, |
|
644 |
trans_id => $invoice->id, |
|
645 |
amount => ($open_amount < $not_assigned_amount) ? $open_amount : $not_assigned_amount, |
|
646 |
payment_type => $payment_type, |
|
647 |
source => $source, |
|
648 |
memo => $memo, |
|
649 |
transdate => $bank_transaction->transdate->to_kivitendo); |
|
650 |
# ... and record the origin via BankTransactionAccTrans |
|
651 |
if (scalar(@acc_ids) != 2) { |
|
652 |
return { |
|
653 |
%data, |
|
654 |
result => 'error', |
|
655 |
message => $::locale->text("Unable to book transactions for bank purpose #1", $bank_transaction->purpose), |
|
656 |
}; |
|
657 |
} |
|
658 |
foreach my $acc_trans_id (@acc_ids) { |
|
659 |
my $id_type = $invoice->is_sales ? 'ar' : 'ap'; |
|
660 |
my %props_acc = ( |
|
661 |
acc_trans_id => $acc_trans_id, |
|
662 |
bank_transaction_id => $bank_transaction->id, |
|
663 |
$id_type => $invoice->id, |
|
664 |
); |
|
665 |
SL::DB::BankTransactionAccTrans->new(%props_acc)->save; |
|
666 |
} |
|
713 | 667 |
# Record a record link from the bank transaction to the invoice |
714 | 668 |
my %props = ( |
715 | 669 |
from_table => 'bank_transactions', |
... | ... | |
965 | 919 |
C<invoice_ids>, an array ref of database IDs to purchase or sales |
966 | 920 |
invoice objects). |
967 | 921 |
|
922 |
This method handles already partly assigned bank transactions. |
|
923 |
|
|
968 | 924 |
This method cannot handle already partly assigned bank transactions, i.e. |
969 | 925 |
a bank transaction that has a invoice_amount <> 0 but not the fully |
970 | 926 |
transaction amount (invoice_amount == amount). |
971 | 927 |
|
972 | 928 |
If the amount of the bank transaction is higher than the sum of |
973 |
the assigned invoices (1 .. n) the last invoice will be overpayed. |
|
929 |
the assigned invoices (1 .. n) the bank transaction will only be |
|
930 |
partly assigned. |
|
974 | 931 |
|
975 | 932 |
The whole function is wrapped in a database transaction. If an |
976 | 933 |
exception occurs the bank transaction is not posted at all. The same |
Auch abrufbar als: Unified diff
BankTransaction: save_single_bank_transaction API-Änderung
S.a. POD und devel-Liste
Testfälle angepasst