bc646b571406fae8032a66eeb787b08721a6afe3
[kivitendo-erp.git] / t / bank / bank_transactions.t
1 use Test::More tests => 176;
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::AccTransaction;
14 use SL::DB::Buchungsgruppe;
15 use SL::DB::Currency;
16 use SL::DB::Customer;
17 use SL::DB::Vendor;
18 use SL::DB::Invoice;
19 use SL::DB::Unit;
20 use SL::DB::Part;
21 use SL::DB::TaxZone;
22 use SL::DB::BankAccount;
23 use SL::DB::PaymentTerm;
24 use SL::DB::PurchaseInvoice;
25 use SL::DB::BankTransaction;
26 use SL::Controller::BankTransaction;
27 use SL::Dev::ALL qw(:ALL);
28 use Data::Dumper;
29
30 my ($customer, $vendor, $currency_id, $unit, $tax, $tax7, $tax_9, $payment_terms, $bank_account);
31 my ($transdate1, $transdate2, $currency);
32 my ($ar_chart,$bank,$ar_amount_chart, $ap_chart, $ap_amount_chart);
33 my ($ar_transaction, $ap_transaction);
34
35 sub clear_up {
36
37   SL::DB::Manager::BankTransaction->delete_all(all => 1);
38   SL::DB::Manager::InvoiceItem->delete_all(all => 1);
39   SL::DB::Manager::InvoiceItem->delete_all(all => 1);
40   SL::DB::Manager::Invoice->delete_all(all => 1);
41   SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
42   SL::DB::Manager::Part->delete_all(all => 1);
43   SL::DB::Manager::Customer->delete_all(all => 1);
44   SL::DB::Manager::Vendor->delete_all(all => 1);
45   SL::DB::Manager::SepaExportItem->delete_all(all => 1);
46   SL::DB::Manager::SepaExport->delete_all(all => 1);
47   SL::DB::Manager::BankAccount->delete_all(all => 1);
48   SL::DB::Manager::PaymentTerm->delete_all(all => 1);
49   SL::DB::Manager::Currency->delete_all(where => [ name => 'CUR' ]);
50 };
51
52 sub save_btcontroller_to_string {
53   my $output;
54   open(my $outputFH, '>', \$output) or die;
55   my $oldFH = select $outputFH;
56
57   my $bt_controller = SL::Controller::BankTransaction->new;
58   $bt_controller->action_save_invoices;
59
60   select $oldFH;
61   close $outputFH;
62   return $output;
63 }
64
65 # starting test:
66 Support::TestSetup::login();
67
68 clear_up();
69 reset_state(); # initialise customers/vendors/bank/currency/...
70
71 test1();
72
73 test_overpayment_with_partialpayment();
74 test_overpayment();
75 test_skonto_exact();
76 test_two_invoices();
77 test_partial_payment();
78 test_credit_note();
79 test_ap_transaction();
80 test_neg_ap_transaction(invoice => 0);
81 test_neg_ap_transaction(invoice => 1);
82 test_ap_payment_transaction();
83 test_ap_payment_part_transaction();
84 test_neg_sales_invoice();
85 test_two_neg_ap_transaction();
86 test_one_inv_and_two_invoices_with_skonto_exact();
87 test_bt_rule1();
88 test_sepa_export();
89
90 # remove all created data at end of test
91 clear_up();
92
93 done_testing();
94
95 ###### functions for setting up data
96
97 sub reset_state {
98   my %params = @_;
99
100   $params{$_} ||= {} for qw(unit customer tax vendor);
101
102   clear_up();
103
104   $transdate1 = DateTime->today;
105   $transdate2 = DateTime->today->add(days => 5);
106
107   $tax             = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} }) || croak "No tax";
108   $tax7            = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07)                    || croak "No tax for 7\%";
109   $tax_9           = SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.19, %{ $params{tax} }) || croak "No tax";
110
111   $currency_id     = $::instance_conf->get_currency_id;
112
113   $bank_account     =  SL::DB::BankAccount->new(
114     account_number  => '123',
115     bank_code       => '123',
116     iban            => '123',
117     bic             => '123',
118     bank            => '123',
119     chart_id        => SL::DB::Manager::Chart->find_by(description => 'Bank')->id,
120     name            => SL::DB::Manager::Chart->find_by(description => 'Bank')->description,
121   )->save;
122
123   $customer = new_customer(
124     name                      => 'Test Customer OLÉ S.L. Årdbärg AB',
125     iban                      => 'DE12500105170648489890',
126     bic                       => 'TESTBIC',
127     account_number            => '648489890',
128     mandate_date_of_signature => $transdate1,
129     mandator_id               => 'foobar',
130     bank                      => 'Geizkasse',
131     bank_code                 => 'G1235',
132     depositor                 => 'Test Customer',
133     customernumber            => 'CUST1704',
134   )->save;
135
136   $payment_terms = create_payment_terms();
137
138   $vendor = new_vendor(
139     name           => 'Test Vendor',
140     payment_id     => $payment_terms->id,
141     iban           => 'DE12500105170648489890',
142     bic            => 'TESTBIC',
143     account_number => '648489890',
144     bank           => 'Geizkasse',
145     bank_code      => 'G1235',
146     depositor      => 'Test Vendor',
147     vendornumber   => 'VEND1704',
148   )->save;
149
150   $ar_chart        = SL::DB::Manager::Chart->find_by( accno => '1400' ); # Forderungen
151   $ap_chart        = SL::DB::Manager::Chart->find_by( accno => '1600' ); # Verbindlichkeiten
152   $bank            = SL::DB::Manager::Chart->find_by( accno => '1200' ); # Bank
153   $ar_amount_chart = SL::DB::Manager::Chart->find_by( accno => '8400' ); # Erlöse
154   $ap_amount_chart = SL::DB::Manager::Chart->find_by( accno => '3400' ); # Wareneingang 19%
155
156 }
157
158 sub test_ar_transaction {
159   my (%params) = @_;
160   my $netamount = 100;
161   my $amount    = $params{amount} || $::form->round_amount(100 * 1.19,2);
162   my $invoice   = SL::DB::Invoice->new(
163       invoice      => 0,
164       invnumber    => $params{invnumber} || undef, # let it use its own invnumber
165       amount       => $amount,
166       netamount    => $netamount,
167       transdate    => $transdate1,
168       taxincluded  => 0,
169       customer_id  => $customer->id,
170       taxzone_id   => $customer->taxzone_id,
171       currency_id  => $currency_id,
172       transactions => [],
173       payment_id   => $params{payment_id} || undef,
174       notes        => 'test_ar_transaction',
175   );
176   $invoice->add_ar_amount_row(
177     amount => $invoice->netamount,
178     chart  => $ar_amount_chart,
179     tax_id => $tax->id,
180   );
181
182   $invoice->create_ar_row(chart => $ar_chart);
183   $invoice->save;
184
185   is($invoice->currency_id , $currency_id , 'currency_id has been saved');
186   is($invoice->netamount   , 100          , 'ar amount has been converted');
187   is($invoice->amount      , 119          , 'ar amount has been converted');
188   is($invoice->taxincluded , 0            , 'ar transaction doesn\'t have taxincluded');
189
190   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');
191   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');
192
193   return $invoice;
194 };
195
196 sub test_ap_transaction {
197   my (%params) = @_;
198   my $testname = 'test_ap_transaction';
199
200   my $netamount = 100;
201   my $amount    = $::form->round_amount($netamount * 1.19,2);
202   my $invoice   = SL::DB::PurchaseInvoice->new(
203     invoice      => 0,
204     invnumber    => $params{invnumber} || $testname,
205     amount       => $amount,
206     netamount    => $netamount,
207     transdate    => $transdate1,
208     taxincluded  => 0,
209     vendor_id    => $vendor->id,
210     taxzone_id   => $vendor->taxzone_id,
211     currency_id  => $currency_id,
212     transactions => [],
213     notes        => 'test_ap_transaction',
214   );
215   $invoice->add_ap_amount_row(
216     amount     => $invoice->netamount,
217     chart      => $ap_amount_chart,
218     tax_id     => $tax_9->id,
219   );
220
221   $invoice->create_ap_row(chart => $ap_chart);
222   $invoice->save;
223
224   is($invoice->currency_id , $currency_id , "$testname: currency_id has been saved");
225   is($invoice->netamount   , 100          , "$testname: ap amount has been converted");
226   is($invoice->amount      , 119          , "$testname: ap amount has been converted");
227   is($invoice->taxincluded , 0            , "$testname: ap transaction doesn\'t have taxincluded");
228
229   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');
230   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');
231
232   return $invoice;
233 };
234
235 ###### test cases
236
237 sub test1 {
238
239   my $testname = 'test1';
240
241   $ar_transaction = test_ar_transaction(invnumber => 'salesinv1');
242
243   my $bt = create_bank_transaction(record => $ar_transaction) or die "Couldn't create bank_transaction";
244
245   $::form->{invoice_ids} = {
246     $bt->id => [ $ar_transaction->id ]
247   };
248
249   save_btcontroller_to_string();
250
251   $ar_transaction->load;
252   $bt->load;
253   is($ar_transaction->paid   , '119.00000' , "$testname: salesinv1 was paid");
254   is($ar_transaction->closed , 1           , "$testname: salesinv1 is closed");
255   is($bt->invoice_amount     , '119.00000' , "$testname: bt invoice amount was assigned");
256
257 };
258
259 sub test_skonto_exact {
260
261   my $testname = 'test_skonto_exact';
262
263   $ar_transaction = test_ar_transaction(invnumber => 'salesinv skonto',
264                                         payment_id => $payment_terms->id,
265                                        );
266
267   my $bt = create_bank_transaction(record        => $ar_transaction,
268                                    bank_chart_id => $bank->id,
269                                    amount        => $ar_transaction->amount_less_skonto
270                                   ) or die "Couldn't create bank_transaction";
271
272   $::form->{invoice_ids} = {
273     $bt->id => [ $ar_transaction->id ]
274   };
275   $::form->{invoice_skontos} = {
276     $bt->id => [ 'with_skonto_pt' ]
277   };
278
279   save_btcontroller_to_string();
280
281   $ar_transaction->load;
282   $bt->load;
283   is($ar_transaction->paid   , '119.00000' , "$testname: salesinv skonto was paid");
284   is($ar_transaction->closed , 1           , "$testname: salesinv skonto is closed");
285   is($bt->invoice_amount     , '113.05000' , "$testname: bt invoice amount was assigned");
286
287 };
288
289 sub test_two_invoices {
290
291   my $testname = 'test_two_invoices';
292
293   my $ar_transaction_1 = test_ar_transaction(invnumber => 'salesinv_1');
294   my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv_2');
295
296   my $bt = create_bank_transaction(record        => $ar_transaction_1,
297                                    amount        => ($ar_transaction_1->amount + $ar_transaction_2->amount),
298                                    purpose       => "Rechnungen " . $ar_transaction_1->invnumber . " und " . $ar_transaction_2->invnumber,
299                                    bank_chart_id => $bank->id,
300                                   ) or die "Couldn't create bank_transaction";
301
302   my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($ar_transaction_1);
303   is($agreement, 16, "points for ar_transaction_1 in test_two_invoices ok");
304
305   $::form->{invoice_ids} = {
306     $bt->id => [ $ar_transaction_1->id, $ar_transaction_2->id ]
307   };
308
309   save_btcontroller_to_string();
310
311   $ar_transaction_1->load;
312   $ar_transaction_2->load;
313   $bt->load;
314
315   is($ar_transaction_1->paid   , '119.00000' , "$testname: salesinv_1 was paid");
316   is($ar_transaction_1->closed , 1           , "$testname: salesinv_1 is closed");
317   is($ar_transaction_2->paid   , '119.00000' , "$testname: salesinv_2 was paid");
318   is($ar_transaction_2->closed , 1           , "$testname: salesinv_2 is closed");
319   is($bt->invoice_amount       , '238.00000' , "$testname: bt invoice amount was assigned");
320
321 }
322
323 sub test_one_inv_and_two_invoices_with_skonto_exact {
324
325   my $testname = 'test_two_invoices_with_skonto_exact';
326
327   my $ar_transaction_1 = test_ar_transaction(invnumber => 'salesinv 1 skonto',
328                                              payment_id => $payment_terms->id,
329                                             );
330   my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv 2 skonto',
331                                              payment_id => $payment_terms->id,
332                                             );
333   my $ar_transaction_3 = test_ar_transaction(invnumber => 'salesinv 3 no skonto');
334
335
336
337   my $bt = create_bank_transaction(record        => $ar_transaction_1,
338                                    bank_chart_id => $bank->id,
339                                    amount        => $ar_transaction_1->amount_less_skonto * 2 + $ar_transaction_3->amount
340                                   ) or die "Couldn't create bank_transaction";
341
342   $::form->{invoice_ids} = {
343     $bt->id => [ $ar_transaction_1->id, $ar_transaction_3->id, $ar_transaction_2->id]
344   };
345   $::form->{invoice_skontos} = {
346     $bt->id => [ 'with_skonto_pt', 'without_skonto', 'with_skonto_pt' ]
347   };
348
349   save_btcontroller_to_string();
350
351   $ar_transaction_1->load;
352   $ar_transaction_2->load;
353   $ar_transaction_3->load;
354   my $skonto_1 = SL::DB::Manager::AccTransaction->find_by(trans_id => $ar_transaction_1->id, chart_id => 162);
355   my $skonto_2 = SL::DB::Manager::AccTransaction->find_by(trans_id => $ar_transaction_2->id, chart_id => 162);
356   $bt->load;
357   is($skonto_1->amount   , '-5.95000' , "$testname: salesinv 1 skonto was booked");
358   is($skonto_2->amount   , '-5.95000' , "$testname: salesinv 2 skonto was booked");
359   is($ar_transaction_1->paid   , '119.00000' , "$testname: salesinv 1 was paid");
360   is($ar_transaction_2->paid   , '119.00000' , "$testname: salesinv 2 was paid");
361   is($ar_transaction_3->paid   , '119.00000' , "$testname: salesinv 3 was paid");
362   is($ar_transaction_1->closed , 1           , "$testname: salesinv 1 skonto is closed");
363   is($ar_transaction_2->closed , 1           , "$testname: salesinv 2 skonto is closed");
364   is($ar_transaction_3->closed , 1           , "$testname: salesinv 2 skonto is closed");
365   is($bt->invoice_amount     , '345.10000' , "$testname: bt invoice amount was assigned");
366
367 }
368
369 sub test_overpayment {
370
371   my $testname = 'test_overpayment';
372
373   $ar_transaction = test_ar_transaction(invnumber => 'salesinv overpaid');
374
375   # amount 135 > 119
376   my $bt = create_bank_transaction(record        => $ar_transaction,
377                                    bank_chart_id => $bank->id,
378                                    amount        => 135
379                                   ) or die "Couldn't create bank_transaction";
380
381   $::form->{invoice_ids} = {
382     $bt->id => [ $ar_transaction->id ]
383   };
384
385   save_btcontroller_to_string();
386
387   $ar_transaction->load;
388   $bt->load;
389
390   is($ar_transaction->paid                     , '135.00000' , "$testname: 'salesinv overpaid' was overpaid");
391   is($bt->invoice_amount                       , '135.00000' , "$testname: bt invoice amount was assigned overpaid amount");
392 { local $TODO = 'this currently fails because closed ignores over-payments, see commit d90966c7';
393   is($ar_transaction->closed                   , 0           , "$testname: 'salesinv overpaid' is open (via 'closed' method')");
394 }
395   is($ar_transaction->open_amount == 0 ? 1 : 0 , 0           , "$testname: 'salesinv overpaid is open (via amount-paid)");
396
397 };
398
399 sub test_overpayment_with_partialpayment {
400
401   # two payments on different days, 10 and 119. If there is only one invoice we want it be overpaid.
402   my $testname = 'test_overpayment_with_partialpayment';
403
404   $ar_transaction = test_ar_transaction(invnumber => 'salesinv overpaid partial');
405
406   my $bt_1 = create_bank_transaction(record        => $ar_transaction,
407                                      bank_chart_id => $bank->id,
408                                      amount        =>  10
409                                     ) or die "Couldn't create bank_transaction";
410   my $bt_2 = create_bank_transaction(record        => $ar_transaction,
411                                      amount        => 119,
412                                      transdate     => DateTime->today->add(days => 5),
413                                      bank_chart_id => $bank->id,
414                                     ) or die "Couldn't create bank_transaction";
415
416   $::form->{invoice_ids} = {
417     $bt_1->id => [ $ar_transaction->id ]
418   };
419   save_btcontroller_to_string();
420
421   $::form->{invoice_ids} = {
422     $bt_2->id => [ $ar_transaction->id ]
423   };
424   save_btcontroller_to_string();
425
426   $ar_transaction->load;
427   $bt_1->load;
428   $bt_2->load;
429
430   is($ar_transaction->paid , '129.00000' , "$testname: 'salesinv overpaid partial' was overpaid");
431   is($bt_1->invoice_amount ,  '10.00000' , "$testname: bt_1 invoice amount was assigned overpaid amount");
432   is($bt_2->invoice_amount , '119.00000' , "$testname: bt_2 invoice amount was assigned overpaid amount");
433
434 };
435
436 sub test_partial_payment {
437
438   my $testname = 'test_partial_payment';
439
440   $ar_transaction = test_ar_transaction(invnumber => 'salesinv partial payment');
441
442   # amount 100 < 119
443   my $bt = create_bank_transaction(record        => $ar_transaction,
444                                    bank_chart_id => $bank->id,
445                                    amount        => 100
446                                   ) or die "Couldn't create bank_transaction";
447
448   $::form->{invoice_ids} = {
449     $bt->id => [ $ar_transaction->id ]
450   };
451
452   save_btcontroller_to_string();
453
454   $ar_transaction->load;
455   $bt->load;
456
457   is($ar_transaction->paid , '100.00000' , "$testname: 'salesinv partial payment' was partially paid");
458   is($bt->invoice_amount   , '100.00000' , "$testname: bt invoice amount was assigned partially paid amount");
459
460 };
461
462 sub test_credit_note {
463
464   my $testname = 'test_credit_note';
465
466   my $part1 = new_part(   partnumber => 'T4254')->save;
467   my $part2 = new_service(partnumber => 'Serv1')->save;
468   my $credit_note = create_credit_note(
469     invnumber    => 'cn 1',
470     customer     => $customer,
471     taxincluded  => 0,
472     invoiceitems => [ create_invoice_item(part => $part1, qty =>  3, sellprice => 70),
473                       create_invoice_item(part => $part2, qty => 10, sellprice => 50),
474                     ]
475   );
476   my $bt            = create_bank_transaction(record        => $credit_note,
477                                                                 amount        => $credit_note->amount,
478                                                                 bank_chart_id => $bank->id,
479                                                                 transdate     => DateTime->today->add(days => 10),
480                                                                );
481   my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($credit_note);
482   is($agreement, 13, "points for credit note ok");
483   is($rule_matches, 'remote_account_number(3) exact_amount(4) wrong_sign(-1) depositor_matches(2) remote_name(2) payment_within_30_days(1) datebonus14(2) ', "rules_matches for credit note ok");
484
485   $::form->{invoice_ids} = {
486     $bt->id => [ $credit_note->id ]
487   };
488
489   save_btcontroller_to_string();
490
491   $credit_note->load;
492   $bt->load;
493   is($credit_note->amount   , '-844.90000', "$testname: amount ok");
494   is($credit_note->netamount, '-710.00000', "$testname: netamount ok");
495   is($credit_note->paid     , '-844.90000', "$testname: paid ok");
496 }
497
498 sub test_neg_ap_transaction {
499   my (%params) = @_;
500   my $testname = 'test_neg_ap_transaction' . $params{invoice} ? ' invoice booking' : ' credit booking';
501   my $netamount = -20;
502   my $amount    = $::form->round_amount($netamount * 1.19,2);
503   my $invoice   = SL::DB::PurchaseInvoice->new(
504     invoice      => $params{invoice} // 0,
505     invnumber    => $params{invnumber} || 'test_neg_ap_transaction',
506     amount       => $amount,
507     netamount    => $netamount,
508     transdate    => $transdate1,
509     taxincluded  => 0,
510     vendor_id    => $vendor->id,
511     taxzone_id   => $vendor->taxzone_id,
512     currency_id  => $currency_id,
513     transactions => [],
514     notes        => 'test_neg_ap_transaction',
515   );
516   $invoice->add_ap_amount_row(
517     amount     => $invoice->netamount,
518     chart      => $ap_amount_chart,
519     tax_id     => $tax_9->id,
520   );
521
522   $invoice->create_ap_row(chart => $ap_chart);
523   $invoice->save;
524
525   is($invoice->netamount, -20  , "$testname: netamount ok");
526   is($invoice->amount   , -23.8, "$testname: amount ok");
527
528   my $bt            = create_bank_transaction(record        => $invoice,
529                                               amount        => $invoice->amount,
530                                               bank_chart_id => $bank->id,
531                                               transdate     => DateTime->today->add(days => 10),
532                                                                );
533   my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($invoice);
534   is($agreement, 15, "points for negative ap transaction ok");
535
536   $::form->{invoice_ids} = {
537     $bt->id => [ $invoice->id ]
538   };
539
540   save_btcontroller_to_string();
541
542   $invoice->load;
543   $bt->load;
544
545   is($invoice->amount   , '-23.80000', "$testname: amount ok");
546   is($invoice->netamount, '-20.00000', "$testname: netamount ok");
547   is($invoice->paid     , '-23.80000', "$testname: paid ok");
548   is($bt->invoice_amount, '23.80000', "$testname: bt invoice amount for ap was assigned");
549
550   return $invoice;
551 };
552 sub test_two_neg_ap_transaction {
553   my $testname='test_two_neg_ap_transaction';
554   my $netamount = -20;
555   my $amount    = $::form->round_amount($netamount * 1.19,2);
556   my $invoice   = SL::DB::PurchaseInvoice->new(
557     invoice      =>  0,
558     invnumber    => 'test_neg_ap_transaction',
559     amount       => $amount,
560     netamount    => $netamount,
561     transdate    => $transdate1,
562     taxincluded  => 0,
563     vendor_id    => $vendor->id,
564     taxzone_id   => $vendor->taxzone_id,
565     currency_id  => $currency_id,
566     transactions => [],
567     notes        => 'test_neg_ap_transaction',
568   );
569   $invoice->add_ap_amount_row(
570     amount     => $invoice->netamount,
571     chart      => $ap_amount_chart,
572     tax_id     => $tax_9->id,
573   );
574
575   $invoice->create_ap_row(chart => $ap_chart);
576   $invoice->save;
577
578   is($invoice->netamount, -20  , "$testname: netamount ok");
579   is($invoice->amount   , -23.8, "$testname: amount ok");
580
581   my $netamount_two = -1.14;
582   my $amount_two    = $::form->round_amount($netamount_two * 1.19,2);
583   my $invoice_two   = SL::DB::PurchaseInvoice->new(
584     invoice      => 0,
585     invnumber    => 'test_neg_ap_transaction_two',
586     amount       => $amount_two,
587     netamount    => $netamount_two,
588     transdate    => $transdate1,
589     taxincluded  => 0,
590     vendor_id    => $vendor->id,
591     taxzone_id   => $vendor->taxzone_id,
592     currency_id  => $currency_id,
593     transactions => [],
594     notes        => 'test_neg_ap_transaction_two',
595   );
596   $invoice_two->add_ap_amount_row(
597     amount     => $invoice_two->netamount,
598     chart      => $ap_amount_chart,
599     tax_id     => $tax_9->id,
600   );
601
602   $invoice_two->create_ap_row(chart => $ap_chart);
603   $invoice_two->save;
604
605   is($invoice_two->netamount, -1.14  , "$testname: netamount ok");
606   is($invoice_two->amount   , -1.36, "$testname: amount ok");
607
608
609   my $bt            = create_bank_transaction(record        => $invoice_two,
610                                               amount        => $invoice_two->amount + $invoice->amount,
611                                               bank_chart_id => $bank->id,
612                                               transdate     => DateTime->today->add(days => 10),
613                                                                );
614   # my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($invoice_two);
615   # is($agreement, 15, "points for negative ap transaction ok");
616
617   $::form->{invoice_ids} = {
618     $bt->id => [ $invoice->id, $invoice_two->id ]
619   };
620
621   save_btcontroller_to_string();
622
623   $invoice->load;
624   $invoice_two->load;
625   $bt->load;
626
627   is($invoice->amount   , '-23.80000', "$testname: first inv amount ok");
628   is($invoice->netamount, '-20.00000', "$testname: first inv netamount ok");
629   is($invoice->paid     , '-23.80000', "$testname: first inv paid ok");
630   is($invoice_two->amount   , '-1.36000', "$testname: second inv amount ok");
631   is($invoice_two->netamount, '-1.14000', "$testname: second inv netamount ok");
632   is($invoice_two->paid     , '-1.36000', "$testname: second inv paid ok");
633   is($bt->invoice_amount, '25.16000', "$testname: bt invoice amount for both invoices were assigned");
634
635
636   return ($invoice, $invoice_two);
637 };
638
639 sub test_ap_payment_transaction {
640   my (%params) = @_;
641   my $testname = 'test_ap_payment_transaction';
642   my $netamount = 115;
643   my $amount    = $::form->round_amount($netamount * 1.19,2);
644   my $invoice   = SL::DB::PurchaseInvoice->new(
645     invoice      => 0,
646     invnumber    => $params{invnumber} || $testname,
647     amount       => $amount,
648     netamount    => $netamount,
649     transdate    => $transdate1,
650     taxincluded  => 0,
651     vendor_id    => $vendor->id,
652     taxzone_id   => $vendor->taxzone_id,
653     currency_id  => $currency_id,
654     transactions => [],
655     notes        => $testname,
656   );
657   $invoice->add_ap_amount_row(
658     amount     => $invoice->netamount,
659     chart      => $ap_amount_chart,
660     tax_id     => $tax_9->id,
661   );
662
663   $invoice->create_ap_row(chart => $ap_chart);
664   $invoice->save;
665
666   is($invoice->netamount, 115  , "$testname: netamount ok");
667   is($invoice->amount   , 136.85, "$testname: amount ok");
668
669   my $bt            = create_bank_transaction(record        => $invoice,
670                                               amount        => $invoice->amount,
671                                               bank_chart_id => $bank->id,
672                                               transdate     => DateTime->today->add(days => 10),
673                                              );
674   $::form->{invoice_ids} = {
675     $bt->id => [ $invoice->id ]
676   };
677
678   save_btcontroller_to_string();
679
680   $invoice->load;
681   $bt->load;
682
683   is($invoice->amount   , '136.85000', "$testname: amount ok");
684   is($invoice->netamount, '115.00000', "$testname: netamount ok");
685   is($bt->amount, '-136.85000', "$testname: bt amount ok");
686   is($invoice->paid     , '136.85000', "$testname: paid ok");
687   is($bt->invoice_amount, '-136.85000', "$testname: bt invoice amount for ap was assigned");
688
689   return $invoice;
690 };
691
692 sub test_ap_payment_part_transaction {
693   my (%params) = @_;
694   my $testname = 'test_ap_payment_p_transaction';
695   my $netamount = 115;
696   my $amount    = $::form->round_amount($netamount * 1.19,2);
697   my $invoice   = SL::DB::PurchaseInvoice->new(
698     invoice      => 0,
699     invnumber    => $params{invnumber} || $testname,
700     amount       => $amount,
701     netamount    => $netamount,
702     transdate    => $transdate1,
703     taxincluded  => 0,
704     vendor_id    => $vendor->id,
705     taxzone_id   => $vendor->taxzone_id,
706     currency_id  => $currency_id,
707     transactions => [],
708     notes        => $testname,
709   );
710   $invoice->add_ap_amount_row(
711     amount     => $invoice->netamount,
712     chart      => $ap_amount_chart,
713     tax_id     => $tax_9->id,
714   );
715
716   $invoice->create_ap_row(chart => $ap_chart);
717   $invoice->save;
718
719   is($invoice->netamount, 115  , "$testname: netamount ok");
720   is($invoice->amount   , 136.85, "$testname: amount ok");
721
722   my $bt            = create_bank_transaction(record        => $invoice,
723                                               amount        => $invoice->amount-100,
724                                               bank_chart_id => $bank->id,
725                                               transdate     => DateTime->today->add(days => 10),
726                                              );
727   $::form->{invoice_ids} = {
728     $bt->id => [ $invoice->id ]
729   };
730
731   save_btcontroller_to_string();
732
733   $invoice->load;
734   $bt->load;
735
736   is($invoice->amount   , '136.85000', "$testname: amount ok");
737   is($invoice->netamount, '115.00000', "$testname: netamount ok");
738   is($bt->amount,         '-36.85000', "$testname: bt amount ok");
739   is($invoice->paid     ,  '36.85000', "$testname: paid ok");
740   is($bt->invoice_amount, '-36.85000', "$testname: bt invoice amount for ap was assigned");
741
742   my $bt2           = create_bank_transaction(record        => $invoice,
743                                               amount        => 100,
744                                               bank_chart_id => $bank->id,
745                                               transdate     => DateTime->today->add(days => 10),
746                                              );
747   $::form->{invoice_ids} = {
748     $bt2->id => [ $invoice->id ]
749   };
750
751   save_btcontroller_to_string();
752   $invoice->load;
753   $bt2->load;
754
755   is($invoice->amount   , '136.85000', "$testname: amount ok");
756   is($invoice->netamount, '115.00000', "$testname: netamount ok");
757   is($bt2->amount,        '-100.00000',"$testname: bt amount ok");
758   is($invoice->paid     , '136.85000', "$testname: paid ok");
759   is($bt2->invoice_amount,'-100.00000', "$testname: bt invoice amount for ap was assigned");
760
761   return $invoice;
762 };
763
764 sub test_neg_sales_invoice {
765
766   my $testname = 'test_neg_sales_invoice';
767
768   my $part1 = new_part(   partnumber => 'Funkenhaube öhm')->save;
769   my $part2 = new_service(partnumber => 'Service-Pauschale Pasch!')->save;
770
771   my $neg_sales_inv = create_sales_invoice(
772     invnumber    => '20172201',
773     customer     => $customer,
774     taxincluded  => 0,
775     invoiceitems => [ create_invoice_item(part => $part1, qty =>  3, sellprice => 70),
776                       create_invoice_item(part => $part2, qty => 10, sellprice => -50),
777                     ]
778   );
779   my $bt            = create_bank_transaction(record        => $neg_sales_inv,
780                                                                 amount        => $neg_sales_inv->amount,
781                                                                 bank_chart_id => $bank->id,
782                                                                 transdate     => DateTime->today,
783                                                                );
784   $::form->{invoice_ids} = {
785     $bt->id => [ $neg_sales_inv->id ]
786   };
787
788   save_btcontroller_to_string();
789
790   $neg_sales_inv->load;
791   $bt->load;
792   is($neg_sales_inv->amount   , '-345.10000', "$testname: amount ok");
793   is($neg_sales_inv->netamount, '-290.00000', "$testname: netamount ok");
794   is($neg_sales_inv->paid     , '-345.10000', "$testname: paid ok");
795   is($bt->amount              , '-345.10000', "$testname: bt amount ok");
796   is($bt->invoice_amount      , '-345.10000', "$testname: bt invoice_amount ok");
797 }
798
799 sub test_bt_rule1 {
800
801   my $testname = 'test_bt_rule1';
802
803   $ar_transaction = test_ar_transaction(invnumber => 'bt_rule1');
804
805   my $bt = create_bank_transaction(record => $ar_transaction) or die "Couldn't create bank_transaction";
806
807   $ar_transaction->load;
808   $bt->load;
809   is($ar_transaction->paid   , '0.00000' , "$testname: not paid");
810   is($bt->invoice_amount     , '0.00000' , "$testname: bt invoice amount was not assigned");
811
812   my $bt_controller = SL::Controller::BankTransaction->new;
813   $::form->{dont_render_for_test} = 1;
814   $::form->{filter}{bank_account} = $bank_account->id;
815   my $bt_transactions = $bt_controller->action_list;
816
817   is(scalar(@$bt_transactions)         , 1  , "$testname: one bank_transaction");
818   is($bt_transactions->[0]->{agreement}, 20 , "$testname: agreement == 20");
819   my $match = join ( ' ',@{$bt_transactions->[0]->{rule_matches}});
820   #print "rule_matches='".$match."'\n";
821   is($match,
822      "remote_account_number(3) exact_amount(4) own_invnumber_in_purpose(5) depositor_matches(2) remote_name(2) payment_within_30_days(1) datebonus0(3) ",
823      "$testname: rule_matches ok");
824   $bt->invoice_amount($bt->amount);
825   $bt->save;
826   is($bt->invoice_amount     , '119.00000' , "$testname: bt invoice amount now set");
827 };
828
829 sub test_sepa_export {
830
831   my $testname = 'test_sepa_export';
832
833   $ar_transaction = test_ar_transaction(invnumber => 'sepa1');
834
835   my $bt  = create_bank_transaction(record => $ar_transaction) or die "Couldn't create bank_transaction";
836   my $se  = create_sepa_export();
837   my $sei = create_sepa_export_item(
838     chart_id       => $bank->id,
839     ar_id          => $ar_transaction->id,
840     sepa_export_id => $se->id,
841     vc_iban        => $customer->iban,
842     vc_bic         => $customer->bic,
843     vc_mandator_id => $customer->mandator_id,
844     vc_depositor   => $customer->depositor,
845     amount         => $ar_transaction->amount,
846   );
847   require SL::SEPA::XML;
848   my $sepa_xml   = SL::SEPA::XML->new('company'     => $customer->name,
849                                       'creditor_id' => "id",
850                                       'src_charset' => 'UTF-8',
851                                       'message_id'  => "test",
852                                       'grouped'     => 1,
853                                       'collection'  => 1,
854                                      );
855   is($sepa_xml->{company}    , 'Test Customer OLE S.L. Ardbaerg AB');
856
857   $ar_transaction->load;
858   $bt->load;
859   $sei->load;
860   is($ar_transaction->paid   , '0.00000' , "$testname: sepa1 not paid");
861   is($bt->invoice_amount     , '0.00000' , "$testname: bt invoice amount was not assigned");
862   is($bt->amount             , '119.00000' , "$testname: bt amount ok");
863   is($sei->amount            , '119.00000' , "$testname: sepa export amount ok");
864
865   my $bt_controller = SL::Controller::BankTransaction->new;
866   $::form->{dont_render_for_test} = 1;
867   $::form->{filter}{bank_account} = $bank_account->id;
868   my $bt_transactions = $bt_controller->action_list;
869
870   is(scalar(@$bt_transactions)         , 1  , "$testname: one bank_transaction");
871   is($bt_transactions->[0]->{agreement}, 25 , "$testname: agreement == 25");
872   my $match = join ( ' ',@{$bt_transactions->[0]->{rule_matches}});
873   is($match,
874      "remote_account_number(3) exact_amount(4) own_invnumber_in_purpose(5) depositor_matches(2) remote_name(2) payment_within_30_days(1) datebonus0(3) sepa_export_item(5) ",
875      "$testname: rule_matches ok");
876 };
877
878
879 1;