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