t/db_helper/payment.t - Testcode verschoben
[kivitendo-erp.git] / t / db_helper / payment.t
1 use Test::More;
2
3 use strict;
4
5 use lib 't';
6 use utf8;
7
8 use Carp;
9 use Support::TestSetup;
10 use Test::Exception;
11 use List::Util qw(sum);
12
13 use SL::Dev::Record qw(create_invoice_item create_sales_invoice create_credit_note);
14 use SL::Dev::CustomerVendor qw(new_customer new_vendor);
15 use SL::Dev::Part qw(new_part);
16 use SL::DB::Buchungsgruppe;
17 use SL::DB::Currency;
18 use SL::DB::Exchangerate;
19 use SL::DB::Customer;
20 use SL::DB::Vendor;
21 use SL::DB::Employee;
22 use SL::DB::Invoice;
23 use SL::DB::Part;
24 use SL::DB::Unit;
25 use SL::DB::TaxZone;
26 use SL::DB::BankAccount;
27 use SL::DB::PaymentTerm;
28 use SL::DBUtils qw(selectfirst_array_query);
29 use Data::Dumper;
30
31 my ($customer, $vendor, $currency_id, @parts, $buchungsgruppe, $buchungsgruppe7, $unit, $employee, $tax, $tax7, $tax_9, $taxzone, $payment_terms, $bank_account);
32 my ($transdate1, $transdate2, $transdate3, $transdate4, $currency, $exchangerate, $exchangerate2, $exchangerate3, $exchangerate4);
33 my ($ar_chart,$bank,$ar_amount_chart, $ap_chart, $ap_amount_chart, $fxloss_chart, $fxgain_chart);
34
35 my $ALWAYS_RESET = 1;
36
37 my $reset_state_counter = 0;
38
39 my $purchase_invoice_counter = 0; # used for generating purchase invnumber
40
41 Support::TestSetup::login();
42
43 # test cases: without_skonto
44 test_default_invoice_one_item_19_without_skonto();
45 test_default_invoice_two_items_19_7_tax_with_skonto();
46 test_default_invoice_two_items_19_7_without_skonto();
47 test_default_invoice_two_items_19_7_without_skonto_incomplete_payment();
48 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments();
49 test_default_purchase_invoice_two_charts_19_7_without_skonto();
50 test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto();
51 test_default_invoice_one_item_19_without_skonto_overpaid();
52 test_credit_note_two_items_19_7_tax_tax_not_included();
53
54 # test cases: difference_as_skonto
55 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
56 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
57 test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
58 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
59 test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
60 test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
61
62 # test cases: with_skonto_pt
63 test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
64 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25();
65 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple();
66 test_default_purchase_invoice_two_charts_19_7_with_skonto();
67 test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included();
68 test_default_invoice_two_items_19_7_tax_with_skonto_tax_included();
69
70 # test payment of ar and ap transactions with currency and tax included/not included
71 # exchangerate = 1.33333
72 test_ar_currency_tax_not_included_and_payment();
73 test_ar_currency_tax_included();
74 test_ap_currency_tax_not_included_and_payment();
75 test_ap_currency_tax_included();
76
77 test_ar_currency_tax_not_included_and_payment_2();              # exchangerate 0.8
78 test_ar_currency_tax_not_included_and_payment_2_credit_note();  # exchangerate 0.8
79
80 test_ap_currency_tax_not_included_and_payment_2();             # two exchangerates, with fx_gain_loss
81 test_ap_currency_tax_not_included_and_payment_2_credit_note(); # two exchangerates, with fx_gain_loss
82
83 { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
84   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");
85 }
86
87 # remove all created data at end of test
88 # clear_up();
89
90 done_testing();
91
92
93 sub clear_up {
94   SL::DB::Manager::InvoiceItem->delete_all(all => 1);
95   SL::DB::Manager::Invoice->delete_all(all => 1);
96   SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
97   SL::DB::Manager::Part->delete_all(all => 1);
98   SL::DB::Manager::Customer->delete_all(all => 1);
99   SL::DB::Manager::Vendor->delete_all(all => 1);
100   SL::DB::Manager::BankAccount->delete_all(all => 1);
101   SL::DB::Manager::PaymentTerm->delete_all(all => 1);
102   SL::DB::Manager::Exchangerate->delete_all(all => 1);
103   SL::DB::Manager::Currency->delete_all(where => [ name => 'CUR' ]);
104 };
105
106 sub reset_state {
107   my %params = @_;
108
109   return if $reset_state_counter;
110
111   $params{$_} ||= {} for qw(buchungsgruppe unit customer part tax vendor);
112
113   clear_up();
114
115   $transdate1 = DateTime->today;
116   $transdate2 = DateTime->today->add(days => 1);
117   $transdate3 = DateTime->today->add(days => 2);
118   $transdate4 = DateTime->today->add(days => 3);
119
120   $buchungsgruppe  = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%', %{ $params{buchungsgruppe} }) || croak "No accounting group";
121   $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%')                                || croak "No accounting group for 7\%";
122   $unit            = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} })                                      || croak "No unit";
123   $employee        = SL::DB::Manager::Employee->current                                                                    || croak "No employee";
124   $tax             = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} })                           || croak "No tax";
125   $tax7            = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07)                                              || croak "No tax for 7\%";
126   $taxzone         = SL::DB::Manager::TaxZone->find_by( description => 'Inland')                                           || croak "No taxzone";
127   $tax_9           = SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.19, %{ $params{tax} })                           || croak "No tax";
128   # $tax7            = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07)                                              || croak "No tax for 7\%";
129
130   $currency_id     = $::instance_conf->get_currency_id;
131
132   $currency = SL::DB::Currency->new(name => 'CUR')->save;
133
134   $fxgain_chart = SL::DB::Manager::Chart->find_by(accno => '2660') or die "Can't find fxgain_chart in test";
135   $fxloss_chart = SL::DB::Manager::Chart->find_by(accno => '2150') or die "Can't find fxloss_chart in test";
136
137   $currency->db->dbh->do('UPDATE defaults SET fxgain_accno_id = ' . $fxgain_chart->id);
138   $currency->db->dbh->do('UPDATE defaults SET fxloss_accno_id = ' . $fxloss_chart->id);
139   $::instance_conf->reload->data;
140   is($fxgain_chart->id,  $::instance_conf->get_fxgain_accno_id, "fxgain_chart was updated in defaults");
141   is($fxloss_chart->id,  $::instance_conf->get_fxloss_accno_id, "fxloss_chart was updated in defaults");
142
143   $exchangerate  = SL::DB::Exchangerate->new(transdate   => $transdate1,
144                                              buy         => '1.33333',
145                                              sell        => '1.33333',
146                                              currency_id => $currency->id,
147                                             )->save;
148   $exchangerate2 = SL::DB::Exchangerate->new(transdate   => $transdate2,
149                                              buy         => '0.8',
150                                              sell        => '0.8',
151                                              currency_id => $currency->id,
152                                             )->save;
153   $exchangerate3 = SL::DB::Exchangerate->new(transdate   => $transdate3,
154                                              buy         => '1.55557',
155                                              sell        => '1.55557',
156                                              currency_id => $currency->id,
157                                             )->save;
158   $exchangerate4 = SL::DB::Exchangerate->new(transdate   => $transdate4,
159                                              buy         => '0.77777',
160                                              sell        => '0.77777',
161                                              currency_id => $currency->id,
162                                             )->save;
163
164   $customer     = new_customer(
165     name        => 'Test Customer',
166     currency_id => $currency_id,
167     taxzone_id  => $taxzone->id,
168   )->save;
169
170   $bank_account     =  SL::DB::BankAccount->new(
171     account_number  => '123',
172     bank_code       => '123',
173     iban            => '123',
174     bic             => '123',
175     bank            => '123',
176     chart_id        => SL::DB::Manager::Chart->find_by( description => 'Bank' )->id,
177     name            => SL::DB::Manager::Chart->find_by( description => 'Bank' )->description,
178   )->save;
179
180   $payment_terms     =  SL::DB::PaymentTerm->new(
181     description      => 'payment',
182     description_long => 'payment',
183     terms_netto      => '30',
184     terms_skonto     => '5',
185     percent_skonto   => '0.05',
186     auto_calculation => 1,
187   )->save;
188
189   $vendor       = new_vendor(
190     name        => 'Test Vendor',
191     currency_id => $currency_id,
192     taxzone_id  => $taxzone->id,
193     payment_id  => $payment_terms->id,
194   )->save;
195
196
197   @parts = ();
198   push @parts, new_part(
199     partnumber         => 'T4254',
200     description        => 'Fourty-two fifty-four',
201     lastcost           => 1.93,
202     sellprice          => 2.34,
203     buchungsgruppen_id => $buchungsgruppe->id,
204     unit               => $unit->name,
205     %{ $params{part1} }
206   )->save;
207
208   push @parts, new_part(
209     partnumber         => 'T0815',
210     description        => 'Zero EIGHT fifteeN @ 7%',
211     lastcost           => 5.473,
212     sellprice          => 9.714,
213     buchungsgruppen_id => $buchungsgruppe7->id,
214     unit               => $unit->name,
215     %{ $params{part2} }
216   )->save;
217   push @parts, new_part(
218     partnumber         => '19%',
219     description        => 'Testware 19%',
220     lastcost           => 0,
221     sellprice          => 50,
222     buchungsgruppen_id => $buchungsgruppe->id,
223     unit               => $unit->name,
224     %{ $params{part3} }
225   )->save;
226   push @parts, new_part(
227     partnumber         => '7%',
228     description        => 'Testware 7%',
229     lastcost           => 0,
230     sellprice          => 50,
231     buchungsgruppen_id => $buchungsgruppe7->id,
232     unit               => $unit->name,
233     %{ $params{part4} }
234   )->save;
235
236   $ar_chart        = SL::DB::Manager::Chart->find_by( accno => '1400' ); # Forderungen
237   $ap_chart        = SL::DB::Manager::Chart->find_by( accno => '1600' ); # Verbindlichkeiten
238   $bank            = SL::DB::Manager::Chart->find_by( accno => '1200' ); # Bank
239   $ar_amount_chart = SL::DB::Manager::Chart->find_by( accno => '8400' ); # Erlöse
240   $ap_amount_chart = SL::DB::Manager::Chart->find_by( accno => '3400' ); # Wareneingang 19%
241
242   $reset_state_counter++;
243 }
244
245 sub new_purchase_invoice {
246   # my %params  = @_;
247   # manually create a Kreditorenbuchung from scratch, ap + acc_trans bookings, as no helper exists yet, like $invoice->post.
248   # arap-Booking must come last in the acc_trans order
249   $purchase_invoice_counter++;
250
251   my $purchase_invoice = SL::DB::PurchaseInvoice->new(
252     vendor_id   => $vendor->id,
253     invnumber   => 'newap ' . $purchase_invoice_counter ,
254     currency_id => $currency_id,
255     employee_id => $employee->id,
256     gldate      => $transdate1,
257     taxzone_id  => $taxzone->id,
258     transdate   => $transdate1,
259     invoice     => 0,
260     type        => 'invoice',
261     taxincluded => 0,
262     amount      => '226',
263     netamount   => '200',
264     paid        => '0',
265     # %params,
266   )->save;
267
268   my $expense_chart  = SL::DB::Manager::Chart->find_by(accno => '3400');
269   my $expense_chart_booking= SL::DB::AccTransaction->new(
270                                         trans_id   => $purchase_invoice->id,
271                                         chart_id   => $expense_chart->id,
272                                         chart_link => $expense_chart->link,
273                                         amount     => '-100',
274                                         transdate  => $transdate1,
275                                         source     => '',
276                                         taxkey     => 9,
277                                         tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
278   $expense_chart_booking->save;
279
280   my $tax_chart  = SL::DB::Manager::Chart->find_by(accno => '1576');
281   my $tax_chart_booking= SL::DB::AccTransaction->new(
282                                         trans_id   => $purchase_invoice->id,
283                                         chart_id   => $tax_chart->id,
284                                         chart_link => $tax_chart->link,
285                                         amount     => '-19',
286                                         transdate  => $transdate1,
287                                         source     => '',
288                                         taxkey     => 0,
289                                         tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
290   $tax_chart_booking->save;
291   $expense_chart  = SL::DB::Manager::Chart->find_by(accno => '3300');
292   $expense_chart_booking= SL::DB::AccTransaction->new(
293                                         trans_id   => $purchase_invoice->id,
294                                         chart_id   => $expense_chart->id,
295                                         chart_link => $expense_chart->link,
296                                         amount     => '-100',
297                                         transdate  => $transdate1,
298                                         source     => '',
299                                         taxkey     => 8,
300                                         tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
301   $expense_chart_booking->save;
302
303
304   $tax_chart  = SL::DB::Manager::Chart->find_by(accno => '1571');
305   $tax_chart_booking= SL::DB::AccTransaction->new(
306                                          trans_id   => $purchase_invoice->id,
307                                          chart_id   => $tax_chart->id,
308                                          chart_link => $tax_chart->link,
309                                          amount     => '-7',
310                                          transdate  => $transdate1,
311                                          source     => '',
312                                          taxkey     => 0,
313                                          tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
314   $tax_chart_booking->save;
315   my $arap_chart  = SL::DB::Manager::Chart->find_by(accno => '1600');
316   my $arap_booking= SL::DB::AccTransaction->new(trans_id   => $purchase_invoice->id,
317                                                 chart_id   => $arap_chart->id,
318                                                 chart_link => $arap_chart->link,
319                                                 amount     => '226',
320                                                 transdate  => $transdate1,
321                                                 source     => '',
322                                                 taxkey     => 0,
323                                                 tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
324   $arap_booking->save;
325
326   return $purchase_invoice;
327 }
328
329 sub number_of_payments {
330   my $invoice = shift;
331
332   my $number_of_payments;
333   my $paid_amount;
334   foreach my $transaction ( @{ $invoice->transactions } ) {
335     if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
336       $paid_amount += $transaction->amount ;
337       $number_of_payments++;
338     };
339   };
340   return ($number_of_payments, $paid_amount);
341 };
342
343 sub total_amount {
344   my $invoice = shift;
345
346   my $total = sum map { $_->amount } @{ $invoice->transactions };
347
348   return $::form->round_amount($total, 5);
349
350 };
351
352
353 # test 1
354 sub test_default_invoice_one_item_19_without_skonto() {
355   reset_state() if $ALWAYS_RESET;
356
357   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
358   my $invoice = create_sales_invoice(
359     taxincluded  => 0,
360     invoiceitems => [ $item ],
361     payment_id   => $payment_terms->id,
362   );
363
364   my $purchase_invoice = new_purchase_invoice();
365
366   # default values
367   my %params = ( chart_id => $bank_account->chart_id,
368                  transdate => DateTime->today_local->to_kivitendo
369                );
370
371   $params{amount} = '6.96';
372   $params{payment_type} = 'without_skonto';
373
374   $invoice->pay_invoice( %params );
375
376   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
377   my $total = total_amount($invoice);
378
379   my $title = 'default invoice, one item, 19% tax, without_skonto';
380
381   is($invoice->netamount,   5.85,      "${title}: netamount");
382   is($invoice->amount,      6.96,      "${title}: amount");
383   is($paid_amount,         -6.96,      "${title}: paid amount");
384   is($number_of_payments,      1,      "${title}: 1 AR_paid booking");
385   is($invoice->paid,        6.96,      "${title}: paid");
386   is($total,                   0,      "${title}: even balance");
387
388 }
389
390 sub test_default_invoice_one_item_19_without_skonto_overpaid() {
391   reset_state() if $ALWAYS_RESET;
392
393   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
394   my $invoice = create_sales_invoice(
395     taxincluded  => 0,
396     invoiceitems => [ $item ],
397     payment_id   => $payment_terms->id,
398   );
399
400   my $purchase_invoice = new_purchase_invoice();
401
402
403   # default values
404   my %params = ( chart_id => $bank_account->chart_id,
405                  transdate => DateTime->today_local->to_kivitendo
406                );
407
408   $params{amount} = '16.96';
409   $params{payment_type} = 'without_skonto';
410   $invoice->pay_invoice( %params );
411
412   $params{amount} = '-10.00';
413   $invoice->pay_invoice( %params );
414
415   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
416   my $total = total_amount($invoice);
417
418   my $title = 'default invoice, one item, 19% tax, without_skonto';
419
420   is($invoice->netamount,   5.85,      "${title}: netamount");
421   is($invoice->amount,      6.96,      "${title}: amount");
422   is($paid_amount,         -6.96,      "${title}: paid amount");
423   is($number_of_payments,      2,      "${title}: 1 AR_paid booking");
424   is($invoice->paid,        6.96,      "${title}: paid");
425   is($total,                   0,      "${title}: even balance");
426
427 }
428
429
430 # test 2
431 sub test_default_invoice_two_items_19_7_tax_with_skonto() {
432   reset_state() if $ALWAYS_RESET;
433
434   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
435   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
436   my $invoice = create_sales_invoice(
437     taxincluded  => 0,
438     invoiceitems => [ $item1, $item2 ],
439     payment_id   => $payment_terms->id,
440   );
441
442   # default values
443   my %params = ( chart_id => $bank_account->chart_id,
444                  transdate => DateTime->today_local->to_kivitendo
445                );
446
447   $params{payment_type} = 'with_skonto_pt';
448   $params{amount}       = $invoice->amount_less_skonto;
449
450   $invoice->pay_invoice( %params );
451
452   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
453   my $total = total_amount($invoice);
454
455   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
456
457   is($invoice->netamount,  5.85 + 11.66,   "${title}: netamount");
458   is($invoice->amount,     6.96 + 12.48,   "${title}: amount");
459   is($paid_amount,               -19.44,   "${title}: paid amount");
460   is($invoice->paid,              19.44,   "${title}: paid");
461   is($number_of_payments,             3,   "${title}: 3 AR_paid bookings");
462   is($total,                          0,   "${title}: even balance");
463 }
464
465 sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included() {
466   reset_state() if $ALWAYS_RESET;
467
468   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
469   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
470   my $invoice = create_sales_invoice(
471     taxincluded  => 1,
472     invoiceitems => [ $item1, $item2 ],
473     payment_id   => $payment_terms->id,
474   );
475
476   # default values
477   my %params = ( chart_id => $bank_account->chart_id,
478                  transdate => DateTime->today_local->to_kivitendo
479                );
480
481   $params{payment_type} = 'with_skonto_pt';
482   $params{amount}       = $invoice->amount_less_skonto;
483
484   $invoice->pay_invoice( %params );
485
486   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
487   my $total = total_amount($invoice);
488
489   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
490
491   is($invoice->netamount,         15.82,   "${title}: netamount");
492   is($invoice->amount,            17.51,   "${title}: amount");
493   is($paid_amount,               -17.51,   "${title}: paid amount");
494   is($invoice->paid,              17.51,   "${title}: paid");
495   is($number_of_payments,             3,   "${title}: 3 AR_paid bookings");
496   { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
497   is($total,                          0,   "${title}: even balance");
498   }
499 }
500
501 # test 3 : two items, without skonto
502 sub test_default_invoice_two_items_19_7_without_skonto() {
503   reset_state() if $ALWAYS_RESET;
504
505   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
506   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
507   my $invoice = create_sales_invoice(
508     taxincluded  => 0,
509     invoiceitems => [ $item1, $item2 ],
510     payment_id   => $payment_terms->id,
511   );
512
513   # default values
514   my %params = ( chart_id => $bank_account->chart_id,
515                  transdate => DateTime->today_local->to_kivitendo
516                );
517
518   $params{amount} = '19.44'; # pass full amount
519   $params{payment_type} = 'without_skonto';
520
521   $invoice->pay_invoice( %params );
522
523   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
524   my $total = total_amount($invoice);
525
526   my $title = 'default invoice, two items, 19/7% tax without skonto';
527
528   is($invoice->netamount,     5.85 + 11.66,     "${title}: netamount");
529   is($invoice->amount,        6.96 + 12.48,     "${title}: amount");
530   is($paid_amount,                  -19.44,     "${title}: paid amount");
531   is($invoice->paid,                 19.44,     "${title}: paid");
532   is($number_of_payments,                1,     "${title}: 1 AR_paid bookings");
533   is($total,                             0,     "${title}: even balance");
534 }
535
536 # test 4
537 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
538   reset_state() if $ALWAYS_RESET;
539
540   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
541   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
542   my $invoice = create_sales_invoice(
543     taxincluded  => 0,
544     invoiceitems => [ $item1, $item2 ],
545     payment_id   => $payment_terms->id,
546   );
547
548   $invoice->pay_invoice( amount       => '9.44',
549                          payment_type => 'without_skonto',
550                          chart_id     => $bank_account->chart_id,
551                          transdate    => DateTime->today_local->to_kivitendo,
552                        );
553
554   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
555   my $total = total_amount($invoice);
556
557   my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
558
559   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
560   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
561   is($paid_amount,              -9.44,             "${title}: paid amount");
562   is($invoice->paid,             9.44,            "${title}: paid");
563   is($number_of_payments,   1,                "${title}: 1 AR_paid bookings");
564   is($total,                    0,                "${title}: even balance");
565 }
566
567 # test 5
568 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
569   reset_state() if $ALWAYS_RESET;
570
571   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
572   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
573   my $invoice = create_sales_invoice(
574     taxincluded  => 0,
575     invoiceitems => [ $item1, $item2 ],
576     payment_id   => $payment_terms->id,
577   );
578
579   $invoice->pay_invoice( amount       => '9.44',
580                          payment_type => 'without_skonto',
581                          chart_id     => $bank_account->chart_id,
582                          transdate    => DateTime->today_local->to_kivitendo
583                        );
584   $invoice->pay_invoice( amount       => '10.00',
585                          chart_id     => $bank_account->chart_id,
586                          transdate    => DateTime->today_local->to_kivitendo
587                        );
588
589   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
590   my $total = total_amount($invoice);
591
592   my $title = 'default invoice, two items, 19/7% tax not included';
593
594   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
595   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
596   is($paid_amount,                     -19.44,     "${title}: paid amount");
597   is($invoice->paid,                    19.44,     "${title}: paid");
598   is($number_of_payments,                   2,     "${title}: 2 AR_paid bookings");
599   is($total,                                0,     "${title}: even balance");
600
601 }
602
603 # test 6
604 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
605   reset_state() if $ALWAYS_RESET;
606
607   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
608   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
609   my $invoice = create_sales_invoice(
610     taxincluded  => 0,
611     invoiceitems => [ $item1, $item2 ],
612     payment_id   => $payment_terms->id,
613   );
614
615   $invoice->pay_invoice( amount       => '9.44',
616                          payment_type => 'without_skonto',
617                          chart_id     => $bank_account->chart_id,
618                          transdate    => DateTime->today_local->to_kivitendo
619                        );
620   $invoice->pay_invoice( amount       => '8.73',
621                          payment_type => 'without_skonto',
622                          chart_id     => $bank_account->chart_id,
623                          transdate    => DateTime->today_local->to_kivitendo
624                        );
625   $invoice->pay_invoice( amount       => $invoice->open_amount,
626                          payment_type => 'difference_as_skonto',
627                          chart_id     => $bank_account->chart_id,
628                          transdate    => DateTime->today_local->to_kivitendo
629                        );
630
631   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
632   my $total = total_amount($invoice);
633
634   my $title = 'default invoice, two items, 19/7% tax not included';
635
636   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
637   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
638   is($paid_amount,                     -19.44,     "${title}: paid amount");
639   is($invoice->paid,                    19.44,     "${title}: paid");
640   is($number_of_payments,                   4,     "${title}: 4 AR_paid bookings");
641   is($total,                                0,     "${title}: even balance");
642
643 }
644
645 sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
646   reset_state() if $ALWAYS_RESET;
647
648   # if there is only one cent left there can only be one skonto booking, the
649   # error handling should choose the highest amount, which is the 7% account
650   # (11.66) rather than the 19% account (5.85).  The actual tax amount is
651   # higher for the 19% case, though (1.11 compared to 0.82)
652
653   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
654   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
655   my $invoice = create_sales_invoice(
656     taxincluded  => 0,
657     invoiceitems => [ $item1, $item2 ],
658     payment_id   => $payment_terms->id,
659   );
660
661   $invoice->pay_invoice( amount       => '19.42',
662                          payment_type => 'without_skonto',
663                          chart_id     => $bank_account->chart_id,
664                          transdate    => DateTime->today_local->to_kivitendo
665                        );
666   $invoice->pay_invoice( amount       => $invoice->open_amount,
667                          payment_type => 'difference_as_skonto',
668                          chart_id     => $bank_account->chart_id,
669                          transdate    => DateTime->today_local->to_kivitendo
670                        );
671
672   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
673   my $total = total_amount($invoice);
674
675   my $title = 'default invoice, two items, 19/7% tax not included';
676
677   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
678   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
679   is($paid_amount,                     -19.44,     "${title}: paid amount");
680   is($invoice->paid,                    19.44,     "${title}: paid");
681   is($number_of_payments,                   3,     "${title}: 2 AR_paid bookings");
682   is($total,                                0,     "${title}: even balance");
683
684 }
685
686 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
687   reset_state() if $ALWAYS_RESET;
688
689   # if there are two cents left there will be two skonto bookings, 1 cent each
690   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
691   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
692   my $invoice = create_sales_invoice(
693     taxincluded  => 0,
694     invoiceitems => [ $item1, $item2 ],
695     payment_id   => $payment_terms->id,
696   );
697
698   $invoice->pay_invoice( amount       => '19.42',
699                          payment_type => 'without_skonto',
700                          chart_id     => $bank_account->chart_id,
701                          transdate    => DateTime->today_local->to_kivitendo
702                        );
703   $invoice->pay_invoice( amount       => $invoice->open_amount,
704                          payment_type => 'difference_as_skonto',
705                          chart_id     => $bank_account->chart_id,
706                          transdate    => DateTime->today_local->to_kivitendo
707                        );
708
709   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
710   my $total = total_amount($invoice);
711
712   my $title = 'default invoice, two items, 19/7% tax not included';
713
714   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
715   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
716   is($paid_amount,                     -19.44,     "${title}: paid amount");
717   is($invoice->paid,                    19.44,     "${title}: paid");
718   is($number_of_payments,                   3,     "${title}: 3 AR_paid bookings");
719   is($total,                                0,     "${title}: even balance");
720
721 }
722
723 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
724   reset_state() if $ALWAYS_RESET;
725
726   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
727   my $invoice = create_sales_invoice(
728     taxincluded  => 0,
729     invoiceitems => [ $item ],
730     payment_id   => $payment_terms->id,
731   );
732
733   # default values
734   my %params = ( chart_id  => $bank_account->chart_id,
735                  transdate => DateTime->today_local->to_kivitendo
736                );
737
738   $params{amount}       = '2.32';
739   $params{payment_type} = 'without_skonto';
740   $invoice->pay_invoice( %params );
741
742   $params{amount}       = '3.81';
743   $params{payment_type} = 'without_skonto';
744   $invoice->pay_invoice( %params );
745
746   $params{amount}       = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
747   $params{payment_type} = 'difference_as_skonto';
748   $invoice->pay_invoice( %params );
749
750   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
751   my $total = total_amount($invoice);
752
753   my $title = 'default invoice, one item, 19% tax, without_skonto';
754
755   is($invoice->netamount,       5.85,     "${title}: netamount");
756   is($invoice->amount,          6.96,     "${title}: amount");
757   is($paid_amount,             -6.96,     "${title}: paid amount");
758   is($number_of_payments,          3,     "${title}: 3 AR_paid booking");
759   is($invoice->paid,            6.96,     "${title}: paid");
760   is($total,                       0,     "${title}: even balance");
761
762 }
763
764 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
765   reset_state() if $ALWAYS_RESET;
766
767   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
768   my $invoice = create_sales_invoice(
769     taxincluded  => 0,
770     invoiceitems => [ $item ],
771     payment_id   => $payment_terms->id,
772   );
773
774   # default values
775   my %params = ( chart_id  => $bank_account->chart_id,
776                  transdate => DateTime->today_local->to_kivitendo
777                );
778
779   $params{amount}       = '6.95';
780   $params{payment_type} = 'without_skonto';
781   $invoice->pay_invoice( %params );
782
783   $params{amount}       = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
784   $params{payment_type} = 'difference_as_skonto';
785   $invoice->pay_invoice( %params );
786
787   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
788   my $total = total_amount($invoice);
789
790   my $title = 'default invoice, one item, 19% tax, without_skonto';
791
792   is($invoice->netamount,       5.85,     "${title}: netamount");
793   is($invoice->amount,          6.96,     "${title}: amount");
794   is($paid_amount,             -6.96,     "${title}: paid amount");
795   is($number_of_payments,          2,     "${title}: 3 AR_paid booking");
796   is($invoice->paid,            6.96,     "${title}: paid");
797   is($total,                       0,     "${title}: even balance");
798
799 }
800
801 # test 3 : two items, without skonto
802 sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
803   reset_state() if $ALWAYS_RESET;
804
805   my $purchase_invoice = new_purchase_invoice();
806
807   my %params = ( chart_id => $bank_account->chart_id,
808                  transdate => DateTime->today_local->to_kivitendo
809                );
810
811   $params{amount} = '226'; # pass full amount
812   $params{payment_type} = 'without_skonto';
813
814   $purchase_invoice->pay_invoice( %params );
815
816   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
817   my $total = total_amount($purchase_invoice);
818
819   my $title = 'default invoice, two items, 19/7% tax without skonto';
820
821   is($paid_amount,         226,     "${title}: paid amount");
822   is($number_of_payments,    1,     "${title}: 1 AP_paid bookings");
823   is($total,                 0,     "${title}: even balance");
824
825 }
826
827 sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
828   reset_state() if $ALWAYS_RESET;
829
830   my $purchase_invoice = new_purchase_invoice();
831
832   my %params = ( chart_id => $bank_account->chart_id,
833                  transdate => DateTime->today_local->to_kivitendo
834                );
835
836   # $params{amount} = '226'; # pass full amount
837   $params{payment_type} = 'with_skonto_pt';
838
839   $purchase_invoice->pay_invoice( %params );
840
841   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
842   my $total = total_amount($purchase_invoice);
843
844   my $title = 'default invoice, two items, 19/7% tax without skonto';
845
846   is($paid_amount,         226,     "${title}: paid amount");
847   is($number_of_payments,    3,     "${title}: 1 AP_paid bookings");
848   is($total,                 0,     "${title}: even balance");
849
850 }
851
852 sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
853   # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
854   reset_state() if $ALWAYS_RESET;
855   my $purchase_invoice = new_purchase_invoice();
856   $purchase_invoice->pay_invoice(
857                           amount       => ( $purchase_invoice->amount / 3 * 2),
858                           payment_type => 'without_skonto',
859                           chart_id     => $bank_account->chart_id,
860                           transdate    => DateTime->today_local->to_kivitendo
861                          );
862   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
863   my $total = total_amount($purchase_invoice);
864
865   my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
866
867   is($paid_amount,         150.67,   "${title}: paid amount");
868   is($number_of_payments,       1,   "${title}: 1 AP_paid bookings");
869   is($total,                    0,   "${title}: even balance");
870 };
871
872
873 sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
874   reset_state() if $ALWAYS_RESET;
875
876   my $purchase_invoice = new_purchase_invoice();
877
878   # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
879   $purchase_invoice->pay_invoice(
880                           amount       => ( $purchase_invoice->amount / 3 * 2),
881                           payment_type => 'without_skonto',
882                           chart_id     => $bank_account->chart_id,
883                           transdate    => DateTime->today_local->to_kivitendo
884                          );
885   $purchase_invoice->pay_invoice(
886                           amount       => ( $purchase_invoice->amount / 5 ),
887                           payment_type => 'without_skonto',
888                           chart_id     => $bank_account->chart_id,
889                           transdate    => DateTime->today_local->to_kivitendo
890                          );
891   $purchase_invoice->pay_invoice(
892                           payment_type => 'difference_as_skonto',
893                           chart_id     => $bank_account->chart_id,
894                           transdate    => DateTime->today_local->to_kivitendo
895                          );
896
897   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice);
898   my $total = total_amount($purchase_invoice);
899
900   my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
901
902   is($paid_amount,         226, "${title}: paid amount");
903   is($number_of_payments,    4, "${title}: 1 AP_paid bookings");
904   is($total,                 0, "${title}: even balance");
905
906 }
907
908 # test
909 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
910   reset_state() if $ALWAYS_RESET;
911
912   my $item1   = create_invoice_item(part => $parts[2], qty => 1);
913   my $item2   = create_invoice_item(part => $parts[3], qty => 1);
914   my $invoice = create_sales_invoice(
915     taxincluded  => 0,
916     invoiceitems => [ $item1, $item2 ],
917     payment_id   => $payment_terms->id,
918   );
919
920   # default values
921   my %params = ( chart_id => $bank_account->chart_id,
922                  transdate => DateTime->today_local->to_kivitendo
923                );
924
925   $params{amount} = $invoice->amount_less_skonto;
926   $params{payment_type} = 'with_skonto_pt';
927
928   $invoice->pay_invoice( %params );
929
930   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
931   my $total = total_amount($invoice);
932
933   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
934
935   is($invoice->netamount,        100,     "${title}: netamount");
936   is($invoice->amount,           113,     "${title}: amount");
937   is($paid_amount,              -113,     "${title}: paid amount");
938   is($invoice->paid,             113,     "${title}: paid");
939   is($number_of_payments,          3,     "${title}: 3 AR_paid bookings");
940   is($total,                       0,     "${title}: even balance");
941 }
942
943 # test
944 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
945   reset_state() if $ALWAYS_RESET;
946
947   my $item1   = create_invoice_item(part => $parts[2], qty => 0.5);
948   my $item2   = create_invoice_item(part => $parts[3], qty => 0.5);
949   my $item3   = create_invoice_item(part => $parts[2], qty => 0.5);
950   my $item4   = create_invoice_item(part => $parts[3], qty => 0.5);
951   my $invoice = create_sales_invoice(
952     taxincluded  => 0,
953     invoiceitems => [ $item1, $item2, $item3, $item4 ],
954     payment_id   => $payment_terms->id,
955   );
956
957   # default values
958   my %params = ( chart_id => $bank_account->chart_id,
959                  transdate => DateTime->today_local->to_kivitendo
960                );
961
962   $params{amount} = $invoice->amount_less_skonto;
963   $params{payment_type} = 'with_skonto_pt';
964
965   $invoice->pay_invoice( %params );
966
967   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
968   my $total = total_amount($invoice);
969
970   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
971
972   is($invoice->netamount , 100  , "${title}: netamount");
973   is($invoice->amount    , 113  , "${title}: amount");
974   is($paid_amount        , -113 , "${title}: paid amount");
975   is($invoice->paid      , 113  , "${title}: paid");
976   is($number_of_payments , 3    , "${title}: 3 AR_paid bookings");
977   is($total              , 0    , "${title}: even balance");
978 }
979
980 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
981   reset_state() if $ALWAYS_RESET;
982
983   my $item1   = create_invoice_item(part => $parts[2], qty => 0.5);
984   my $item2   = create_invoice_item(part => $parts[3], qty => 0.5);
985   my $item3   = create_invoice_item(part => $parts[2], qty => 0.5);
986   my $item4   = create_invoice_item(part => $parts[3], qty => 0.5);
987   my $invoice = create_sales_invoice(
988     taxincluded  => 1,
989     invoiceitems => [ $item1, $item2, $item3, $item4 ],
990     payment_id   => $payment_terms->id,
991   );
992
993   # default values
994   my %params = ( chart_id => $bank_account->chart_id,
995                  transdate => DateTime->today_local->to_kivitendo
996                );
997
998   $params{amount} = $invoice->amount_less_skonto;
999   $params{payment_type} = 'with_skonto_pt';
1000
1001   $invoice->pay_invoice( %params );
1002
1003   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
1004   my $total = total_amount($invoice);
1005
1006   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
1007
1008   is($invoice->netamount,   88.75,    "${title}: netamount");
1009   is($invoice->amount,        100,    "${title}: amount");
1010   is($paid_amount,           -100,    "${title}: paid amount");
1011   is($invoice->paid,          100,    "${title}: paid");
1012   is($number_of_payments,       3,    "${title}: 3 AR_paid bookings");
1013   { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
1014   is($total,                    0,    "${title}: even balance");
1015   }
1016 }
1017
1018 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
1019   reset_state() if $ALWAYS_RESET;
1020
1021   my $item1   = create_invoice_item(part => $parts[2], qty => 0.5);
1022   my $item2   = create_invoice_item(part => $parts[3], qty => 0.5);
1023   my $item3   = create_invoice_item(part => $parts[2], qty => 0.5);
1024   my $item4   = create_invoice_item(part => $parts[3], qty => 0.5);
1025   my $invoice = create_sales_invoice(
1026     taxincluded  => 0,
1027     invoiceitems => [ $item1, $item2, $item3, $item4 ],
1028     payment_id   => $payment_terms->id,
1029   );
1030
1031   $invoice->pay_invoice( amount       => '90',
1032                          payment_type => 'without_skonto',
1033                          chart_id     => $bank_account->chart_id,
1034                          transdate => DateTime->today_local->to_kivitendo
1035                        );
1036   $invoice->pay_invoice( payment_type => 'difference_as_skonto',
1037                          chart_id     => $bank_account->chart_id,
1038                          transdate    => DateTime->today_local->to_kivitendo
1039                        );
1040
1041   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
1042   my $total = total_amount($invoice);
1043
1044   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
1045
1046   is($invoice->netamount,  100,     "${title}: netamount");
1047   is($invoice->amount,     113,     "${title}: amount");
1048   is($paid_amount,        -113,     "${title}: paid amount");
1049   is($invoice->paid,       113,     "${title}: paid");
1050   is($number_of_payments,    3,     "${title}: 3 AR_paid bookings");
1051   is($total,                 0,     "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
1052 }
1053
1054 sub test_ar_currency_tax_not_included_and_payment {
1055   my $netamount = $::form->round_amount(75 * $exchangerate->sell,2); #  75 in CUR, 100.00 in EUR
1056   my $amount    = $::form->round_amount($netamount * 1.19,2);        # 100 in CUR, 119.00 in EUR
1057   my $invoice   = SL::DB::Invoice->new(
1058       invoice      => 0,
1059       amount       => $amount,
1060       netamount    => $netamount,
1061       transdate    => $transdate1,
1062       taxincluded  => 0,
1063       customer_id  => $customer->id,
1064       taxzone_id   => $customer->taxzone_id,
1065       currency_id  => $currency->id,
1066       transactions => [],
1067       notes        => 'test_ar_currency_tax_not_included_and_payment',
1068   );
1069   $invoice->add_ar_amount_row(
1070     amount     => $invoice->netamount,
1071     chart      => $ar_amount_chart,
1072     tax_id     => $tax->id,
1073   );
1074
1075   $invoice->create_ar_row(chart => $ar_chart);
1076   $invoice->save;
1077
1078   is(SL::DB::Manager::Invoice->get_all_count(where => [ invoice => 0 ]), 1, 'there is one ar transaction');
1079   is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1080   is($invoice->netamount   , 100           , 'ar amount has been converted');
1081   is($invoice->amount      , 119           , 'ar amount has been converted');
1082   is($invoice->taxincluded ,   0           , 'ar transaction doesn\'t have taxincluded');
1083   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');
1084   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');
1085
1086   $invoice->pay_invoice(chart_id   => $bank->id,
1087                         amount     => 50,
1088                         currency   => 'CUR',
1089                         transdate  => $transdate1->to_kivitendo,
1090                        );
1091   $invoice->pay_invoice(chart_id   => $bank->id,
1092                         amount     => 39.25,
1093                         currency   => 'CUR',
1094                         transdate  => $transdate1->to_kivitendo,
1095                        );
1096   # $invoice->pay_invoice(chart_id   => $bank->id,
1097   #                       amount     => 30,
1098   #                       transdate  => $transdate2->to_kivitendo,
1099   #                      );
1100   is(scalar @{$invoice->transactions}, 9, 'ar transaction has 9 transactions (incl. fxtransactions)');
1101   is($invoice->paid, $invoice->amount, 'ar transaction paid = amount in default currency');
1102 };
1103
1104 sub test_ar_currency_tax_included {
1105   # we want the acc_trans amount to be 100
1106   my $amount    = $::form->round_amount(75 * $exchangerate->sell * 1.19);
1107   my $netamount = $::form->round_amount($amount / 1.19,2);
1108   my $invoice = SL::DB::Invoice->new(
1109       invoice      => 0,
1110       amount       => 119,
1111       netamount    => 100,
1112       transdate    => $transdate1,
1113       taxincluded  => 1,
1114       customer_id  => $customer->id,
1115       taxzone_id   => $customer->taxzone_id,
1116       currency_id  => $currency->id,
1117       notes        => 'test_ar_currency_tax_included',
1118       transactions => [],
1119   );
1120   $invoice->add_ar_amount_row( # should take care of taxincluded
1121     amount     => $invoice->amount, # tax included in local currency
1122     chart      => $ar_amount_chart,
1123     tax_id     => $tax->id,
1124   );
1125
1126   $invoice->create_ar_row( chart => $ar_chart );
1127   $invoice->save;
1128   is(SL::DB::Manager::Invoice->get_all_count(where => [ invoice => 0 ]), 2, 'there are now two ar transactions');
1129   is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1130   is($invoice->amount      , $amount       , 'amount ok');
1131   is($invoice->netamount   , $netamount    , 'netamount ok');
1132   is($invoice->taxincluded , 1             , 'ar transaction has taxincluded');
1133   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');
1134   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');
1135   $invoice->pay_invoice(chart_id   => $bank->id,
1136                         amount     => 89.25,
1137                         currency   => 'CUR',
1138                         transdate  => $transdate1->to_kivitendo,
1139                        );
1140
1141 };
1142
1143 sub test_ap_currency_tax_not_included_and_payment {
1144   my $netamount = $::form->round_amount(75 * $exchangerate->buy,2); #  75 in CUR, 100.00 in EUR
1145   my $amount    = $::form->round_amount($netamount * 1.19,2);        # 100 in CUR, 119.00 in EUR
1146   my $invoice   = SL::DB::PurchaseInvoice->new(
1147       invoice      => 0,
1148       invnumber    => 'test_ap_currency_tax_not_included_and_payment',
1149       amount       => $amount,
1150       netamount    => $netamount,
1151       transdate    => $transdate1,
1152       taxincluded  => 0,
1153       vendor_id    => $vendor->id,
1154       taxzone_id   => $vendor->taxzone_id,
1155       currency_id  => $currency->id,
1156       transactions => [],
1157       notes        => 'test_ap_currency_tax_not_included_and_payment',
1158   );
1159   $invoice->add_ap_amount_row(
1160     amount     => $invoice->netamount,
1161     chart      => $ap_amount_chart,
1162     tax_id     => $tax_9->id,
1163   );
1164
1165   $invoice->create_ap_row(chart => $ap_chart);
1166   $invoice->save;
1167
1168   is($invoice->currency_id, $currency->id, 'currency_id has been saved');
1169   is($invoice->netamount, 100, 'ap amount has been converted');
1170   is($invoice->amount, 119, 'ap amount has been converted');
1171   is($invoice->taxincluded, 0, 'ap transaction doesn\'t have taxincluded');
1172   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');
1173   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');
1174
1175   $invoice->pay_invoice(chart_id   => $bank->id,
1176                         amount     => 50,
1177                         currency   => 'CUR',
1178                         transdate  => $transdate1->to_kivitendo,
1179                        );
1180   $invoice->pay_invoice(chart_id   => $bank->id,
1181                         amount     => 39.25,
1182                         currency   => 'CUR',
1183                         transdate  => $transdate1->to_kivitendo,
1184                        );
1185   is(scalar @{$invoice->transactions}, 9, 'ap transaction has 9 transactions (incl. fxtransactions)');
1186   is($invoice->paid, $invoice->amount, 'ap transaction paid = amount in default currency');
1187 };
1188
1189 sub test_ap_currency_tax_included {
1190   # we want the acc_trans amount to be 100
1191   my $amount    = $::form->round_amount(75 * $exchangerate->buy * 1.19);
1192   my $netamount = $::form->round_amount($amount / 1.19,2);
1193   my $invoice = SL::DB::PurchaseInvoice->new(
1194       invoice      => 0,
1195       amount       => 119, #$amount,
1196       netamount    => 100, #$netamount,
1197       transdate    => $transdate1,
1198       taxincluded  => 1,
1199       vendor_id    => $vendor->id,
1200       taxzone_id   => $vendor->taxzone_id,
1201       currency_id  => $currency->id,
1202       notes        => 'test_ap_currency_tax_included',
1203       invnumber    => 'test_ap_currency_tax_included',
1204       transactions => [],
1205   );
1206   $invoice->add_ap_amount_row( # should take care of taxincluded
1207     amount     => $invoice->amount, # tax included in local currency
1208     chart      => $ap_amount_chart,
1209     tax_id     => $tax_9->id,
1210   );
1211
1212   $invoice->create_ap_row( chart => $ap_chart );
1213   $invoice->save;
1214   is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1215   is($invoice->amount      , $amount       , 'amount ok');
1216   is($invoice->netamount   , $netamount    , 'netamount ok');
1217   is($invoice->taxincluded , 1             , 'ap transaction has taxincluded');
1218   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');
1219   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');
1220
1221   $invoice->pay_invoice(chart_id   => $bank->id,
1222                         amount     => 89.25,
1223                         currency   => 'CUR',
1224                         transdate  => $transdate1->to_kivitendo,
1225                        );
1226
1227 };
1228
1229 sub test_ar_currency_tax_not_included_and_payment_2 {
1230   my $title = 'test_ar_currency_tax_not_included_and_payment_2';
1231   my $netamount = $::form->round_amount(125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1232   my $amount    = $::form->round_amount($netamount * 1.19,2);          # 148.75 in CUR, 119.00 in EUR
1233   my $invoice   = SL::DB::Invoice->new(
1234       invoice      => 0,
1235       amount       => $amount,
1236       netamount    => $netamount,
1237       transdate    => $transdate2,
1238       taxincluded  => 0,
1239       customer_id  => $customer->id,
1240       taxzone_id   => $customer->taxzone_id,
1241       currency_id  => $currency->id,
1242       transactions => [],
1243       notes        => 'test_ar_currency_tax_not_included_and_payment 0.8',
1244       invnumber    => 'test_ar_currency_tax_not_included_and_payment 0.8',
1245   );
1246   $invoice->add_ar_amount_row(
1247     amount     => $invoice->netamount,
1248     chart      => $ar_amount_chart,
1249     tax_id     => $tax->id,
1250   );
1251
1252   $invoice->create_ar_row(chart => $ar_chart);
1253   $invoice->save;
1254
1255   is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1256   is($invoice->netamount   , 100           , "$title: ar amount has been converted");
1257   is($invoice->amount      , 119           , "$title: ar amount has been converted");
1258   is($invoice->taxincluded ,   0           , "$title: ar transaction doesn\"t have taxincluded");
1259   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");
1260   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');
1261
1262   $invoice->pay_invoice(chart_id   => $bank->id,
1263                         amount     => 123.45,
1264                         currency   => 'CUR',
1265                         transdate  => $transdate2->to_kivitendo,
1266                        );
1267   $invoice->pay_invoice(chart_id   => $bank->id,
1268                         amount     => 15.30,
1269                         currency   => 'CUR',
1270                         transdate  => $transdate3->to_kivitendo,
1271                        );
1272   $invoice->pay_invoice(chart_id   => $bank->id,
1273                         amount     => 10.00,
1274                         currency   => 'CUR',
1275                         transdate  => $transdate4->to_kivitendo,
1276                        );
1277   # $invoice->pay_invoice(chart_id   => $bank->id,
1278   #                       amount     => 30,
1279   #                       transdate  => $transdate2->to_kivitendo,
1280   #                      );
1281   my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1282   is(scalar @{$fx_transactions}, 3, "$title: ar transaction has 3 fx transactions");
1283   is($fx_transactions->[0]->amount, '24.69000', "$title fx transactions 1: 123.45-(123.45*0.8) = 24.69");
1284
1285   is(scalar @{$invoice->transactions}, 14, "$title ar transaction has 14 transactions (incl. fxtransactions and fx_gain)");
1286   is($invoice->paid, $invoice->amount, "$title ar transaction paid = amount in default currency");
1287 };
1288
1289 sub test_ar_currency_tax_not_included_and_payment_2_credit_note {
1290   my $netamount = $::form->round_amount(-125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1291   my $amount    = $::form->round_amount($netamount * 1.19,2);          # 148.75 in CUR, 119.00 in EUR
1292   my $invoice   = SL::DB::Invoice->new(
1293       invoice      => 0,
1294       amount       => $amount,
1295       netamount    => $netamount,
1296       transdate    => $transdate2,
1297       taxincluded  => 0,
1298       customer_id  => $customer->id,
1299       taxzone_id   => $customer->taxzone_id,
1300       currency_id  => $currency->id,
1301       transactions => [],
1302       notes        => 'test_ar_currency_tax_not_included_and_payment credit note 0.8',
1303       invnumber    => 'test_ar_currency_tax_not_included_and_payment credit note 0.8',
1304   );
1305   $invoice->add_ar_amount_row(
1306     amount     => $invoice->netamount,
1307     chart      => $ar_amount_chart,
1308     tax_id     => $tax->id,
1309   );
1310
1311   $invoice->create_ar_row(chart => $ar_chart);
1312   $invoice->save;
1313
1314   is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1315   is($invoice->netamount   , -100          , 'ar amount has been converted');
1316   is($invoice->amount      , -119          , 'ar amount has been converted');
1317   is($invoice->taxincluded ,   0           , 'ar transaction doesn\'t have taxincluded');
1318   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');
1319   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');
1320
1321   $invoice->pay_invoice(chart_id   => $bank->id,
1322                         amount     => -123.45,
1323                         currency   => 'CUR',
1324                         transdate  => $transdate2->to_kivitendo,
1325                        );
1326   $invoice->pay_invoice(chart_id   => $bank->id,
1327                         amount     => -25.30,
1328                         currency   => 'CUR',
1329                         transdate  => $transdate2->to_kivitendo,
1330                        );
1331   my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1332   is(scalar @{$fx_transactions}, 2, 'ar transaction has 2 fx transactions');
1333   is($fx_transactions->[0]->amount, '-24.69000', 'fx transactions 1: 123.45-(123.45*0.8) = 24.69');
1334
1335   is(scalar @{$invoice->transactions}, 9, 'ar transaction has 9 transactions (incl. fxtransactions)');
1336   is($invoice->paid, $invoice->amount, 'ar transaction paid = amount in default currency');
1337 };
1338
1339 sub test_ap_currency_tax_not_included_and_payment_2 {
1340   my $title = 'test_ap_currency_tax_not_included_and_payment_2';
1341   my $netamount = $::form->round_amount(125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1342   my $amount    = $::form->round_amount($netamount * 1.19,2);          # 148.75 in CUR, 119.00 in EUR
1343   my $invoice   = SL::DB::PurchaseInvoice->new(
1344       invoice      => 0,
1345       amount       => $amount,
1346       netamount    => $netamount,
1347       transdate    => $transdate2,
1348       taxincluded  => 0,
1349       vendor_id    => $vendor->id,
1350       taxzone_id   => $vendor->taxzone_id,
1351       currency_id  => $currency->id,
1352       transactions => [],
1353       notes        => 'test_ap_currency_tax_not_included_and_payment_2 0.8 + 1.33333',
1354       invnumber    => 'test_ap_currency_tax_not_included_and_payment_2 0.8 + 1.33333',
1355   );
1356   $invoice->add_ap_amount_row(
1357     amount     => $invoice->netamount,
1358     chart      => $ap_amount_chart,
1359     tax_id     => $tax_9->id,
1360   );
1361
1362   $invoice->create_ap_row(chart => $ap_chart);
1363   $invoice->save;
1364
1365   is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1366   is($invoice->netamount   ,  100          , "$title: ap amount has been converted");
1367   is($invoice->amount      ,  119          , "$title: ap amount has been converted");
1368   is($invoice->taxincluded ,    0          , "$title: ap transaction doesn\'t have taxincluded");
1369   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');
1370   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');
1371
1372   $invoice->pay_invoice(chart_id   => $bank->id,
1373                         amount     => 10,
1374                         currency   => 'CUR',
1375                         transdate  => $transdate2->to_kivitendo,
1376                        );
1377   $invoice->pay_invoice(chart_id   => $bank->id,
1378                         amount     => 123.45,
1379                         currency   => 'CUR',
1380                         transdate  => $transdate3->to_kivitendo,
1381                        );
1382   $invoice->pay_invoice(chart_id   => $bank->id,
1383                         amount     => 15.30,
1384                         currency   => 'CUR',
1385                         transdate  => $transdate4->to_kivitendo,
1386                        );
1387   my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1388   is(scalar @{$fx_transactions}, 3, "$title: ap transaction has 3 fx transactions");
1389   is($fx_transactions->[0]->amount,  '-2.00000', "$title: fx transaction 1:  10.00-( 10.00*0.80000) =   2.00000");
1390   is($fx_transactions->[1]->amount,  '68.59000', "$title: fx transaction 2: 123.45-(123.45*1.55557) = -68.58511");
1391   is($fx_transactions->[2]->amount,  '-3.40000', "$title: fx transaction 3:  15.30-(15.30 *0.77777) =   3.40012");
1392
1393   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'));
1394   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'));
1395   is($fx_gain_transactions->[0]->amount,   '0.34000', "$title: fx gain amount ok");
1396   is($fx_loss_transactions->[0]->amount, '-93.28000', "$title: fx loss amount ok");
1397
1398   is(scalar @{$invoice->transactions}, 14, "$title: ap transaction has 14 transactions (incl. fxtransactions and gain_loss)");
1399   is($invoice->paid, $invoice->amount, "$title: ap transaction paid = amount in default currency");
1400   is(total_amount($invoice), 0,   "$title: even balance");
1401 };
1402
1403 sub test_ap_currency_tax_not_included_and_payment_2_credit_note {
1404   my $title = 'test_ap_currency_tax_not_included_and_payment_2_credit_note';
1405   my $netamount = $::form->round_amount(-125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1406   my $amount    = $::form->round_amount($netamount * 1.19,2);          # 148.75 in CUR, 119.00 in EUR
1407   my $invoice   = SL::DB::PurchaseInvoice->new(
1408       invoice      => 0,
1409       amount       => $amount,
1410       netamount    => $netamount,
1411       transdate    => $transdate2,
1412       taxincluded  => 0,
1413       vendor_id    => $vendor->id,
1414       taxzone_id   => $vendor->taxzone_id,
1415       currency_id  => $currency->id,
1416       transactions => [],
1417       notes        => 'test_ap_currency_tax_not_included_and_payment credit note 0.8 + 1.33333',
1418       invnumber    => 'test_ap_currency_tax_not_included_and_payment credit note 0.8 + 1.33333',
1419   );
1420   $invoice->add_ap_amount_row(
1421     amount     => $invoice->netamount,
1422     chart      => $ap_amount_chart,
1423     tax_id     => $tax_9->id,
1424   );
1425
1426   $invoice->create_ap_row(chart => $ap_chart);
1427   $invoice->save;
1428
1429   is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1430   is($invoice->netamount   , -100          , "$title: ap amount has been converted");
1431   is($invoice->amount      , -119          , "$title: ap amount has been converted");
1432   is($invoice->taxincluded ,   0           , "$title: ap transaction doesn\'t have taxincluded");
1433   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');
1434   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');
1435
1436   $invoice->pay_invoice(chart_id   => $bank->id,
1437                         amount     => -10,
1438                         currency   => 'CUR',
1439                         transdate  => $transdate2->to_kivitendo,
1440                        );
1441   $invoice->pay_invoice(chart_id   => $bank->id,
1442                         amount     => -123.45,
1443                         currency   => 'CUR',
1444                         transdate  => $transdate3->to_kivitendo,
1445                        );
1446   $invoice->pay_invoice(chart_id   => $bank->id,
1447                         amount     => -15.30,
1448                         currency   => 'CUR',
1449                         transdate  => $transdate4->to_kivitendo,
1450                        );
1451   my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1452   is(scalar @{$fx_transactions}, 3, "$title: ap transaction has 3 fx transactions");
1453   is($fx_transactions->[0]->amount,   '2.00000', "$title: fx transaction 1:  10.00-( 10.00*0.80000) =   2.00000");
1454   is($fx_transactions->[1]->amount, '-68.59000', "$title: fx transaction 2: 123.45-(123.45*1.55557) = -68.58511");
1455   is($fx_transactions->[2]->amount,   '3.40000', "$title: fx transaction 3:  15.30-(15.30 *0.77777) =   3.40012");
1456
1457   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'));
1458   is($fx_gain_loss_transactions->[0]->amount, '93.28000', "$title: fx gain loss amount ok");
1459
1460   is(scalar @{$invoice->transactions}, 14, "$title: ap transaction has 14 transactions (incl. fxtransactions and gain_loss)");
1461   is($invoice->paid, $invoice->amount, "$title: ap transaction paid = amount in default currency");
1462   is(total_amount($invoice), 0,   "$title: even balance");
1463 };
1464
1465 sub test_credit_note_two_items_19_7_tax_tax_not_included() {
1466   reset_state() if $ALWAYS_RESET;
1467
1468   my $item1   = create_invoice_item(part => $parts[0], qty => 5);
1469   my $item2   = create_invoice_item(part => $parts[1], qty => 3);
1470   my $invoice = create_credit_note(
1471     invnumber    => 'cn1',
1472     taxincluded  => 0,
1473     invoiceitems => [ $item1, $item2 ],
1474   );
1475
1476   # default values
1477   my %params = ( chart_id => $bank_account->chart_id,
1478                  transdate => DateTime->today_local->to_kivitendo,
1479                );
1480
1481   $params{amount}       = $invoice->amount,
1482
1483   $invoice->pay_invoice( %params );
1484
1485   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
1486   my $total = total_amount($invoice);
1487
1488   my $title = 'credit_note, two items, 19/7%, tax not included';
1489
1490   is($invoice->netamount,        -40.84,   "${title}: netamount");
1491   is($invoice->amount,           -45.10,   "${title}: amount");
1492   is($paid_amount,                45.10,   "${title}: paid amount according to acc_trans is positive (Haben)");
1493   is($invoice->paid,             -45.10,   "${title}: paid");
1494   is($number_of_payments,             1,   "${title}: 1 AR_paid bookings");
1495   is($total,                          0,   "${title}: even balance");
1496 }
1497
1498 1;