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',
87 auto_calculation => 1,
90 $vendor = SL::DB::Vendor->new(
91 name => 'Test Vendor',
92 currency_id => $currency_id,
93 taxzone_id => $taxzone->id,
94 payment_id => $payment_terms->id,
100 push @parts, SL::DB::Part->new(
101 partnumber => 'T4254',
102 description => 'Fourty-two fifty-four',
105 buchungsgruppen_id => $buchungsgruppe->id,
110 push @parts, SL::DB::Part->new(
111 partnumber => 'T0815',
112 description => 'Zero EIGHT fifteeN @ 7%',
115 buchungsgruppen_id => $buchungsgruppe7->id,
119 push @parts, SL::DB::Part->new(
121 description => 'Testware 19%',
124 buchungsgruppen_id => $buchungsgruppe->id,
128 push @parts, SL::DB::Part->new(
130 description => 'Testware 7%',
133 buchungsgruppen_id => $buchungsgruppe7->id,
138 $reset_state_counter++;
144 return SL::DB::Invoice->new(
145 customer_id => $customer->id,
146 currency_id => $currency_id,
147 employee_id => $employee->id,
148 salesman_id => $employee->id,
149 gldate => DateTime->today_local->to_kivitendo,
150 taxzone_id => $taxzone->id,
151 transdate => DateTime->today_local->to_kivitendo,
159 sub new_purchase_invoice {
161 # manually create a Kreditorenbuchung from scratch, ap + acc_trans bookings, as no helper exists yet, like $invoice->post.
162 # arap-Booking must come last in the acc_trans order
163 $purchase_invoice_counter++;
165 my $purchase_invoice = SL::DB::PurchaseInvoice->new(
166 vendor_id => $vendor->id,
167 invnumber => 'newap ' . $purchase_invoice_counter ,
168 currency_id => $currency_id,
169 employee_id => $employee->id,
170 gldate => DateTime->today_local->to_kivitendo,
171 taxzone_id => $taxzone->id,
172 transdate => DateTime->today_local->to_kivitendo,
182 my $today = DateTime->today_local->to_kivitendo;
183 my $expense_chart = SL::DB::Manager::Chart->find_by(accno => '3400');
184 my $expense_chart_booking= SL::DB::AccTransaction->new(
185 trans_id => $purchase_invoice->id,
186 chart_id => $expense_chart->id,
187 chart_link => $expense_chart->link,
192 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
193 $expense_chart_booking->save;
195 my $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1576');
196 my $tax_chart_booking= SL::DB::AccTransaction->new(
197 trans_id => $purchase_invoice->id,
198 chart_id => $tax_chart->id,
199 chart_link => $tax_chart->link,
204 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
205 $tax_chart_booking->save;
206 $expense_chart = SL::DB::Manager::Chart->find_by(accno => '3300');
207 $expense_chart_booking= SL::DB::AccTransaction->new(
208 trans_id => $purchase_invoice->id,
209 chart_id => $expense_chart->id,
210 chart_link => $expense_chart->link,
215 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
216 $expense_chart_booking->save;
219 $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1571');
220 $tax_chart_booking= SL::DB::AccTransaction->new(
221 trans_id => $purchase_invoice->id,
222 chart_id => $tax_chart->id,
223 chart_link => $tax_chart->link,
228 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
229 $tax_chart_booking->save;
230 my $arap_chart = SL::DB::Manager::Chart->find_by(accno => '1600');
231 my $arap_booking= SL::DB::AccTransaction->new(trans_id => $purchase_invoice->id,
232 chart_id => $arap_chart->id,
233 chart_link => $arap_chart->link,
238 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
241 return $purchase_invoice;
247 my $part = delete($params{part}) || $parts[0];
249 return SL::DB::InvoiceItem->new(
250 parts_id => $part->id,
251 lastcost => $part->lastcost,
252 sellprice => $part->sellprice,
253 description => $part->description,
259 sub number_of_payments {
260 my $transactions = shift;
262 my $number_of_payments;
264 foreach my $transaction ( @$transactions ) {
265 if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
266 $paid_amount += $transaction->amount ;
267 $number_of_payments++;
270 return ($number_of_payments, $paid_amount);
274 my $transactions = shift;
276 my $total = sum map { $_->amount } @$transactions;
278 return $::form->round_amount($total, 5);
284 sub test_default_invoice_one_item_19_without_skonto() {
285 reset_state() if $ALWAYS_RESET;
287 my $item = new_item(qty => 2.5);
288 my $invoice = new_invoice(
290 invoiceitems => [ $item ],
291 payment_id => $payment_terms->id,
295 my $purchase_invoice = new_purchase_invoice();
299 my %params = ( chart_id => $bank_account->chart_id,
300 transdate => DateTime->today_local->to_kivitendo
303 $params{amount} = '6.96';
304 $params{payment_type} = 'without_skonto';
306 $invoice->pay_invoice( %params );
308 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
309 my $total = total_amount($invoice->transactions);
311 my $title = 'default invoice, one item, 19% tax, without_skonto';
313 is($invoice->netamount, 5.85, "${title}: netamount");
314 is($invoice->amount, 6.96, "${title}: amount");
315 is($paid_amount, -6.96, "${title}: paid amount");
316 is($number_of_payments, 1, "${title}: 1 AR_paid booking");
317 is($invoice->paid, 6.96, "${title}: paid");
318 is($total, 0, "${title}: even balance");
322 sub test_default_invoice_one_item_19_without_skonto_overpaid() {
323 reset_state() if $ALWAYS_RESET;
325 my $item = new_item(qty => 2.5);
326 my $invoice = new_invoice(
328 invoiceitems => [ $item ],
329 payment_id => $payment_terms->id,
333 my $purchase_invoice = new_purchase_invoice();
337 my %params = ( chart_id => $bank_account->chart_id,
338 transdate => DateTime->today_local->to_kivitendo
341 $params{amount} = '16.96';
342 $params{payment_type} = 'without_skonto';
343 $invoice->pay_invoice( %params );
345 $params{amount} = '-10.00';
346 $invoice->pay_invoice( %params );
348 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
349 my $total = total_amount($invoice->transactions);
351 my $title = 'default invoice, one item, 19% tax, without_skonto';
353 is($invoice->netamount, 5.85, "${title}: netamount");
354 is($invoice->amount, 6.96, "${title}: amount");
355 is($paid_amount, -6.96, "${title}: paid amount");
356 is($number_of_payments, 2, "${title}: 1 AR_paid booking");
357 is($invoice->paid, 6.96, "${title}: paid");
358 is($total, 0, "${title}: even balance");
364 sub test_default_invoice_two_items_19_7_tax_with_skonto() {
365 reset_state() if $ALWAYS_RESET;
367 my $item1 = new_item(qty => 2.5);
368 my $item2 = new_item(qty => 1.2, part => $parts[1]);
369 my $invoice = new_invoice(
371 invoiceitems => [ $item1, $item2 ],
372 payment_id => $payment_terms->id,
377 my %params = ( chart_id => $bank_account->chart_id,
378 transdate => DateTime->today_local->to_kivitendo
381 $params{payment_type} = 'with_skonto_pt';
382 $params{amount} = $invoice->amount_less_skonto;
384 $invoice->pay_invoice( %params );
386 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
387 my $total = total_amount($invoice->transactions);
389 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
391 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
392 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
393 is($paid_amount, -19.44, "${title}: paid amount");
394 is($invoice->paid, 19.44, "${title}: paid");
395 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
396 is($total, 0, "${title}: even balance");
399 sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included() {
400 reset_state() if $ALWAYS_RESET;
402 my $item1 = new_item(qty => 2.5);
403 my $item2 = new_item(qty => 1.2, part => $parts[1]);
404 my $invoice = new_invoice(
406 invoiceitems => [ $item1, $item2 ],
407 payment_id => $payment_terms->id,
412 my %params = ( chart_id => $bank_account->chart_id,
413 transdate => DateTime->today_local->to_kivitendo
416 $params{payment_type} = 'with_skonto_pt';
417 $params{amount} = $invoice->amount_less_skonto;
419 $invoice->pay_invoice( %params );
421 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
422 my $total = total_amount($invoice->transactions);
424 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
426 is($invoice->netamount, 15.82, "${title}: netamount");
427 is($invoice->amount, 17.51, "${title}: amount");
428 is($paid_amount, -17.51, "${title}: paid amount");
429 is($invoice->paid, 17.51, "${title}: paid");
430 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
431 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
432 is($total, 0, "${title}: even balance");
436 # test 3 : two items, without skonto
437 sub test_default_invoice_two_items_19_7_without_skonto() {
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{amount} = '19.44'; # pass full amount
455 $params{payment_type} = 'without_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 invoice, two items, 19/7% tax without skonto';
464 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
465 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
466 is($paid_amount, -19.44, "${title}: paid amount");
467 is($invoice->paid, 19.44, "${title}: paid");
468 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
469 is($total, 0, "${title}: even balance");
473 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
474 reset_state() if $ALWAYS_RESET;
476 my $item1 = new_item(qty => 2.5);
477 my $item2 = new_item(qty => 1.2, part => $parts[1]);
478 my $invoice = new_invoice(
480 invoiceitems => [ $item1, $item2 ],
481 payment_id => $payment_terms->id,
485 $invoice->pay_invoice( amount => '9.44',
486 payment_type => 'without_skonto',
487 chart_id => $bank_account->chart_id,
488 transdate => DateTime->today_local->to_kivitendo,
491 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
492 my $total = total_amount($invoice->transactions);
494 my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
496 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
497 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
498 is($paid_amount, -9.44, "${title}: paid amount");
499 is($invoice->paid, 9.44, "${title}: paid");
500 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
501 is($total, 0, "${title}: even balance");
505 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
506 reset_state() if $ALWAYS_RESET;
508 my $item1 = new_item(qty => 2.5);
509 my $item2 = new_item(qty => 1.2, part => $parts[1]);
510 my $invoice = new_invoice(
512 invoiceitems => [ $item1, $item2 ],
513 payment_id => $payment_terms->id,
517 $invoice->pay_invoice( amount => '9.44',
518 payment_type => 'without_skonto',
519 chart_id => $bank_account->chart_id,
520 transdate => DateTime->today_local->to_kivitendo
522 $invoice->pay_invoice( amount => '10.00',
523 chart_id => $bank_account->chart_id,
524 transdate => DateTime->today_local->to_kivitendo
527 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
528 my $total = total_amount($invoice->transactions);
530 my $title = 'default invoice, two items, 19/7% tax not included';
532 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
533 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
534 is($paid_amount, -19.44, "${title}: paid amount");
535 is($invoice->paid, 19.44, "${title}: paid");
536 is($number_of_payments, 2, "${title}: 2 AR_paid bookings");
537 is($total, 0, "${title}: even balance");
542 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
543 reset_state() if $ALWAYS_RESET;
545 my $item1 = new_item(qty => 2.5);
546 my $item2 = new_item(qty => 1.2, part => $parts[1]);
547 my $invoice = new_invoice(
549 invoiceitems => [ $item1, $item2 ],
550 payment_id => $payment_terms->id,
554 $invoice->pay_invoice( amount => '9.44',
555 payment_type => 'without_skonto',
556 chart_id => $bank_account->chart_id,
557 transdate => DateTime->today_local->to_kivitendo
559 $invoice->pay_invoice( amount => '8.73',
560 payment_type => 'without_skonto',
561 chart_id => $bank_account->chart_id,
562 transdate => DateTime->today_local->to_kivitendo
564 $invoice->pay_invoice( amount => $invoice->open_amount,
565 payment_type => 'difference_as_skonto',
566 chart_id => $bank_account->chart_id,
567 transdate => DateTime->today_local->to_kivitendo
570 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
571 my $total = total_amount($invoice->transactions);
573 my $title = 'default invoice, two items, 19/7% tax not included';
575 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
576 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
577 is($paid_amount, -19.44, "${title}: paid amount");
578 is($invoice->paid, 19.44, "${title}: paid");
579 is($number_of_payments, 4, "${title}: 4 AR_paid bookings");
580 is($total, 0, "${title}: even balance");
584 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
585 reset_state() if $ALWAYS_RESET;
587 # if there is only one cent left there can only be one skonto booking, the
588 # error handling should choose the highest amount, which is the 7% account
589 # (11.66) rather than the 19% account (5.85). The actual tax amount is
590 # higher for the 19% case, though (1.11 compared to 0.82)
592 my $item1 = new_item(qty => 2.5);
593 my $item2 = new_item(qty => 1.2, part => $parts[1]);
594 my $invoice = new_invoice(
596 invoiceitems => [ $item1, $item2 ],
597 payment_id => $payment_terms->id,
601 $invoice->pay_invoice( amount => '19.42',
602 payment_type => 'without_skonto',
603 chart_id => $bank_account->chart_id,
604 transdate => DateTime->today_local->to_kivitendo
606 $invoice->pay_invoice( amount => $invoice->open_amount,
607 payment_type => 'difference_as_skonto',
608 chart_id => $bank_account->chart_id,
609 transdate => DateTime->today_local->to_kivitendo
612 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
613 my $total = total_amount($invoice->transactions);
615 my $title = 'default invoice, two items, 19/7% tax not included';
617 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
618 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
619 is($paid_amount, -19.44, "${title}: paid amount");
620 is($invoice->paid, 19.44, "${title}: paid");
621 is($number_of_payments, 3, "${title}: 2 AR_paid bookings");
622 is($total, 0, "${title}: even balance");
626 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
627 reset_state() if $ALWAYS_RESET;
629 # if there are two cents left there will be two skonto bookings, 1 cent each
630 my $item1 = new_item(qty => 2.5);
631 my $item2 = new_item(qty => 1.2, part => $parts[1]);
632 my $invoice = new_invoice(
634 invoiceitems => [ $item1, $item2 ],
635 payment_id => $payment_terms->id,
639 $invoice->pay_invoice( amount => '19.42',
640 payment_type => 'without_skonto',
641 chart_id => $bank_account->chart_id,
642 transdate => DateTime->today_local->to_kivitendo
644 $invoice->pay_invoice( amount => $invoice->open_amount,
645 payment_type => 'difference_as_skonto',
646 chart_id => $bank_account->chart_id,
647 transdate => DateTime->today_local->to_kivitendo
650 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
651 my $total = total_amount($invoice->transactions);
653 my $title = 'default invoice, two items, 19/7% tax not included';
655 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
656 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
657 is($paid_amount, -19.44, "${title}: paid amount");
658 is($invoice->paid, 19.44, "${title}: paid");
659 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
660 is($total, 0, "${title}: even balance");
664 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
665 reset_state() if $ALWAYS_RESET;
667 my $item = new_item(qty => 2.5);
668 my $invoice = new_invoice(
670 invoiceitems => [ $item ],
671 payment_id => $payment_terms->id,
676 my %params = ( chart_id => $bank_account->chart_id,
677 transdate => DateTime->today_local->to_kivitendo
680 $params{amount} = '2.32';
681 $params{payment_type} = 'without_skonto';
682 $invoice->pay_invoice( %params );
684 $params{amount} = '3.81';
685 $params{payment_type} = 'without_skonto';
686 $invoice->pay_invoice( %params );
688 $params{amount} = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
689 $params{payment_type} = 'difference_as_skonto';
690 $invoice->pay_invoice( %params );
692 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
693 my $total = total_amount($invoice->transactions);
695 my $title = 'default invoice, one item, 19% tax, without_skonto';
697 is($invoice->netamount, 5.85, "${title}: netamount");
698 is($invoice->amount, 6.96, "${title}: amount");
699 is($paid_amount, -6.96, "${title}: paid amount");
700 is($number_of_payments, 3, "${title}: 3 AR_paid booking");
701 is($invoice->paid, 6.96, "${title}: paid");
702 is($total, 0, "${title}: even balance");
706 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
707 reset_state() if $ALWAYS_RESET;
709 my $item = new_item(qty => 2.5);
710 my $invoice = new_invoice(
712 invoiceitems => [ $item ],
713 payment_id => $payment_terms->id,
718 my %params = ( chart_id => $bank_account->chart_id,
719 transdate => DateTime->today_local->to_kivitendo
722 $params{amount} = '6.95';
723 $params{payment_type} = 'without_skonto';
724 $invoice->pay_invoice( %params );
726 $params{amount} = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
727 $params{payment_type} = 'difference_as_skonto';
728 $invoice->pay_invoice( %params );
730 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
731 my $total = total_amount($invoice->transactions);
733 my $title = 'default invoice, one item, 19% tax, without_skonto';
735 is($invoice->netamount, 5.85, "${title}: netamount");
736 is($invoice->amount, 6.96, "${title}: amount");
737 is($paid_amount, -6.96, "${title}: paid amount");
738 is($number_of_payments, 2, "${title}: 3 AR_paid booking");
739 is($invoice->paid, 6.96, "${title}: paid");
740 is($total, 0, "${title}: even balance");
744 # test 3 : two items, without skonto
745 sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
746 reset_state() if $ALWAYS_RESET;
748 my $purchase_invoice = new_purchase_invoice();
750 my %params = ( chart_id => $bank_account->chart_id,
751 transdate => DateTime->today_local->to_kivitendo
754 $params{amount} = '226'; # pass full amount
755 $params{payment_type} = 'without_skonto';
757 $purchase_invoice->pay_invoice( %params );
759 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
760 my $total = total_amount($purchase_invoice->transactions);
762 my $title = 'default invoice, two items, 19/7% tax without skonto';
764 is($paid_amount, 226, "${title}: paid amount");
765 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
766 is($total, 0, "${title}: even balance");
770 sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
771 reset_state() if $ALWAYS_RESET;
773 my $purchase_invoice = new_purchase_invoice();
775 my %params = ( chart_id => $bank_account->chart_id,
776 transdate => DateTime->today_local->to_kivitendo
779 # $params{amount} = '226'; # pass full amount
780 $params{payment_type} = 'with_skonto_pt';
782 $purchase_invoice->pay_invoice( %params );
784 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
785 my $total = total_amount($purchase_invoice->transactions);
787 my $title = 'default invoice, two items, 19/7% tax without skonto';
789 is($paid_amount, 226, "${title}: paid amount");
790 is($number_of_payments, 3, "${title}: 1 AP_paid bookings");
791 is($total, 0, "${title}: even balance");
795 sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
796 # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
797 reset_state() if $ALWAYS_RESET;
798 my $purchase_invoice = new_purchase_invoice();
799 $purchase_invoice->pay_invoice(
800 amount => ( $purchase_invoice->amount / 3 * 2),
801 payment_type => 'without_skonto',
802 chart_id => $bank_account->chart_id,
803 transdate => DateTime->today_local->to_kivitendo
805 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
806 my $total = total_amount($purchase_invoice->transactions);
808 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
810 is($paid_amount, 150.67, "${title}: paid amount");
811 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
812 is($total, 0, "${title}: even balance");
816 sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
817 reset_state() if $ALWAYS_RESET;
819 my $purchase_invoice = new_purchase_invoice();
821 # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
822 $purchase_invoice->pay_invoice(
823 amount => ( $purchase_invoice->amount / 3 * 2),
824 payment_type => 'without_skonto',
825 chart_id => $bank_account->chart_id,
826 transdate => DateTime->today_local->to_kivitendo
828 $purchase_invoice->pay_invoice(
829 amount => ( $purchase_invoice->amount / 5 ),
830 payment_type => 'without_skonto',
831 chart_id => $bank_account->chart_id,
832 transdate => DateTime->today_local->to_kivitendo
834 $purchase_invoice->pay_invoice(
835 payment_type => 'difference_as_skonto',
836 chart_id => $bank_account->chart_id,
837 transdate => DateTime->today_local->to_kivitendo
840 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
841 my $total = total_amount($purchase_invoice->transactions);
843 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
845 is($paid_amount, 226, "${title}: paid amount");
846 is($number_of_payments, 4, "${title}: 1 AP_paid bookings");
847 is($total, 0, "${title}: even balance");
852 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
853 reset_state() if $ALWAYS_RESET;
855 my $item1 = new_item(qty => 1, part => $parts[2]);
856 my $item2 = new_item(qty => 1, part => $parts[3]);
857 my $invoice = new_invoice(
859 invoiceitems => [ $item1, $item2 ],
860 payment_id => $payment_terms->id,
865 my %params = ( chart_id => $bank_account->chart_id,
866 transdate => DateTime->today_local->to_kivitendo
869 $params{amount} = $invoice->amount_less_skonto;
870 $params{payment_type} = 'with_skonto_pt';
872 $invoice->pay_invoice( %params );
874 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
875 my $total = total_amount($invoice->transactions);
877 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
879 is($invoice->netamount, 100, "${title}: netamount");
880 is($invoice->amount, 113, "${title}: amount");
881 is($paid_amount, -113, "${title}: paid amount");
882 is($invoice->paid, 113, "${title}: paid");
883 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
884 is($total, 0, "${title}: even balance");
888 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
889 reset_state() if $ALWAYS_RESET;
891 my $item1 = new_item(qty => 0.5, part => $parts[2]);
892 my $item2 = new_item(qty => 0.5, part => $parts[3]);
893 my $item3 = new_item(qty => 0.5, part => $parts[2]);
894 my $item4 = new_item(qty => 0.5, part => $parts[3]);
895 my $invoice = new_invoice(
897 invoiceitems => [ $item1, $item2, $item3, $item4 ],
898 payment_id => $payment_terms->id,
903 my %params = ( chart_id => $bank_account->chart_id,
904 transdate => DateTime->today_local->to_kivitendo
907 $params{amount} = $invoice->amount_less_skonto;
908 $params{payment_type} = 'with_skonto_pt';
910 $invoice->pay_invoice( %params );
912 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
913 my $total = total_amount($invoice->transactions);
915 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
917 is($invoice->netamount , 100 , "${title}: netamount");
918 is($invoice->amount , 113 , "${title}: amount");
919 is($paid_amount , -113 , "${title}: paid amount");
920 is($invoice->paid , 113 , "${title}: paid");
921 is($number_of_payments , 3 , "${title}: 3 AR_paid bookings");
922 is($total , 0 , "${title}: even balance");
925 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
926 reset_state() if $ALWAYS_RESET;
928 my $item1 = new_item(qty => 0.5, part => $parts[2]);
929 my $item2 = new_item(qty => 0.5, part => $parts[3]);
930 my $item3 = new_item(qty => 0.5, part => $parts[2]);
931 my $item4 = new_item(qty => 0.5, part => $parts[3]);
932 my $invoice = new_invoice(
934 invoiceitems => [ $item1, $item2, $item3, $item4 ],
935 payment_id => $payment_terms->id,
940 my %params = ( chart_id => $bank_account->chart_id,
941 transdate => DateTime->today_local->to_kivitendo
944 $params{amount} = $invoice->amount_less_skonto;
945 $params{payment_type} = 'with_skonto_pt';
947 $invoice->pay_invoice( %params );
949 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
950 my $total = total_amount($invoice->transactions);
952 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
954 is($invoice->netamount, 88.75, "${title}: netamount");
955 is($invoice->amount, 100, "${title}: amount");
956 is($paid_amount, -100, "${title}: paid amount");
957 is($invoice->paid, 100, "${title}: paid");
958 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
959 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
960 is($total, 0, "${title}: even balance");
964 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
965 reset_state() if $ALWAYS_RESET;
967 my $item1 = new_item(qty => 0.5, part => $parts[2]);
968 my $item2 = new_item(qty => 0.5, part => $parts[3]);
969 my $item3 = new_item(qty => 0.5, part => $parts[2]);
970 my $item4 = new_item(qty => 0.5, part => $parts[3]);
971 my $invoice = new_invoice(
973 invoiceitems => [ $item1, $item2, $item3, $item4 ],
974 payment_id => $payment_terms->id,
978 $invoice->pay_invoice( amount => '90',
979 payment_type => 'without_skonto',
980 chart_id => $bank_account->chart_id,
981 transdate => DateTime->today_local->to_kivitendo
983 $invoice->pay_invoice( payment_type => 'difference_as_skonto',
984 chart_id => $bank_account->chart_id,
985 transdate => DateTime->today_local->to_kivitendo
988 my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
989 my $total = total_amount($invoice->transactions);
991 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
993 is($invoice->netamount, 100, "${title}: netamount");
994 is($invoice->amount, 113, "${title}: amount");
995 is($paid_amount, -113, "${title}: paid amount");
996 is($invoice->paid, 113, "${title}: paid");
997 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
998 is($total, 0, "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
1001 Support::TestSetup::login();
1004 # test cases: without_skonto
1005 test_default_invoice_one_item_19_without_skonto();
1006 test_default_invoice_two_items_19_7_tax_with_skonto();
1007 test_default_invoice_two_items_19_7_without_skonto();
1008 test_default_invoice_two_items_19_7_without_skonto_incomplete_payment();
1009 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments();
1010 test_default_purchase_invoice_two_charts_19_7_without_skonto();
1011 test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto();
1012 test_default_invoice_one_item_19_without_skonto_overpaid();
1014 # test cases: difference_as_skonto
1015 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1016 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
1017 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
1018 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
1019 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
1020 test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1022 # test cases: with_skonto_pt
1023 test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
1024 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25();
1025 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple();
1026 test_default_purchase_invoice_two_charts_19_7_with_skonto();
1027 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included();
1028 test_default_invoice_two_items_19_7_tax_with_skonto_tax_included();
1030 # remove all created data at end of test