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
|
BankTransaction: save_single_bank_transaction API-Änderung
S.a. POD und devel-Liste
Testfälle angepasst