);
$main::lxdebug->message(LXDebug->DEBUG2(),"count bt=".scalar(@{$bank_transactions}." bank_account=".$bank_account->id." chart=".$bank_account->chart_id));
- my $all_open_ar_invoices = SL::DB::Manager::Invoice ->get_all(where => [amount => { gt => \'paid' }], with_objects => ['customer','payment_terms']);
- my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => [amount => { gt => \'paid' }], with_objects => ['vendor' ,'payment_terms']);
+ # credit notes have a negative amount, treat differently
+ my $all_open_ar_invoices = SL::DB::Manager::Invoice ->get_all(where => [ or => [ amount => { gt => \'paid' },
+ and => [ type => 'credit_note',
+ amount => { lt => \'paid' }
+ ],
+ ],
+ ],
+ with_objects => ['customer','payment_terms']);
+
+ my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => [amount => { ne => \'paid' }], with_objects => ['vendor' ,'payment_terms']);
my $all_open_sepa_export_items = SL::DB::Manager::SepaExportItem->get_all(where => [chart_id => $bank_account->chart_id ,
'sepa_export.executed' => 0, 'sepa_export.closed' => 0 ], with_objects => ['sepa_export']);
$main::lxdebug->message(LXDebug->DEBUG2(),"count sepaexport=".scalar(@{$all_open_sepa_export_items}));
push @all_open_invoices, map { $_->{is_ar}=1 ; $_ } grep { abs($_->amount - $_->paid) >= 0.01 } @{ $all_open_ar_invoices };
push @all_open_invoices, map { $_->{is_ar}=0 ; $_ } grep { abs($_->amount - $_->paid) >= 0.01 } @{ $all_open_ap_invoices };
$main::lxdebug->message(LXDebug->DEBUG2(),"bank_account=".$::form->{filter}{bank_account}." invoices: ".scalar(@{ $all_open_ar_invoices }).
- " + ".scalar(@{ $all_open_ap_invoices })." transactions=".scalar(@{ $bank_transactions }));
+ " + ".scalar(@{ $all_open_ap_invoices })." non fully paid=".scalar(@all_open_invoices)." transactions=".scalar(@{ $bank_transactions }));
my @all_sepa_invoices;
my @all_non_sepa_invoices;
$open_invoice->{skonto_type} = 'without_skonto';
foreach ( @{$all_open_sepa_export_items}) {
if ( $_->ap_id == $open_invoice->id || $_->ar_id == $open_invoice->id ) {
- my $factor = ( $_->ar_id == $open_invoice->id>0?1:-1);
+ my $factor = ($_->ar_id == $open_invoice->id?1:-1);
$main::lxdebug->message(LXDebug->DEBUG2(),"exitem=".$_->id." for invoice ".$open_invoice->id." factor=".$factor);
$open_invoice->{realamount} = $::form->format_amount(\%::myconfig,$open_invoice->amount*$factor,2);
$open_invoice->{sepa_export_item} = $_ ;
#$main::lxdebug->message(LXDebug->DEBUG2(),"exitem2=".$_->id." for invoice ".$open_invoice->id);
my $factor = ( $_->ar_id == $open_invoice->id?1:-1);
$_->amount($_->amount*1);
- #$main::lxdebug->message(LXDebug->DEBUG2(),"remote account '".$bt->{remote_account_number}."' bt_amount=". ($bt->amount * $factor));
+ #$main::lxdebug->message(LXDebug->DEBUG2(),"remote account '".$bt->{remote_account_number}."' bt_amount=".$bt->amount." factor=".$factor);
#$main::lxdebug->message(LXDebug->DEBUG2(),"compare with '".$_->vc_iban."' amount=".$_->amount);
- if ( $bt->{remote_account_number} eq $_->vc_iban && abs(( $_->amount *1 ) - ($bt->amount * $factor)) < 0.01 ) {
- ($open_invoice->{agreement}, $open_invoice->{rule_matches}) = $bt->get_agreement_with_invoice($open_invoice);
- $open_invoice->{agreement} += 5;
- $open_invoice->{rule_matches} .= 'sepa_export_item(5) ';
- $main::lxdebug->message(LXDebug->DEBUG2(),"sepa invoice_id=".$open_invoice->id." agreement=".$open_invoice->{agreement}." rules matches=".$open_invoice->{rule_matches});
- $open_invoice->{realamount} = $::form->format_amount(\%::myconfig,$open_invoice->amount*$factor,2);
+ if ( $bt->{remote_account_number} eq $_->vc_iban && abs(abs($_->amount) - abs($bt->amount)) < 0.01 ) {
+ my $iban;
+ $iban = $open_invoice->customer->iban if $open_invoice->is_sales;
+ $iban = $open_invoice->vendor->iban if ! $open_invoice->is_sales;
+ if($bt->{remote_account_number} eq $iban && abs(abs($open_invoice->amount) - abs($bt->amount)) < 0.01 ) {
+ ($open_invoice->{agreement}, $open_invoice->{rule_matches}) = $bt->get_agreement_with_invoice($open_invoice);
+ $open_invoice->{agreement} += 5;
+ $open_invoice->{rule_matches} .= 'sepa_export_item(5) ';
+ $main::lxdebug->message(LXDebug->DEBUG2(),"sepa invoice_id=".$open_invoice->id." agreement=".$open_invoice->{agreement}." rules matches=".$open_invoice->{rule_matches});
+ $open_invoice->{realamount} = $::form->format_amount(\%::myconfig,$open_invoice->amount*$factor,2);
+ }
}
}
}
foreach my $open_invoice (@all_non_sepa_invoices){
($open_invoice->{agreement}, $open_invoice->{rule_matches}) = $bt->get_agreement_with_invoice($open_invoice);
$open_invoice->{realamount} = $::form->format_amount(\%::myconfig,$open_invoice->amount*($open_invoice->{is_ar}?1:-1),2);
- $main::lxdebug->message(LXDebug->DEBUG2(),"nons invoice_id=".$open_invoice->id." agreement=".$open_invoice->{agreement}." rules matches=".$open_invoice->{rule_matches});
+ $main::lxdebug->message(LXDebug->DEBUG2(),"nons invoice_id=".$open_invoice->id." amount=".$open_invoice->amount." agreement=".$open_invoice->{agreement}." rules matches=".$open_invoice->{rule_matches}) if $open_invoice->{agreement} > 2;
};
my $agreement = 15;
$bank_transactions = [ sort { $a->{agreement} <=> $b->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 1;
$bank_transactions = [ sort { $b->{agreement} <=> $a->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 0;
-
+ $::request->layout->add_javascripts("kivi.BankTransaction.js");
$self->render('bank_transactions/list',
title => t8('Bank transactions MT940'),
BANK_TRANSACTIONS => $bank_transactions,
vendor_id => $use_vendor_filter ? $vendor_of_transaction->id : undef,
vendor_name => $use_vendor_filter ? $vendor_of_transaction->name : undef,
ALL_VENDORS => $all_vendors,
- limit => $myconfig{vclimit},
callback => $callback,
);
}
value_key => 'payment_type',
title_key => 'display' )
if @select_options;
- $html .= '<a href=# onclick="delete_invoice(' . $::form->{bt_id} . ',' . $::form->{prop_id} . ');">x</a>';
- $html = SL::Presenter->html_tag('div', $html, id => $::form->{bt_id} . '.' . $::form->{prop_id});
+ $html .= SL::Presenter->html_tag('a', 'x', href => '#', onclick => "kivi.BankTransaction.delete_invoice(" . $::form->{bt_id} . ',' . $::form->{prop_id} . ")");
+ $html = SL::Presenter->html_tag('div', $html, id => $::form->{bt_id} . '.' . $::form->{prop_id}, 'data-invoice-amount' => $invoice->open_amount * 1);
$self->render(\ SL::JSON::to_json( { 'html' => $html } ), { layout => 0, type => 'json', process => 0 });
};
push @{ $self->problems }, $self->save_single_bank_transaction(
bank_transaction_id => $bank_transaction_id,
invoice_ids => $invoice_ids,
+ sources => ($::form->{sources} // {})->{$_},
+ memos => ($::form->{memos} // {})->{$_},
);
$count += scalar( @{$invoice_ids} );
}
sub action_save_proposals {
my ($self) = @_;
+
if ( $::form->{proposal_ids} ) {
my $propcount = scalar(@{ $::form->{proposal_ids} });
if ( $propcount > 0 ) {
my $payment_received = $bank_transaction->amount > 0;
my $payment_sent = $bank_transaction->amount < 0;
+
foreach my $invoice_id (@{ $params{invoice_ids} }) {
my $invoice = SL::DB::Manager::Invoice->find_by(id => $invoice_id) || SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id);
if (!$invoice) {
message => $::locale->text("The ID #1 is not a valid database ID.", $invoice_id),
};
}
-
push @{ $data{invoices} }, $invoice;
}
my $n_invoices = 0;
foreach my $invoice (@{ $data{invoices} }) {
+ my $source = ($data{sources} // [])->[$n_invoices];
+ my $memo = ($data{memos} // [])->[$n_invoices];
$n_invoices++ ;
$payment_type = 'without_skonto';
};
+
# pay invoice or go to the next bank transaction if the amount is not sufficiently high
if ($invoice->open_amount <= $amount_of_transaction && $n_invoices < $max_invoices) {
my $open_amount = ($payment_type eq 'with_skonto_pt'?$invoice->amount_less_skonto:$invoice->open_amount);
trans_id => $invoice->id,
amount => $open_amount,
payment_type => $payment_type,
+ source => $source,
+ memo => $memo,
+ transdate => $bank_transaction->transdate->to_kivitendo);
+ } elsif ( $invoice->is_sales && $invoice->type eq 'credit_note' ) {
+ # no check for overpayment/multiple payments
+ $invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id,
+ trans_id => $invoice->id,
+ amount => $invoice->open_amount,
+ payment_type => $payment_type,
+ source => $source,
+ memo => $memo,
transdate => $bank_transaction->transdate->to_kivitendo);
} else { # use the whole amount of the bank transaction for the invoice, overpay the invoice if necessary
my $overpaid_amount = $amount_of_transaction - $invoice->open_amount;
trans_id => $invoice->id,
amount => $amount_of_transaction,
payment_type => $payment_type,
+ source => $source,
+ memo => $memo,
transdate => $bank_transaction->transdate->to_kivitendo);
$bank_transaction->invoice_amount($bank_transaction->amount);
$amount_of_transaction = 0;