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 is($total, 0, "${title}: even balance");
433 # test 3 : two items, without skonto
434 sub test_default_invoice_two_items_19_7_without_skonto() {
435 reset_state() if $ALWAYS_RESET;
437 my $item1 = new_item(qty => 2.5);
438 my $item2 = new_item(qty => 1.2, part => $parts[1]);
439 my $invoice = new_invoice(
441 invoiceitems => [ $item1, $item2 ],
442 payment_id => $payment_terms->id,
447 my %params = ( chart_id => $bank_account->chart_id,
448 transdate => DateTime->today_local->to_kivitendo
451 $params{amount} = '19.44'; # pass full amount
452 $params{payment_type} = 'without_skonto';
454 $invoice->pay_invoice( %params );
456 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
457 my $total = total_amount($invoice->transactions);
459 my $title = 'default invoice, two items, 19/7% tax without skonto';
461 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
462 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
463 is($paid_amount, -19.44, "${title}: paid amount");
464 is($invoice->paid, 19.44, "${title}: paid");
465 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
466 is($total, 0, "${title}: even balance");
470 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
471 reset_state() if $ALWAYS_RESET;
473 my $item1 = new_item(qty => 2.5);
474 my $item2 = new_item(qty => 1.2, part => $parts[1]);
475 my $invoice = new_invoice(
477 invoiceitems => [ $item1, $item2 ],
478 payment_id => $payment_terms->id,
482 $invoice->pay_invoice( amount => '9.44',
483 payment_type => 'without_skonto',
484 chart_id => $bank_account->chart_id,
485 transdate => DateTime->today_local->to_kivitendo,
488 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
489 my $total = total_amount($invoice->transactions);
491 my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
493 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
494 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
495 is($paid_amount, -9.44, "${title}: paid amount");
496 is($invoice->paid, 9.44, "${title}: paid");
497 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
498 is($total, 0, "${title}: even balance");
502 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
503 reset_state() if $ALWAYS_RESET;
505 my $item1 = new_item(qty => 2.5);
506 my $item2 = new_item(qty => 1.2, part => $parts[1]);
507 my $invoice = new_invoice(
509 invoiceitems => [ $item1, $item2 ],
510 payment_id => $payment_terms->id,
514 $invoice->pay_invoice( amount => '9.44',
515 payment_type => 'without_skonto',
516 chart_id => $bank_account->chart_id,
517 transdate => DateTime->today_local->to_kivitendo
519 $invoice->pay_invoice( amount => '10.00',
520 chart_id => $bank_account->chart_id,
521 transdate => DateTime->today_local->to_kivitendo
524 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
525 my $total = total_amount($invoice->transactions);
527 my $title = 'default invoice, two items, 19/7% tax not included';
529 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
530 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
531 is($paid_amount, -19.44, "${title}: paid amount");
532 is($invoice->paid, 19.44, "${title}: paid");
533 is($number_of_payments, 2, "${title}: 2 AR_paid bookings");
534 is($total, 0, "${title}: even balance");
539 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
540 reset_state() if $ALWAYS_RESET;
542 my $item1 = new_item(qty => 2.5);
543 my $item2 = new_item(qty => 1.2, part => $parts[1]);
544 my $invoice = new_invoice(
546 invoiceitems => [ $item1, $item2 ],
547 payment_id => $payment_terms->id,
551 $invoice->pay_invoice( amount => '9.44',
552 payment_type => 'without_skonto',
553 chart_id => $bank_account->chart_id,
554 transdate => DateTime->today_local->to_kivitendo
556 $invoice->pay_invoice( amount => '8.73',
557 payment_type => 'without_skonto',
558 chart_id => $bank_account->chart_id,
559 transdate => DateTime->today_local->to_kivitendo
561 $invoice->pay_invoice( amount => $invoice->open_amount,
562 payment_type => 'difference_as_skonto',
563 chart_id => $bank_account->chart_id,
564 transdate => DateTime->today_local->to_kivitendo
567 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
568 my $total = total_amount($invoice->transactions);
570 my $title = 'default invoice, two items, 19/7% tax not included';
572 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
573 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
574 is($paid_amount, -19.44, "${title}: paid amount");
575 is($invoice->paid, 19.44, "${title}: paid");
576 is($number_of_payments, 4, "${title}: 4 AR_paid bookings");
577 is($total, 0, "${title}: even balance");
581 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
582 reset_state() if $ALWAYS_RESET;
584 # if there is only one cent left there can only be one skonto booking, the
585 # error handling should choose the highest amount, which is the 7% account
586 # (11.66) rather than the 19% account (5.85). The actual tax amount is
587 # higher for the 19% case, though (1.11 compared to 0.82)
589 my $item1 = new_item(qty => 2.5);
590 my $item2 = new_item(qty => 1.2, part => $parts[1]);
591 my $invoice = new_invoice(
593 invoiceitems => [ $item1, $item2 ],
594 payment_id => $payment_terms->id,
598 $invoice->pay_invoice( amount => '19.42',
599 payment_type => 'without_skonto',
600 chart_id => $bank_account->chart_id,
601 transdate => DateTime->today_local->to_kivitendo
603 $invoice->pay_invoice( amount => $invoice->open_amount,
604 payment_type => 'difference_as_skonto',
605 chart_id => $bank_account->chart_id,
606 transdate => DateTime->today_local->to_kivitendo
609 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
610 my $total = total_amount($invoice->transactions);
612 my $title = 'default invoice, two items, 19/7% tax not included';
614 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
615 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
616 is($paid_amount, -19.44, "${title}: paid amount");
617 is($invoice->paid, 19.44, "${title}: paid");
618 is($number_of_payments, 3, "${title}: 2 AR_paid bookings");
619 is($total, 0, "${title}: even balance");
623 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
624 reset_state() if $ALWAYS_RESET;
626 # if there are two cents left there will be two skonto bookings, 1 cent each
627 my $item1 = new_item(qty => 2.5);
628 my $item2 = new_item(qty => 1.2, part => $parts[1]);
629 my $invoice = new_invoice(
631 invoiceitems => [ $item1, $item2 ],
632 payment_id => $payment_terms->id,
636 $invoice->pay_invoice( amount => '19.42',
637 payment_type => 'without_skonto',
638 chart_id => $bank_account->chart_id,
639 transdate => DateTime->today_local->to_kivitendo
641 $invoice->pay_invoice( amount => $invoice->open_amount,
642 payment_type => 'difference_as_skonto',
643 chart_id => $bank_account->chart_id,
644 transdate => DateTime->today_local->to_kivitendo
647 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
648 my $total = total_amount($invoice->transactions);
650 my $title = 'default invoice, two items, 19/7% tax not included';
652 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
653 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
654 is($paid_amount, -19.44, "${title}: paid amount");
655 is($invoice->paid, 19.44, "${title}: paid");
656 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
657 is($total, 0, "${title}: even balance");
661 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
662 reset_state() if $ALWAYS_RESET;
664 my $item = new_item(qty => 2.5);
665 my $invoice = new_invoice(
667 invoiceitems => [ $item ],
668 payment_id => $payment_terms->id,
673 my %params = ( chart_id => $bank_account->chart_id,
674 transdate => DateTime->today_local->to_kivitendo
677 $params{amount} = '2.32';
678 $params{payment_type} = 'without_skonto';
679 $invoice->pay_invoice( %params );
681 $params{amount} = '3.81';
682 $params{payment_type} = 'without_skonto';
683 $invoice->pay_invoice( %params );
685 $params{amount} = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
686 $params{payment_type} = 'difference_as_skonto';
687 $invoice->pay_invoice( %params );
689 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
690 my $total = total_amount($invoice->transactions);
692 my $title = 'default invoice, one item, 19% tax, without_skonto';
694 is($invoice->netamount, 5.85, "${title}: netamount");
695 is($invoice->amount, 6.96, "${title}: amount");
696 is($paid_amount, -6.96, "${title}: paid amount");
697 is($number_of_payments, 3, "${title}: 3 AR_paid booking");
698 is($invoice->paid, 6.96, "${title}: paid");
699 is($total, 0, "${title}: even balance");
703 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
704 reset_state() if $ALWAYS_RESET;
706 my $item = new_item(qty => 2.5);
707 my $invoice = new_invoice(
709 invoiceitems => [ $item ],
710 payment_id => $payment_terms->id,
715 my %params = ( chart_id => $bank_account->chart_id,
716 transdate => DateTime->today_local->to_kivitendo
719 $params{amount} = '6.95';
720 $params{payment_type} = 'without_skonto';
721 $invoice->pay_invoice( %params );
723 $params{amount} = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
724 $params{payment_type} = 'difference_as_skonto';
725 $invoice->pay_invoice( %params );
727 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
728 my $total = total_amount($invoice->transactions);
730 my $title = 'default invoice, one item, 19% tax, without_skonto';
732 is($invoice->netamount, 5.85, "${title}: netamount");
733 is($invoice->amount, 6.96, "${title}: amount");
734 is($paid_amount, -6.96, "${title}: paid amount");
735 is($number_of_payments, 2, "${title}: 3 AR_paid booking");
736 is($invoice->paid, 6.96, "${title}: paid");
737 is($total, 0, "${title}: even balance");
741 # test 3 : two items, without skonto
742 sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
743 reset_state() if $ALWAYS_RESET;
745 my $purchase_invoice = new_purchase_invoice();
747 my %params = ( chart_id => $bank_account->chart_id,
748 transdate => DateTime->today_local->to_kivitendo
751 $params{amount} = '226'; # pass full amount
752 $params{payment_type} = 'without_skonto';
754 $purchase_invoice->pay_invoice( %params );
756 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
757 my $total = total_amount($purchase_invoice->transactions);
759 my $title = 'default invoice, two items, 19/7% tax without skonto';
761 is($paid_amount, 226, "${title}: paid amount");
762 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
763 is($total, 0, "${title}: even balance");
767 sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
768 reset_state() if $ALWAYS_RESET;
770 my $purchase_invoice = new_purchase_invoice();
772 my %params = ( chart_id => $bank_account->chart_id,
773 transdate => DateTime->today_local->to_kivitendo
776 # $params{amount} = '226'; # pass full amount
777 $params{payment_type} = 'with_skonto_pt';
779 $purchase_invoice->pay_invoice( %params );
781 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
782 my $total = total_amount($purchase_invoice->transactions);
784 my $title = 'default invoice, two items, 19/7% tax without skonto';
786 is($paid_amount, 226, "${title}: paid amount");
787 is($number_of_payments, 3, "${title}: 1 AP_paid bookings");
788 is($total, 0, "${title}: even balance");
792 sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
793 # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
794 reset_state() if $ALWAYS_RESET;
795 my $purchase_invoice = new_purchase_invoice();
796 $purchase_invoice->pay_invoice(
797 amount => ( $purchase_invoice->amount / 3 * 2),
798 payment_type => 'without_skonto',
799 chart_id => $bank_account->chart_id,
800 transdate => DateTime->today_local->to_kivitendo
802 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
803 my $total = total_amount($purchase_invoice->transactions);
805 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
807 is($paid_amount, 150.67, "${title}: paid amount");
808 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
809 is($total, 0, "${title}: even balance");
813 sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
814 reset_state() if $ALWAYS_RESET;
816 my $purchase_invoice = new_purchase_invoice();
818 # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
819 $purchase_invoice->pay_invoice(
820 amount => ( $purchase_invoice->amount / 3 * 2),
821 payment_type => 'without_skonto',
822 chart_id => $bank_account->chart_id,
823 transdate => DateTime->today_local->to_kivitendo
825 $purchase_invoice->pay_invoice(
826 amount => ( $purchase_invoice->amount / 5 ),
827 payment_type => 'without_skonto',
828 chart_id => $bank_account->chart_id,
829 transdate => DateTime->today_local->to_kivitendo
831 $purchase_invoice->pay_invoice(
832 payment_type => 'difference_as_skonto',
833 chart_id => $bank_account->chart_id,
834 transdate => DateTime->today_local->to_kivitendo
837 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
838 my $total = total_amount($purchase_invoice->transactions);
840 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
842 is($paid_amount, 226, "${title}: paid amount");
843 is($number_of_payments, 4, "${title}: 1 AP_paid bookings");
844 is($total, 0, "${title}: even balance");
849 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
850 reset_state() if $ALWAYS_RESET;
852 my $item1 = new_item(qty => 1, part => $parts[2]);
853 my $item2 = new_item(qty => 1, part => $parts[3]);
854 my $invoice = new_invoice(
856 invoiceitems => [ $item1, $item2 ],
857 payment_id => $payment_terms->id,
862 my %params = ( chart_id => $bank_account->chart_id,
863 transdate => DateTime->today_local->to_kivitendo
866 $params{amount} = $invoice->amount_less_skonto;
867 $params{payment_type} = 'with_skonto_pt';
869 $invoice->pay_invoice( %params );
871 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
872 my $total = total_amount($invoice->transactions);
874 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
876 is($invoice->netamount, 100, "${title}: netamount");
877 is($invoice->amount, 113, "${title}: amount");
878 is($paid_amount, -113, "${title}: paid amount");
879 is($invoice->paid, 113, "${title}: paid");
880 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
881 is($total, 0, "${title}: even balance");
885 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
886 reset_state() if $ALWAYS_RESET;
888 my $item1 = new_item(qty => 0.5, part => $parts[2]);
889 my $item2 = new_item(qty => 0.5, part => $parts[3]);
890 my $item3 = new_item(qty => 0.5, part => $parts[2]);
891 my $item4 = new_item(qty => 0.5, part => $parts[3]);
892 my $invoice = new_invoice(
894 invoiceitems => [ $item1, $item2, $item3, $item4 ],
895 payment_id => $payment_terms->id,
900 my %params = ( chart_id => $bank_account->chart_id,
901 transdate => DateTime->today_local->to_kivitendo
904 $params{amount} = $invoice->amount_less_skonto;
905 $params{payment_type} = 'with_skonto_pt';
907 $invoice->pay_invoice( %params );
909 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
910 my $total = total_amount($invoice->transactions);
912 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
914 is($invoice->netamount , 100 , "${title}: netamount");
915 is($invoice->amount , 113 , "${title}: amount");
916 is($paid_amount , -113 , "${title}: paid amount");
917 is($invoice->paid , 113 , "${title}: paid");
918 is($number_of_payments , 3 , "${title}: 3 AR_paid bookings");
919 is($total , 0 , "${title}: even balance");
922 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
923 reset_state() if $ALWAYS_RESET;
925 my $item1 = new_item(qty => 0.5, part => $parts[2]);
926 my $item2 = new_item(qty => 0.5, part => $parts[3]);
927 my $item3 = new_item(qty => 0.5, part => $parts[2]);
928 my $item4 = new_item(qty => 0.5, part => $parts[3]);
929 my $invoice = new_invoice(
931 invoiceitems => [ $item1, $item2, $item3, $item4 ],
932 payment_id => $payment_terms->id,
937 my %params = ( chart_id => $bank_account->chart_id,
938 transdate => DateTime->today_local->to_kivitendo
941 $params{amount} = $invoice->amount_less_skonto;
942 $params{payment_type} = 'with_skonto_pt';
944 $invoice->pay_invoice( %params );
946 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
947 my $total = total_amount($invoice->transactions);
949 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
951 is($invoice->netamount, 88.75, "${title}: netamount");
952 is($invoice->amount, 100, "${title}: amount");
953 is($paid_amount, -100, "${title}: paid amount");
954 is($invoice->paid, 100, "${title}: paid");
955 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
956 # currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct
957 is($total, 0, "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
960 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
961 reset_state() if $ALWAYS_RESET;
963 my $item1 = new_item(qty => 0.5, part => $parts[2]);
964 my $item2 = new_item(qty => 0.5, part => $parts[3]);
965 my $item3 = new_item(qty => 0.5, part => $parts[2]);
966 my $item4 = new_item(qty => 0.5, part => $parts[3]);
967 my $invoice = new_invoice(
969 invoiceitems => [ $item1, $item2, $item3, $item4 ],
970 payment_id => $payment_terms->id,
974 $invoice->pay_invoice( amount => '90',
975 payment_type => 'without_skonto',
976 chart_id => $bank_account->chart_id,
977 transdate => DateTime->today_local->to_kivitendo
979 $invoice->pay_invoice( payment_type => 'difference_as_skonto',
980 chart_id => $bank_account->chart_id,
981 transdate => DateTime->today_local->to_kivitendo
984 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
985 my $total = total_amount($invoice->transactions);
987 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
989 is($invoice->netamount, 100, "${title}: netamount");
990 is($invoice->amount, 113, "${title}: amount");
991 is($paid_amount, -113, "${title}: paid amount");
992 is($invoice->paid, 113, "${title}: paid");
993 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
994 is($total, 0, "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
997 Support::TestSetup::login();
1000 # test cases: without_skonto
1001 test_default_invoice_one_item_19_without_skonto();
1002 test_default_invoice_two_items_19_7_tax_with_skonto();
1003 test_default_invoice_two_items_19_7_without_skonto();
1004 test_default_invoice_two_items_19_7_without_skonto_incomplete_payment();
1005 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments();
1006 test_default_purchase_invoice_two_charts_19_7_without_skonto();
1007 test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto();
1008 test_default_invoice_one_item_19_without_skonto_overpaid();
1010 # test cases: difference_as_skonto
1011 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1012 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
1013 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
1014 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
1015 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
1016 test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1018 # test cases: with_skonto_pt
1019 test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
1020 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25();
1021 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple();
1022 test_default_purchase_invoice_two_charts_19_7_with_skonto();
1023 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included();
1024 test_default_invoice_two_items_19_7_tax_with_skonto_tax_included();
1026 # remove all created data at end of test