Payment Helper Test nutzt create_ap_transaction
[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::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 $ap_transaction_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_ap_transaction_two_charts_19_7_without_skonto();
49 test_default_ap_transaction_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_ap_transaction_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_ap_transaction_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_ap_transaction {
242   $ap_transaction_counter++;
243
244   my $ap_transaction = create_ap_transaction(
245     vendor      => $vendor,
246     invnumber   => 'newap ' . $ap_transaction_counter,
247     taxincluded => 0,
248     amount      => '226',
249     netamount   => '200',
250     gldate      => $transdate1,
251     taxzone_id  => $taxzone->id,
252     transdate   => $transdate1,
253     bookings    => [
254                      {
255                        chart => SL::DB::Manager::Chart->find_by(accno => '3400'),
256                        amount => 100,
257                      },
258                      {
259                        chart => SL::DB::Manager::Chart->find_by(accno => '3300'),
260                        amount => 100,
261                      },
262                    ],
263  );
264
265   return $ap_transaction;
266 }
267
268 sub number_of_payments {
269   my $invoice = shift;
270
271   my $number_of_payments;
272   my $paid_amount;
273   foreach my $transaction ( @{ $invoice->transactions } ) {
274     if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
275       $paid_amount += $transaction->amount ;
276       $number_of_payments++;
277     }
278   };
279   return ($number_of_payments, $paid_amount);
280 };
281
282 sub total_amount {
283   my $invoice = shift;
284
285   my $total = sum map { $_->amount } @{ $invoice->transactions };
286
287   return $::form->round_amount($total, 5);
288
289 };
290
291
292 # test 1
293 sub test_default_invoice_one_item_19_without_skonto {
294   my $title = 'default invoice, one item, 19% tax, without_skonto';
295   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
296   my $invoice = create_sales_invoice(
297     taxincluded  => 0,
298     invoiceitems => [ $item ],
299     payment_id   => $payment_terms->id,
300   );
301
302   my $ap_transaction = new_ap_transaction();
303
304   # default values
305   my %params = ( chart_id => $bank_account->chart_id,
306                  transdate => DateTime->today_local->to_kivitendo
307                );
308
309   $params{amount} = '6.96';
310   $params{payment_type} = 'without_skonto';
311
312   $invoice->pay_invoice( %params );
313
314   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
315   my $total = total_amount($invoice);
316
317   is($invoice->netamount,   5.85,      "${title}: netamount");
318   is($invoice->amount,      6.96,      "${title}: amount");
319   is($paid_amount,         -6.96,      "${title}: paid amount");
320   is($number_of_payments,      1,      "${title}: 1 AR_paid booking");
321   is($invoice->paid,        6.96,      "${title}: paid");
322   is($total,                   0,      "${title}: even balance");
323
324 }
325
326 sub test_default_invoice_one_item_19_without_skonto_overpaid {
327   my $title = 'default invoice, one item, 19% tax, without_skonto';
328
329   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
330   my $invoice = create_sales_invoice(
331     taxincluded  => 0,
332     invoiceitems => [ $item ],
333     payment_id   => $payment_terms->id,
334   );
335
336   my $ap_transaction = new_ap_transaction();
337
338
339   # default values
340   my %params = ( chart_id => $bank_account->chart_id,
341                  transdate => DateTime->today_local->to_kivitendo
342                );
343
344   $params{amount} = '16.96';
345   $params{payment_type} = 'without_skonto';
346   $invoice->pay_invoice( %params );
347
348   $params{amount} = '-10.00';
349   $invoice->pay_invoice( %params );
350
351   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
352   my $total = total_amount($invoice);
353
354   is($invoice->netamount,   5.85,      "${title}: netamount");
355   is($invoice->amount,      6.96,      "${title}: amount");
356   is($paid_amount,         -6.96,      "${title}: paid amount");
357   is($number_of_payments,      2,      "${title}: 1 AR_paid booking");
358   is($invoice->paid,        6.96,      "${title}: paid");
359   is($total,                   0,      "${title}: even balance");
360
361 }
362
363
364 # test 2
365 sub test_default_invoice_two_items_19_7_tax_with_skonto {
366   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
367
368   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
369   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
370   my $invoice = create_sales_invoice(
371     taxincluded  => 0,
372     invoiceitems => [ $item1, $item2 ],
373     payment_id   => $payment_terms->id,
374   );
375
376   # default values
377   my %params = ( chart_id => $bank_account->chart_id,
378                  transdate => DateTime->today_local->to_kivitendo
379                );
380
381   $params{payment_type} = 'with_skonto_pt';
382   $params{amount}       = $invoice->amount_less_skonto;
383
384   $invoice->pay_invoice( %params );
385
386   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
387   my $total = total_amount($invoice);
388
389   is($invoice->netamount,  5.85 + 11.66,   "${title}: netamount");
390   is($invoice->amount,     6.96 + 12.48,   "${title}: amount");
391   is($paid_amount,               -19.44,   "${title}: paid amount");
392   is($invoice->paid,              19.44,   "${title}: paid");
393   is($number_of_payments,             3,   "${title}: 3 AR_paid bookings");
394   is($total,                          0,   "${title}: even balance");
395 }
396
397 sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included {
398   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
399
400   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
401   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
402   my $invoice = create_sales_invoice(
403     taxincluded  => 1,
404     invoiceitems => [ $item1, $item2 ],
405     payment_id   => $payment_terms->id,
406   );
407
408   # default values
409   my %params = ( chart_id => $bank_account->chart_id,
410                  transdate => DateTime->today_local->to_kivitendo
411                );
412
413   $params{payment_type} = 'with_skonto_pt';
414   $params{amount}       = $invoice->amount_less_skonto;
415
416   $invoice->pay_invoice( %params );
417
418   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
419   my $total = total_amount($invoice);
420
421   is($invoice->netamount,         15.82,   "${title}: netamount");
422   is($invoice->amount,            17.51,   "${title}: amount");
423   is($paid_amount,               -17.51,   "${title}: paid amount");
424   is($invoice->paid,              17.51,   "${title}: paid");
425   is($number_of_payments,             3,   "${title}: 3 AR_paid bookings");
426
427 TODO: {
428   local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
429   is($total,                          0,   "${title}: even balance");
430   }
431 }
432
433 # test 3 : two items, without skonto
434 sub test_default_invoice_two_items_19_7_without_skonto {
435   my $title = 'default invoice, two items, 19/7% tax without skonto';
436
437   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
438   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
439   my $invoice = create_sales_invoice(
440     taxincluded  => 0,
441     invoiceitems => [ $item1, $item2 ],
442     payment_id   => $payment_terms->id,
443   );
444
445   # default values
446   my %params = ( chart_id => $bank_account->chart_id,
447                  transdate => DateTime->today_local->to_kivitendo
448                );
449
450   $params{amount} = '19.44'; # pass full amount
451   $params{payment_type} = 'without_skonto';
452
453   $invoice->pay_invoice( %params );
454
455   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
456   my $total = total_amount($invoice);
457
458   is($invoice->netamount,     5.85 + 11.66,     "${title}: netamount");
459   is($invoice->amount,        6.96 + 12.48,     "${title}: amount");
460   is($paid_amount,                  -19.44,     "${title}: paid amount");
461   is($invoice->paid,                 19.44,     "${title}: paid");
462   is($number_of_payments,                1,     "${title}: 1 AR_paid bookings");
463   is($total,                             0,     "${title}: even balance");
464 }
465
466 # test 4
467 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment {
468   my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
469
470   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
471   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
472   my $invoice = create_sales_invoice(
473     taxincluded  => 0,
474     invoiceitems => [ $item1, $item2 ],
475     payment_id   => $payment_terms->id,
476   );
477
478   $invoice->pay_invoice( amount       => '9.44',
479                          payment_type => 'without_skonto',
480                          chart_id     => $bank_account->chart_id,
481                          transdate    => DateTime->today_local->to_kivitendo,
482                        );
483
484   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
485   my $total = total_amount($invoice);
486
487   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
488   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
489   is($paid_amount,              -9.44,             "${title}: paid amount");
490   is($invoice->paid,             9.44,            "${title}: paid");
491   is($number_of_payments,   1,                "${title}: 1 AR_paid bookings");
492   is($total,                    0,                "${title}: even balance");
493 }
494
495 # test 5
496 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments {
497   my $title = 'default invoice, two items, 19/7% tax not included';
498
499   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
500   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
501   my $invoice = create_sales_invoice(
502     taxincluded  => 0,
503     invoiceitems => [ $item1, $item2 ],
504     payment_id   => $payment_terms->id,
505   );
506
507   $invoice->pay_invoice( amount       => '9.44',
508                          payment_type => 'without_skonto',
509                          chart_id     => $bank_account->chart_id,
510                          transdate    => DateTime->today_local->to_kivitendo
511                        );
512   $invoice->pay_invoice( amount       => '10.00',
513                          chart_id     => $bank_account->chart_id,
514                          transdate    => DateTime->today_local->to_kivitendo
515                        );
516
517   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
518   my $total = total_amount($invoice);
519
520   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
521   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
522   is($paid_amount,                     -19.44,     "${title}: paid amount");
523   is($invoice->paid,                    19.44,     "${title}: paid");
524   is($number_of_payments,                   2,     "${title}: 2 AR_paid bookings");
525   is($total,                                0,     "${title}: even balance");
526
527 }
528
529 # test 6
530 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto {
531   my $title = 'default invoice, two items, 19/7% tax not included';
532
533   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
534   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
535   my $invoice = create_sales_invoice(
536     taxincluded  => 0,
537     invoiceitems => [ $item1, $item2 ],
538     payment_id   => $payment_terms->id,
539   );
540
541   $invoice->pay_invoice( amount       => '9.44',
542                          payment_type => 'without_skonto',
543                          chart_id     => $bank_account->chart_id,
544                          transdate    => DateTime->today_local->to_kivitendo
545                        );
546   $invoice->pay_invoice( amount       => '8.73',
547                          payment_type => 'without_skonto',
548                          chart_id     => $bank_account->chart_id,
549                          transdate    => DateTime->today_local->to_kivitendo
550                        );
551   $invoice->pay_invoice( amount       => $invoice->open_amount,
552                          payment_type => 'difference_as_skonto',
553                          chart_id     => $bank_account->chart_id,
554                          transdate    => DateTime->today_local->to_kivitendo
555                        );
556
557   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
558   my $total = total_amount($invoice);
559
560   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
561   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
562   is($paid_amount,                     -19.44,     "${title}: paid amount");
563   is($invoice->paid,                    19.44,     "${title}: paid");
564   is($number_of_payments,                   4,     "${title}: 4 AR_paid bookings");
565   is($total,                                0,     "${title}: even balance");
566
567 }
568
569 sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent {
570   my $title = 'default invoice, two items, 19/7% tax not included';
571
572   # if there is only one cent left there can only be one skonto booking, the
573   # error handling should choose the highest amount, which is the 7% account
574   # (11.66) rather than the 19% account (5.85).  The actual tax amount is
575   # higher for the 19% case, though (1.11 compared to 0.82)
576
577   my $item1   = create_invoice_item(part => $parts[0], qty => 2.5);
578   my $item2   = create_invoice_item(part => $parts[1], qty => 1.2);
579   my $invoice = create_sales_invoice(
580     taxincluded  => 0,
581     invoiceitems => [ $item1, $item2 ],
582     payment_id   => $payment_terms->id,
583   );
584
585   $invoice->pay_invoice( amount       => '19.42',
586                          payment_type => 'without_skonto',
587                          chart_id     => $bank_account->chart_id,
588                          transdate    => DateTime->today_local->to_kivitendo
589                        );
590   $invoice->pay_invoice( amount       => $invoice->open_amount,
591                          payment_type => 'difference_as_skonto',
592                          chart_id     => $bank_account->chart_id,
593                          transdate    => DateTime->today_local->to_kivitendo
594                        );
595
596   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
597   my $total = total_amount($invoice);
598
599   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
600   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
601   is($paid_amount,                     -19.44,     "${title}: paid amount");
602   is($invoice->paid,                    19.44,     "${title}: paid");
603   is($number_of_payments,                   3,     "${title}: 2 AR_paid bookings");
604   is($total,                                0,     "${title}: even balance");
605
606 }
607
608 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent {
609   my $title = 'default invoice, two items, 19/7% tax not included';
610
611   # if there are two cents left there will be two skonto bookings, 1 cent each
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     invoiceitems => [ $item1, $item2 ],
617     payment_id   => $payment_terms->id,
618   );
619
620   $invoice->pay_invoice( amount       => '19.42',
621                          payment_type => 'without_skonto',
622                          chart_id     => $bank_account->chart_id,
623                          transdate    => DateTime->today_local->to_kivitendo
624                        );
625   $invoice->pay_invoice( amount       => $invoice->open_amount,
626                          payment_type => 'difference_as_skonto',
627                          chart_id     => $bank_account->chart_id,
628                          transdate    => DateTime->today_local->to_kivitendo
629                        );
630
631   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
632   my $total = total_amount($invoice);
633
634   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
635   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
636   is($paid_amount,                     -19.44,     "${title}: paid amount");
637   is($invoice->paid,                    19.44,     "${title}: paid");
638   is($number_of_payments,                   3,     "${title}: 3 AR_paid bookings");
639   is($total,                                0,     "${title}: even balance");
640
641 }
642
643 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto {
644   my $title = 'default invoice, one item, 19% tax, without_skonto';
645
646   my $item    = create_invoice_item(part => $parts[0], qty => 2.5);
647   my $invoice = create_sales_invoice(
648     taxincluded  => 0,
649     invoiceitems => [ $item ],
650     payment_id   => $payment_terms->id,
651   );
652
653   # default values
654   my %params = ( chart_id  => $bank_account->chart_id,
655                  transdate => DateTime->today_local->to_kivitendo
656                );
657
658   $params{amount}       = '2.32';
659   $params{payment_type} = 'without_skonto';
660   $invoice->pay_invoice( %params );
661
662   $params{amount}       = '3.81';
663   $params{payment_type} = 'without_skonto';
664   $invoice->pay_invoice( %params );
665
666   $params{amount}       = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
667   $params{payment_type} = 'difference_as_skonto';
668   $invoice->pay_invoice( %params );
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,     "${title}: netamount");
674   is($invoice->amount,          6.96,     "${title}: amount");
675   is($paid_amount,             -6.96,     "${title}: paid amount");
676   is($number_of_payments,          3,     "${title}: 3 AR_paid booking");
677   is($invoice->paid,            6.96,     "${title}: paid");
678   is($total,                       0,     "${title}: even balance");
679
680 }
681
682 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent {
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     invoiceitems => [ $item ],
689     payment_id   => $payment_terms->id,
690   );
691
692   # default values
693   my %params = ( chart_id  => $bank_account->chart_id,
694                  transdate => DateTime->today_local->to_kivitendo
695                );
696
697   $params{amount}       = '6.95';
698   $params{payment_type} = 'without_skonto';
699   $invoice->pay_invoice( %params );
700
701   $params{amount}       = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
702   $params{payment_type} = 'difference_as_skonto';
703   $invoice->pay_invoice( %params );
704
705   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
706   my $total = total_amount($invoice);
707
708   is($invoice->netamount,       5.85,     "${title}: netamount");
709   is($invoice->amount,          6.96,     "${title}: amount");
710   is($paid_amount,             -6.96,     "${title}: paid amount");
711   is($number_of_payments,          2,     "${title}: 3 AR_paid booking");
712   is($invoice->paid,            6.96,     "${title}: paid");
713   is($total,                       0,     "${title}: even balance");
714
715 }
716
717 # test 3 : two items, without skonto
718 sub test_default_ap_transaction_two_charts_19_7_without_skonto {
719   my $title = 'default invoice, two items, 19/7% tax without skonto';
720
721   my $ap_transaction = new_ap_transaction();
722
723   my %params = ( chart_id => $bank_account->chart_id,
724                  transdate => DateTime->today_local->to_kivitendo
725                );
726
727   $params{amount} = '226'; # pass full amount
728   $params{payment_type} = 'without_skonto';
729
730   $ap_transaction->pay_invoice( %params );
731
732   my ($number_of_payments, $paid_amount) = number_of_payments($ap_transaction);
733   my $total = total_amount($ap_transaction);
734
735   is($paid_amount,         226,     "${title}: paid amount");
736   is($number_of_payments,    1,     "${title}: 1 AP_paid bookings");
737   is($total,                 0,     "${title}: even balance");
738
739 }
740
741 sub test_default_ap_transaction_two_charts_19_7_with_skonto {
742   my $title = 'default invoice, two items, 19/7% tax without skonto';
743
744   my $ap_transaction = new_ap_transaction();
745
746   my %params = ( chart_id => $bank_account->chart_id,
747                  transdate => DateTime->today_local->to_kivitendo
748                );
749
750   # $params{amount} = '226'; # pass full amount
751   $params{payment_type} = 'with_skonto_pt';
752
753   $ap_transaction->pay_invoice( %params );
754
755   my ($number_of_payments, $paid_amount) = number_of_payments($ap_transaction);
756   my $total = total_amount($ap_transaction);
757
758   is($paid_amount,         226,     "${title}: paid amount");
759   is($number_of_payments,    3,     "${title}: 1 AP_paid bookings");
760   is($total,                 0,     "${title}: even balance");
761
762 }
763
764 sub test_default_ap_transaction_two_charts_19_7_tax_partial_unrounded_payment_without_skonto {
765   my $title = 'default ap_transaction, two charts, 19/7% tax multiple payments with final difference as skonto';
766
767   # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
768   my $ap_transaction = new_ap_transaction();
769   $ap_transaction->pay_invoice(
770                           amount       => ( $ap_transaction->amount / 3 * 2),
771                           payment_type => 'without_skonto',
772                           chart_id     => $bank_account->chart_id,
773                           transdate    => DateTime->today_local->to_kivitendo
774                          );
775   my ($number_of_payments, $paid_amount) = number_of_payments($ap_transaction);
776   my $total = total_amount($ap_transaction);
777
778   is($paid_amount,         150.67,   "${title}: paid amount");
779   is($number_of_payments,       1,   "${title}: 1 AP_paid bookings");
780   is($total,                    0,   "${title}: even balance");
781 };
782
783
784 sub test_default_ap_transaction_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto {
785   my $title = 'default ap_transaction, two charts, 19/7% tax multiple payments with final difference as skonto';
786
787   my $ap_transaction = new_ap_transaction();
788
789   # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
790   $ap_transaction->pay_invoice(
791                           amount       => ( $ap_transaction->amount / 3 * 2),
792                           payment_type => 'without_skonto',
793                           chart_id     => $bank_account->chart_id,
794                           transdate    => DateTime->today_local->to_kivitendo
795                          );
796   $ap_transaction->pay_invoice(
797                           amount       => ( $ap_transaction->amount / 5 ),
798                           payment_type => 'without_skonto',
799                           chart_id     => $bank_account->chart_id,
800                           transdate    => DateTime->today_local->to_kivitendo
801                          );
802   $ap_transaction->pay_invoice(
803                           payment_type => 'difference_as_skonto',
804                           chart_id     => $bank_account->chart_id,
805                           transdate    => DateTime->today_local->to_kivitendo
806                          );
807
808   my ($number_of_payments, $paid_amount) = number_of_payments($ap_transaction);
809   my $total = total_amount($ap_transaction);
810
811   is($paid_amount,         226, "${title}: paid amount");
812   is($number_of_payments,    4, "${title}: 1 AP_paid bookings");
813   is($total,                 0, "${title}: even balance");
814
815 }
816
817 # test
818 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50 {
819   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
820
821   my $item1   = create_invoice_item(part => $parts[2], qty => 1);
822   my $item2   = create_invoice_item(part => $parts[3], qty => 1);
823   my $invoice = create_sales_invoice(
824     taxincluded  => 0,
825     invoiceitems => [ $item1, $item2 ],
826     payment_id   => $payment_terms->id,
827   );
828
829   # default values
830   my %params = ( chart_id => $bank_account->chart_id,
831                  transdate => DateTime->today_local->to_kivitendo
832                );
833
834   $params{amount} = $invoice->amount_less_skonto;
835   $params{payment_type} = 'with_skonto_pt';
836
837   $invoice->pay_invoice( %params );
838
839   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
840   my $total = total_amount($invoice);
841
842   is($invoice->netamount,        100,     "${title}: netamount");
843   is($invoice->amount,           113,     "${title}: amount");
844   is($paid_amount,              -113,     "${title}: paid amount");
845   is($invoice->paid,             113,     "${title}: paid");
846   is($number_of_payments,          3,     "${title}: 3 AR_paid bookings");
847   is($total,                       0,     "${title}: even balance");
848 }
849
850 # test
851 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25 {
852   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
853
854   my $item1   = create_invoice_item(part => $parts[2], qty => 0.5);
855   my $item2   = create_invoice_item(part => $parts[3], qty => 0.5);
856   my $item3   = create_invoice_item(part => $parts[2], qty => 0.5);
857   my $item4   = create_invoice_item(part => $parts[3], qty => 0.5);
858   my $invoice = create_sales_invoice(
859     taxincluded  => 0,
860     invoiceitems => [ $item1, $item2, $item3, $item4 ],
861     payment_id   => $payment_terms->id,
862   );
863
864   # default values
865   my %params = ( chart_id => $bank_account->chart_id,
866                  transdate => DateTime->today_local->to_kivitendo
867                );
868
869   $params{amount} = $invoice->amount_less_skonto;
870   $params{payment_type} = 'with_skonto_pt';
871
872   $invoice->pay_invoice( %params );
873
874   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
875   my $total = total_amount($invoice);
876
877   is($invoice->netamount , 100  , "${title}: netamount");
878   is($invoice->amount    , 113  , "${title}: amount");
879   is($paid_amount        , -113 , "${title}: paid amount");
880   is($invoice->paid      , 113  , "${title}: paid");
881   is($number_of_payments , 3    , "${title}: 3 AR_paid bookings");
882   is($total              , 0    , "${title}: even balance");
883 }
884
885 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included {
886   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
887
888   my $item1   = create_invoice_item(part => $parts[2], qty => 0.5);
889   my $item2   = create_invoice_item(part => $parts[3], qty => 0.5);
890   my $item3   = create_invoice_item(part => $parts[2], qty => 0.5);
891   my $item4   = create_invoice_item(part => $parts[3], qty => 0.5);
892   my $invoice = create_sales_invoice(
893     taxincluded  => 1,
894     invoiceitems => [ $item1, $item2, $item3, $item4 ],
895     payment_id   => $payment_terms->id,
896   );
897
898   # default values
899   my %params = ( chart_id => $bank_account->chart_id,
900                  transdate => DateTime->today_local->to_kivitendo
901                );
902
903   $params{amount} = $invoice->amount_less_skonto;
904   $params{payment_type} = 'with_skonto_pt';
905
906   $invoice->pay_invoice( %params );
907
908   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
909   my $total = total_amount($invoice);
910
911   is($invoice->netamount,   88.75,    "${title}: netamount");
912   is($invoice->amount,        100,    "${title}: amount");
913   is($paid_amount,           -100,    "${title}: paid amount");
914   is($invoice->paid,          100,    "${title}: paid");
915   is($number_of_payments,       3,    "${title}: 3 AR_paid bookings");
916 TODO: {
917   local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
918   is($total,                    0,    "${title}: even balance");
919   }
920 }
921
922 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple {
923   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
924
925   my $item1   = create_invoice_item(part => $parts[2], qty => 0.5);
926   my $item2   = create_invoice_item(part => $parts[3], qty => 0.5);
927   my $item3   = create_invoice_item(part => $parts[2], qty => 0.5);
928   my $item4   = create_invoice_item(part => $parts[3], qty => 0.5);
929   my $invoice = create_sales_invoice(
930     taxincluded  => 0,
931     invoiceitems => [ $item1, $item2, $item3, $item4 ],
932     payment_id   => $payment_terms->id,
933   );
934
935   $invoice->pay_invoice( amount       => '90',
936                          payment_type => 'without_skonto',
937                          chart_id     => $bank_account->chart_id,
938                          transdate => DateTime->today_local->to_kivitendo
939                        );
940   $invoice->pay_invoice( payment_type => 'difference_as_skonto',
941                          chart_id     => $bank_account->chart_id,
942                          transdate    => DateTime->today_local->to_kivitendo
943                        );
944
945   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
946   my $total = total_amount($invoice);
947
948   is($invoice->netamount,  100,     "${title}: netamount");
949   is($invoice->amount,     113,     "${title}: amount");
950   is($paid_amount,        -113,     "${title}: paid amount");
951   is($invoice->paid,       113,     "${title}: paid");
952   is($number_of_payments,    3,     "${title}: 3 AR_paid bookings");
953   is($total,                 0,     "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
954 }
955
956 sub test_ar_currency_tax_not_included_and_payment {
957   my $title = 'test_ar_currency_tax_not_included_and_payment_2';
958
959   my $netamount = $::form->round_amount(75 * $exchangerate->sell,2); #  75 in CUR, 100.00 in EUR
960   my $amount    = $::form->round_amount($netamount * 1.19,2);        # 100 in CUR, 119.00 in EUR
961   my $invoice   = SL::DB::Invoice->new(
962       invoice      => 0,
963       amount       => $amount,
964       netamount    => $netamount,
965       transdate    => $transdate1,
966       taxincluded  => 0,
967       customer_id  => $customer->id,
968       taxzone_id   => $customer->taxzone_id,
969       currency_id  => $currency->id,
970       transactions => [],
971       notes        => 'test_ar_currency_tax_not_included_and_payment',
972   );
973   $invoice->add_ar_amount_row(
974     amount     => $invoice->netamount,
975     chart      => $ar_amount_chart,
976     tax_id     => $tax->id,
977   );
978
979   $invoice->create_ar_row(chart => $ar_chart);
980   $invoice->save;
981
982   is(SL::DB::Manager::Invoice->get_all_count(where => [ invoice => 0 ]), 1, 'there is one ar transaction');
983   is($invoice->currency_id , $currency->id , 'currency_id has been saved');
984   is($invoice->netamount   , 100           , 'ar amount has been converted');
985   is($invoice->amount      , 119           , 'ar amount has been converted');
986   is($invoice->taxincluded ,   0           , 'ar transaction doesn\'t have taxincluded');
987   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');
988   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');
989
990   $invoice->pay_invoice(chart_id   => $bank->id,
991                         amount     => 50,
992                         currency   => 'CUR',
993                         transdate  => $transdate1->to_kivitendo,
994                        );
995   $invoice->pay_invoice(chart_id   => $bank->id,
996                         amount     => 39.25,
997                         currency   => 'CUR',
998                         transdate  => $transdate1->to_kivitendo,
999                        );
1000   # $invoice->pay_invoice(chart_id   => $bank->id,
1001   #                       amount     => 30,
1002   #                       transdate  => $transdate2->to_kivitendo,
1003   #                      );
1004   is(scalar @{$invoice->transactions}, 9, 'ar transaction has 9 transactions (incl. fxtransactions)');
1005   is($invoice->paid, $invoice->amount, 'ar transaction paid = amount in default currency');
1006 };
1007
1008 sub test_ar_currency_tax_included {
1009   my $title = 'test_ar_currency_tax_included';
1010
1011   # we want the acc_trans amount to be 100
1012   my $amount    = $::form->round_amount(75 * $exchangerate->sell * 1.19);
1013   my $netamount = $::form->round_amount($amount / 1.19,2);
1014   my $invoice = SL::DB::Invoice->new(
1015       invoice      => 0,
1016       amount       => 119,
1017       netamount    => 100,
1018       transdate    => $transdate1,
1019       taxincluded  => 1,
1020       customer_id  => $customer->id,
1021       taxzone_id   => $customer->taxzone_id,
1022       currency_id  => $currency->id,
1023       notes        => 'test_ar_currency_tax_included',
1024       transactions => [],
1025   );
1026   $invoice->add_ar_amount_row( # should take care of taxincluded
1027     amount     => $invoice->amount, # tax included in local currency
1028     chart      => $ar_amount_chart,
1029     tax_id     => $tax->id,
1030   );
1031
1032   $invoice->create_ar_row( chart => $ar_chart );
1033   $invoice->save;
1034   is(SL::DB::Manager::Invoice->get_all_count(where => [ invoice => 0 ]), 2, 'there are now two ar transactions');
1035   is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1036   is($invoice->amount      , $amount       , 'amount ok');
1037   is($invoice->netamount   , $netamount    , 'netamount ok');
1038   is($invoice->taxincluded , 1             , 'ar transaction has taxincluded');
1039   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');
1040   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');
1041   $invoice->pay_invoice(chart_id   => $bank->id,
1042                         amount     => 89.25,
1043                         currency   => 'CUR',
1044                         transdate  => $transdate1->to_kivitendo,
1045                        );
1046
1047 };
1048
1049 sub test_ap_currency_tax_not_included_and_payment {
1050   my $title = 'test_ap_currency_tax_not_included_and_payment';
1051
1052   my $netamount = $::form->round_amount(75 * $exchangerate->buy,2); #  75 in CUR, 100.00 in EUR
1053   my $amount    = $::form->round_amount($netamount * 1.19,2);        # 100 in CUR, 119.00 in EUR
1054   my $invoice   = SL::DB::PurchaseInvoice->new(
1055       invoice      => 0,
1056       invnumber    => 'test_ap_currency_tax_not_included_and_payment',
1057       amount       => $amount,
1058       netamount    => $netamount,
1059       transdate    => $transdate1,
1060       taxincluded  => 0,
1061       vendor_id    => $vendor->id,
1062       taxzone_id   => $vendor->taxzone_id,
1063       currency_id  => $currency->id,
1064       transactions => [],
1065       notes        => 'test_ap_currency_tax_not_included_and_payment',
1066   );
1067   $invoice->add_ap_amount_row(
1068     amount     => $invoice->netamount,
1069     chart      => $ap_amount_chart,
1070     tax_id     => $tax_9->id,
1071   );
1072
1073   $invoice->create_ap_row(chart => $ap_chart);
1074   $invoice->save;
1075
1076   is($invoice->currency_id, $currency->id, 'currency_id has been saved');
1077   is($invoice->netamount, 100, 'ap amount has been converted');
1078   is($invoice->amount, 119, 'ap amount has been converted');
1079   is($invoice->taxincluded, 0, 'ap transaction doesn\'t have taxincluded');
1080   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');
1081   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');
1082
1083   $invoice->pay_invoice(chart_id   => $bank->id,
1084                         amount     => 50,
1085                         currency   => 'CUR',
1086                         transdate  => $transdate1->to_kivitendo,
1087                        );
1088   $invoice->pay_invoice(chart_id   => $bank->id,
1089                         amount     => 39.25,
1090                         currency   => 'CUR',
1091                         transdate  => $transdate1->to_kivitendo,
1092                        );
1093   is(scalar @{$invoice->transactions}, 9, 'ap transaction has 9 transactions (incl. fxtransactions)');
1094   is($invoice->paid, $invoice->amount, 'ap transaction paid = amount in default currency');
1095 };
1096
1097 sub test_ap_currency_tax_included {
1098   my $title = 'test_ap_currency_tax_included';
1099
1100   # we want the acc_trans amount to be 100
1101   my $amount    = $::form->round_amount(75 * $exchangerate->buy * 1.19);
1102   my $netamount = $::form->round_amount($amount / 1.19,2);
1103   my $invoice = SL::DB::PurchaseInvoice->new(
1104       invoice      => 0,
1105       amount       => 119, #$amount,
1106       netamount    => 100, #$netamount,
1107       transdate    => $transdate1,
1108       taxincluded  => 1,
1109       vendor_id    => $vendor->id,
1110       taxzone_id   => $vendor->taxzone_id,
1111       currency_id  => $currency->id,
1112       notes        => 'test_ap_currency_tax_included',
1113       invnumber    => 'test_ap_currency_tax_included',
1114       transactions => [],
1115   );
1116   $invoice->add_ap_amount_row( # should take care of taxincluded
1117     amount     => $invoice->amount, # tax included in local currency
1118     chart      => $ap_amount_chart,
1119     tax_id     => $tax_9->id,
1120   );
1121
1122   $invoice->create_ap_row( chart => $ap_chart );
1123   $invoice->save;
1124   is($invoice->currency_id , $currency->id , 'currency_id has been saved');
1125   is($invoice->amount      , $amount       , 'amount ok');
1126   is($invoice->netamount   , $netamount    , 'netamount ok');
1127   is($invoice->taxincluded , 1             , 'ap transaction has taxincluded');
1128   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');
1129   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');
1130
1131   $invoice->pay_invoice(chart_id   => $bank->id,
1132                         amount     => 89.25,
1133                         currency   => 'CUR',
1134                         transdate  => $transdate1->to_kivitendo,
1135                        );
1136
1137 };
1138
1139 sub test_ar_currency_tax_not_included_and_payment_2 {
1140   my $title = 'test_ar_currency_tax_not_included_and_payment_2';
1141
1142   my $netamount = $::form->round_amount(125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1143   my $amount    = $::form->round_amount($netamount * 1.19,2);          # 148.75 in CUR, 119.00 in EUR
1144   my $invoice   = SL::DB::Invoice->new(
1145       invoice      => 0,
1146       amount       => $amount,
1147       netamount    => $netamount,
1148       transdate    => $transdate2,
1149       taxincluded  => 0,
1150       customer_id  => $customer->id,
1151       taxzone_id   => $customer->taxzone_id,
1152       currency_id  => $currency->id,
1153       transactions => [],
1154       notes        => 'test_ar_currency_tax_not_included_and_payment 0.8',
1155       invnumber    => 'test_ar_currency_tax_not_included_and_payment 0.8',
1156   );
1157   $invoice->add_ar_amount_row(
1158     amount     => $invoice->netamount,
1159     chart      => $ar_amount_chart,
1160     tax_id     => $tax->id,
1161   );
1162
1163   $invoice->create_ar_row(chart => $ar_chart);
1164   $invoice->save;
1165
1166   is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1167   is($invoice->netamount   , 100           , "$title: ar amount has been converted");
1168   is($invoice->amount      , 119           , "$title: ar amount has been converted");
1169   is($invoice->taxincluded ,   0           , "$title: ar transaction doesn\"t have taxincluded");
1170   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");
1171   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');
1172
1173   $invoice->pay_invoice(chart_id   => $bank->id,
1174                         amount     => 123.45,
1175                         currency   => 'CUR',
1176                         transdate  => $transdate2->to_kivitendo,
1177                        );
1178   $invoice->pay_invoice(chart_id   => $bank->id,
1179                         amount     => 15.30,
1180                         currency   => 'CUR',
1181                         transdate  => $transdate3->to_kivitendo,
1182                        );
1183   $invoice->pay_invoice(chart_id   => $bank->id,
1184                         amount     => 10.00,
1185                         currency   => 'CUR',
1186                         transdate  => $transdate4->to_kivitendo,
1187                        );
1188   # $invoice->pay_invoice(chart_id   => $bank->id,
1189   #                       amount     => 30,
1190   #                       transdate  => $transdate2->to_kivitendo,
1191   #                      );
1192   my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1193   is(scalar @{$fx_transactions}, 3, "$title: ar transaction has 3 fx transactions");
1194   is($fx_transactions->[0]->amount, '24.69000', "$title fx transactions 1: 123.45-(123.45*0.8) = 24.69");
1195
1196   is(scalar @{$invoice->transactions}, 14, "$title ar transaction has 14 transactions (incl. fxtransactions and fx_gain)");
1197   is($invoice->paid, $invoice->amount, "$title ar transaction paid = amount in default currency");
1198 };
1199
1200 sub test_ar_currency_tax_not_included_and_payment_2_credit_note {
1201   my $title = 'test_ar_currency_tax_not_included_and_payment_2_credit_note';
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 credit note 0.8',
1216       invnumber    => 'test_ar_currency_tax_not_included_and_payment credit note 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 , 'currency_id has been saved');
1228   is($invoice->netamount   , -100          , 'ar amount has been converted');
1229   is($invoice->amount      , -119          , 'ar amount has been converted');
1230   is($invoice->taxincluded ,   0           , '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', $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', $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     => -25.30,
1241                         currency   => 'CUR',
1242                         transdate  => $transdate2->to_kivitendo,
1243                        );
1244   my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1245   is(scalar @{$fx_transactions}, 2, 'ar transaction has 2 fx transactions');
1246   is($fx_transactions->[0]->amount, '-24.69000', 'fx transactions 1: 123.45-(123.45*0.8) = 24.69');
1247
1248   is(scalar @{$invoice->transactions}, 9, 'ar transaction has 9 transactions (incl. fxtransactions)');
1249   is($invoice->paid, $invoice->amount, 'ar transaction paid = amount in default currency');
1250 };
1251
1252 sub test_ap_currency_tax_not_included_and_payment_2 {
1253   my $title = 'test_ap_currency_tax_not_included_and_payment_2';
1254
1255   my $netamount = $::form->round_amount(125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1256   my $amount    = $::form->round_amount($netamount * 1.19,2);          # 148.75 in CUR, 119.00 in EUR
1257   my $invoice   = SL::DB::PurchaseInvoice->new(
1258       invoice      => 0,
1259       amount       => $amount,
1260       netamount    => $netamount,
1261       transdate    => $transdate2,
1262       taxincluded  => 0,
1263       vendor_id    => $vendor->id,
1264       taxzone_id   => $vendor->taxzone_id,
1265       currency_id  => $currency->id,
1266       transactions => [],
1267       notes        => 'test_ap_currency_tax_not_included_and_payment_2 0.8 + 1.33333',
1268       invnumber    => 'test_ap_currency_tax_not_included_and_payment_2 0.8 + 1.33333',
1269   );
1270   $invoice->add_ap_amount_row(
1271     amount     => $invoice->netamount,
1272     chart      => $ap_amount_chart,
1273     tax_id     => $tax_9->id,
1274   );
1275
1276   $invoice->create_ap_row(chart => $ap_chart);
1277   $invoice->save;
1278
1279   is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1280   is($invoice->netamount   ,  100          , "$title: ap amount has been converted");
1281   is($invoice->amount      ,  119          , "$title: ap amount has been converted");
1282   is($invoice->taxincluded ,    0          , "$title: ap transaction doesn\'t have taxincluded");
1283   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');
1284   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');
1285
1286   $invoice->pay_invoice(chart_id   => $bank->id,
1287                         amount     => 10,
1288                         currency   => 'CUR',
1289                         transdate  => $transdate2->to_kivitendo,
1290                        );
1291   $invoice->pay_invoice(chart_id   => $bank->id,
1292                         amount     => 123.45,
1293                         currency   => 'CUR',
1294                         transdate  => $transdate3->to_kivitendo,
1295                        );
1296   $invoice->pay_invoice(chart_id   => $bank->id,
1297                         amount     => 15.30,
1298                         currency   => 'CUR',
1299                         transdate  => $transdate4->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}, 3, "$title: ap transaction has 3 fx transactions");
1303   is($fx_transactions->[0]->amount,  '-2.00000', "$title: fx transaction 1:  10.00-( 10.00*0.80000) =   2.00000");
1304   is($fx_transactions->[1]->amount,  '68.59000', "$title: fx transaction 2: 123.45-(123.45*1.55557) = -68.58511");
1305   is($fx_transactions->[2]->amount,  '-3.40000', "$title: fx transaction 3:  15.30-(15.30 *0.77777) =   3.40012");
1306
1307   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'));
1308   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'));
1309   is($fx_gain_transactions->[0]->amount,   '0.34000', "$title: fx gain amount ok");
1310   is($fx_loss_transactions->[0]->amount, '-93.28000', "$title: fx loss amount ok");
1311
1312   is(scalar @{$invoice->transactions}, 14, "$title: ap transaction has 14 transactions (incl. fxtransactions and gain_loss)");
1313   is($invoice->paid, $invoice->amount, "$title: ap transaction paid = amount in default currency");
1314   is(total_amount($invoice), 0,   "$title: even balance");
1315 };
1316
1317 sub test_ap_currency_tax_not_included_and_payment_2_credit_note {
1318   my $title = 'test_ap_currency_tax_not_included_and_payment_2_credit_note';
1319
1320   my $netamount = $::form->round_amount(-125 * $exchangerate2->sell,2); # 125.00 in CUR, 100.00 in EUR
1321   my $amount    = $::form->round_amount($netamount * 1.19,2);          # 148.75 in CUR, 119.00 in EUR
1322   my $invoice   = SL::DB::PurchaseInvoice->new(
1323       invoice      => 0,
1324       amount       => $amount,
1325       netamount    => $netamount,
1326       transdate    => $transdate2,
1327       taxincluded  => 0,
1328       vendor_id    => $vendor->id,
1329       taxzone_id   => $vendor->taxzone_id,
1330       currency_id  => $currency->id,
1331       transactions => [],
1332       notes        => 'test_ap_currency_tax_not_included_and_payment credit note 0.8 + 1.33333',
1333       invnumber    => 'test_ap_currency_tax_not_included_and_payment credit note 0.8 + 1.33333',
1334   );
1335   $invoice->add_ap_amount_row(
1336     amount     => $invoice->netamount,
1337     chart      => $ap_amount_chart,
1338     tax_id     => $tax_9->id,
1339   );
1340
1341   $invoice->create_ap_row(chart => $ap_chart);
1342   $invoice->save;
1343
1344   is($invoice->currency_id , $currency->id , "$title: currency_id has been saved");
1345   is($invoice->netamount   , -100          , "$title: ap amount has been converted");
1346   is($invoice->amount      , -119          , "$title: ap amount has been converted");
1347   is($invoice->taxincluded ,   0           , "$title: ap transaction doesn\'t have taxincluded");
1348   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');
1349   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');
1350
1351   $invoice->pay_invoice(chart_id   => $bank->id,
1352                         amount     => -10,
1353                         currency   => 'CUR',
1354                         transdate  => $transdate2->to_kivitendo,
1355                        );
1356   $invoice->pay_invoice(chart_id   => $bank->id,
1357                         amount     => -123.45,
1358                         currency   => 'CUR',
1359                         transdate  => $transdate3->to_kivitendo,
1360                        );
1361   $invoice->pay_invoice(chart_id   => $bank->id,
1362                         amount     => -15.30,
1363                         currency   => 'CUR',
1364                         transdate  => $transdate4->to_kivitendo,
1365                        );
1366   my $fx_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, fx_transaction => 1 ], sort_by => ('acc_trans_id'));
1367   is(scalar @{$fx_transactions}, 3, "$title: ap transaction has 3 fx transactions");
1368   is($fx_transactions->[0]->amount,   '2.00000', "$title: fx transaction 1:  10.00-( 10.00*0.80000) =   2.00000");
1369   is($fx_transactions->[1]->amount, '-68.59000', "$title: fx transaction 2: 123.45-(123.45*1.55557) = -68.58511");
1370   is($fx_transactions->[2]->amount,   '3.40000', "$title: fx transaction 3:  15.30-(15.30 *0.77777) =   3.40012");
1371
1372   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'));
1373   is($fx_gain_loss_transactions->[0]->amount, '93.28000', "$title: fx gain loss amount ok");
1374
1375   is(scalar @{$invoice->transactions}, 14, "$title: ap transaction has 14 transactions (incl. fxtransactions and gain_loss)");
1376   is($invoice->paid, $invoice->amount, "$title: ap transaction paid = amount in default currency");
1377   is(total_amount($invoice), 0,   "$title: even balance");
1378 };
1379
1380 sub test_credit_note_two_items_19_7_tax_tax_not_included {
1381   my $title = 'test_credit_note_two_items_19_7_tax_tax_not_included';
1382
1383   my $item1   = create_invoice_item(part => $parts[0], qty => 5);
1384   my $item2   = create_invoice_item(part => $parts[1], qty => 3);
1385   my $invoice = create_credit_note(
1386     invnumber    => 'cn1',
1387     taxincluded  => 0,
1388     invoiceitems => [ $item1, $item2 ],
1389   );
1390
1391   # default values
1392   my %params = ( chart_id => $bank_account->chart_id,
1393                  transdate => DateTime->today_local->to_kivitendo,
1394                );
1395
1396   $params{amount}       = $invoice->amount,
1397
1398   $invoice->pay_invoice( %params );
1399
1400   my ($number_of_payments, $paid_amount) = number_of_payments($invoice);
1401   my $total = total_amount($invoice);
1402
1403   is($invoice->netamount,        -40.84,   "${title}: netamount");
1404   is($invoice->amount,           -45.10,   "${title}: amount");
1405   is($paid_amount,                45.10,   "${title}: paid amount according to acc_trans is positive (Haben)");
1406   is($invoice->paid,             -45.10,   "${title}: paid");
1407   is($number_of_payments,             1,   "${title}: 1 AR_paid bookings");
1408   is($total,                          0,   "${title}: even balance");
1409 }
1410
1411 1;