9 use Support::TestSetup;
11 use List::Util qw(sum);
13 use SL::DB::Buchungsgruppe;
22 use SL::DB::BankAccount;
23 use SL::DB::PaymentTerm;
26 my ($customer, $vendor, $currency_id, @parts, $buchungsgruppe, $buchungsgruppe7, $unit, $employee, $tax, $tax7, $taxzone,
27 $bank_chart, $expense_chart, $tax_chart, $expense_chart7, $tax_chart7, $arap_chart,
28 $payment_terms, $bank_account);
32 my $reset_state_counter = 0;
34 my $purchase_invoice_counter = 0; # used for generating purchase invnumber
37 SL::DB::Manager::InvoiceItem->delete_all(all => 1);
38 SL::DB::Manager::Invoice->delete_all(all => 1);
39 SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
40 SL::DB::Manager::Part->delete_all(all => 1);
41 SL::DB::Manager::Customer->delete_all(all => 1);
42 SL::DB::Manager::Vendor->delete_all(all => 1);
43 SL::DB::Manager::BankAccount->delete_all(all => 1);
44 SL::DB::Manager::PaymentTerm->delete_all(all => 1);
50 return if $reset_state_counter;
52 $params{$_} ||= {} for qw(buchungsgruppe unit customer part tax vendor);
56 $default_manager = $::lx_office_conf{system}->{default_manager};
57 if ($default_manager eq "swiss") {
58 $buchungsgruppe = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 8%', %{ $params{buchungsgruppe} }) || croak "No accounting group for 8\%";
59 $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 2.5%') || croak "No accounting group for 2.5\%";
60 $unit = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} }) || croak "No unit";
61 $employee = SL::DB::Manager::Employee->current || croak "No employee";
62 $tax = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.08, %{ $params{tax} }) || croak "No tax for 8\%";
63 $tax7 = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.025) || croak "No tax for 2.5\%";
64 $taxzone = SL::DB::Manager::TaxZone->find_by( description => 'Schweiz') || croak "No taxzone";
65 $bank_chart = SL::DB::Manager::Chart->find_by( description => 'Kasse' ) || croak "No bank-account";
66 $expense_chart = SL::DB::Manager::Chart->find_by(accno => '4200') || croak "No expense-account for 8\%";
67 $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1170') || croak "No tax-account for 8\%";
68 $expense_chart7 = SL::DB::Manager::Chart->find_by(accno => '4201') || croak "No expense-account for 2.5\%";
69 $tax_chart7 = SL::DB::Manager::Chart->find_by(accno => '1170') || croak "No tax-account for 2.5\%";
70 $arap_chart = SL::DB::Manager::Chart->find_by(accno => '2000') || croak "No arap-account";
72 $buchungsgruppe = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%', %{ $params{buchungsgruppe} }) || croak "No accounting group";
73 $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%') || croak "No accounting group for 7\%";
74 $unit = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} }) || croak "No unit";
75 $employee = SL::DB::Manager::Employee->current || croak "No employee";
76 $tax = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} }) || croak "No tax";
77 $tax7 = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07) || croak "No tax for 7\%";
78 $taxzone = SL::DB::Manager::TaxZone->find_by( description => 'Inland') || croak "No taxzone";
79 $bank_chart = SL::DB::Manager::Chart->find_by( description => 'Bank' ) || croak "No bankaccount";
80 $expense_chart = SL::DB::Manager::Chart->find_by(accno => '3400') || croak "No expense-account for 16\%";
81 $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1576') || croak "No tax-account for 19\%";
82 $expense_chart7 = SL::DB::Manager::Chart->find_by(accno => '3300') || croak "No expense-account for 7\%";
83 $tax_chart7 = SL::DB::Manager::Chart->find_by(accno => '1571') || croak "No tax-account for 7\%";
84 $arap_chart = SL::DB::Manager::Chart->find_by(accno => '1600') || croak "No arap-account";
87 $currency_id = $::instance_conf->get_currency_id;
89 $customer = SL::DB::Customer->new(
90 name => 'Test Customer',
91 currency_id => $currency_id,
92 taxzone_id => $taxzone->id,
93 %{ $params{customer} }
96 $bank_account = SL::DB::BankAccount->new(
97 account_number => '123',
102 chart_id => $bank_chart->id,
103 name => $bank_chart->description,
106 $payment_terms = SL::DB::PaymentTerm->new(
107 description => 'payment',
108 description_long => 'payment',
111 percent_skonto => '0.05',
112 auto_calculation => 1,
115 $vendor = SL::DB::Vendor->new(
116 name => 'Test Vendor',
117 currency_id => $currency_id,
118 taxzone_id => $taxzone->id,
119 payment_id => $payment_terms->id,
125 push @parts, SL::DB::Part->new(
126 partnumber => 'T4254',
127 description => 'Fourty-two fifty-four',
130 buchungsgruppen_id => $buchungsgruppe->id,
135 push @parts, SL::DB::Part->new(
136 partnumber => 'T0815',
137 description => 'Zero EIGHT fifteeN @ 7%',
140 buchungsgruppen_id => $buchungsgruppe7->id,
144 push @parts, SL::DB::Part->new(
146 description => 'Testware 19%',
149 buchungsgruppen_id => $buchungsgruppe->id,
153 push @parts, SL::DB::Part->new(
155 description => 'Testware 7%',
158 buchungsgruppen_id => $buchungsgruppe7->id,
163 $reset_state_counter++;
169 return SL::DB::Invoice->new(
170 customer_id => $customer->id,
171 currency_id => $currency_id,
172 employee_id => $employee->id,
173 salesman_id => $employee->id,
174 gldate => DateTime->today_local->to_kivitendo,
175 taxzone_id => $taxzone->id,
176 transdate => DateTime->today_local->to_kivitendo,
184 sub new_purchase_invoice {
186 # manually create a Kreditorenbuchung from scratch, ap + acc_trans bookings, as no helper exists yet, like $invoice->post.
187 # arap-Booking must come last in the acc_trans order
188 $purchase_invoice_counter++;
190 my $purchase_invoice = SL::DB::PurchaseInvoice->new(
191 vendor_id => $vendor->id,
192 invnumber => 'newap ' . $purchase_invoice_counter ,
193 currency_id => $currency_id,
194 employee_id => $employee->id,
195 gldate => DateTime->today_local->to_kivitendo,
196 taxzone_id => $taxzone->id,
197 transdate => DateTime->today_local->to_kivitendo,
201 amount => $default_manager eq "swiss" ? '210.5' : '226',
207 my $today = DateTime->today_local->to_kivitendo;
208 my $expense_chart_booking= SL::DB::AccTransaction->new(
209 trans_id => $purchase_invoice->id,
210 chart_id => $expense_chart->id,
211 chart_link => $expense_chart->link,
215 taxkey => $default_manager eq "swiss" ? 4 : 9,
216 tax_id => SL::DB::Manager::Tax->find_by(taxkey => $default_manager eq "swiss" ? 4 : 9)->id);
217 $expense_chart_booking->save;
219 my $tax_chart_booking= SL::DB::AccTransaction->new(
220 trans_id => $purchase_invoice->id,
221 chart_id => $tax_chart->id,
222 chart_link => $tax_chart->link,
223 amount => $default_manager eq "swiss" ? '-8' : '-19',
227 tax_id => SL::DB::Manager::Tax->find_by(taxkey => $default_manager eq "swiss" ? 4 : 9)->id);
228 $tax_chart_booking->save;
229 $expense_chart_booking= SL::DB::AccTransaction->new(
230 trans_id => $purchase_invoice->id,
231 chart_id => $expense_chart7->id,
232 chart_link => $expense_chart7->link,
236 taxkey => $default_manager eq "swiss" ? 5 : 8,
237 tax_id => SL::DB::Manager::Tax->find_by(taxkey => $default_manager eq "swiss" ? 5 : 8)->id);
238 $expense_chart_booking->save;
241 $tax_chart_booking= SL::DB::AccTransaction->new(
242 trans_id => $purchase_invoice->id,
243 chart_id => $tax_chart7->id,
244 chart_link => $tax_chart7->link,
245 amount => $default_manager eq "swiss" ? '-2.5' : '-7',
249 tax_id => SL::DB::Manager::Tax->find_by(taxkey => $default_manager eq "swiss" ? 5 : 8)->id);
250 $tax_chart_booking->save;
251 my $arap_booking= SL::DB::AccTransaction->new(trans_id => $purchase_invoice->id,
252 chart_id => $arap_chart->id,
253 chart_link => $arap_chart->link,
254 amount => $default_manager eq "swiss" ? '210.5' : '226',
258 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
261 return $purchase_invoice;
267 my $part = delete($params{part}) || $parts[0];
269 return SL::DB::InvoiceItem->new(
270 parts_id => $part->id,
271 lastcost => $part->lastcost,
272 sellprice => $part->sellprice,
273 description => $part->description,
279 sub number_of_payments {
280 my $transactions = shift;
282 my $number_of_payments;
284 foreach my $transaction ( @$transactions ) {
285 if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
286 $paid_amount += $transaction->amount ;
287 $number_of_payments++;
290 return ($number_of_payments, $paid_amount);
294 my $transactions = shift;
296 my $total = sum map { $_->amount } @$transactions;
298 return $::form->round_amount($total, 5);
304 sub test_default_invoice_one_item_19_without_skonto() {
305 reset_state() if $ALWAYS_RESET;
307 my $item = new_item(qty => 2.5);
308 my $invoice = new_invoice(
310 invoiceitems => [ $item ],
311 payment_id => $payment_terms->id,
315 my $purchase_invoice = new_purchase_invoice();
319 my %params = ( chart_id => $bank_account->chart_id,
320 transdate => DateTime->today_local->to_kivitendo
323 $params{amount} = $default_manager eq "swiss" ? '6.32' : '6.96';
324 $params{payment_type} = 'without_skonto';
326 $invoice->pay_invoice( %params );
328 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
329 my $total = total_amount($invoice->transactions);
331 my $title = $default_manager eq "swiss" ? 'default invoice, one item, 8% tax, without_skonto' : 'default invoice, one item, 19% tax, without_skonto';
333 is($invoice->netamount, 5.85, "${title}: netamount");
334 if ($default_manager eq "swiss") {
335 is($invoice->amount, 6.32, "${title}: amount");
336 is($paid_amount, -6.32, "${title}: paid amount");
337 is($invoice->paid, 6.32, "${title}: paid");
339 is($invoice->amount, 6.96, "${title}: amount");
340 is($paid_amount, -6.96, "${title}: paid amount");
341 is($invoice->paid, 6.96, "${title}: paid");
343 is($number_of_payments, 1, "${title}: 1 AR_paid booking");
344 is($total, 0, "${title}: even balance");
348 sub test_default_invoice_one_item_19_without_skonto_overpaid() {
349 reset_state() if $ALWAYS_RESET;
351 my $item = new_item(qty => 2.5);
352 my $invoice = new_invoice(
354 invoiceitems => [ $item ],
355 payment_id => $payment_terms->id,
359 my $purchase_invoice = new_purchase_invoice();
363 my %params = ( chart_id => $bank_account->chart_id,
364 transdate => DateTime->today_local->to_kivitendo
367 $params{amount} = $default_manager eq "swiss" ? '16.32' : '16.96';
368 $params{payment_type} = 'without_skonto';
369 $invoice->pay_invoice( %params );
371 $params{amount} = '-10.00';
372 $invoice->pay_invoice( %params );
374 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
375 my $total = total_amount($invoice->transactions);
377 my $title = $default_manager eq "swiss" ? 'default invoice, one item, 8% tax, without_skonto_overpaid' : 'default invoice, one item, 19% tax, without_skonto_overpaid';
379 is($invoice->netamount, 5.85, "${title}: netamount");
380 if ($default_manager eq "swiss") {
381 is($invoice->amount, 6.32, "${title}: amount");
382 is($paid_amount, -6.32, "${title}: paid amount");
383 is($invoice->paid, 6.32, "${title}: paid");
385 is($invoice->amount, 6.96, "${title}: amount");
386 is($paid_amount, -6.96, "${title}: paid amount");
387 is($invoice->paid, 6.96, "${title}: paid");
389 is($number_of_payments, 2, "${title}: 1 AR_paid booking");
390 is($total, 0, "${title}: even balance");
396 sub test_default_invoice_two_items_19_7_tax_with_skonto() {
397 reset_state() if $ALWAYS_RESET;
399 my $item1 = new_item(qty => 2.5);
400 my $item2 = new_item(qty => 1.2, part => $parts[1]);
401 my $invoice = new_invoice(
403 invoiceitems => [ $item1, $item2 ],
404 payment_id => $payment_terms->id,
409 my %params = ( chart_id => $bank_account->chart_id,
410 transdate => DateTime->today_local->to_kivitendo
413 $params{payment_type} = 'with_skonto_pt';
414 $params{amount} = $invoice->amount_less_skonto;
416 $invoice->pay_invoice( %params );
418 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
419 my $total = total_amount($invoice->transactions);
421 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax with_skonto_pt' : 'default invoice, two items, 19/7% tax with_skonto_pt';
423 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
424 if ($default_manager eq "swiss") {
425 is($invoice->amount, 6.32 + 11.95, "${title}: amount");
426 is($paid_amount, -18.27, "${title}: paid amount");
427 is($invoice->paid, 18.27, "${title}: paid");
429 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
430 is($paid_amount, -19.44, "${title}: paid amount");
431 is($invoice->paid, 19.44, "${title}: paid");
433 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
434 is($total, 0, "${title}: even balance");
437 sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included() {
438 reset_state() if $ALWAYS_RESET;
440 my $item1 = new_item(qty => 2.5);
441 my $item2 = new_item(qty => 1.2, part => $parts[1]);
442 my $invoice = new_invoice(
444 invoiceitems => [ $item1, $item2 ],
445 payment_id => $payment_terms->id,
450 my %params = ( chart_id => $bank_account->chart_id,
451 transdate => DateTime->today_local->to_kivitendo
454 $params{payment_type} = 'with_skonto_pt';
455 $params{amount} = $invoice->amount_less_skonto;
457 $invoice->pay_invoice( %params );
459 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
460 my $total = total_amount($invoice->transactions);
462 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax with_skonto_pt' : 'default invoice, two items, 19/7% tax with_skonto_pt';
464 if ($default_manager eq "swiss") {
465 is($invoice->netamount, 16.80, "${title}: netamount");
467 is($invoice->netamount, 15.82, "${title}: netamount");
469 is($invoice->amount, 17.51, "${title}: amount");
470 is($paid_amount, -17.51, "${title}: paid amount");
471 is($invoice->paid, 17.51, "${title}: paid");
472 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
473 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
474 is($total, 0, "${title}: even balance");
478 # test 3 : two items, without skonto
479 sub test_default_invoice_two_items_19_7_without_skonto() {
480 reset_state() if $ALWAYS_RESET;
482 my $item1 = new_item(qty => 2.5);
483 my $item2 = new_item(qty => 1.2, part => $parts[1]);
484 my $invoice = new_invoice(
486 invoiceitems => [ $item1, $item2 ],
487 payment_id => $payment_terms->id,
492 my %params = ( chart_id => $bank_account->chart_id,
493 transdate => DateTime->today_local->to_kivitendo
496 $params{amount} = $default_manager eq "swiss" ? '18.27' : '19.44'; # pass full amount
497 $params{payment_type} = 'without_skonto';
499 $invoice->pay_invoice( %params );
501 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
502 my $total = total_amount($invoice->transactions);
504 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax without skonto' : 'default invoice, two items, 19/7% tax without skonto';
506 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
507 if ($default_manager eq "swiss") {
508 is($invoice->amount, 6.32 + 11.95, "${title}: amount");
509 is($paid_amount, -18.27, "${title}: paid amount");
510 is($invoice->paid, 18.27, "${title}: paid");
512 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
513 is($paid_amount, -19.44, "${title}: paid amount");
514 is($invoice->paid, 19.44, "${title}: paid");
516 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
517 is($total, 0, "${title}: even balance");
521 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
522 reset_state() if $ALWAYS_RESET;
524 my $item1 = new_item(qty => 2.5);
525 my $item2 = new_item(qty => 1.2, part => $parts[1]);
526 my $invoice = new_invoice(
528 invoiceitems => [ $item1, $item2 ],
529 payment_id => $payment_terms->id,
533 $invoice->pay_invoice( amount => $default_manager eq "swiss" ? '8.27' : '9.44',
534 payment_type => 'without_skonto',
535 chart_id => $bank_account->chart_id,
536 transdate => DateTime->today_local->to_kivitendo,
539 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
540 my $total = total_amount($invoice->transactions);
542 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax without skonto incomplete payment' : 'default invoice, two items, 19/7% tax without skonto incomplete payment';
544 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
545 if ($default_manager eq "swiss") {
546 is($invoice->amount, 6.32 + 11.95, "${title}: amount");
547 is($paid_amount, -8.27, "${title}: paid amount");
548 is($invoice->paid, 8.27, "${title}: paid");
550 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
551 is($paid_amount, -9.44, "${title}: paid amount");
552 is($invoice->paid, 9.44, "${title}: paid");
554 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
555 is($total, 0, "${title}: even balance");
559 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
560 reset_state() if $ALWAYS_RESET;
562 my $item1 = new_item(qty => 2.5);
563 my $item2 = new_item(qty => 1.2, part => $parts[1]);
564 my $invoice = new_invoice(
566 invoiceitems => [ $item1, $item2 ],
567 payment_id => $payment_terms->id,
571 $invoice->pay_invoice( amount => $default_manager eq "swiss" ? '8.27' : '9.44',
572 payment_type => 'without_skonto',
573 chart_id => $bank_account->chart_id,
574 transdate => DateTime->today_local->to_kivitendo
576 $invoice->pay_invoice( amount => '10.00',
577 chart_id => $bank_account->chart_id,
578 transdate => DateTime->today_local->to_kivitendo
581 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
582 my $total = total_amount($invoice->transactions);
584 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax not included' : 'default invoice, two items, 19/7% tax not included';
585 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
586 if ($default_manager eq "swiss") {
587 is($invoice->amount, 6.32 + 11.95, "${title}: amount");
588 is($paid_amount, -18.27, "${title}: paid amount");
589 is($invoice->paid, 18.27, "${title}: paid");
591 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
592 is($paid_amount, -19.44, "${title}: paid amount");
593 is($invoice->paid, 19.44, "${title}: paid");
595 is($number_of_payments, 2, "${title}: 2 AR_paid bookings");
596 is($total, 0, "${title}: even balance");
601 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
602 reset_state() if $ALWAYS_RESET;
604 my $item1 = new_item(qty => 2.5);
605 my $item2 = new_item(qty => 1.2, part => $parts[1]);
606 my $invoice = new_invoice(
608 invoiceitems => [ $item1, $item2 ],
609 payment_id => $payment_terms->id,
613 $invoice->pay_invoice( amount => $default_manager eq "swiss" ? '8.27' : '9.44',
614 payment_type => 'without_skonto',
615 chart_id => $bank_account->chart_id,
616 transdate => DateTime->today_local->to_kivitendo
618 $invoice->pay_invoice( amount => $default_manager eq "swiss" ? '7.56' : '8.73',
619 payment_type => 'without_skonto',
620 chart_id => $bank_account->chart_id,
621 transdate => DateTime->today_local->to_kivitendo
623 $invoice->pay_invoice( amount => $invoice->open_amount,
624 payment_type => 'difference_as_skonto',
625 chart_id => $bank_account->chart_id,
626 transdate => DateTime->today_local->to_kivitendo
629 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
630 my $total = total_amount($invoice->transactions);
632 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax not included' : 'default invoice, two items, 19/7% tax not included';
634 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
635 if ($default_manager eq "swiss") {
636 is($invoice->amount, 6.32 + 11.95, "${title}: amount");
637 is($paid_amount, -18.27, "${title}: paid amount");
638 is($invoice->paid, 18.27, "${title}: paid");
640 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
641 is($paid_amount, -19.44, "${title}: paid amount");
642 is($invoice->paid, 19.44, "${title}: paid");
644 is($number_of_payments, 4, "${title}: 4 AR_paid bookings");
645 is($total, 0, "${title}: even balance");
649 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
650 reset_state() if $ALWAYS_RESET;
652 # if there is only one cent left there can only be one skonto booking, the
653 # error handling should choose the highest amount, which is the 7% account
654 # (11.66) rather than the 19% account (5.85). The actual tax amount is
655 # higher for the 19% case, though (1.11 compared to 0.82)
657 my $item1 = new_item(qty => 2.5);
658 my $item2 = new_item(qty => 1.2, part => $parts[1]);
659 my $invoice = new_invoice(
661 invoiceitems => [ $item1, $item2 ],
662 payment_id => $payment_terms->id,
666 $invoice->pay_invoice( amount => $default_manager eq "swiss" ? '18.25' : '19.42',
667 payment_type => 'without_skonto',
668 chart_id => $bank_account->chart_id,
669 transdate => DateTime->today_local->to_kivitendo
671 $invoice->pay_invoice( amount => $invoice->open_amount,
672 payment_type => 'difference_as_skonto',
673 chart_id => $bank_account->chart_id,
674 transdate => DateTime->today_local->to_kivitendo
677 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
678 my $total = total_amount($invoice->transactions);
680 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax not included' : 'default invoice, two items, 19/7% tax not included';
682 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
683 if ($default_manager eq "swiss") {
684 is($invoice->amount, 6.32 + 11.95, "${title}: amount");
685 is($paid_amount, -18.27, "${title}: paid amount");
686 is($invoice->paid, 18.27, "${title}: paid");
688 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
689 is($paid_amount, -19.44, "${title}: paid amount");
690 is($invoice->paid, 19.44, "${title}: paid");
692 is($number_of_payments, 3, "${title}: 2 AR_paid bookings");
693 is($total, 0, "${title}: even balance");
697 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
698 reset_state() if $ALWAYS_RESET;
700 # if there are two cents left there will be two skonto bookings, 1 cent each
701 my $item1 = new_item(qty => 2.5);
702 my $item2 = new_item(qty => 1.2, part => $parts[1]);
703 my $invoice = new_invoice(
705 invoiceitems => [ $item1, $item2 ],
706 payment_id => $payment_terms->id,
710 $invoice->pay_invoice( amount => $default_manager eq "swiss" ? '18.25' : '19.42',
711 payment_type => 'without_skonto',
712 chart_id => $bank_account->chart_id,
713 transdate => DateTime->today_local->to_kivitendo
715 $invoice->pay_invoice( amount => $invoice->open_amount,
716 payment_type => 'difference_as_skonto',
717 chart_id => $bank_account->chart_id,
718 transdate => DateTime->today_local->to_kivitendo
721 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
722 my $total = total_amount($invoice->transactions);
724 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax not included' : 'default invoice, two items, 19/7% tax not included';
726 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
727 if ($default_manager eq "swiss") {
728 is($invoice->amount, 6.32 + 11.95, "${title}: amount");
729 is($paid_amount, -18.27, "${title}: paid amount");
730 is($invoice->paid, 18.27, "${title}: paid");
732 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
733 is($paid_amount, -19.44, "${title}: paid amount");
734 is($invoice->paid, 19.44, "${title}: paid");
736 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
737 is($total, 0, "${title}: even balance");
741 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
742 reset_state() if $ALWAYS_RESET;
744 my $item = new_item(qty => 2.5);
745 my $invoice = new_invoice(
747 invoiceitems => [ $item ],
748 payment_id => $payment_terms->id,
753 my %params = ( chart_id => $bank_account->chart_id,
754 transdate => DateTime->today_local->to_kivitendo
757 $params{amount} = '2.32';
758 $params{payment_type} = 'without_skonto';
759 $invoice->pay_invoice( %params );
761 $params{amount} = '3.81';
762 $params{payment_type} = 'without_skonto';
763 $invoice->pay_invoice( %params );
765 $params{amount} = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
766 $params{payment_type} = 'difference_as_skonto';
767 $invoice->pay_invoice( %params );
769 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
770 my $total = total_amount($invoice->transactions);
772 my $title = $default_manager eq "swiss" ? 'default invoice, one item, 8% tax, without_skonto' : 'default invoice, one item, 19% tax, without_skonto';
774 is($invoice->netamount, 5.85, "${title}: netamount");
775 if ($default_manager eq "swiss") {
776 is($invoice->amount, 6.32, "${title}: amount");
777 is($paid_amount, -6.32, "${title}: paid amount");
778 is($invoice->paid, 6.32, "${title}: paid");
780 is($invoice->amount, 6.96, "${title}: amount");
781 is($paid_amount, -6.96, "${title}: paid amount");
782 is($invoice->paid, 6.96, "${title}: paid");
784 is($number_of_payments, 3, "${title}: 3 AR_paid booking");
785 is($total, 0, "${title}: even balance");
789 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
790 reset_state() if $ALWAYS_RESET;
792 my $item = new_item(qty => 2.5);
793 my $invoice = new_invoice(
795 invoiceitems => [ $item ],
796 payment_id => $payment_terms->id,
801 my %params = ( chart_id => $bank_account->chart_id,
802 transdate => DateTime->today_local->to_kivitendo
805 $params{amount} = $default_manager eq "swiss" ? '6.31' : '6.95';
806 $params{payment_type} = 'without_skonto';
807 $invoice->pay_invoice( %params );
809 $params{amount} = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
810 $params{payment_type} = 'difference_as_skonto';
811 $invoice->pay_invoice( %params );
813 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
814 my $total = total_amount($invoice->transactions);
816 my $title = $default_manager eq "swiss" ? 'default invoice, one item, 8% tax, without_skonto' : 'default invoice, one item, 19% tax, without_skonto';
818 is($invoice->netamount, 5.85, "${title}: netamount");
819 if ($default_manager eq "swiss") {
820 is($invoice->amount, 6.32, "${title}: amount");
821 is($paid_amount, -6.32, "${title}: paid amount");
822 is($invoice->paid, 6.32, "${title}: paid");
824 is($invoice->amount, 6.96, "${title}: amount");
825 is($paid_amount, -6.96, "${title}: paid amount");
826 is($invoice->paid, 6.96, "${title}: paid");
828 is($number_of_payments, 2, "${title}: 3 AR_paid booking");
829 is($total, 0, "${title}: even balance");
833 # test 3 : two items, without skonto
834 sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
835 reset_state() if $ALWAYS_RESET;
837 my $purchase_invoice = new_purchase_invoice();
839 my %params = ( chart_id => $bank_account->chart_id,
840 transdate => DateTime->today_local->to_kivitendo
843 $params{amount} = $default_manager eq "swiss" ? '210.5' : '226'; # pass full amount
844 $params{payment_type} = 'without_skonto';
846 $purchase_invoice->pay_invoice( %params );
848 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
849 my $total = total_amount($purchase_invoice->transactions);
851 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax without skonto' : 'default invoice, two items, 19/7% tax without skonto';
853 if ($default_manager eq "swiss") {
854 is($paid_amount, 210.5, "${title}: paid amount");
856 is($paid_amount, 226, "${title}: paid amount");
858 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
859 is($total, 0, "${title}: even balance");
863 sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
864 reset_state() if $ALWAYS_RESET;
866 my $purchase_invoice = new_purchase_invoice();
868 my %params = ( chart_id => $bank_account->chart_id,
869 transdate => DateTime->today_local->to_kivitendo
872 $params{amount} = $purchase_invoice->amount_less_skonto;
873 $params{payment_type} = 'with_skonto_pt';
875 $purchase_invoice->pay_invoice( %params );
877 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
878 my $total = total_amount($purchase_invoice->transactions);
880 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax with skonto' : 'default invoice, two items, 19/7% tax with skonto';
882 if ($default_manager eq "swiss") {
883 is($paid_amount, 210.5, "${title}: paid amount");
885 is($paid_amount, 226, "${title}: paid amount");
887 is($number_of_payments, 3, "${title}: 1 AP_paid bookings");
888 is($total, 0, "${title}: even balance");
892 sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
893 # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
894 reset_state() if $ALWAYS_RESET;
895 my $purchase_invoice = new_purchase_invoice();
896 $purchase_invoice->pay_invoice(
897 amount => ( $purchase_invoice->amount / 3 * 2),
898 payment_type => 'without_skonto',
899 chart_id => $bank_account->chart_id,
900 transdate => DateTime->today_local->to_kivitendo
902 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
903 my $total = total_amount($purchase_invoice->transactions);
905 my $title = $default_manager eq "swiss" ? 'default purchase_invoice, two charts, 8/2.5% tax multiple payments with final difference as skonto' : 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
907 if ($default_manager eq "swiss") {
908 is($paid_amount, 140.33, "${title}: paid amount");
910 is($paid_amount, 150.67, "${title}: paid amount");
912 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
913 is($total, 0, "${title}: even balance");
916 sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
917 reset_state() if $ALWAYS_RESET;
919 my $purchase_invoice = new_purchase_invoice();
921 # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
922 $purchase_invoice->pay_invoice(
923 amount => ( $purchase_invoice->amount / 3 * 2),
924 payment_type => 'without_skonto',
925 chart_id => $bank_account->chart_id,
926 transdate => DateTime->today_local->to_kivitendo
928 $purchase_invoice->pay_invoice(
929 amount => ( $purchase_invoice->amount / 5 ),
930 payment_type => 'without_skonto',
931 chart_id => $bank_account->chart_id,
932 transdate => DateTime->today_local->to_kivitendo
934 $purchase_invoice->pay_invoice(
935 payment_type => 'difference_as_skonto',
936 chart_id => $bank_account->chart_id,
937 transdate => DateTime->today_local->to_kivitendo
940 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
941 my $total = total_amount($purchase_invoice->transactions);
943 my $title = $default_manager eq "swiss" ? 'default purchase_invoice, two charts, 8/2.5% tax multiple payments with final difference as skonto' : 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
945 if ($default_manager eq "swiss") {
946 is($paid_amount, 210.5, "${title}: paid amount");
948 is($paid_amount, 226, "${title}: paid amount");
950 is($number_of_payments, 4, "${title}: 1 AP_paid bookings");
951 is($total, 0, "${title}: even balance");
956 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
957 reset_state() if $ALWAYS_RESET;
959 my $item1 = new_item(qty => 1, part => $parts[2]);
960 my $item2 = new_item(qty => 1, part => $parts[3]);
961 my $invoice = new_invoice(
963 invoiceitems => [ $item1, $item2 ],
964 payment_id => $payment_terms->id,
969 my %params = ( chart_id => $bank_account->chart_id,
970 transdate => DateTime->today_local->to_kivitendo
973 $params{amount} = $invoice->amount_less_skonto;
974 $params{payment_type} = 'with_skonto_pt';
976 $invoice->pay_invoice( %params );
978 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
979 my $total = total_amount($invoice->transactions);
981 my $title = $default_manager eq "swiss" ? 'default invoice, two items, 8/2.5% tax with_skonto_pt 50/50' : 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
983 is($invoice->netamount, 100, "${title}: netamount");
984 if ($default_manager eq "swiss") {
985 is($invoice->amount, 105.25, "${title}: amount");
986 is($paid_amount, -105.25, "${title}: paid amount");
987 is($invoice->paid, 105.25, "${title}: paid");
989 is($invoice->amount, 113, "${title}: amount");
990 is($paid_amount, -113, "${title}: paid amount");
991 is($invoice->paid, 113, "${title}: paid");
993 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
994 is($total, 0, "${title}: even balance");
998 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
999 reset_state() if $ALWAYS_RESET;
1001 my $item1 = new_item(qty => 0.5, part => $parts[2]);
1002 my $item2 = new_item(qty => 0.5, part => $parts[3]);
1003 my $item3 = new_item(qty => 0.5, part => $parts[2]);
1004 my $item4 = new_item(qty => 0.5, part => $parts[3]);
1005 my $invoice = new_invoice(
1007 invoiceitems => [ $item1, $item2, $item3, $item4 ],
1008 payment_id => $payment_terms->id,
1013 my %params = ( chart_id => $bank_account->chart_id,
1014 transdate => DateTime->today_local->to_kivitendo
1017 $params{amount} = $invoice->amount_less_skonto;
1018 $params{payment_type} = 'with_skonto_pt';
1020 $invoice->pay_invoice( %params );
1022 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
1023 my $total = total_amount($invoice->transactions);
1025 my $title = $default_manager eq "swiss" ? 'default invoice, four items, 8/2.5% tax with_skonto_pt 4x25' : 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
1027 is($invoice->netamount, 100 , "${title}: netamount");
1028 if ($default_manager eq "swiss") {
1029 is($invoice->amount, 105.25, "${title}: amount");
1030 is($paid_amount, -105.25, "${title}: paid amount");
1031 is($invoice->paid, 105.25, "${title}: paid");
1033 is($invoice->amount, 113, "${title}: amount");
1034 is($paid_amount, -113, "${title}: paid amount");
1035 is($invoice->paid, 113, "${title}: paid");
1037 is($number_of_payments, 3 , "${title}: 3 AR_paid bookings");
1038 is($total, 0 , "${title}: even balance");
1041 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
1042 reset_state() if $ALWAYS_RESET;
1044 my $item1 = new_item(qty => 0.5, part => $parts[2]);
1045 my $item2 = new_item(qty => 0.5, part => $parts[3]);
1046 my $item3 = new_item(qty => 0.5, part => $parts[2]);
1047 my $item4 = new_item(qty => 0.5, part => $parts[3]);
1048 my $invoice = new_invoice(
1050 invoiceitems => [ $item1, $item2, $item3, $item4 ],
1051 payment_id => $payment_terms->id,
1056 my %params = ( chart_id => $bank_account->chart_id,
1057 transdate => DateTime->today_local->to_kivitendo
1060 $params{amount} = $invoice->amount_less_skonto;
1061 $params{payment_type} = 'with_skonto_pt';
1063 $invoice->pay_invoice( %params );
1065 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
1066 my $total = total_amount($invoice->transactions);
1068 my $title = $default_manager eq "swiss" ? 'default invoice, four items, 8/2.5% tax with_skonto_pt 4x25' : 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
1070 if ($default_manager eq "swiss") {
1071 is($invoice->netamount, 95.08, "${title}: netamount");
1073 is($invoice->netamount, 88.75, "${title}: netamount");
1075 is($invoice->amount, 100, "${title}: amount");
1076 is($paid_amount, -100, "${title}: paid amount");
1077 is($invoice->paid, 100, "${title}: paid");
1078 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
1079 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
1080 is($total, 0, "${title}: even balance");
1084 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
1085 reset_state() if $ALWAYS_RESET;
1087 my $item1 = new_item(qty => 0.5, part => $parts[2]);
1088 my $item2 = new_item(qty => 0.5, part => $parts[3]);
1089 my $item3 = new_item(qty => 0.5, part => $parts[2]);
1090 my $item4 = new_item(qty => 0.5, part => $parts[3]);
1091 my $invoice = new_invoice(
1093 invoiceitems => [ $item1, $item2, $item3, $item4 ],
1094 payment_id => $payment_terms->id,
1098 $invoice->pay_invoice( amount => '90',
1099 payment_type => 'without_skonto',
1100 chart_id => $bank_account->chart_id,
1101 transdate => DateTime->today_local->to_kivitendo
1103 $invoice->pay_invoice( payment_type => 'difference_as_skonto',
1104 chart_id => $bank_account->chart_id,
1105 transdate => DateTime->today_local->to_kivitendo
1108 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
1109 my $total = total_amount($invoice->transactions);
1111 my $title = $default_manager eq "swiss" ? 'default invoice, four items, 8/2.5% tax with_skonto_pt 4x25' : 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
1113 is($invoice->netamount, 100, "${title}: netamount");
1114 if ($default_manager eq "swiss") {
1115 is($invoice->amount, 105.25, "${title}: amount");
1116 is($paid_amount, -105.25, "${title}: paid amount");
1117 is($invoice->paid, 105.25, "${title}: paid");
1119 is($invoice->amount, 113, "${title}: amount");
1120 is($paid_amount, -113, "${title}: paid amount");
1121 is($invoice->paid, 113, "${title}: paid");
1123 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
1124 is($total, 0, "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
1127 Support::TestSetup::login();
1130 # test cases: without_skonto
1131 test_default_invoice_one_item_19_without_skonto();
1132 test_default_invoice_two_items_19_7_tax_with_skonto();
1133 test_default_invoice_two_items_19_7_without_skonto();
1134 test_default_invoice_two_items_19_7_without_skonto_incomplete_payment();
1135 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments();
1136 test_default_purchase_invoice_two_charts_19_7_without_skonto();
1137 test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto();
1138 test_default_invoice_one_item_19_without_skonto_overpaid();
1140 # test cases: difference_as_skonto
1141 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1142 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
1143 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
1144 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
1145 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
1146 test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1148 # test cases: with_skonto_pt
1149 test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
1150 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25();
1151 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple();
1152 test_default_purchase_invoice_two_charts_19_7_with_skonto();
1153 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included();
1154 test_default_invoice_two_items_19_7_tax_with_skonto_tax_included();
1156 # remove all created data at end of test