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;
25 my ($customer, $vendor, $currency_id, @parts, $buchungsgruppe, $buchungsgruppe7, $unit, $employee, $tax, $tax7, $taxzone, $payment_terms, $bank_account);
29 my $reset_state_counter = 0;
31 my $purchase_invoice_counter = 0; # used for generating purchase invnumber
34 SL::DB::Manager::InvoiceItem->delete_all(all => 1);
35 SL::DB::Manager::Invoice->delete_all(all => 1);
36 SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
37 SL::DB::Manager::Part->delete_all(all => 1);
38 SL::DB::Manager::Customer->delete_all(all => 1);
39 SL::DB::Manager::Vendor->delete_all(all => 1);
40 SL::DB::Manager::BankAccount->delete_all(all => 1);
41 SL::DB::Manager::PaymentTerm->delete_all(all => 1);
47 return if $reset_state_counter;
49 $params{$_} ||= {} for qw(buchungsgruppe unit customer part tax vendor);
54 $buchungsgruppe = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%', %{ $params{buchungsgruppe} }) || croak "No accounting group";
55 $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%') || croak "No accounting group for 7\%";
56 $unit = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} }) || croak "No unit";
57 $employee = SL::DB::Manager::Employee->current || croak "No employee";
58 $tax = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} }) || croak "No tax";
59 $tax7 = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07) || croak "No tax for 7\%";
60 $taxzone = SL::DB::Manager::TaxZone->find_by( description => 'Inland') || croak "No taxzone";
62 $currency_id = $::instance_conf->get_currency_id;
64 $customer = SL::DB::Customer->new(
65 name => 'Test Customer',
66 currency_id => $currency_id,
67 taxzone_id => $taxzone->id,
68 %{ $params{customer} }
71 $bank_account = SL::DB::BankAccount->new(
72 account_number => '123',
77 chart_id => SL::DB::Manager::Chart->find_by( description => 'Bank' )->id,
78 name => SL::DB::Manager::Chart->find_by( description => 'Bank' )->description,
81 $payment_terms = SL::DB::PaymentTerm->new(
82 description => 'payment',
83 description_long => 'payment',
86 percent_skonto => '0.05'
89 $vendor = SL::DB::Vendor->new(
90 name => 'Test Vendor',
91 currency_id => $currency_id,
92 taxzone_id => $taxzone->id,
93 payment_id => $payment_terms->id,
99 push @parts, SL::DB::Part->new(
100 partnumber => 'T4254',
101 description => 'Fourty-two fifty-four',
104 buchungsgruppen_id => $buchungsgruppe->id,
109 push @parts, SL::DB::Part->new(
110 partnumber => 'T0815',
111 description => 'Zero EIGHT fifteeN @ 7%',
114 buchungsgruppen_id => $buchungsgruppe7->id,
118 push @parts, SL::DB::Part->new(
120 description => 'Testware 19%',
123 buchungsgruppen_id => $buchungsgruppe->id,
127 push @parts, SL::DB::Part->new(
129 description => 'Testware 7%',
132 buchungsgruppen_id => $buchungsgruppe7->id,
137 $reset_state_counter++;
143 return SL::DB::Invoice->new(
144 customer_id => $customer->id,
145 currency_id => $currency_id,
146 employee_id => $employee->id,
147 salesman_id => $employee->id,
148 gldate => DateTime->today_local->to_kivitendo,
149 taxzone_id => $taxzone->id,
150 transdate => DateTime->today_local->to_kivitendo,
158 sub new_purchase_invoice {
160 # manually create a Kreditorenbuchung from scratch, ap + acc_trans bookings, as no helper exists yet, like $invoice->post.
161 # arap-Booking must come last in the acc_trans order
162 $purchase_invoice_counter++;
164 my $purchase_invoice = SL::DB::PurchaseInvoice->new(
165 vendor_id => $vendor->id,
166 invnumber => 'newap ' . $purchase_invoice_counter ,
167 currency_id => $currency_id,
168 employee_id => $employee->id,
169 gldate => DateTime->today_local->to_kivitendo,
170 taxzone_id => $taxzone->id,
171 transdate => DateTime->today_local->to_kivitendo,
181 my $today = DateTime->today_local->to_kivitendo;
182 my $expense_chart = SL::DB::Manager::Chart->find_by(accno => '3400');
183 my $expense_chart_booking= SL::DB::AccTransaction->new(
184 trans_id => $purchase_invoice->id,
185 chart_id => $expense_chart->id,
186 chart_link => $expense_chart->link,
191 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
192 $expense_chart_booking->save;
194 my $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1576');
195 my $tax_chart_booking= SL::DB::AccTransaction->new(
196 trans_id => $purchase_invoice->id,
197 chart_id => $tax_chart->id,
198 chart_link => $tax_chart->link,
203 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
204 $tax_chart_booking->save;
205 $expense_chart = SL::DB::Manager::Chart->find_by(accno => '3300');
206 $expense_chart_booking= SL::DB::AccTransaction->new(
207 trans_id => $purchase_invoice->id,
208 chart_id => $expense_chart->id,
209 chart_link => $expense_chart->link,
214 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
215 $expense_chart_booking->save;
218 $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1571');
219 $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,
227 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
228 $tax_chart_booking->save;
229 my $arap_chart = SL::DB::Manager::Chart->find_by(accno => '1600');
230 my $arap_booking= SL::DB::AccTransaction->new(trans_id => $purchase_invoice->id,
231 chart_id => $arap_chart->id,
232 chart_link => $arap_chart->link,
237 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
240 return $purchase_invoice;
246 my $part = delete($params{part}) || $parts[0];
248 return SL::DB::InvoiceItem->new(
249 parts_id => $part->id,
250 lastcost => $part->lastcost,
251 sellprice => $part->sellprice,
252 description => $part->description,
258 sub number_of_payments {
259 my $transactions = shift;
261 my $number_of_payments;
263 foreach my $transaction ( @$transactions ) {
264 if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
265 $paid_amount += $transaction->amount ;
266 $number_of_payments++;
269 return ($number_of_payments, $paid_amount);
273 my $transactions = shift;
275 my $total = sum map { $_->amount } @$transactions;
277 return $::form->round_amount($total, 5);
283 sub test_default_invoice_one_item_19_without_skonto() {
284 reset_state() if $ALWAYS_RESET;
286 my $item = new_item(qty => 2.5);
287 my $invoice = new_invoice(
289 invoiceitems => [ $item ],
290 payment_id => $payment_terms->id,
294 my $purchase_invoice = new_purchase_invoice();
298 my %params = ( chart_id => $bank_account->chart_id,
299 transdate => DateTime->today_local->to_kivitendo
302 $params{amount} = '6.96';
303 $params{payment_type} = 'without_skonto';
305 $invoice->pay_invoice( %params );
307 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
308 my $total = total_amount($invoice->transactions);
310 my $title = 'default invoice, one item, 19% tax, without_skonto';
312 is($invoice->netamount, 5.85, "${title}: netamount");
313 is($invoice->amount, 6.96, "${title}: amount");
314 is($paid_amount, -6.96, "${title}: paid amount");
315 is($number_of_payments, 1, "${title}: 1 AR_paid booking");
316 is($invoice->paid, 6.96, "${title}: paid");
317 is($total, 0, "${title}: even balance");
321 sub test_default_invoice_one_item_19_without_skonto_overpaid() {
322 reset_state() if $ALWAYS_RESET;
324 my $item = new_item(qty => 2.5);
325 my $invoice = new_invoice(
327 invoiceitems => [ $item ],
328 payment_id => $payment_terms->id,
332 my $purchase_invoice = new_purchase_invoice();
336 my %params = ( chart_id => $bank_account->chart_id,
337 transdate => DateTime->today_local->to_kivitendo
340 $params{amount} = '16.96';
341 $params{payment_type} = 'without_skonto';
342 $invoice->pay_invoice( %params );
344 $params{amount} = '-10.00';
345 $invoice->pay_invoice( %params );
347 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
348 my $total = total_amount($invoice->transactions);
350 my $title = 'default invoice, one item, 19% tax, without_skonto';
352 is($invoice->netamount, 5.85, "${title}: netamount");
353 is($invoice->amount, 6.96, "${title}: amount");
354 is($paid_amount, -6.96, "${title}: paid amount");
355 is($number_of_payments, 2, "${title}: 1 AR_paid booking");
356 is($invoice->paid, 6.96, "${title}: paid");
357 is($total, 0, "${title}: even balance");
363 sub test_default_invoice_two_items_19_7_tax_with_skonto() {
364 reset_state() if $ALWAYS_RESET;
366 my $item1 = new_item(qty => 2.5);
367 my $item2 = new_item(qty => 1.2, part => $parts[1]);
368 my $invoice = new_invoice(
370 invoiceitems => [ $item1, $item2 ],
371 payment_id => $payment_terms->id,
376 my %params = ( chart_id => $bank_account->chart_id,
377 transdate => DateTime->today_local->to_kivitendo
380 $params{payment_type} = 'with_skonto_pt';
381 $params{amount} = $invoice->amount_less_skonto;
383 $invoice->pay_invoice( %params );
385 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
386 my $total = total_amount($invoice->transactions);
388 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
390 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
391 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
392 is($paid_amount, -19.44, "${title}: paid amount");
393 is($invoice->paid, 19.44, "${title}: paid");
394 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
395 is($total, 0, "${title}: even balance");
398 sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included() {
399 reset_state() if $ALWAYS_RESET;
401 my $item1 = new_item(qty => 2.5);
402 my $item2 = new_item(qty => 1.2, part => $parts[1]);
403 my $invoice = new_invoice(
405 invoiceitems => [ $item1, $item2 ],
406 payment_id => $payment_terms->id,
411 my %params = ( chart_id => $bank_account->chart_id,
412 transdate => DateTime->today_local->to_kivitendo
415 $params{payment_type} = 'with_skonto_pt';
416 $params{amount} = $invoice->amount_less_skonto;
418 $invoice->pay_invoice( %params );
420 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
421 my $total = total_amount($invoice->transactions);
423 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
425 is($invoice->netamount, 15.82, "${title}: netamount");
426 is($invoice->amount, 17.51, "${title}: amount");
427 is($paid_amount, -17.51, "${title}: paid amount");
428 is($invoice->paid, 17.51, "${title}: paid");
429 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
430 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
431 is($total, 0, "${title}: even balance");
435 # test 3 : two items, without skonto
436 sub test_default_invoice_two_items_19_7_without_skonto() {
437 reset_state() if $ALWAYS_RESET;
439 my $item1 = new_item(qty => 2.5);
440 my $item2 = new_item(qty => 1.2, part => $parts[1]);
441 my $invoice = new_invoice(
443 invoiceitems => [ $item1, $item2 ],
444 payment_id => $payment_terms->id,
449 my %params = ( chart_id => $bank_account->chart_id,
450 transdate => DateTime->today_local->to_kivitendo
453 $params{amount} = '19.44'; # pass full amount
454 $params{payment_type} = 'without_skonto';
456 $invoice->pay_invoice( %params );
458 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
459 my $total = total_amount($invoice->transactions);
461 my $title = 'default invoice, two items, 19/7% tax without skonto';
463 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
464 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
465 is($paid_amount, -19.44, "${title}: paid amount");
466 is($invoice->paid, 19.44, "${title}: paid");
467 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
468 is($total, 0, "${title}: even balance");
472 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
473 reset_state() if $ALWAYS_RESET;
475 my $item1 = new_item(qty => 2.5);
476 my $item2 = new_item(qty => 1.2, part => $parts[1]);
477 my $invoice = new_invoice(
479 invoiceitems => [ $item1, $item2 ],
480 payment_id => $payment_terms->id,
484 $invoice->pay_invoice( amount => '9.44',
485 payment_type => 'without_skonto',
486 chart_id => $bank_account->chart_id,
487 transdate => DateTime->today_local->to_kivitendo,
490 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
491 my $total = total_amount($invoice->transactions);
493 my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
495 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
496 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
497 is($paid_amount, -9.44, "${title}: paid amount");
498 is($invoice->paid, 9.44, "${title}: paid");
499 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
500 is($total, 0, "${title}: even balance");
504 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
505 reset_state() if $ALWAYS_RESET;
507 my $item1 = new_item(qty => 2.5);
508 my $item2 = new_item(qty => 1.2, part => $parts[1]);
509 my $invoice = new_invoice(
511 invoiceitems => [ $item1, $item2 ],
512 payment_id => $payment_terms->id,
516 $invoice->pay_invoice( amount => '9.44',
517 payment_type => 'without_skonto',
518 chart_id => $bank_account->chart_id,
519 transdate => DateTime->today_local->to_kivitendo
521 $invoice->pay_invoice( amount => '10.00',
522 chart_id => $bank_account->chart_id,
523 transdate => DateTime->today_local->to_kivitendo
526 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
527 my $total = total_amount($invoice->transactions);
529 my $title = 'default invoice, two items, 19/7% tax not included';
531 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
532 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
533 is($paid_amount, -19.44, "${title}: paid amount");
534 is($invoice->paid, 19.44, "${title}: paid");
535 is($number_of_payments, 2, "${title}: 2 AR_paid bookings");
536 is($total, 0, "${title}: even balance");
541 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
542 reset_state() if $ALWAYS_RESET;
544 my $item1 = new_item(qty => 2.5);
545 my $item2 = new_item(qty => 1.2, part => $parts[1]);
546 my $invoice = new_invoice(
548 invoiceitems => [ $item1, $item2 ],
549 payment_id => $payment_terms->id,
553 $invoice->pay_invoice( amount => '9.44',
554 payment_type => 'without_skonto',
555 chart_id => $bank_account->chart_id,
556 transdate => DateTime->today_local->to_kivitendo
558 $invoice->pay_invoice( amount => '8.73',
559 payment_type => 'without_skonto',
560 chart_id => $bank_account->chart_id,
561 transdate => DateTime->today_local->to_kivitendo
563 $invoice->pay_invoice( amount => $invoice->open_amount,
564 payment_type => 'difference_as_skonto',
565 chart_id => $bank_account->chart_id,
566 transdate => DateTime->today_local->to_kivitendo
569 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
570 my $total = total_amount($invoice->transactions);
572 my $title = 'default invoice, two items, 19/7% tax not included';
574 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
575 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
576 is($paid_amount, -19.44, "${title}: paid amount");
577 is($invoice->paid, 19.44, "${title}: paid");
578 is($number_of_payments, 4, "${title}: 4 AR_paid bookings");
579 is($total, 0, "${title}: even balance");
583 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
584 reset_state() if $ALWAYS_RESET;
586 # if there is only one cent left there can only be one skonto booking, the
587 # error handling should choose the highest amount, which is the 7% account
588 # (11.66) rather than the 19% account (5.85). The actual tax amount is
589 # higher for the 19% case, though (1.11 compared to 0.82)
591 my $item1 = new_item(qty => 2.5);
592 my $item2 = new_item(qty => 1.2, part => $parts[1]);
593 my $invoice = new_invoice(
595 invoiceitems => [ $item1, $item2 ],
596 payment_id => $payment_terms->id,
600 $invoice->pay_invoice( amount => '19.42',
601 payment_type => 'without_skonto',
602 chart_id => $bank_account->chart_id,
603 transdate => DateTime->today_local->to_kivitendo
605 $invoice->pay_invoice( amount => $invoice->open_amount,
606 payment_type => 'difference_as_skonto',
607 chart_id => $bank_account->chart_id,
608 transdate => DateTime->today_local->to_kivitendo
611 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
612 my $total = total_amount($invoice->transactions);
614 my $title = 'default invoice, two items, 19/7% tax not included';
616 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
617 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
618 is($paid_amount, -19.44, "${title}: paid amount");
619 is($invoice->paid, 19.44, "${title}: paid");
620 is($number_of_payments, 3, "${title}: 2 AR_paid bookings");
621 is($total, 0, "${title}: even balance");
625 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
626 reset_state() if $ALWAYS_RESET;
628 # if there are two cents left there will be two skonto bookings, 1 cent each
629 my $item1 = new_item(qty => 2.5);
630 my $item2 = new_item(qty => 1.2, part => $parts[1]);
631 my $invoice = new_invoice(
633 invoiceitems => [ $item1, $item2 ],
634 payment_id => $payment_terms->id,
638 $invoice->pay_invoice( amount => '19.42',
639 payment_type => 'without_skonto',
640 chart_id => $bank_account->chart_id,
641 transdate => DateTime->today_local->to_kivitendo
643 $invoice->pay_invoice( amount => $invoice->open_amount,
644 payment_type => 'difference_as_skonto',
645 chart_id => $bank_account->chart_id,
646 transdate => DateTime->today_local->to_kivitendo
649 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
650 my $total = total_amount($invoice->transactions);
652 my $title = 'default invoice, two items, 19/7% tax not included';
654 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
655 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
656 is($paid_amount, -19.44, "${title}: paid amount");
657 is($invoice->paid, 19.44, "${title}: paid");
658 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
659 is($total, 0, "${title}: even balance");
663 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
664 reset_state() if $ALWAYS_RESET;
666 my $item = new_item(qty => 2.5);
667 my $invoice = new_invoice(
669 invoiceitems => [ $item ],
670 payment_id => $payment_terms->id,
675 my %params = ( chart_id => $bank_account->chart_id,
676 transdate => DateTime->today_local->to_kivitendo
679 $params{amount} = '2.32';
680 $params{payment_type} = 'without_skonto';
681 $invoice->pay_invoice( %params );
683 $params{amount} = '3.81';
684 $params{payment_type} = 'without_skonto';
685 $invoice->pay_invoice( %params );
687 $params{amount} = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
688 $params{payment_type} = 'difference_as_skonto';
689 $invoice->pay_invoice( %params );
691 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
692 my $total = total_amount($invoice->transactions);
694 my $title = 'default invoice, one item, 19% tax, without_skonto';
696 is($invoice->netamount, 5.85, "${title}: netamount");
697 is($invoice->amount, 6.96, "${title}: amount");
698 is($paid_amount, -6.96, "${title}: paid amount");
699 is($number_of_payments, 3, "${title}: 3 AR_paid booking");
700 is($invoice->paid, 6.96, "${title}: paid");
701 is($total, 0, "${title}: even balance");
705 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
706 reset_state() if $ALWAYS_RESET;
708 my $item = new_item(qty => 2.5);
709 my $invoice = new_invoice(
711 invoiceitems => [ $item ],
712 payment_id => $payment_terms->id,
717 my %params = ( chart_id => $bank_account->chart_id,
718 transdate => DateTime->today_local->to_kivitendo
721 $params{amount} = '6.95';
722 $params{payment_type} = 'without_skonto';
723 $invoice->pay_invoice( %params );
725 $params{amount} = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
726 $params{payment_type} = 'difference_as_skonto';
727 $invoice->pay_invoice( %params );
729 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
730 my $total = total_amount($invoice->transactions);
732 my $title = 'default invoice, one item, 19% tax, without_skonto';
734 is($invoice->netamount, 5.85, "${title}: netamount");
735 is($invoice->amount, 6.96, "${title}: amount");
736 is($paid_amount, -6.96, "${title}: paid amount");
737 is($number_of_payments, 2, "${title}: 3 AR_paid booking");
738 is($invoice->paid, 6.96, "${title}: paid");
739 is($total, 0, "${title}: even balance");
743 # test 3 : two items, without skonto
744 sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
745 reset_state() if $ALWAYS_RESET;
747 my $purchase_invoice = new_purchase_invoice();
749 my %params = ( chart_id => $bank_account->chart_id,
750 transdate => DateTime->today_local->to_kivitendo
753 $params{amount} = '226'; # pass full amount
754 $params{payment_type} = 'without_skonto';
756 $purchase_invoice->pay_invoice( %params );
758 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
759 my $total = total_amount($purchase_invoice->transactions);
761 my $title = 'default invoice, two items, 19/7% tax without skonto';
763 is($paid_amount, 226, "${title}: paid amount");
764 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
765 is($total, 0, "${title}: even balance");
769 sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
770 reset_state() if $ALWAYS_RESET;
772 my $purchase_invoice = new_purchase_invoice();
774 my %params = ( chart_id => $bank_account->chart_id,
775 transdate => DateTime->today_local->to_kivitendo
778 # $params{amount} = '226'; # pass full amount
779 $params{payment_type} = 'with_skonto_pt';
781 $purchase_invoice->pay_invoice( %params );
783 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
784 my $total = total_amount($purchase_invoice->transactions);
786 my $title = 'default invoice, two items, 19/7% tax without skonto';
788 is($paid_amount, 226, "${title}: paid amount");
789 is($number_of_payments, 3, "${title}: 1 AP_paid bookings");
790 is($total, 0, "${title}: even balance");
794 sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
795 # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
796 reset_state() if $ALWAYS_RESET;
797 my $purchase_invoice = new_purchase_invoice();
798 $purchase_invoice->pay_invoice(
799 amount => ( $purchase_invoice->amount / 3 * 2),
800 payment_type => 'without_skonto',
801 chart_id => $bank_account->chart_id,
802 transdate => DateTime->today_local->to_kivitendo
804 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
805 my $total = total_amount($purchase_invoice->transactions);
807 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
809 is($paid_amount, 150.67, "${title}: paid amount");
810 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
811 is($total, 0, "${title}: even balance");
815 sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
816 reset_state() if $ALWAYS_RESET;
818 my $purchase_invoice = new_purchase_invoice();
820 # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
821 $purchase_invoice->pay_invoice(
822 amount => ( $purchase_invoice->amount / 3 * 2),
823 payment_type => 'without_skonto',
824 chart_id => $bank_account->chart_id,
825 transdate => DateTime->today_local->to_kivitendo
827 $purchase_invoice->pay_invoice(
828 amount => ( $purchase_invoice->amount / 5 ),
829 payment_type => 'without_skonto',
830 chart_id => $bank_account->chart_id,
831 transdate => DateTime->today_local->to_kivitendo
833 $purchase_invoice->pay_invoice(
834 payment_type => 'difference_as_skonto',
835 chart_id => $bank_account->chart_id,
836 transdate => DateTime->today_local->to_kivitendo
839 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
840 my $total = total_amount($purchase_invoice->transactions);
842 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
844 is($paid_amount, 226, "${title}: paid amount");
845 is($number_of_payments, 4, "${title}: 1 AP_paid bookings");
846 is($total, 0, "${title}: even balance");
851 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
852 reset_state() if $ALWAYS_RESET;
854 my $item1 = new_item(qty => 1, part => $parts[2]);
855 my $item2 = new_item(qty => 1, part => $parts[3]);
856 my $invoice = new_invoice(
858 invoiceitems => [ $item1, $item2 ],
859 payment_id => $payment_terms->id,
864 my %params = ( chart_id => $bank_account->chart_id,
865 transdate => DateTime->today_local->to_kivitendo
868 $params{amount} = $invoice->amount_less_skonto;
869 $params{payment_type} = 'with_skonto_pt';
871 $invoice->pay_invoice( %params );
873 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
874 my $total = total_amount($invoice->transactions);
876 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
878 is($invoice->netamount, 100, "${title}: netamount");
879 is($invoice->amount, 113, "${title}: amount");
880 is($paid_amount, -113, "${title}: paid amount");
881 is($invoice->paid, 113, "${title}: paid");
882 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
883 is($total, 0, "${title}: even balance");
887 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
888 reset_state() if $ALWAYS_RESET;
890 my $item1 = new_item(qty => 0.5, part => $parts[2]);
891 my $item2 = new_item(qty => 0.5, part => $parts[3]);
892 my $item3 = new_item(qty => 0.5, part => $parts[2]);
893 my $item4 = new_item(qty => 0.5, part => $parts[3]);
894 my $invoice = new_invoice(
896 invoiceitems => [ $item1, $item2, $item3, $item4 ],
897 payment_id => $payment_terms->id,
902 my %params = ( chart_id => $bank_account->chart_id,
903 transdate => DateTime->today_local->to_kivitendo
906 $params{amount} = $invoice->amount_less_skonto;
907 $params{payment_type} = 'with_skonto_pt';
909 $invoice->pay_invoice( %params );
911 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
912 my $total = total_amount($invoice->transactions);
914 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
916 is($invoice->netamount , 100 , "${title}: netamount");
917 is($invoice->amount , 113 , "${title}: amount");
918 is($paid_amount , -113 , "${title}: paid amount");
919 is($invoice->paid , 113 , "${title}: paid");
920 is($number_of_payments , 3 , "${title}: 3 AR_paid bookings");
921 is($total , 0 , "${title}: even balance");
924 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
925 reset_state() if $ALWAYS_RESET;
927 my $item1 = new_item(qty => 0.5, part => $parts[2]);
928 my $item2 = new_item(qty => 0.5, part => $parts[3]);
929 my $item3 = new_item(qty => 0.5, part => $parts[2]);
930 my $item4 = new_item(qty => 0.5, part => $parts[3]);
931 my $invoice = new_invoice(
933 invoiceitems => [ $item1, $item2, $item3, $item4 ],
934 payment_id => $payment_terms->id,
939 my %params = ( chart_id => $bank_account->chart_id,
940 transdate => DateTime->today_local->to_kivitendo
943 $params{amount} = $invoice->amount_less_skonto;
944 $params{payment_type} = 'with_skonto_pt';
946 $invoice->pay_invoice( %params );
948 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
949 my $total = total_amount($invoice->transactions);
951 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
953 is($invoice->netamount, 88.75, "${title}: netamount");
954 is($invoice->amount, 100, "${title}: amount");
955 is($paid_amount, -100, "${title}: paid amount");
956 is($invoice->paid, 100, "${title}: paid");
957 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
958 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
959 is($total, 0, "${title}: even balance");
963 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
964 reset_state() if $ALWAYS_RESET;
966 my $item1 = new_item(qty => 0.5, part => $parts[2]);
967 my $item2 = new_item(qty => 0.5, part => $parts[3]);
968 my $item3 = new_item(qty => 0.5, part => $parts[2]);
969 my $item4 = new_item(qty => 0.5, part => $parts[3]);
970 my $invoice = new_invoice(
972 invoiceitems => [ $item1, $item2, $item3, $item4 ],
973 payment_id => $payment_terms->id,
977 $invoice->pay_invoice( amount => '90',
978 payment_type => 'without_skonto',
979 chart_id => $bank_account->chart_id,
980 transdate => DateTime->today_local->to_kivitendo
982 $invoice->pay_invoice( payment_type => 'difference_as_skonto',
983 chart_id => $bank_account->chart_id,
984 transdate => DateTime->today_local->to_kivitendo
987 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
988 my $total = total_amount($invoice->transactions);
990 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
992 is($invoice->netamount, 100, "${title}: netamount");
993 is($invoice->amount, 113, "${title}: amount");
994 is($paid_amount, -113, "${title}: paid amount");
995 is($invoice->paid, 113, "${title}: paid");
996 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
997 is($total, 0, "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
1000 Support::TestSetup::login();
1003 # test cases: without_skonto
1004 test_default_invoice_one_item_19_without_skonto();
1005 test_default_invoice_two_items_19_7_tax_with_skonto();
1006 test_default_invoice_two_items_19_7_without_skonto();
1007 test_default_invoice_two_items_19_7_without_skonto_incomplete_payment();
1008 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments();
1009 test_default_purchase_invoice_two_charts_19_7_without_skonto();
1010 test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto();
1011 test_default_invoice_one_item_19_without_skonto_overpaid();
1013 # test cases: difference_as_skonto
1014 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1015 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
1016 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
1017 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
1018 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
1019 test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1021 # test cases: with_skonto_pt
1022 test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
1023 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25();
1024 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple();
1025 test_default_purchase_invoice_two_charts_19_7_with_skonto();
1026 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included();
1027 test_default_invoice_two_items_19_7_tax_with_skonto_tax_included();
1029 # remove all created data at end of test