Tests: 2 Tests in db_helper/payment.t auf TODO gesetzt
[kivitendo-erp.git] / t / db_helper / payment.t
1 use Test::More;
2
3 use strict;
4
5 use lib 't';
6 use utf8;
7
8 use Carp;
9 use Support::TestSetup;
10 use Test::Exception;
11 use List::Util qw(sum);
12
13 use SL::DB::Buchungsgruppe;
14 use SL::DB::Currency;
15 use SL::DB::Customer;
16 use SL::DB::Vendor;
17 use SL::DB::Employee;
18 use SL::DB::Invoice;
19 use SL::DB::Part;
20 use SL::DB::Unit;
21 use SL::DB::TaxZone;
22 use SL::DB::BankAccount;
23 use SL::DB::PaymentTerm;
24
25 my ($customer, $vendor, $currency_id, @parts, $buchungsgruppe, $buchungsgruppe7, $unit, $employee, $tax, $tax7, $taxzone, $payment_terms, $bank_account);
26
27 my $ALWAYS_RESET = 1;
28
29 my $reset_state_counter = 0;
30
31 my $purchase_invoice_counter = 0; # used for generating purchase invnumber
32
33 sub clear_up {
34   SL::DB::Manager::InvoiceItem->delete_all(all => 1);
35   SL::DB::Manager::Invoice->delete_all(all => 1);
36   SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
37   SL::DB::Manager::Part->delete_all(all => 1);
38   SL::DB::Manager::Customer->delete_all(all => 1);
39   SL::DB::Manager::Vendor->delete_all(all => 1);
40   SL::DB::Manager::BankAccount->delete_all(all => 1);
41   SL::DB::Manager::PaymentTerm->delete_all(all => 1);
42 };
43
44 sub reset_state {
45   my %params = @_;
46
47   return if $reset_state_counter;
48
49   $params{$_} ||= {} for qw(buchungsgruppe unit customer part tax vendor);
50
51   clear_up();
52
53
54   $buchungsgruppe  = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%', %{ $params{buchungsgruppe} }) || croak "No accounting group";
55   $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%')                                || croak "No accounting group for 7\%";
56   $unit            = SL::DB::Manager::Unit->find_by(name => 'kg', %{ $params{unit} })                                      || croak "No unit";
57   $employee        = SL::DB::Manager::Employee->current                                                                    || croak "No employee";
58   $tax             = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} })                           || croak "No tax";
59   $tax7            = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07)                                              || croak "No tax for 7\%";
60   $taxzone         = SL::DB::Manager::TaxZone->find_by( description => 'Inland')                                           || croak "No taxzone";
61
62   $currency_id     = $::instance_conf->get_currency_id;
63
64   $customer     = SL::DB::Customer->new(
65     name        => 'Test Customer',
66     currency_id => $currency_id,
67     taxzone_id  => $taxzone->id,
68     %{ $params{customer} }
69   )->save;
70
71   $bank_account     =  SL::DB::BankAccount->new(
72     account_number  => '123',
73     bank_code       => '123',
74     iban            => '123',
75     bic             => '123',
76     bank            => '123',
77     chart_id        => SL::DB::Manager::Chart->find_by( description => 'Bank' )->id,
78     name            => SL::DB::Manager::Chart->find_by( description => 'Bank' )->description,
79   )->save;
80
81   $payment_terms     =  SL::DB::PaymentTerm->new(
82     description      => 'payment',
83     description_long => 'payment',
84     terms_netto      => '30',
85     terms_skonto     => '5',
86     percent_skonto   => '0.05'
87   )->save;
88
89   $vendor       = SL::DB::Vendor->new(
90     name        => 'Test Vendor',
91     currency_id => $currency_id,
92     taxzone_id  => $taxzone->id,
93     payment_id  => $payment_terms->id,
94     %{ $params{vendor} }
95   )->save;
96
97
98   @parts = ();
99   push @parts, SL::DB::Part->new(
100     partnumber         => 'T4254',
101     description        => 'Fourty-two fifty-four',
102     lastcost           => 1.93,
103     sellprice          => 2.34,
104     buchungsgruppen_id => $buchungsgruppe->id,
105     unit               => $unit->name,
106     %{ $params{part1} }
107   )->save;
108
109   push @parts, SL::DB::Part->new(
110     partnumber         => 'T0815',
111     description        => 'Zero EIGHT fifteeN @ 7%',
112     lastcost           => 5.473,
113     sellprice          => 9.714,
114     buchungsgruppen_id => $buchungsgruppe7->id,
115     unit               => $unit->name,
116     %{ $params{part2} }
117   )->save;
118   push @parts, SL::DB::Part->new(
119     partnumber         => '19%',
120     description        => 'Testware 19%',
121     lastcost           => 0,
122     sellprice          => 50,
123     buchungsgruppen_id => $buchungsgruppe->id,
124     unit               => $unit->name,
125     %{ $params{part3} }
126   )->save;
127   push @parts, SL::DB::Part->new(
128     partnumber         => '7%',
129     description        => 'Testware 7%',
130     lastcost           => 0,
131     sellprice          => 50,
132     buchungsgruppen_id => $buchungsgruppe7->id,
133     unit               => $unit->name,
134     %{ $params{part4} }
135   )->save;
136
137   $reset_state_counter++;
138 }
139
140 sub new_invoice {
141   my %params  = @_;
142
143   return SL::DB::Invoice->new(
144     customer_id => $customer->id,
145     currency_id => $currency_id,
146     employee_id => $employee->id,
147     salesman_id => $employee->id,
148     gldate      => DateTime->today_local->to_kivitendo,
149     taxzone_id  => $taxzone->id,
150     transdate   => DateTime->today_local->to_kivitendo,
151     invoice     => 1,
152     type        => 'invoice',
153     %params,
154   );
155
156 }
157
158 sub new_purchase_invoice {
159   # my %params  = @_;
160   # manually create a Kreditorenbuchung from scratch, ap + acc_trans bookings, as no helper exists yet, like $invoice->post.
161   # arap-Booking must come last in the acc_trans order
162   $purchase_invoice_counter++;
163
164   my $purchase_invoice = SL::DB::PurchaseInvoice->new(
165     vendor_id   => $vendor->id,
166     invnumber   => 'newap ' . $purchase_invoice_counter ,
167     currency_id => $currency_id,
168     employee_id => $employee->id,
169     gldate      => DateTime->today_local->to_kivitendo,
170     taxzone_id  => $taxzone->id,
171     transdate   => DateTime->today_local->to_kivitendo,
172     invoice     => 0,
173     type        => 'invoice',
174     taxincluded => 0,
175     amount      => '226',
176     netamount   => '200',
177     paid        => '0',
178     # %params,
179   )->save;
180
181   my $today = DateTime->today_local->to_kivitendo;
182   my $expense_chart  = SL::DB::Manager::Chart->find_by(accno => '3400');
183   my $expense_chart_booking= SL::DB::AccTransaction->new(
184                                         trans_id   => $purchase_invoice->id,
185                                         chart_id   => $expense_chart->id,
186                                         chart_link => $expense_chart->link,
187                                         amount     => '-100',
188                                         transdate  => $today,
189                                         source     => '',
190                                         taxkey     => 9,
191                                         tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
192   $expense_chart_booking->save;
193
194   my $tax_chart  = SL::DB::Manager::Chart->find_by(accno => '1576');
195   my $tax_chart_booking= SL::DB::AccTransaction->new(
196                                         trans_id   => $purchase_invoice->id,
197                                         chart_id   => $tax_chart->id,
198                                         chart_link => $tax_chart->link,
199                                         amount     => '-19',
200                                         transdate  => $today,
201                                         source     => '',
202                                         taxkey     => 0,
203                                         tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 9)->id);
204   $tax_chart_booking->save;
205   $expense_chart  = SL::DB::Manager::Chart->find_by(accno => '3300');
206   $expense_chart_booking= SL::DB::AccTransaction->new(
207                                         trans_id   => $purchase_invoice->id,
208                                         chart_id   => $expense_chart->id,
209                                         chart_link => $expense_chart->link,
210                                         amount     => '-100',
211                                         transdate  => $today,
212                                         source     => '',
213                                         taxkey     => 8,
214                                         tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
215   $expense_chart_booking->save;
216
217
218   $tax_chart  = SL::DB::Manager::Chart->find_by(accno => '1571');
219   $tax_chart_booking= SL::DB::AccTransaction->new(
220                                          trans_id   => $purchase_invoice->id,
221                                          chart_id   => $tax_chart->id,
222                                          chart_link => $tax_chart->link,
223                                          amount     => '-7',
224                                          transdate  => $today,
225                                          source     => '',
226                                          taxkey     => 0,
227                                          tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 8)->id);
228   $tax_chart_booking->save;
229   my $arap_chart  = SL::DB::Manager::Chart->find_by(accno => '1600');
230   my $arap_booking= SL::DB::AccTransaction->new(trans_id   => $purchase_invoice->id,
231                                                 chart_id   => $arap_chart->id,
232                                                 chart_link => $arap_chart->link,
233                                                 amount     => '226',
234                                                 transdate  => $today,
235                                                 source     => '',
236                                                 taxkey     => 0,
237                                                 tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
238   $arap_booking->save;
239
240   return $purchase_invoice;
241 }
242
243 sub new_item {
244   my (%params) = @_;
245
246   my $part = delete($params{part}) || $parts[0];
247
248   return SL::DB::InvoiceItem->new(
249     parts_id    => $part->id,
250     lastcost    => $part->lastcost,
251     sellprice   => $part->sellprice,
252     description => $part->description,
253     unit        => $part->unit,
254     %params,
255   );
256 }
257
258 sub number_of_payments {
259   my $transactions = shift;
260
261   my $number_of_payments;
262   my $paid_amount;
263   foreach my $transaction ( @$transactions ) {
264     if ( $transaction->chart_link =~ /(AR_paid|AP_paid)/ ) {
265       $paid_amount += $transaction->amount ;
266       $number_of_payments++;
267     };
268   };
269   return ($number_of_payments, $paid_amount);
270 };
271
272 sub total_amount {
273   my $transactions = shift;
274
275   my $total = sum map { $_->amount } @$transactions;
276
277   return $::form->round_amount($total, 5);
278
279 };
280
281
282 # test 1
283 sub test_default_invoice_one_item_19_without_skonto() {
284   reset_state() if $ALWAYS_RESET;
285
286   my $item    = new_item(qty => 2.5);
287   my $invoice = new_invoice(
288     taxincluded  => 0,
289     invoiceitems => [ $item ],
290     payment_id   => $payment_terms->id,
291   );
292   $invoice->post;
293
294   my $purchase_invoice = new_purchase_invoice();
295
296
297   # default values
298   my %params = ( chart_id => $bank_account->chart_id,
299                  transdate => DateTime->today_local->to_kivitendo
300                );
301
302   $params{amount} = '6.96';
303   $params{payment_type} = 'without_skonto';
304
305   $invoice->pay_invoice( %params );
306
307   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
308   my $total = total_amount($invoice->transactions);
309
310   my $title = 'default invoice, one item, 19% tax, without_skonto';
311
312   is($invoice->netamount,   5.85,      "${title}: netamount");
313   is($invoice->amount,      6.96,      "${title}: amount");
314   is($paid_amount,         -6.96,      "${title}: paid amount");
315   is($number_of_payments,      1,      "${title}: 1 AR_paid booking");
316   is($invoice->paid,        6.96,      "${title}: paid");
317   is($total,                   0,      "${title}: even balance");
318
319 }
320
321 sub test_default_invoice_one_item_19_without_skonto_overpaid() {
322   reset_state() if $ALWAYS_RESET;
323
324   my $item    = new_item(qty => 2.5);
325   my $invoice = new_invoice(
326     taxincluded  => 0,
327     invoiceitems => [ $item ],
328     payment_id   => $payment_terms->id,
329   );
330   $invoice->post;
331
332   my $purchase_invoice = new_purchase_invoice();
333
334
335   # default values
336   my %params = ( chart_id => $bank_account->chart_id,
337                  transdate => DateTime->today_local->to_kivitendo
338                );
339
340   $params{amount} = '16.96';
341   $params{payment_type} = 'without_skonto';
342   $invoice->pay_invoice( %params );
343
344   $params{amount} = '-10.00';
345   $invoice->pay_invoice( %params );
346
347   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
348   my $total = total_amount($invoice->transactions);
349
350   my $title = 'default invoice, one item, 19% tax, without_skonto';
351
352   is($invoice->netamount,   5.85,      "${title}: netamount");
353   is($invoice->amount,      6.96,      "${title}: amount");
354   is($paid_amount,         -6.96,      "${title}: paid amount");
355   is($number_of_payments,      2,      "${title}: 1 AR_paid booking");
356   is($invoice->paid,        6.96,      "${title}: paid");
357   is($total,                   0,      "${title}: even balance");
358
359 }
360
361
362 # test 2
363 sub test_default_invoice_two_items_19_7_tax_with_skonto() {
364   reset_state() if $ALWAYS_RESET;
365
366   my $item1   = new_item(qty => 2.5);
367   my $item2   = new_item(qty => 1.2, part => $parts[1]);
368   my $invoice = new_invoice(
369     taxincluded  => 0,
370     invoiceitems => [ $item1, $item2 ],
371     payment_id  => $payment_terms->id,
372   );
373   $invoice->post;
374
375   # default values
376   my %params = ( chart_id => $bank_account->chart_id,
377                  transdate => DateTime->today_local->to_kivitendo
378                );
379
380   $params{payment_type} = 'with_skonto_pt';
381   $params{amount}       = $invoice->amount_less_skonto;
382
383   $invoice->pay_invoice( %params );
384
385   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
386   my $total = total_amount($invoice->transactions);
387
388   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
389
390   is($invoice->netamount,  5.85 + 11.66,   "${title}: netamount");
391   is($invoice->amount,     6.96 + 12.48,   "${title}: amount");
392   is($paid_amount,               -19.44,   "${title}: paid amount");
393   is($invoice->paid,              19.44,   "${title}: paid");
394   is($number_of_payments,             3,   "${title}: 3 AR_paid bookings");
395   is($total,                          0,   "${title}: even balance");
396 }
397
398 sub test_default_invoice_two_items_19_7_tax_with_skonto_tax_included() {
399   reset_state() if $ALWAYS_RESET;
400
401   my $item1   = new_item(qty => 2.5);
402   my $item2   = new_item(qty => 1.2, part => $parts[1]);
403   my $invoice = new_invoice(
404     taxincluded  => 1,
405     invoiceitems => [ $item1, $item2 ],
406     payment_id  => $payment_terms->id,
407   );
408   $invoice->post;
409
410   # default values
411   my %params = ( chart_id => $bank_account->chart_id,
412                  transdate => DateTime->today_local->to_kivitendo
413                );
414
415   $params{payment_type} = 'with_skonto_pt';
416   $params{amount}       = $invoice->amount_less_skonto;
417
418   $invoice->pay_invoice( %params );
419
420   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
421   my $total = total_amount($invoice->transactions);
422
423   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt';
424
425   is($invoice->netamount,         15.82,   "${title}: netamount");
426   is($invoice->amount,            17.51,   "${title}: amount");
427   is($paid_amount,               -17.51,   "${title}: paid amount");
428   is($invoice->paid,              17.51,   "${title}: paid");
429   is($number_of_payments,             3,   "${title}: 3 AR_paid bookings");
430   { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
431   is($total,                          0,   "${title}: even balance");
432   }
433 }
434
435 # test 3 : two items, without skonto
436 sub test_default_invoice_two_items_19_7_without_skonto() {
437   reset_state() if $ALWAYS_RESET;
438
439   my $item1   = new_item(qty => 2.5);
440   my $item2   = new_item(qty => 1.2, part => $parts[1]);
441   my $invoice = new_invoice(
442     taxincluded  => 0,
443     invoiceitems => [ $item1, $item2 ],
444     payment_id  => $payment_terms->id,
445   );
446   $invoice->post;
447
448   # default values
449   my %params = ( chart_id => $bank_account->chart_id,
450                  transdate => DateTime->today_local->to_kivitendo
451                );
452
453   $params{amount} = '19.44'; # pass full amount
454   $params{payment_type} = 'without_skonto';
455
456   $invoice->pay_invoice( %params );
457
458   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
459   my $total = total_amount($invoice->transactions);
460
461   my $title = 'default invoice, two items, 19/7% tax without skonto';
462
463   is($invoice->netamount,     5.85 + 11.66,     "${title}: netamount");
464   is($invoice->amount,        6.96 + 12.48,     "${title}: amount");
465   is($paid_amount,                  -19.44,     "${title}: paid amount");
466   is($invoice->paid,                 19.44,     "${title}: paid");
467   is($number_of_payments,                1,     "${title}: 1 AR_paid bookings");
468   is($total,                             0,     "${title}: even balance");
469 }
470
471 # test 4
472 sub test_default_invoice_two_items_19_7_without_skonto_incomplete_payment() {
473   reset_state() if $ALWAYS_RESET;
474
475   my $item1   = new_item(qty => 2.5);
476   my $item2   = new_item(qty => 1.2, part => $parts[1]);
477   my $invoice = new_invoice(
478     taxincluded  => 0,
479     invoiceitems => [ $item1, $item2 ],
480     payment_id  => $payment_terms->id,
481   );
482   $invoice->post;
483
484   $invoice->pay_invoice( amount       => '9.44',
485                          payment_type => 'without_skonto',
486                          chart_id     => $bank_account->chart_id,
487                          transdate    => DateTime->today_local->to_kivitendo,
488                        );
489
490   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
491   my $total = total_amount($invoice->transactions);
492
493   my $title = 'default invoice, two items, 19/7% tax without skonto incomplete payment';
494
495   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
496   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
497   is($paid_amount,              -9.44,             "${title}: paid amount");
498   is($invoice->paid,             9.44,            "${title}: paid");
499   is($number_of_payments,   1,                "${title}: 1 AR_paid bookings");
500   is($total,                    0,                "${title}: even balance");
501 }
502
503 # test 5
504 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments() {
505   reset_state() if $ALWAYS_RESET;
506
507   my $item1   = new_item(qty => 2.5);
508   my $item2   = new_item(qty => 1.2, part => $parts[1]);
509   my $invoice = new_invoice(
510     taxincluded  => 0,
511     invoiceitems => [ $item1, $item2 ],
512     payment_id  => $payment_terms->id,
513   );
514   $invoice->post;
515
516   $invoice->pay_invoice( amount       => '9.44',
517                          payment_type => 'without_skonto',
518                          chart_id     => $bank_account->chart_id,
519                          transdate    => DateTime->today_local->to_kivitendo
520                        );
521   $invoice->pay_invoice( amount       => '10.00',
522                          chart_id     => $bank_account->chart_id,
523                          transdate    => DateTime->today_local->to_kivitendo
524                        );
525
526   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
527   my $total = total_amount($invoice->transactions);
528
529   my $title = 'default invoice, two items, 19/7% tax not included';
530
531   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
532   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
533   is($paid_amount,                     -19.44,     "${title}: paid amount");
534   is($invoice->paid,                    19.44,     "${title}: paid");
535   is($number_of_payments,                   2,     "${title}: 2 AR_paid bookings");
536   is($total,                                0,     "${title}: even balance");
537
538 }
539
540 # test 6
541 sub test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
542   reset_state() if $ALWAYS_RESET;
543
544   my $item1   = new_item(qty => 2.5);
545   my $item2   = new_item(qty => 1.2, part => $parts[1]);
546   my $invoice = new_invoice(
547     taxincluded  => 0,
548     invoiceitems => [ $item1, $item2 ],
549     payment_id  => $payment_terms->id,
550   );
551   $invoice->post;
552
553   $invoice->pay_invoice( amount       => '9.44',
554                          payment_type => 'without_skonto',
555                          chart_id     => $bank_account->chart_id,
556                          transdate    => DateTime->today_local->to_kivitendo
557                        );
558   $invoice->pay_invoice( amount       => '8.73',
559                          payment_type => 'without_skonto',
560                          chart_id     => $bank_account->chart_id,
561                          transdate    => DateTime->today_local->to_kivitendo
562                        );
563   $invoice->pay_invoice( amount       => $invoice->open_amount,
564                          payment_type => 'difference_as_skonto',
565                          chart_id     => $bank_account->chart_id,
566                          transdate    => DateTime->today_local->to_kivitendo
567                        );
568
569   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
570   my $total = total_amount($invoice->transactions);
571
572   my $title = 'default invoice, two items, 19/7% tax not included';
573
574   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
575   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
576   is($paid_amount,                     -19.44,     "${title}: paid amount");
577   is($invoice->paid,                    19.44,     "${title}: paid");
578   is($number_of_payments,                   4,     "${title}: 4 AR_paid bookings");
579   is($total,                                0,     "${title}: even balance");
580
581 }
582
583 sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent() {
584   reset_state() if $ALWAYS_RESET;
585
586   # if there is only one cent left there can only be one skonto booking, the
587   # error handling should choose the highest amount, which is the 7% account
588   # (11.66) rather than the 19% account (5.85).  The actual tax amount is
589   # higher for the 19% case, though (1.11 compared to 0.82)
590
591   my $item1   = new_item(qty => 2.5);
592   my $item2   = new_item(qty => 1.2, part => $parts[1]);
593   my $invoice = new_invoice(
594     taxincluded  => 0,
595     invoiceitems => [ $item1, $item2 ],
596     payment_id  => $payment_terms->id,
597   );
598   $invoice->post;
599
600   $invoice->pay_invoice( amount       => '19.42',
601                          payment_type => 'without_skonto',
602                          chart_id     => $bank_account->chart_id,
603                          transdate    => DateTime->today_local->to_kivitendo
604                        );
605   $invoice->pay_invoice( amount       => $invoice->open_amount,
606                          payment_type => 'difference_as_skonto',
607                          chart_id     => $bank_account->chart_id,
608                          transdate    => DateTime->today_local->to_kivitendo
609                        );
610
611   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
612   my $total = total_amount($invoice->transactions);
613
614   my $title = 'default invoice, two items, 19/7% tax not included';
615
616   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
617   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
618   is($paid_amount,                     -19.44,     "${title}: paid amount");
619   is($invoice->paid,                    19.44,     "${title}: paid");
620   is($number_of_payments,                   3,     "${title}: 2 AR_paid bookings");
621   is($total,                                0,     "${title}: even balance");
622
623 }
624
625 sub  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent() {
626   reset_state() if $ALWAYS_RESET;
627
628   # if there are two cents left there will be two skonto bookings, 1 cent each
629   my $item1   = new_item(qty => 2.5);
630   my $item2   = new_item(qty => 1.2, part => $parts[1]);
631   my $invoice = new_invoice(
632     taxincluded  => 0,
633     invoiceitems => [ $item1, $item2 ],
634     payment_id  => $payment_terms->id,
635   );
636   $invoice->post;
637
638   $invoice->pay_invoice( amount       => '19.42',
639                          payment_type => 'without_skonto',
640                          chart_id     => $bank_account->chart_id,
641                          transdate    => DateTime->today_local->to_kivitendo
642                        );
643   $invoice->pay_invoice( amount       => $invoice->open_amount,
644                          payment_type => 'difference_as_skonto',
645                          chart_id     => $bank_account->chart_id,
646                          transdate    => DateTime->today_local->to_kivitendo
647                        );
648
649   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
650   my $total = total_amount($invoice->transactions);
651
652   my $title = 'default invoice, two items, 19/7% tax not included';
653
654   is($invoice->netamount,        5.85 + 11.66,     "${title}: netamount");
655   is($invoice->amount,           6.96 + 12.48,     "${title}: amount");
656   is($paid_amount,                     -19.44,     "${title}: paid amount");
657   is($invoice->paid,                    19.44,     "${title}: paid");
658   is($number_of_payments,                   3,     "${title}: 3 AR_paid bookings");
659   is($total,                                0,     "${title}: even balance");
660
661 }
662
663 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto() {
664   reset_state() if $ALWAYS_RESET;
665
666   my $item    = new_item(qty => 2.5);
667   my $invoice = new_invoice(
668     taxincluded  => 0,
669     invoiceitems => [ $item ],
670     payment_id   => $payment_terms->id,
671   );
672   $invoice->post;
673
674   # default values
675   my %params = ( chart_id  => $bank_account->chart_id,
676                  transdate => DateTime->today_local->to_kivitendo
677                );
678
679   $params{amount}       = '2.32';
680   $params{payment_type} = 'without_skonto';
681   $invoice->pay_invoice( %params );
682
683   $params{amount}       = '3.81';
684   $params{payment_type} = 'without_skonto';
685   $invoice->pay_invoice( %params );
686
687   $params{amount}       = $invoice->open_amount; # set amount, otherwise previous 3.81 is used
688   $params{payment_type} = 'difference_as_skonto';
689   $invoice->pay_invoice( %params );
690
691   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
692   my $total = total_amount($invoice->transactions);
693
694   my $title = 'default invoice, one item, 19% tax, without_skonto';
695
696   is($invoice->netamount,       5.85,     "${title}: netamount");
697   is($invoice->amount,          6.96,     "${title}: amount");
698   is($paid_amount,             -6.96,     "${title}: paid amount");
699   is($number_of_payments,          3,     "${title}: 3 AR_paid booking");
700   is($invoice->paid,            6.96,     "${title}: paid");
701   is($total,                       0,     "${title}: even balance");
702
703 }
704
705 sub test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent() {
706   reset_state() if $ALWAYS_RESET;
707
708   my $item    = new_item(qty => 2.5);
709   my $invoice = new_invoice(
710     taxincluded  => 0,
711     invoiceitems => [ $item ],
712     payment_id   => $payment_terms->id,
713   );
714   $invoice->post;
715
716   # default values
717   my %params = ( chart_id  => $bank_account->chart_id,
718                  transdate => DateTime->today_local->to_kivitendo
719                );
720
721   $params{amount}       = '6.95';
722   $params{payment_type} = 'without_skonto';
723   $invoice->pay_invoice( %params );
724
725   $params{amount}       = $invoice->open_amount; # set amount, otherwise previous value 6.95 is used
726   $params{payment_type} = 'difference_as_skonto';
727   $invoice->pay_invoice( %params );
728
729   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
730   my $total = total_amount($invoice->transactions);
731
732   my $title = 'default invoice, one item, 19% tax, without_skonto';
733
734   is($invoice->netamount,       5.85,     "${title}: netamount");
735   is($invoice->amount,          6.96,     "${title}: amount");
736   is($paid_amount,             -6.96,     "${title}: paid amount");
737   is($number_of_payments,          2,     "${title}: 3 AR_paid booking");
738   is($invoice->paid,            6.96,     "${title}: paid");
739   is($total,                       0,     "${title}: even balance");
740
741 }
742
743 # test 3 : two items, without skonto
744 sub test_default_purchase_invoice_two_charts_19_7_without_skonto() {
745   reset_state() if $ALWAYS_RESET;
746
747   my $purchase_invoice = new_purchase_invoice();
748
749   my %params = ( chart_id => $bank_account->chart_id,
750                  transdate => DateTime->today_local->to_kivitendo
751                );
752
753   $params{amount} = '226'; # pass full amount
754   $params{payment_type} = 'without_skonto';
755
756   $purchase_invoice->pay_invoice( %params );
757
758   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
759   my $total = total_amount($purchase_invoice->transactions);
760
761   my $title = 'default invoice, two items, 19/7% tax without skonto';
762
763   is($paid_amount,         226,     "${title}: paid amount");
764   is($number_of_payments,    1,     "${title}: 1 AP_paid bookings");
765   is($total,                 0,     "${title}: even balance");
766
767 }
768
769 sub test_default_purchase_invoice_two_charts_19_7_with_skonto() {
770   reset_state() if $ALWAYS_RESET;
771
772   my $purchase_invoice = new_purchase_invoice();
773
774   my %params = ( chart_id => $bank_account->chart_id,
775                  transdate => DateTime->today_local->to_kivitendo
776                );
777
778   # $params{amount} = '226'; # pass full amount
779   $params{payment_type} = 'with_skonto_pt';
780
781   $purchase_invoice->pay_invoice( %params );
782
783   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
784   my $total = total_amount($purchase_invoice->transactions);
785
786   my $title = 'default invoice, two items, 19/7% tax without skonto';
787
788   is($paid_amount,         226,     "${title}: paid amount");
789   is($number_of_payments,    3,     "${title}: 1 AP_paid bookings");
790   is($total,                 0,     "${title}: even balance");
791
792 }
793
794 sub test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto() {
795   # check whether unrounded amounts passed via $params{amount} are rounded for without_skonto case
796   reset_state() if $ALWAYS_RESET;
797   my $purchase_invoice = new_purchase_invoice();
798   $purchase_invoice->pay_invoice(
799                           amount       => ( $purchase_invoice->amount / 3 * 2),
800                           payment_type => 'without_skonto',
801                           chart_id     => $bank_account->chart_id,
802                           transdate    => DateTime->today_local->to_kivitendo
803                          );
804   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
805   my $total = total_amount($purchase_invoice->transactions);
806
807   my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
808
809   is($paid_amount,         150.67,   "${title}: paid amount");
810   is($number_of_payments,       1,   "${title}: 1 AP_paid bookings");
811   is($total,                    0,   "${title}: even balance");
812 };
813
814
815 sub test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto() {
816   reset_state() if $ALWAYS_RESET;
817
818   my $purchase_invoice = new_purchase_invoice();
819
820   # pay 2/3 and 1/5, leaves 3.83% to be used as Skonto
821   $purchase_invoice->pay_invoice(
822                           amount       => ( $purchase_invoice->amount / 3 * 2),
823                           payment_type => 'without_skonto',
824                           chart_id     => $bank_account->chart_id,
825                           transdate    => DateTime->today_local->to_kivitendo
826                          );
827   $purchase_invoice->pay_invoice(
828                           amount       => ( $purchase_invoice->amount / 5 ),
829                           payment_type => 'without_skonto',
830                           chart_id     => $bank_account->chart_id,
831                           transdate    => DateTime->today_local->to_kivitendo
832                          );
833   $purchase_invoice->pay_invoice(
834                           payment_type => 'difference_as_skonto',
835                           chart_id     => $bank_account->chart_id,
836                           transdate    => DateTime->today_local->to_kivitendo
837                          );
838
839   my ($number_of_payments, $paid_amount) = number_of_payments($purchase_invoice->transactions);
840   my $total = total_amount($purchase_invoice->transactions);
841
842   my $title = 'default purchase_invoice, two charts, 19/7% tax multiple payments with final difference as skonto';
843
844   is($paid_amount,         226, "${title}: paid amount");
845   is($number_of_payments,    4, "${title}: 1 AP_paid bookings");
846   is($total,                 0, "${title}: even balance");
847
848 }
849
850 # test
851 sub test_default_invoice_two_items_19_7_tax_with_skonto_50_50() {
852   reset_state() if $ALWAYS_RESET;
853
854   my $item1   = new_item(qty => 1, part => $parts[2]);
855   my $item2   = new_item(qty => 1, part => $parts[3]);
856   my $invoice = new_invoice(
857     taxincluded  => 0,
858     invoiceitems => [ $item1, $item2 ],
859     payment_id  => $payment_terms->id,
860   );
861   $invoice->post;
862
863   # default values
864   my %params = ( chart_id => $bank_account->chart_id,
865                  transdate => DateTime->today_local->to_kivitendo
866                );
867
868   $params{amount} = $invoice->amount_less_skonto;
869   $params{payment_type} = 'with_skonto_pt';
870
871   $invoice->pay_invoice( %params );
872
873   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
874   my $total = total_amount($invoice->transactions);
875
876   my $title = 'default invoice, two items, 19/7% tax with_skonto_pt 50/50';
877
878   is($invoice->netamount,        100,     "${title}: netamount");
879   is($invoice->amount,           113,     "${title}: amount");
880   is($paid_amount,              -113,     "${title}: paid amount");
881   is($invoice->paid,             113,     "${title}: paid");
882   is($number_of_payments,          3,     "${title}: 3 AR_paid bookings");
883   is($total,                       0,     "${title}: even balance");
884 }
885
886 # test
887 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25() {
888   reset_state() if $ALWAYS_RESET;
889
890   my $item1   = new_item(qty => 0.5, part => $parts[2]);
891   my $item2   = new_item(qty => 0.5, part => $parts[3]);
892   my $item3   = new_item(qty => 0.5, part => $parts[2]);
893   my $item4   = new_item(qty => 0.5, part => $parts[3]);
894   my $invoice = new_invoice(
895     taxincluded  => 0,
896     invoiceitems => [ $item1, $item2, $item3, $item4 ],
897     payment_id  => $payment_terms->id,
898   );
899   $invoice->post;
900
901   # default values
902   my %params = ( chart_id => $bank_account->chart_id,
903                  transdate => DateTime->today_local->to_kivitendo
904                );
905
906   $params{amount} = $invoice->amount_less_skonto;
907   $params{payment_type} = 'with_skonto_pt';
908
909   $invoice->pay_invoice( %params );
910
911   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
912   my $total = total_amount($invoice->transactions);
913
914   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
915
916   is($invoice->netamount , 100  , "${title}: netamount");
917   is($invoice->amount    , 113  , "${title}: amount");
918   is($paid_amount        , -113 , "${title}: paid amount");
919   is($invoice->paid      , 113  , "${title}: paid");
920   is($number_of_payments , 3    , "${title}: 3 AR_paid bookings");
921   is($total              , 0    , "${title}: even balance");
922 }
923
924 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included() {
925   reset_state() if $ALWAYS_RESET;
926
927   my $item1   = new_item(qty => 0.5, part => $parts[2]);
928   my $item2   = new_item(qty => 0.5, part => $parts[3]);
929   my $item3   = new_item(qty => 0.5, part => $parts[2]);
930   my $item4   = new_item(qty => 0.5, part => $parts[3]);
931   my $invoice = new_invoice(
932     taxincluded  => 1,
933     invoiceitems => [ $item1, $item2, $item3, $item4 ],
934     payment_id  => $payment_terms->id,
935   );
936   $invoice->post;
937
938   # default values
939   my %params = ( chart_id => $bank_account->chart_id,
940                  transdate => DateTime->today_local->to_kivitendo
941                );
942
943   $params{amount} = $invoice->amount_less_skonto;
944   $params{payment_type} = 'with_skonto_pt';
945
946   $invoice->pay_invoice( %params );
947
948   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
949   my $total = total_amount($invoice->transactions);
950
951   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
952
953   is($invoice->netamount,   88.75,    "${title}: netamount");
954   is($invoice->amount,        100,    "${title}: amount");
955   is($paid_amount,           -100,    "${title}: paid amount");
956   is($invoice->paid,          100,    "${title}: paid");
957   is($number_of_payments,       3,    "${title}: 3 AR_paid bookings");
958   { local $TODO = "currently this test fails because the code writing the invoice is buggy, the calculation of skonto is correct";
959   is($total,                    0,    "${title}: even balance");
960   }
961 }
962
963 sub test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple() {
964   reset_state() if $ALWAYS_RESET;
965
966   my $item1   = new_item(qty => 0.5, part => $parts[2]);
967   my $item2   = new_item(qty => 0.5, part => $parts[3]);
968   my $item3   = new_item(qty => 0.5, part => $parts[2]);
969   my $item4   = new_item(qty => 0.5, part => $parts[3]);
970   my $invoice = new_invoice(
971     taxincluded  => 0,
972     invoiceitems => [ $item1, $item2, $item3, $item4 ],
973     payment_id  => $payment_terms->id,
974   );
975   $invoice->post;
976
977   $invoice->pay_invoice( amount       => '90',
978                          payment_type => 'without_skonto',
979                          chart_id     => $bank_account->chart_id,
980                          transdate => DateTime->today_local->to_kivitendo
981                        );
982   $invoice->pay_invoice( payment_type => 'difference_as_skonto',
983                          chart_id     => $bank_account->chart_id,
984                          transdate    => DateTime->today_local->to_kivitendo
985                        );
986
987   my ($number_of_payments, $paid_amount) = number_of_payments($invoice->transactions);
988   my $total = total_amount($invoice->transactions);
989
990   my $title = 'default invoice, four items, 19/7% tax with_skonto_pt 4x25';
991
992   is($invoice->netamount,  100,     "${title}: netamount");
993   is($invoice->amount,     113,     "${title}: amount");
994   is($paid_amount,        -113,     "${title}: paid amount");
995   is($invoice->paid,       113,     "${title}: paid");
996   is($number_of_payments,    3,     "${title}: 3 AR_paid bookings");
997   is($total,                 0,     "${title}: even balance: this will fail due to rounding error in invoice post, not the skonto");
998 }
999
1000 Support::TestSetup::login();
1001  # die;
1002
1003 # test cases: without_skonto
1004  test_default_invoice_one_item_19_without_skonto();
1005  test_default_invoice_two_items_19_7_tax_with_skonto();
1006  test_default_invoice_two_items_19_7_without_skonto();
1007  test_default_invoice_two_items_19_7_without_skonto_incomplete_payment();
1008  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments();
1009  test_default_purchase_invoice_two_charts_19_7_without_skonto();
1010  test_default_purchase_invoice_two_charts_19_7_tax_partial_unrounded_payment_without_skonto();
1011  test_default_invoice_one_item_19_without_skonto_overpaid();
1012
1013 # test cases: difference_as_skonto
1014  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1015  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_1cent();
1016  test_default_invoice_two_items_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto_2cent();
1017  test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto();
1018  test_default_invoice_one_item_19_multiple_payment_final_difference_as_skonto_1cent();
1019  test_default_purchase_invoice_two_charts_19_7_tax_without_skonto_multiple_payments_final_difference_as_skonto();
1020
1021 # test cases: with_skonto_pt
1022  test_default_invoice_two_items_19_7_tax_with_skonto_50_50();
1023  test_default_invoice_four_items_19_7_tax_with_skonto_4x_25();
1024  test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_multiple();
1025  test_default_purchase_invoice_two_charts_19_7_with_skonto();
1026  test_default_invoice_four_items_19_7_tax_with_skonto_4x_25_tax_included();
1027  test_default_invoice_two_items_19_7_tax_with_skonto_tax_included();
1028
1029 # remove all created data at end of test
1030 clear_up();
1031
1032 done_testing();
1033
1034 1;