my $worker = sub {
my $bt_id = $data{bank_transaction_id};
my $sign = $bank_transaction->amount < 0 ? -1 : 1;
- my $not_assigned_amount = $bank_transaction->not_assigned_amount;
my $payment_received = $bank_transaction->amount > 0;
my $payment_sent = $bank_transaction->amount < 0;
my $memo = ($data{memos} // [])->[$n_invoices];
$n_invoices++ ;
+ # safety check invoice open
+ croak("Invoice closed. Cannot proceed.") unless ($invoice->open_amount);
-
- if (!$not_assigned_amount && $invoice->open_amount) {
+ if ( ($payment_sent && $bank_transaction->not_assigned_amount >= 0)
+ || ($payment_received && $bank_transaction->not_assigned_amount <= 0)) {
return {
%data,
result => 'error',
};
}
- my $payment_type;
+ my ($payment_type, $free_skonto_amount);
if ( defined $::form->{invoice_skontos}->{"$bt_id"} ) {
$payment_type = shift(@{ $::form->{invoice_skontos}->{"$bt_id"} });
} else {
$payment_type = 'without_skonto';
- };
+ }
+
+ if ($payment_type eq 'free_skonto') {
+ # parse user input > 0
+ if ($::form->parse_amount(\%::myconfig, $::form->{"free_skonto_amount"}->{"$bt_id"}{$invoice->id}) > 0) {
+ $free_skonto_amount = $::form->parse_amount(\%::myconfig, $::form->{"free_skonto_amount"}->{"$bt_id"}{$invoice->id});
+ } else {
+ return {
+ %data,
+ result => 'error',
+ message => $::locale->text("Free skonto amount has to be a positive number."),
+ };
+ }
+ }
# pay invoice
# TODO rewrite this: really booked amount should be a return value of Payment.pm
# also this controller shouldnt care about how to calc skonto. we simply delegate the
# should be better done elsewhere - changing not_assigned_amount to abs feels seriously bogus
my $open_amount = $payment_type eq 'with_skonto_pt' ? $invoice->amount_less_skonto : $invoice->open_amount;
- $open_amount = abs($open_amount);
- $not_assigned_amount = abs($not_assigned_amount);
- my $amount_for_booking = ($open_amount < $not_assigned_amount) ? $open_amount : $not_assigned_amount;
- my $amount_for_payment = $amount_for_booking;
+ $open_amount = abs($open_amount);
+ $open_amount -= $free_skonto_amount if ($payment_type eq 'free_skonto');
+ my $not_assigned_amount = abs($bank_transaction->not_assigned_amount);
+ my $amount_for_booking = ($open_amount < $not_assigned_amount) ? $open_amount : $not_assigned_amount;
+ my $amount_for_payment = $amount_for_booking;
# get the right direction for the payment bookings (all amounts < 0 are stornos, credit notes or negative ap)
$amount_for_payment *= -1 if $invoice->amount < 0;
+ $free_skonto_amount *= -1 if ($free_skonto_amount && $invoice->amount < 0);
# get the right direction for the bank transaction
$amount_for_booking *= $sign;
# ... and then pay the invoice
my @acc_ids = $invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id,
- trans_id => $invoice->id,
- amount => $amount_for_payment,
- payment_type => $payment_type,
- source => $source,
- memo => $memo,
- transdate => $bank_transaction->valutadate->to_kivitendo);
+ trans_id => $invoice->id,
+ amount => $amount_for_payment,
+ payment_type => $payment_type,
+ source => $source,
+ memo => $memo,
+ skonto_amount => $free_skonto_amount,
+ transdate => $bank_transaction->valutadate->to_kivitendo);
# ... and record the origin via BankTransactionAccTrans
if (scalar(@acc_ids) < 2) {
return {
my $query = qq|UPDATE $type SET paid =
(SELECT COALESCE(abs(sum(amount)),0) FROM acc_trans
WHERE trans_id = ?
- AND chart_link ilike '%paid%')|;
+ AND chart_link ilike '%paid%')
+ WHERE id = ?|;
- die if (do_query($::form, $bank_transaction->db->dbh, $query, $trans_id) == -1);
+ die if (do_query($::form, $bank_transaction->db->dbh, $query, $trans_id, $trans_id) == -1);
}
# 4. and delete all (if any) record links
my $rl = SL::DB::Manager::RecordLink->delete_all(where => [ from_id => $bt_id, from_table => 'bank_transactions' ]);
'form_defaults.callback' => $self->callback,
'form_defaults.bt_id' => $self->transaction->id,
'form_defaults.bt_chart_id' => $self->transaction->local_bank_account->chart->id,
+ 'form_defaults.description' => $self->transaction->purpose,
);
}