9 use Support::TestSetup;
11 use List::Util qw(sum);
13 use SL::DB::Buchungsgruppe;
15 use SL::DB::Exchangerate;
23 use SL::DB::BankAccount;
24 use SL::DB::PaymentTerm;
25 use SL::DBUtils qw(selectfirst_array_query);
28 my ($customer, $vendor, $currency_id, @parts, $buchungsgruppe, $buchungsgruppe7, $unit, $employee, $tax, $tax7, $tax_9, $taxzone, $payment_terms, $bank_account);
29 my ($transdate1, $transdate2, $transdate3, $transdate4, $currency, $exchangerate, $exchangerate2, $exchangerate3, $exchangerate4);
30 my ($ar_chart,$bank,$ar_amount_chart, $ap_chart, $ap_amount_chart, $fxloss_chart, $fxgain_chart);
34 my $reset_state_counter = 0;
36 my $purchase_invoice_counter = 0; # used for generating purchase invnumber
39 SL::DB::Manager::InvoiceItem->delete_all(all => 1);
40 SL::DB::Manager::Invoice->delete_all(all => 1);
41 SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
42 SL::DB::Manager::Part->delete_all(all => 1);
43 SL::DB::Manager::Customer->delete_all(all => 1);
44 SL::DB::Manager::Vendor->delete_all(all => 1);
45 SL::DB::Manager::BankAccount->delete_all(all => 1);
46 SL::DB::Manager::PaymentTerm->delete_all(all => 1);
47 SL::DB::Manager::Exchangerate->delete_all(all => 1);
48 SL::DB::Manager::Currency->delete_all(where => [ name => 'CUR' ]);
54 return if $reset_state_counter;
56 $params{$_} ||= {} for qw(buchungsgruppe unit customer part tax vendor);
60 $transdate1 = DateTime->today;
61 $transdate2 = DateTime->today->add(days => 1);
62 $transdate3 = DateTime->today->add(days => 2);
63 $transdate4 = DateTime->today->add(days => 3);
65 $buchungsgruppe = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%', %{ $params{buchungsgruppe} }) || croak "No accounting group";
66 $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%') || croak "No accounting group for 7\%";
67 $unit = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} }) || croak "No unit";
68 $employee = SL::DB::Manager::Employee->current || croak "No employee";
69 $tax = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} }) || croak "No tax";
70 $tax7 = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07) || croak "No tax for 7\%";
71 $taxzone = SL::DB::Manager::TaxZone->find_by( description => 'Inland') || croak "No taxzone";
72 $tax_9 = SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.19, %{ $params{tax} }) || croak "No tax";
73 # $tax7 = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07) || croak "No tax for 7\%";
75 $currency_id = $::instance_conf->get_currency_id;
77 $currency = SL::DB::Currency->new(name => 'CUR')->save;
79 $fxgain_chart = SL::DB::Manager::Chart->find_by(accno => '2660') or die "Can't find fxgain_chart in test";
80 $fxloss_chart = SL::DB::Manager::Chart->find_by(accno => '2150') or die "Can't find fxloss_chart in test";
82 $currency->db->dbh->do('UPDATE defaults SET fxgain_accno_id = ' . $fxgain_chart->id);
83 $currency->db->dbh->do('UPDATE defaults SET fxloss_accno_id = ' . $fxloss_chart->id);
84 $::instance_conf->reload->data;
85 is($fxgain_chart->id, $::instance_conf->get_fxgain_accno_id, "fxgain_chart was updated in defaults");
86 is($fxloss_chart->id, $::instance_conf->get_fxloss_accno_id, "fxloss_chart was updated in defaults");
88 $exchangerate = SL::DB::Exchangerate->new(transdate => $transdate1,
91 currency_id => $currency->id,
93 $exchangerate2 = SL::DB::Exchangerate->new(transdate => $transdate2,
96 currency_id => $currency->id,
98 $exchangerate3 = SL::DB::Exchangerate->new(transdate => $transdate3,
101 currency_id => $currency->id,
103 $exchangerate4 = SL::DB::Exchangerate->new(transdate => $transdate4,
106 currency_id => $currency->id,
109 $customer = SL::DB::Customer->new(
110 name => 'Test Customer',
111 currency_id => $currency_id,
112 taxzone_id => $taxzone->id,
113 %{ $params{customer} }
116 $bank_account = SL::DB::BankAccount->new(
117 account_number => '123',
122 chart_id => SL::DB::Manager::Chart->find_by( description => 'Bank' )->id,
123 name => SL::DB::Manager::Chart->find_by( description => 'Bank' )->description,
126 $payment_terms = SL::DB::PaymentTerm->new(
127 description => 'payment',
128 description_long => 'payment',
131 percent_skonto => '0.05',
132 auto_calculation => 1,
135 $vendor = SL::DB::Vendor->new(
136 name => 'Test Vendor',
137 currency_id => $currency_id,
138 taxzone_id => $taxzone->id,
139 payment_id => $payment_terms->id,
145 push @parts, SL::DB::Part->new(
146 partnumber => 'T4254',
147 description => 'Fourty-two fifty-four',
150 buchungsgruppen_id => $buchungsgruppe->id,
155 push @parts, SL::DB::Part->new(
156 partnumber => 'T0815',
157 description => 'Zero EIGHT fifteeN @ 7%',
160 buchungsgruppen_id => $buchungsgruppe7->id,
164 push @parts, SL::DB::Part->new(
166 description => 'Testware 19%',
169 buchungsgruppen_id => $buchungsgruppe->id,
173 push @parts, SL::DB::Part->new(
175 description => 'Testware 7%',
178 buchungsgruppen_id => $buchungsgruppe7->id,
183 $ar_chart = SL::DB::Manager::Chart->find_by( accno => '1400' ); # Forderungen
184 $ap_chart = SL::DB::Manager::Chart->find_by( accno => '1600' ); # Verbindlichkeiten
185 $bank = SL::DB::Manager::Chart->find_by( accno => '1200' ); # Bank
186 $ar_amount_chart = SL::DB::Manager::Chart->find_by( accno => '8400' ); # Erlöse
187 $ap_amount_chart = SL::DB::Manager::Chart->find_by( accno => '3400' ); # Wareneingang 19%
189 $reset_state_counter++;
195 return SL::DB::Invoice->new(
196 customer_id => $customer->id,
197 currency_id => $currency_id,
198 employee_id => $employee->id,
199 salesman_id => $employee->id,
200 gldate => $transdate1,
201 taxzone_id => $taxzone->id,
202 transdate => $transdate1,
210 sub new_purchase_invoice {
212 # manually create a Kreditorenbuchung from scratch, ap + acc_trans bookings, as no helper exists yet, like $invoice->post.
213 # arap-Booking must come last in the acc_trans order
214 $purchase_invoice_counter++;
216 my $purchase_invoice = SL::DB::PurchaseInvoice->new(
217 vendor_id => $vendor->id,
218 invnumber => 'newap ' . $purchase_invoice_counter ,
219 currency_id => $currency_id,
220 employee_id => $employee->id,
221 gldate => $transdate1,
222 taxzone_id => $taxzone->id,
223 transdate => $transdate1,
233 my $expense_chart = SL::DB::Manager::Chart->find_by(accno => '3400');
234 my $expense_chart_booking= SL::DB::AccTransaction->new(
235 trans_id => $purchase_invoice->id,
236 chart_id => $expense_chart->id,
237 chart_link => $expense_chart->link,
239 transdate => $transdate1,
242 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
243 $expense_chart_booking->save;
245 my $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1576');
246 my $tax_chart_booking= SL::DB::AccTransaction->new(
247 trans_id => $purchase_invoice->id,
248 chart_id => $tax_chart->id,
249 chart_link => $tax_chart->link,
251 transdate => $transdate1,
254 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
255 $tax_chart_booking->save;
256 $expense_chart = SL::DB::Manager::Chart->find_by(accno => '3300');
257 $expense_chart_booking= SL::DB::AccTransaction->new(
258 trans_id => $purchase_invoice->id,
259 chart_id => $expense_chart->id,
260 chart_link => $expense_chart->link,
262 transdate => $transdate1,
265 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
266 $expense_chart_booking->save;
269 $tax_chart = SL::DB::Manager::Chart->find_by(accno => '1571');
270 $tax_chart_booking= SL::DB::AccTransaction->new(
271 trans_id => $purchase_invoice->id,
272 chart_id => $tax_chart->id,
273 chart_link => $tax_chart->link,
275 transdate => $transdate1,
278 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
279 $tax_chart_booking->save;
280 my $arap_chart = SL::DB::Manager::Chart->find_by(accno => '1600');
281 my $arap_booking= SL::DB::AccTransaction->new(trans_id => $purchase_invoice->id,
282 chart_id => $arap_chart->id,
283 chart_link => $arap_chart->link,
285 transdate => $transdate1,
288 tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
291 return $purchase_invoice;
297 my $part = delete($params{part}) || $parts[0];
299 return SL::DB::InvoiceItem->new(
300 parts_id => $part->id,
301 lastcost => $part->lastcost,
302 sellprice => $part->sellprice,
303 description => $part->description,
309 sub number_of_payments {
312 my $number_of_payments;
314 foreach my $transaction ( @{ $invoice->transactions } ) {
315 if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
316 $paid_amount += $transaction->amount ;
317 $number_of_payments++;
320 return ($number_of_payments, $paid_amount);
326 my $total = sum map { $_->amount } @{ $invoice->transactions };
328 return $::form->round_amount($total, 5);
334 sub test_default_invoice_one_item_19_without_skonto() {
335 reset_state() if $ALWAYS_RESET;
337 my $item = new_item(qty => 2.5);
338 my $invoice = new_invoice(
340 invoiceitems => [ $item ],
341 payment_id => $payment_terms->id,
345 my $purchase_invoice = new_purchase_invoice();
349 my %params = ( chart_id => $bank_account->chart_id,
350 transdate => DateTime->today_local->to_kivitendo
353 $params{amount} = '6.96';
354 $params{payment_type} = 'without_skonto';
356 $invoice->pay_invoice( %params );
358 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
359 my $total = total_amount($invoice);
361 my $title = 'default invoice, one item, 19% tax, without_skonto';
363 is($invoice->netamount, 5.85, "${title}: netamount");
364 is($invoice->amount, 6.96, "${title}: amount");
365 is($paid_amount, -6.96, "${title}: paid amount");
366 is($number_of_payments, 1, "${title}: 1 AR_paid booking");
367 is($invoice->paid, 6.96, "${title}: paid");
368 is($total, 0, "${title}: even balance");
372 sub test_default_invoice_one_item_19_without_skonto_overpaid() {
373 reset_state() if $ALWAYS_RESET;
375 my $item = new_item(qty => 2.5);
376 my $invoice = new_invoice(
378 invoiceitems => [ $item ],
379 payment_id => $payment_terms->id,
383 my $purchase_invoice = new_purchase_invoice();
387 my %params = ( chart_id => $bank_account->chart_id,
388 transdate => DateTime->today_local->to_kivitendo
391 $params{amount} = '16.96';
392 $params{payment_type} = 'without_skonto';
393 $invoice->pay_invoice( %params );
395 $params{amount} = '-10.00';
396 $invoice->pay_invoice( %params );
398 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
399 my $total = total_amount($invoice);
401 my $title = 'default invoice, one item, 19% tax, without_skonto';
403 is($invoice->netamount, 5.85, "${title}: netamount");
404 is($invoice->amount, 6.96, "${title}: amount");
405 is($paid_amount, -6.96, "${title}: paid amount");
406 is($number_of_payments, 2, "${title}: 1 AR_paid booking");
407 is($invoice->paid, 6.96, "${title}: paid");
408 is($total, 0, "${title}: even balance");
414 sub test_default_invoice_two_items_19_7_tax_with_skonto() {
415 reset_state() if $ALWAYS_RESET;
417 my $item1 = new_item(qty => 2.5);
418 my $item2 = new_item(qty => 1.2, part => $parts[1]);
419 my $invoice = new_invoice(
421 invoiceitems => [ $item1, $item2 ],
422 payment_id => $payment_terms->id,
427 my %params = ( chart_id => $bank_account->chart_id,
428 transdate => DateTime->today_local->to_kivitendo
431 $params{payment_type} = 'with_skonto_pt';
432 $params{amount} = $invoice->amount_less_skonto;
434 $invoice->pay_invoice( %params );
436 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
437 my $total = total_amount($invoice);
439 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
441 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
442 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
443 is($paid_amount, -19.44, "${title}: paid amount");
444 is($invoice->paid, 19.44, "${title}: paid");
445 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
446 is($total, 0, "${title}: even balance");
449 sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included() {
450 reset_state() if $ALWAYS_RESET;
452 my $item1 = new_item(qty => 2.5);
453 my $item2 = new_item(qty => 1.2, part => $parts[1]);
454 my $invoice = new_invoice(
456 invoiceitems => [ $item1, $item2 ],
457 payment_id => $payment_terms->id,
462 my %params = ( chart_id => $bank_account->chart_id,
463 transdate => DateTime->today_local->to_kivitendo
466 $params{payment_type} = 'with_skonto_pt';
467 $params{amount} = $invoice->amount_less_skonto;
469 $invoice->pay_invoice( %params );
471 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
472 my $total = total_amount($invoice);
474 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
476 is($invoice->netamount, 15.82, "${title}: netamount");
477 is($invoice->amount, 17.51, "${title}: amount");
478 is($paid_amount, -17.51, "${title}: paid amount");
479 is($invoice->paid, 17.51, "${title}: paid");
480 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
481 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
482 is($total, 0, "${title}: even balance");
486 # test 3 : two items, without skonto
487 sub test_default_invoice_two_items_19_7_without_skonto() {
488 reset_state() if $ALWAYS_RESET;
490 my $item1 = new_item(qty => 2.5);
491 my $item2 = new_item(qty => 1.2, part => $parts[1]);
492 my $invoice = new_invoice(
494 invoiceitems => [ $item1, $item2 ],
495 payment_id => $payment_terms->id,
500 my %params = ( chart_id => $bank_account->chart_id,
501 transdate => DateTime->today_local->to_kivitendo
504 $params{amount} = '19.44'; # pass full amount
505 $params{payment_type} = 'without_skonto';
507 $invoice->pay_invoice( %params );
509 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
510 my $total = total_amount($invoice);
512 my $title = 'default invoice, two items, 19/7% tax without skonto';
514 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
515 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
516 is($paid_amount, -19.44, "${title}: paid amount");
517 is($invoice->paid, 19.44, "${title}: paid");
518 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
519 is($total, 0, "${title}: even balance");
523 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
524 reset_state() if $ALWAYS_RESET;
526 my $item1 = new_item(qty => 2.5);
527 my $item2 = new_item(qty => 1.2, part => $parts[1]);
528 my $invoice = new_invoice(
530 invoiceitems => [ $item1, $item2 ],
531 payment_id => $payment_terms->id,
535 $invoice->pay_invoice( amount => '9.44',
536 payment_type => 'without_skonto',
537 chart_id => $bank_account->chart_id,
538 transdate => DateTime->today_local->to_kivitendo,
541 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
542 my $total = total_amount($invoice);
544 my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
546 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
547 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
548 is($paid_amount, -9.44, "${title}: paid amount");
549 is($invoice->paid, 9.44, "${title}: paid");
550 is($number_of_payments, 1, "${title}: 1 AR_paid bookings");
551 is($total, 0, "${title}: even balance");
555 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
556 reset_state() if $ALWAYS_RESET;
558 my $item1 = new_item(qty => 2.5);
559 my $item2 = new_item(qty => 1.2, part => $parts[1]);
560 my $invoice = new_invoice(
562 invoiceitems => [ $item1, $item2 ],
563 payment_id => $payment_terms->id,
567 $invoice->pay_invoice( amount => '9.44',
568 payment_type => 'without_skonto',
569 chart_id => $bank_account->chart_id,
570 transdate => DateTime->today_local->to_kivitendo
572 $invoice->pay_invoice( amount => '10.00',
573 chart_id => $bank_account->chart_id,
574 transdate => DateTime->today_local->to_kivitendo
577 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
578 my $total = total_amount($invoice);
580 my $title = 'default invoice, two items, 19/7% tax not included';
582 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
583 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
584 is($paid_amount, -19.44, "${title}: paid amount");
585 is($invoice->paid, 19.44, "${title}: paid");
586 is($number_of_payments, 2, "${title}: 2 AR_paid bookings");
587 is($total, 0, "${title}: even balance");
592 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
593 reset_state() if $ALWAYS_RESET;
595 my $item1 = new_item(qty => 2.5);
596 my $item2 = new_item(qty => 1.2, part => $parts[1]);
597 my $invoice = new_invoice(
599 invoiceitems => [ $item1, $item2 ],
600 payment_id => $payment_terms->id,
604 $invoice->pay_invoice( amount => '9.44',
605 payment_type => 'without_skonto',
606 chart_id => $bank_account->chart_id,
607 transdate => DateTime->today_local->to_kivitendo
609 $invoice->pay_invoice( amount => '8.73',
610 payment_type => 'without_skonto',
611 chart_id => $bank_account->chart_id,
612 transdate => DateTime->today_local->to_kivitendo
614 $invoice->pay_invoice( amount => $invoice->open_amount,
615 payment_type => 'difference_as_skonto',
616 chart_id => $bank_account->chart_id,
617 transdate => DateTime->today_local->to_kivitendo
620 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
621 my $total = total_amount($invoice);
623 my $title = 'default invoice, two items, 19/7% tax not included';
625 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
626 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
627 is($paid_amount, -19.44, "${title}: paid amount");
628 is($invoice->paid, 19.44, "${title}: paid");
629 is($number_of_payments, 4, "${title}: 4 AR_paid bookings");
630 is($total, 0, "${title}: even balance");
634 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
635 reset_state() if $ALWAYS_RESET;
637 # if there is only one cent left there can only be one skonto booking, the
638 # error handling should choose the highest amount, which is the 7% account
639 # (11.66) rather than the 19% account (5.85). The actual tax amount is
640 # higher for the 19% case, though (1.11 compared to 0.82)
642 my $item1 = new_item(qty => 2.5);
643 my $item2 = new_item(qty => 1.2, part => $parts[1]);
644 my $invoice = new_invoice(
646 invoiceitems => [ $item1, $item2 ],
647 payment_id => $payment_terms->id,
651 $invoice->pay_invoice( amount => '19.42',
652 payment_type => 'without_skonto',
653 chart_id => $bank_account->chart_id,
654 transdate => DateTime->today_local->to_kivitendo
656 $invoice->pay_invoice( amount => $invoice->open_amount,
657 payment_type => 'difference_as_skonto',
658 chart_id => $bank_account->chart_id,
659 transdate => DateTime->today_local->to_kivitendo
662 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
663 my $total = total_amount($invoice);
665 my $title = 'default invoice, two items, 19/7% tax not included';
667 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
668 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
669 is($paid_amount, -19.44, "${title}: paid amount");
670 is($invoice->paid, 19.44, "${title}: paid");
671 is($number_of_payments, 3, "${title}: 2 AR_paid bookings");
672 is($total, 0, "${title}: even balance");
676 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
677 reset_state() if $ALWAYS_RESET;
679 # if there are two cents left there will be two skonto bookings, 1 cent each
680 my $item1 = new_item(qty => 2.5);
681 my $item2 = new_item(qty => 1.2, part => $parts[1]);
682 my $invoice = new_invoice(
684 invoiceitems => [ $item1, $item2 ],
685 payment_id => $payment_terms->id,
689 $invoice->pay_invoice( amount => '19.42',
690 payment_type => 'without_skonto',
691 chart_id => $bank_account->chart_id,
692 transdate => DateTime->today_local->to_kivitendo
694 $invoice->pay_invoice( amount => $invoice->open_amount,
695 payment_type => 'difference_as_skonto',
696 chart_id => $bank_account->chart_id,
697 transdate => DateTime->today_local->to_kivitendo
700 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
701 my $total = total_amount($invoice);
703 my $title = 'default invoice, two items, 19/7% tax not included';
705 is($invoice->netamount, 5.85 + 11.66, "${title}: netamount");
706 is($invoice->amount, 6.96 + 12.48, "${title}: amount");
707 is($paid_amount, -19.44, "${title}: paid amount");
708 is($invoice->paid, 19.44, "${title}: paid");
709 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
710 is($total, 0, "${title}: even balance");
714 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
715 reset_state() if $ALWAYS_RESET;
717 my $item = new_item(qty => 2.5);
718 my $invoice = new_invoice(
720 invoiceitems => [ $item ],
721 payment_id => $payment_terms->id,
726 my %params = ( chart_id => $bank_account->chart_id,
727 transdate => DateTime->today_local->to_kivitendo
730 $params{amount} = '2.32';
731 $params{payment_type} = 'without_skonto';
732 $invoice->pay_invoice( %params );
734 $params{amount} = '3.81';
735 $params{payment_type} = 'without_skonto';
736 $invoice->pay_invoice( %params );
738 $params{amount} = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
739 $params{payment_type} = 'difference_as_skonto';
740 $invoice->pay_invoice( %params );
742 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
743 my $total = total_amount($invoice);
745 my $title = 'default invoice, one item, 19% tax, without_skonto';
747 is($invoice->netamount, 5.85, "${title}: netamount");
748 is($invoice->amount, 6.96, "${title}: amount");
749 is($paid_amount, -6.96, "${title}: paid amount");
750 is($number_of_payments, 3, "${title}: 3 AR_paid booking");
751 is($invoice->paid, 6.96, "${title}: paid");
752 is($total, 0, "${title}: even balance");
756 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
757 reset_state() if $ALWAYS_RESET;
759 my $item = new_item(qty => 2.5);
760 my $invoice = new_invoice(
762 invoiceitems => [ $item ],
763 payment_id => $payment_terms->id,
768 my %params = ( chart_id => $bank_account->chart_id,
769 transdate => DateTime->today_local->to_kivitendo
772 $params{amount} = '6.95';
773 $params{payment_type} = 'without_skonto';
774 $invoice->pay_invoice( %params );
776 $params{amount} = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
777 $params{payment_type} = 'difference_as_skonto';
778 $invoice->pay_invoice( %params );
780 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
781 my $total = total_amount($invoice);
783 my $title = 'default invoice, one item, 19% tax, without_skonto';
785 is($invoice->netamount, 5.85, "${title}: netamount");
786 is($invoice->amount, 6.96, "${title}: amount");
787 is($paid_amount, -6.96, "${title}: paid amount");
788 is($number_of_payments, 2, "${title}: 3 AR_paid booking");
789 is($invoice->paid, 6.96, "${title}: paid");
790 is($total, 0, "${title}: even balance");
794 # test 3 : two items, without skonto
795 sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
796 reset_state() if $ALWAYS_RESET;
798 my $purchase_invoice = new_purchase_invoice();
800 my %params = ( chart_id => $bank_account->chart_id,
801 transdate => DateTime->today_local->to_kivitendo
804 $params{amount} = '226'; # pass full amount
805 $params{payment_type} = 'without_skonto';
807 $purchase_invoice->pay_invoice( %params );
809 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
810 my $total = total_amount($purchase_invoice);
812 my $title = 'default invoice, two items, 19/7% tax without skonto';
814 is($paid_amount, 226, "${title}: paid amount");
815 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
816 is($total, 0, "${title}: even balance");
820 sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
821 reset_state() if $ALWAYS_RESET;
823 my $purchase_invoice = new_purchase_invoice();
825 my %params = ( chart_id => $bank_account->chart_id,
826 transdate => DateTime->today_local->to_kivitendo
829 # $params{amount} = '226'; # pass full amount
830 $params{payment_type} = 'with_skonto_pt';
832 $purchase_invoice->pay_invoice( %params );
834 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
835 my $total = total_amount($purchase_invoice);
837 my $title = 'default invoice, two items, 19/7% tax without skonto';
839 is($paid_amount, 226, "${title}: paid amount");
840 is($number_of_payments, 3, "${title}: 1 AP_paid bookings");
841 is($total, 0, "${title}: even balance");
845 sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
846 # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
847 reset_state() if $ALWAYS_RESET;
848 my $purchase_invoice = new_purchase_invoice();
849 $purchase_invoice->pay_invoice(
850 amount => ( $purchase_invoice->amount / 3 * 2),
851 payment_type => 'without_skonto',
852 chart_id => $bank_account->chart_id,
853 transdate => DateTime->today_local->to_kivitendo
855 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
856 my $total = total_amount($purchase_invoice);
858 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
860 is($paid_amount, 150.67, "${title}: paid amount");
861 is($number_of_payments, 1, "${title}: 1 AP_paid bookings");
862 is($total, 0, "${title}: even balance");
866 sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
867 reset_state() if $ALWAYS_RESET;
869 my $purchase_invoice = new_purchase_invoice();
871 # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
872 $purchase_invoice->pay_invoice(
873 amount => ( $purchase_invoice->amount / 3 * 2),
874 payment_type => 'without_skonto',
875 chart_id => $bank_account->chart_id,
876 transdate => DateTime->today_local->to_kivitendo
878 $purchase_invoice->pay_invoice(
879 amount => ( $purchase_invoice->amount / 5 ),
880 payment_type => 'without_skonto',
881 chart_id => $bank_account->chart_id,
882 transdate => DateTime->today_local->to_kivitendo
884 $purchase_invoice->pay_invoice(
885 payment_type => 'difference_as_skonto',
886 chart_id => $bank_account->chart_id,
887 transdate => DateTime->today_local->to_kivitendo
890 my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
891 my $total = total_amount($purchase_invoice);
893 my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
895 is($paid_amount, 226, "${title}: paid amount");
896 is($number_of_payments, 4, "${title}: 1 AP_paid bookings");
897 is($total, 0, "${title}: even balance");
902 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
903 reset_state() if $ALWAYS_RESET;
905 my $item1 = new_item(qty => 1, part => $parts[2]);
906 my $item2 = new_item(qty => 1, part => $parts[3]);
907 my $invoice = new_invoice(
909 invoiceitems => [ $item1, $item2 ],
910 payment_id => $payment_terms->id,
915 my %params = ( chart_id => $bank_account->chart_id,
916 transdate => DateTime->today_local->to_kivitendo
919 $params{amount} = $invoice->amount_less_skonto;
920 $params{payment_type} = 'with_skonto_pt';
922 $invoice->pay_invoice( %params );
924 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
925 my $total = total_amount($invoice);
927 my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
929 is($invoice->netamount, 100, "${title}: netamount");
930 is($invoice->amount, 113, "${title}: amount");
931 is($paid_amount, -113, "${title}: paid amount");
932 is($invoice->paid, 113, "${title}: paid");
933 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
934 is($total, 0, "${title}: even balance");
938 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
939 reset_state() if $ALWAYS_RESET;
941 my $item1 = new_item(qty => 0.5, part => $parts[2]);
942 my $item2 = new_item(qty => 0.5, part => $parts[3]);
943 my $item3 = new_item(qty => 0.5, part => $parts[2]);
944 my $item4 = new_item(qty => 0.5, part => $parts[3]);
945 my $invoice = new_invoice(
947 invoiceitems => [ $item1, $item2, $item3, $item4 ],
948 payment_id => $payment_terms->id,
953 my %params = ( chart_id => $bank_account->chart_id,
954 transdate => DateTime->today_local->to_kivitendo
957 $params{amount} = $invoice->amount_less_skonto;
958 $params{payment_type} = 'with_skonto_pt';
960 $invoice->pay_invoice( %params );
962 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
963 my $total = total_amount($invoice);
965 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
967 is($invoice->netamount , 100 , "${title}: netamount");
968 is($invoice->amount , 113 , "${title}: amount");
969 is($paid_amount , -113 , "${title}: paid amount");
970 is($invoice->paid , 113 , "${title}: paid");
971 is($number_of_payments , 3 , "${title}: 3 AR_paid bookings");
972 is($total , 0 , "${title}: even balance");
975 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
976 reset_state() if $ALWAYS_RESET;
978 my $item1 = new_item(qty => 0.5, part => $parts[2]);
979 my $item2 = new_item(qty => 0.5, part => $parts[3]);
980 my $item3 = new_item(qty => 0.5, part => $parts[2]);
981 my $item4 = new_item(qty => 0.5, part => $parts[3]);
982 my $invoice = new_invoice(
984 invoiceitems => [ $item1, $item2, $item3, $item4 ],
985 payment_id => $payment_terms->id,
990 my %params = ( chart_id => $bank_account->chart_id,
991 transdate => DateTime->today_local->to_kivitendo
994 $params{amount} = $invoice->amount_less_skonto;
995 $params{payment_type} = 'with_skonto_pt';
997 $invoice->pay_invoice( %params );
999 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
1000 my $total = total_amount($invoice);
1002 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
1004 is($invoice->netamount, 88.75, "${title}: netamount");
1005 is($invoice->amount, 100, "${title}: amount");
1006 is($paid_amount, -100, "${title}: paid amount");
1007 is($invoice->paid, 100, "${title}: paid");
1008 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
1009 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
1010 is($total, 0, "${title}: even balance");
1014 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
1015 reset_state() if $ALWAYS_RESET;
1017 my $item1 = new_item(qty => 0.5, part => $parts[2]);
1018 my $item2 = new_item(qty => 0.5, part => $parts[3]);
1019 my $item3 = new_item(qty => 0.5, part => $parts[2]);
1020 my $item4 = new_item(qty => 0.5, part => $parts[3]);
1021 my $invoice = new_invoice(
1023 invoiceitems => [ $item1, $item2, $item3, $item4 ],
1024 payment_id => $payment_terms->id,
1028 $invoice->pay_invoice( amount => '90',
1029 payment_type => 'without_skonto',
1030 chart_id => $bank_account->chart_id,
1031 transdate => DateTime->today_local->to_kivitendo
1033 $invoice->pay_invoice( payment_type => 'difference_as_skonto',
1034 chart_id => $bank_account->chart_id,
1035 transdate => DateTime->today_local->to_kivitendo
1038 my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
1039 my $total = total_amount($invoice);
1041 my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
1043 is($invoice->netamount, 100, "${title}: netamount");
1044 is($invoice->amount, 113, "${title}: amount");
1045 is($paid_amount, -113, "${title}: paid amount");
1046 is($invoice->paid, 113, "${title}: paid");
1047 is($number_of_payments, 3, "${title}: 3 AR_paid bookings");
1048 is($total, 0, "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
1051 sub test_ar_currency_tax_not_included_and_payment {
1052 my $netamount = $::form->round_amount(75 * $exchangerate->sell,2); # 75 in CUR, 100.00 in EUR
1053 my $amount = $::form->round_amount($netamount * 1.19,2); # 100 in CUR, 119.00 in EUR
1054 my $invoice = SL::DB::Invoice->new(
1057 netamount => $netamount,
1058 transdate => $transdate1,
1060 customer_id => $customer->id,
1061 taxzone_id => $customer->taxzone_id,
1062 currency_id => $currency->id,
1064 notes => 'test_ar_currency_tax_not_included_and_payment',
1066 $invoice->add_ar_amount_row(
1067 amount => $invoice->netamount,
1068 chart => $ar_amount_chart,
1072 $invoice->create_ar_row(chart => $ar_chart);
1075 is(SL::DB::Manager::Invoice->get_all_count(where => [ invoice => 0 ]), 1, 'there is one ar transaction');
1076 is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1077 is($invoice->netamount , 100 , 'ar amount has been converted');
1078 is($invoice->amount , 119 , 'ar amount has been converted');
1079 is($invoice->taxincluded , 0 , 'ar transaction doesn\'t have taxincluded');
1080 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_amount_chart->id, trans_id => $invoice->id)->amount, '100.00000', $ar_amount_chart->accno . ': has been converted for currency');
1081 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_chart->id, trans_id => $invoice->id)->amount, '-119.00000', $ar_chart->accno . ': has been converted for currency');
1083 $invoice->pay_invoice(chart_id => $bank->id,
1086 transdate => $transdate1->to_kivitendo,
1088 $invoice->pay_invoice(chart_id => $bank->id,
1091 transdate => $transdate1->to_kivitendo,
1093 # $invoice->pay_invoice(chart_id => $bank->id,
1095 # transdate => $transdate2->to_kivitendo,
1097 is(scalar @{$invoice->transactions}, 9, 'ar transaction has 9 transactions (incl. fxtransactions)');
1098 is($invoice->paid, $invoice->amount, 'ar transaction paid = amount in default currency');
1101 sub test_ar_currency_tax_included {
1102 # we want the acc_trans amount to be 100
1103 my $amount = $::form->round_amount(75 * $exchangerate->sell * 1.19);
1104 my $netamount = $::form->round_amount($amount / 1.19,2);
1105 my $invoice = SL::DB::Invoice->new(
1109 transdate => $transdate1,
1111 customer_id => $customer->id,
1112 taxzone_id => $customer->taxzone_id,
1113 currency_id => $currency->id,
1114 notes => 'test_ar_currency_tax_included',
1117 $invoice->add_ar_amount_row( # should take care of taxincluded
1118 amount => $invoice->amount, # tax included in local currency
1119 chart => $ar_amount_chart,
1123 $invoice->create_ar_row( chart => $ar_chart );
1125 is(SL::DB::Manager::Invoice->get_all_count(where => [ invoice => 0 ]), 2, 'there are now two ar transactions');
1126 is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1127 is($invoice->amount , $amount , 'amount ok');
1128 is($invoice->netamount , $netamount , 'netamount ok');
1129 is($invoice->taxincluded , 1 , 'ar transaction has taxincluded');
1130 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_amount_chart->id, trans_id => $invoice->id)->amount, '100.00000', $ar_amount_chart->accno . ': has been converted for currency');
1131 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_chart->id, trans_id => $invoice->id)->amount, '-119.00000', $ar_chart->accno . ': has been converted for currency');
1132 $invoice->pay_invoice(chart_id => $bank->id,
1135 transdate => $transdate1->to_kivitendo,
1140 sub test_ap_currency_tax_not_included_and_payment {
1141 my $netamount = $::form->round_amount(75 * $exchangerate->buy,2); # 75 in CUR, 100.00 in EUR
1142 my $amount = $::form->round_amount($netamount * 1.19,2); # 100 in CUR, 119.00 in EUR
1143 my $invoice = SL::DB::PurchaseInvoice->new(
1145 invnumber => 'test_ap_currency_tax_not_included_and_payment',
1147 netamount => $netamount,
1148 transdate => $transdate1,
1150 vendor_id => $vendor->id,
1151 taxzone_id => $vendor->taxzone_id,
1152 currency_id => $currency->id,
1154 notes => 'test_ap_currency_tax_not_included_and_payment',
1156 $invoice->add_ap_amount_row(
1157 amount => $invoice->netamount,
1158 chart => $ap_amount_chart,
1159 tax_id => $tax_9->id,
1162 $invoice->create_ap_row(chart => $ap_chart);
1165 is($invoice->currency_id, $currency->id, 'currency_id has been saved');
1166 is($invoice->netamount, 100, 'ap amount has been converted');
1167 is($invoice->amount, 119, 'ap amount has been converted');
1168 is($invoice->taxincluded, 0, 'ap transaction doesn\'t have taxincluded');
1169 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_amount_chart->id, trans_id => $invoice->id)->amount, '-100.00000', $ap_amount_chart->accno . ': has been converted for currency');
1170 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_chart->id, trans_id => $invoice->id)->amount, '119.00000', $ap_chart->accno . ': has been converted for currency');
1172 $invoice->pay_invoice(chart_id => $bank->id,
1175 transdate => $transdate1->to_kivitendo,
1177 $invoice->pay_invoice(chart_id => $bank->id,
1180 transdate => $transdate1->to_kivitendo,
1182 is(scalar @{$invoice->transactions}, 9, 'ap transaction has 9 transactions (incl. fxtransactions)');
1183 is($invoice->paid, $invoice->amount, 'ap transaction paid = amount in default currency');
1186 sub test_ap_currency_tax_included {
1187 # we want the acc_trans amount to be 100
1188 my $amount = $::form->round_amount(75 * $exchangerate->buy * 1.19);
1189 my $netamount = $::form->round_amount($amount / 1.19,2);
1190 my $invoice = SL::DB::PurchaseInvoice->new(
1192 amount => 119, #$amount,
1193 netamount => 100, #$netamount,
1194 transdate => $transdate1,
1196 vendor_id => $vendor->id,
1197 taxzone_id => $vendor->taxzone_id,
1198 currency_id => $currency->id,
1199 notes => 'test_ap_currency_tax_included',
1200 invnumber => 'test_ap_currency_tax_included',
1203 $invoice->add_ap_amount_row( # should take care of taxincluded
1204 amount => $invoice->amount, # tax included in local currency
1205 chart => $ap_amount_chart,
1206 tax_id => $tax_9->id,
1209 $invoice->create_ap_row( chart => $ap_chart );
1211 is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1212 is($invoice->amount , $amount , 'amount ok');
1213 is($invoice->netamount , $netamount , 'netamount ok');
1214 is($invoice->taxincluded , 1 , 'ap transaction has taxincluded');
1215 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_amount_chart->id, trans_id => $invoice->id)->amount, '-100.00000', $ap_amount_chart->accno . ': has been converted for currency');
1216 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_chart->id, trans_id => $invoice->id)->amount, '119.00000', $ap_chart->accno . ': has been converted for currency');
1218 $invoice->pay_invoice(chart_id => $bank->id,
1221 transdate => $transdate1->to_kivitendo,
1226 sub test_ar_currency_tax_not_included_and_payment_2 {
1227 my $title = 'test_ar_currency_tax_not_included_and_payment_2';
1228 my $netamount = $::form->round_amount(125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1229 my $amount = $::form->round_amount($netamount * 1.19,2); # 148.75 in CUR, 119.00 in EUR
1230 my $invoice = SL::DB::Invoice->new(
1233 netamount => $netamount,
1234 transdate => $transdate2,
1236 customer_id => $customer->id,
1237 taxzone_id => $customer->taxzone_id,
1238 currency_id => $currency->id,
1240 notes => 'test_ar_currency_tax_not_included_and_payment 0.8',
1241 invnumber => 'test_ar_currency_tax_not_included_and_payment 0.8',
1243 $invoice->add_ar_amount_row(
1244 amount => $invoice->netamount,
1245 chart => $ar_amount_chart,
1249 $invoice->create_ar_row(chart => $ar_chart);
1252 is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1253 is($invoice->netamount , 100 , "$title: ar amount has been converted");
1254 is($invoice->amount , 119 , "$title: ar amount has been converted");
1255 is($invoice->taxincluded , 0 , "$title: ar transaction doesn\"t have taxincluded");
1256 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_amount_chart->id, trans_id => $invoice->id)->amount, '100.00000', $title . " " . $ar_amount_chart->accno . ": has been converted for currency");
1257 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_chart->id, trans_id => $invoice->id)->amount, '-119.00000', $title . " " . $ar_chart->accno . ': has been converted for currency');
1259 $invoice->pay_invoice(chart_id => $bank->id,
1262 transdate => $transdate2->to_kivitendo,
1264 $invoice->pay_invoice(chart_id => $bank->id,
1267 transdate => $transdate3->to_kivitendo,
1269 $invoice->pay_invoice(chart_id => $bank->id,
1272 transdate => $transdate4->to_kivitendo,
1274 # $invoice->pay_invoice(chart_id => $bank->id,
1276 # transdate => $transdate2->to_kivitendo,
1278 my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1279 is(scalar @{$fx_transactions}, 3, "$title: ar transaction has 3 fx transactions");
1280 is($fx_transactions->[0]->amount, '24.69000', "$title fx transactions 1: 123.45-(123.45*0.8) = 24.69");
1282 is(scalar @{$invoice->transactions}, 14, "$title ar transaction has 14 transactions (incl. fxtransactions and fx_gain)");
1283 is($invoice->paid, $invoice->amount, "$title ar transaction paid = amount in default currency");
1286 sub test_ar_currency_tax_not_included_and_payment_2_credit_note {
1287 my $netamount = $::form->round_amount(-125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1288 my $amount = $::form->round_amount($netamount * 1.19,2); # 148.75 in CUR, 119.00 in EUR
1289 my $invoice = SL::DB::Invoice->new(
1292 netamount => $netamount,
1293 transdate => $transdate2,
1295 customer_id => $customer->id,
1296 taxzone_id => $customer->taxzone_id,
1297 currency_id => $currency->id,
1299 notes => 'test_ar_currency_tax_not_included_and_payment credit note 0.8',
1300 invnumber => 'test_ar_currency_tax_not_included_and_payment credit note 0.8',
1302 $invoice->add_ar_amount_row(
1303 amount => $invoice->netamount,
1304 chart => $ar_amount_chart,
1308 $invoice->create_ar_row(chart => $ar_chart);
1311 is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1312 is($invoice->netamount , -100 , 'ar amount has been converted');
1313 is($invoice->amount , -119 , 'ar amount has been converted');
1314 is($invoice->taxincluded , 0 , 'ar transaction doesn\'t have taxincluded');
1315 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_amount_chart->id, trans_id => $invoice->id)->amount, '-100.00000', $ar_amount_chart->accno . ': has been converted for currency');
1316 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_chart->id, trans_id => $invoice->id)->amount, '119.00000', $ar_chart->accno . ': has been converted for currency');
1318 $invoice->pay_invoice(chart_id => $bank->id,
1321 transdate => $transdate2->to_kivitendo,
1323 $invoice->pay_invoice(chart_id => $bank->id,
1326 transdate => $transdate2->to_kivitendo,
1328 my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1329 is(scalar @{$fx_transactions}, 2, 'ar transaction has 2 fx transactions');
1330 is($fx_transactions->[0]->amount, '-24.69000', 'fx transactions 1: 123.45-(123.45*0.8) = 24.69');
1332 is(scalar @{$invoice->transactions}, 9, 'ar transaction has 9 transactions (incl. fxtransactions)');
1333 is($invoice->paid, $invoice->amount, 'ar transaction paid = amount in default currency');
1336 sub test_ap_currency_tax_not_included_and_payment_2 {
1337 my $title = 'test_ap_currency_tax_not_included_and_payment_2';
1338 my $netamount = $::form->round_amount(125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1339 my $amount = $::form->round_amount($netamount * 1.19,2); # 148.75 in CUR, 119.00 in EUR
1340 my $invoice = SL::DB::PurchaseInvoice->new(
1343 netamount => $netamount,
1344 transdate => $transdate2,
1346 vendor_id => $vendor->id,
1347 taxzone_id => $vendor->taxzone_id,
1348 currency_id => $currency->id,
1350 notes => 'test_ap_currency_tax_not_included_and_payment_2 0.8 + 1.33333',
1351 invnumber => 'test_ap_currency_tax_not_included_and_payment_2 0.8 + 1.33333',
1353 $invoice->add_ap_amount_row(
1354 amount => $invoice->netamount,
1355 chart => $ap_amount_chart,
1356 tax_id => $tax_9->id,
1359 $invoice->create_ap_row(chart => $ap_chart);
1362 is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1363 is($invoice->netamount , 100 , "$title: ap amount has been converted");
1364 is($invoice->amount , 119 , "$title: ap amount has been converted");
1365 is($invoice->taxincluded , 0 , "$title: ap transaction doesn\'t have taxincluded");
1366 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_amount_chart->id, trans_id => $invoice->id)->amount, '-100.00000', $ap_amount_chart->accno . ': has been converted for currency');
1367 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_chart->id, trans_id => $invoice->id)->amount, '119.00000', $ap_chart->accno . ': has been converted for currency');
1369 $invoice->pay_invoice(chart_id => $bank->id,
1372 transdate => $transdate2->to_kivitendo,
1374 $invoice->pay_invoice(chart_id => $bank->id,
1377 transdate => $transdate3->to_kivitendo,
1379 $invoice->pay_invoice(chart_id => $bank->id,
1382 transdate => $transdate4->to_kivitendo,
1384 my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1385 is(scalar @{$fx_transactions}, 3, "$title: ap transaction has 3 fx transactions");
1386 is($fx_transactions->[0]->amount, '-2.00000', "$title: fx transaction 1: 10.00-( 10.00*0.80000) = 2.00000");
1387 is($fx_transactions->[1]->amount, '68.59000', "$title: fx transaction 2: 123.45-(123.45*1.55557) = -68.58511");
1388 is($fx_transactions->[2]->amount, '-3.40000', "$title: fx transaction 3: 15.30-(15.30 *0.77777) = 3.40012");
1390 my $fx_loss_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, chart_id => $fxloss_chart->id ], sort_by => ('acc_trans_id'));
1391 my $fx_gain_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, chart_id => $fxgain_chart->id ], sort_by => ('acc_trans_id'));
1392 is($fx_gain_transactions->[0]->amount, '0.34000', "$title: fx gain amount ok");
1393 is($fx_loss_transactions->[0]->amount, '-93.28000', "$title: fx loss amount ok");
1395 is(scalar @{$invoice->transactions}, 14, "$title: ap transaction has 14 transactions (incl. fxtransactions and gain_loss)");
1396 is($invoice->paid, $invoice->amount, "$title: ap transaction paid = amount in default currency");
1397 is(total_amount($invoice), 0, "$title: even balance");
1400 sub test_ap_currency_tax_not_included_and_payment_2_credit_note {
1401 my $title = 'test_ap_currency_tax_not_included_and_payment_2_credit_note';
1402 my $netamount = $::form->round_amount(-125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1403 my $amount = $::form->round_amount($netamount * 1.19,2); # 148.75 in CUR, 119.00 in EUR
1404 my $invoice = SL::DB::PurchaseInvoice->new(
1407 netamount => $netamount,
1408 transdate => $transdate2,
1410 vendor_id => $vendor->id,
1411 taxzone_id => $vendor->taxzone_id,
1412 currency_id => $currency->id,
1414 notes => 'test_ap_currency_tax_not_included_and_payment credit note 0.8 + 1.33333',
1415 invnumber => 'test_ap_currency_tax_not_included_and_payment credit note 0.8 + 1.33333',
1417 $invoice->add_ap_amount_row(
1418 amount => $invoice->netamount,
1419 chart => $ap_amount_chart,
1420 tax_id => $tax_9->id,
1423 $invoice->create_ap_row(chart => $ap_chart);
1426 is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1427 is($invoice->netamount , -100 , "$title: ap amount has been converted");
1428 is($invoice->amount , -119 , "$title: ap amount has been converted");
1429 is($invoice->taxincluded , 0 , "$title: ap transaction doesn\'t have taxincluded");
1430 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_amount_chart->id, trans_id => $invoice->id)->amount, '100.00000', $ap_amount_chart->accno . ': has been converted for currency');
1431 is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_chart->id, trans_id => $invoice->id)->amount, '-119.00000', $ap_chart->accno . ': has been converted for currency');
1433 $invoice->pay_invoice(chart_id => $bank->id,
1436 transdate => $transdate2->to_kivitendo,
1438 $invoice->pay_invoice(chart_id => $bank->id,
1441 transdate => $transdate3->to_kivitendo,
1443 $invoice->pay_invoice(chart_id => $bank->id,
1446 transdate => $transdate4->to_kivitendo,
1448 my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1449 is(scalar @{$fx_transactions}, 3, "$title: ap transaction has 3 fx transactions");
1450 is($fx_transactions->[0]->amount, '2.00000', "$title: fx transaction 1: 10.00-( 10.00*0.80000) = 2.00000");
1451 is($fx_transactions->[1]->amount, '-68.59000', "$title: fx transaction 2: 123.45-(123.45*1.55557) = -68.58511");
1452 is($fx_transactions->[2]->amount, '3.40000', "$title: fx transaction 3: 15.30-(15.30 *0.77777) = 3.40012");
1454 my $fx_gain_loss_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, chart_id => $fxgain_chart->id ], sort_by => ('acc_trans_id'));
1455 is($fx_gain_loss_transactions->[0]->amount, '93.28000', "$title: fx gain loss amount ok");
1457 is(scalar @{$invoice->transactions}, 14, "$title: ap transaction has 14 transactions (incl. fxtransactions and gain_loss)");
1458 is($invoice->paid, $invoice->amount, "$title: ap transaction paid = amount in default currency");
1459 is(total_amount($invoice), 0, "$title: even balance");
1462 Support::TestSetup::login();
1464 # test cases: without_skonto
1465 test_default_invoice_one_item_19_without_skonto();
1466 test_default_invoice_two_items_19_7_tax_with_skonto();
1467 test_default_invoice_two_items_19_7_without_skonto();
1468 test_default_invoice_two_items_19_7_without_skonto_incomplete_payment();
1469 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments();
1470 test_default_purchase_invoice_two_charts_19_7_without_skonto();
1471 test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto();
1472 test_default_invoice_one_item_19_without_skonto_overpaid();
1474 # test cases: difference_as_skonto
1475 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1476 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
1477 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
1478 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
1479 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
1480 test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1482 # test cases: with_skonto_pt
1483 test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
1484 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25();
1485 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple();
1486 test_default_purchase_invoice_two_charts_19_7_with_skonto();
1487 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included();
1488 test_default_invoice_two_items_19_7_tax_with_skonto_tax_included();
1490 # test payment of ar and ap transactions with currency and tax included/not included
1491 # exchangerate = 1.33333
1492 test_ar_currency_tax_not_included_and_payment();
1493 test_ar_currency_tax_included();
1494 test_ap_currency_tax_not_included_and_payment();
1495 test_ap_currency_tax_included();
1497 test_ar_currency_tax_not_included_and_payment_2(); # exchangerate 0.8
1498 test_ar_currency_tax_not_included_and_payment_2_credit_note(); # exchangerate 0.8
1500 test_ap_currency_tax_not_included_and_payment_2(); # two exchangerates, with fx_gain_loss
1501 test_ap_currency_tax_not_included_and_payment_2_credit_note(); # two exchangerates, with fx_gain_loss
1503 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
1504 my ($acc_trans_sum) = selectfirst_array_query($::form, $currency->db->dbh, 'SELECT SUM(amount) FROM acc_trans'); is($acc_trans_sum, '0.00000', "sum of all acc_trans is 0");
1507 # remove all created data at end of test