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