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++ ;
-
-
- 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',
# 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;
tax => $tax });
}
- pairwise { $a->{linetotal} = $b->{linetotal} } @{$self->order->items}, @{$pat{items}};
+ pairwise { $a->{linetotal} = $b->{linetotal} } @{$self->order->items_sorted}, @{$pat{items}};
}
# get data for saving, printing, ..., that is not changed in the form
addr_city addr_country addr_gln business_id salesman_id insertdateto insertdatefrom all
), "$form->{db}number",
map({ "cvar_$_->{name}" } @searchable_custom_variables),
+ map({'cvar_'. $_->{name} .'_from'} grep({$_->{type} eq 'date'} @searchable_custom_variables)),
+ map({'cvar_'. $_->{name} .'_to'} grep({$_->{type} eq 'date'} @searchable_custom_variables)),
map({'cvar_'. $_->{name} .'_qtyop'} grep({$_->{type} eq 'number'} @searchable_custom_variables)),
map({ "l_$_" } @columns),
);
@itemstatus_keys,
@callback_keys,
map({ "cvar_$_->{name}" } @searchable_custom_variables),
+ map({'cvar_'. $_->{name} .'_from'} grep({$_->{type} eq 'date'} @searchable_custom_variables)),
+ map({'cvar_'. $_->{name} .'_to'} grep({$_->{type} eq 'date'} @searchable_custom_variables)),
map({'cvar_'. $_->{name} .'_qtyop'} grep({$_->{type} eq 'number'} @searchable_custom_variables)),
map({ "l_$_" } @columns),
);
var amount = $container.data('invoice-amount') * 1;
$('[id^="' + bank_transaction_id + '."]').each(function(idx, elt) {
- amount += $(elt).data('invoice-amount');
+ if ($("input[name='skonto_pt." + elt.id + "']").val() == 1) {
+ // skonto payment term
+ amount += $(elt).data('invoice-amount-less-skonto');
+ } else {
+ // normal amount
+ amount += $(elt).data('invoice-amount');
+ //subtract free skonto if checked (no check for number!)
+ if ($("input[name='skonto_pt." + elt.id + "']").val() == 'free_skonto') {
+ amount -= $("input[name='free_skonto_amount." + elt.id + "']").val();
+ }
+ }
});
$container.html(kivi.format_amount(amount, 2));
});
};
ns.update_skonto = function(caller, bt_id, prop_id, formatted_amount_with_skonto_pt) {
+
if (caller.value === 'free_skonto') {
$('#free_skonto_amount_' + bt_id + '_' + prop_id).val("");
$('#free_skonto_amount_' + bt_id + '_' + prop_id).prop('disabled', false);
+ $("input[name='skonto_pt." + bt_id + '.' + prop_id + "']").val('free_skonto');
$('#free_skonto_amount_' + bt_id + '_' + prop_id).focus();
}
if (caller.value === 'without_skonto') {
$('#free_skonto_amount_' + bt_id + '_' + prop_id).val(kivi.format_amount(0,2));
$('#free_skonto_amount_' + bt_id + '_' + prop_id).prop('disabled', true);
+ $("input[name='skonto_pt." + bt_id + '.' + prop_id + "']").val(0);
}
if (caller.value === 'with_skonto_pt') {
$('#free_skonto_amount_' + bt_id + '_' + prop_id).val(formatted_amount_with_skonto_pt);
$('#free_skonto_amount_' + bt_id + '_' + prop_id).prop('disabled', true);
+ $("input[name='skonto_pt." + bt_id + '.' + prop_id + "']").val(1);
}
+ // recalc assigned amount
+ ns.update_invoice_amount(bt_id);
};
});
'Bank Connections' => 'Bankverbindungen',
'Bank Import' => 'Kontoauszug importieren',
'Bank Transaction' => 'Bankkonto',
+ 'Bank Transaction is in a closed period.' => 'Die Bankbewegung befindet sich innerhalb eines geschlossenen Zeitraums.',
'Bank account' => 'Bankkonto',
'Bank accounts' => 'Bankkonten',
'Bank code' => 'Bankleitzahl',
'Formula' => 'Formel',
'France' => 'Frankreich',
'Free report period' => 'Freier Zeitraum',
+ 'Free skonto amount has to be a positive number.' => 'Der freie Skontobetrag muss positiv (absolut) sein.',
'Free-form text' => 'Textzeile',
'Fristsetzung' => 'Fristsetzung',
'From' => 'Von',
'You have to specify an execution date for each antry.' => 'Sie müssen für jeden zu buchenden Eintrag ein Ausführungsdatum angeben.',
'You must chose a user.' => 'Sie müssen einen Benutzer auswählen.',
'You must enter a name for your new print templates.' => 'Sie müssen einen Namen für die neuen Druckvorlagen angeben.',
+ 'You must not change this AP transaction.' => 'Sie dürfen diese Kreditorenbuchung nicht verändern.',
'You must not change this AR transaction.' => 'Sie dürfen diese Debitorenbuchung nicht verändern.',
'You must not change this invoice.' => 'Sie dürfen diese Rechnung nicht verändern.',
'You must not print this invoice.' => 'Sie dürfen diese Rechnung nicht drucken.',
'for date' => 'zum Stichtag',
'found' => 'Gefunden',
'found_br' => 'Gef.',
+ 'free skonto' => 'Freier Skontobetrag',
'from' => 'von',
'from \'#1\' imported Files' => 'Von \'#1\' importierte Dateien',
'from (time)' => 'von',
--- /dev/null
+-- @tag: bank_transactions_check_constraint_invoice_amount
+-- @description: Bank-Transaktionen dürfen mehrfach verbucht werden - Sicherheitscheck auf DB-Ebene, Überbuchen der Bankbewegung verbieten
+-- @depends: bank_transactions_type2 release_3_5_3
+
+ALTER TABLE bank_transactions ADD CHECK (abs(invoice_amount) <= abs(amount));
-use Test::More tests => 290;
+use Test::More tests => 289;
use strict;
SL::DB::Manager::BankAccount->delete_all(all => 1);
SL::DB::Manager::PaymentTerm->delete_all(all => 1);
SL::DB::Manager::Currency->delete_all(where => [ name => 'CUR' ]);
+ # SL::DB::Manager::Default->delete_all(all => 1);
};
my $bt_controller;
is($bt1->closed_period, 0, "$testname undefined closedto");
my $defaults = SL::DB::Manager::Default->get_all(limit => 1)->[0];
- $defaults->closedto(DateTime->new(year => 2019, month => 12, day => 30));
+ $defaults->closedto(DateTime->new(year => 2019, month => 12, day => 31));
$defaults->save();
$::instance_conf->reload->data;
$bt1->load();
+ is($bt1->closed_period, 1, "$testname defined and next date closedto");
- is($bt1->closed_period, 1, "$testname defined and same date closedto");
-
- $bt1->valutadate(DateTime->new(year => 2019, month => 12, day => 31));
+ $bt1->valutadate(DateTime->new(year => 2020, month => 1, day => 1));
$bt1->save();
$bt1->load();
is($bt1->closed_period, 0, "$testname defined closedto and next date valuta");
+ $defaults->closedto(undef);
+ $defaults->save();
}
# test 1
-sub test_default_invoice_one_item_19_without_skonto() {
+sub test_default_invoice_one_item_19_without_skonto {
my $title = 'default invoice, one item, 19% tax, without_skonto';
my $item = create_invoice_item(part => $parts[0], qty => 2.5);
my $invoice = create_sales_invoice(
}
-sub test_default_invoice_one_item_19_without_skonto_overpaid() {
+sub test_default_invoice_one_item_19_without_skonto_overpaid {
my $title = 'default invoice, one item, 19% tax, without_skonto';
my $item = create_invoice_item(part => $parts[0], qty => 2.5);
# test 2
-sub test_default_invoice_two_items_19_7_tax_with_skonto() {
+sub test_default_invoice_two_items_19_7_tax_with_skonto {
my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
my $item1 = create_invoice_item(part => $parts[0], qty => 2.5);
is($total, 0, "${title}: even balance");
}
-sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included() {
+sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included {
my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
my $item1 = create_invoice_item(part => $parts[0], qty => 2.5);
}
# test 3 : two items, without skonto
-sub test_default_invoice_two_items_19_7_without_skonto() {
+sub test_default_invoice_two_items_19_7_without_skonto {
my $title = 'default invoice, two items, 19/7% tax without skonto';
my $item1 = create_invoice_item(part => $parts[0], qty => 2.5);
}
# test 4
-sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
+sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment {
my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
my $item1 = create_invoice_item(part => $parts[0], qty => 2.5);
}
# test 5
-sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
+sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments {
my $title = 'default invoice, two items, 19/7% tax not included';
my $item1 = create_invoice_item(part => $parts[0], qty => 2.5);
}
# test 6
-sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
+sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto {
my $title = 'default invoice, two items, 19/7% tax not included';
my $item1 = create_invoice_item(part => $parts[0], qty => 2.5);
}
-sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
+sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent {
my $title = 'default invoice, two items, 19/7% tax not included';
# if there is only one cent left there can only be one skonto booking, the
}
-sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
+sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent {
my $title = 'default invoice, two items, 19/7% tax not included';
# if there are two cents left there will be two skonto bookings, 1 cent each
}
-sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
+sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto {
my $title = 'default invoice, one item, 19% tax, without_skonto';
my $item = create_invoice_item(part => $parts[0], qty => 2.5);
}
-sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
+sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent {
my $title = 'default invoice, one item, 19% tax, without_skonto';
my $item = create_invoice_item(part => $parts[0], qty => 2.5);
}
# test 3 : two items, without skonto
-sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
+sub test_default_purchase_invoice_two_charts_19_7_without_skonto {
my $title = 'default invoice, two items, 19/7% tax without skonto';
my $purchase_invoice = new_purchase_invoice();
}
-sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
+sub test_default_purchase_invoice_two_charts_19_7_with_skonto {
my $title = 'default invoice, two items, 19/7% tax without skonto';
my $purchase_invoice = new_purchase_invoice();
}
-sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
+sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto {
my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
# check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
};
-sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
+sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto {
my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
my $purchase_invoice = new_purchase_invoice();
}
# test
-sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
+sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50 {
my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
my $item1 = create_invoice_item(part => $parts[2], qty => 1);
}
# test
-sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
+sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25 {
my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
my $item1 = create_invoice_item(part => $parts[2], qty => 0.5);
is($total , 0 , "${title}: even balance");
}
-sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
+sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included {
my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
my $item1 = create_invoice_item(part => $parts[2], qty => 0.5);
}
}
-sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
+sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple {
my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
my $item1 = create_invoice_item(part => $parts[2], qty => 0.5);
[%- USE P -%][%- USE HTML -%][%- USE LxERP -%]
-<span id="[% HTML.escape(bt_id) %].[% HTML.escape(invoice.id) %]" data-invoice-amount="[% HTML.escape(invoice.open_amount * 1) %]">
+[% SELECT_OPTIONS = invoice.get_payment_select_options_for_bank_transaction(bt_id) %]
+[% is_skonto_pt = SELECT_OPTIONS.1.selected %]
+[% formatted_skonto_amount = LxERP.format_amount(invoice.skonto_amount, 2) %]
+[% formatted_skonto_amount_selected = is_skonto_pt ? $formatted_skonto_amount : LxERP.format_amount(0, 2) %]
+<span id="[% HTML.escape(bt_id) %].[% HTML.escape(invoice.id) %]"
+ data-invoice-amount="[% HTML.escape(invoice.open_amount * 1) %]"
+ data-invoice-amount-less-skonto="[% HTML.escape(invoice.amount_less_skonto * 1) %]">
[% P.hidden_tag("invoice_ids." _ bt_id _ "[]", invoice.id) %]
- [% SELECT_OPTIONS = invoice.get_payment_select_options_for_bank_transaction(bt_id) %]
- [% formatted_skonto_amount_selected = SELECT_OPTIONS.1.selected ? LxERP.format_amount(invoice.skonto_amount, 2) : LxERP.format_amount(0, 2) %]
- [% formatted_skonto_amount = LxERP.format_amount(invoice.skonto_amount, 2) %]
+ [% P.hidden_tag("skonto_pt." _ bt_id _ "." _ invoice.id _ "", is_skonto_pt) %]
[% LxERP.t8("Invno.") %]: [% HTML.escape(invoice.invnumber) %]</br>
[% LxERP.t8("Open amount") %]: [% LxERP.format_amount(invoice.open_amount, 2) %]</br>
[% P.select_tag("invoice_skontos." _ bt_id _ "[]", SELECT_OPTIONS, value_key="payment_type", title_key="display", onChange="kivi.BankTransaction.update_skonto(this, " _ bt_id _ ", " _ invoice.id _ ", '$formatted_skonto_amount')" ) %]</br>
- [% LxERP.t8("Skonto amount") %]: [% P.input_tag("free_skonto_amount." _ bt_id _ "." _ invoice.id _ "", "$formatted_skonto_amount_selected", default=0, style=style, disabled=1, size=4, class='numeric') %]
+ [% LxERP.t8("Skonto amount") %]: [% P.input_tag("free_skonto_amount." _ bt_id _ "." _ invoice.id _ "", "$formatted_skonto_amount_selected", default=0, style=style, disabled=1, size=4, class='numeric', onblur="kivi.BankTransaction.update_invoice_amount(" _ bt_id _ ", 0, this)") %]
[% P.link_tag("#", "x", onclick="kivi.BankTransaction.delete_invoice(" _ bt_id _ "," _ invoice.id _ ")") %]
</span>