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