067270b7b370f3ab726c0997ceb28bf4150acaf4
[kivitendo-erp.git] / t / bank / bank_transactions.t
1 use Test::More tests => 282;
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::BankTransactionAccTrans;
15 use SL::DB::Buchungsgruppe;
16 use SL::DB::Currency;
17 use SL::DB::Customer;
18 use SL::DB::Vendor;
19 use SL::DB::Invoice;
20 use SL::DB::Unit;
21 use SL::DB::Part;
22 use SL::DB::TaxZone;
23 use SL::DB::BankAccount;
24 use SL::DB::PaymentTerm;
25 use SL::DB::PurchaseInvoice;
26 use SL::DB::BankTransaction;
27 use SL::Controller::BankTransaction;
28 use SL::Controller::Reconciliation;
29 use SL::Dev::ALL qw(:ALL);
30 use Data::Dumper;
31
32 my ($customer, $vendor, $currency_id, $unit, $tax, $tax0, $tax7, $tax_9, $payment_terms, $bank_account);
33 my ($transdate1, $transdate2, $currency);
34 my ($ar_chart,$bank,$ar_amount_chart, $ap_chart, $ap_amount_chart);
35 my ($ar_transaction, $ap_transaction);
36
37 sub clear_up {
38
39   SL::DB::Manager::BankTransactionAccTrans->delete_all(all => 1);
40   SL::DB::Manager::BankTransaction->delete_all(all => 1);
41   SL::DB::Manager::InvoiceItem->delete_all(all => 1);
42   SL::DB::Manager::InvoiceItem->delete_all(all => 1);
43   SL::DB::Manager::Invoice->delete_all(all => 1);
44   SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
45   SL::DB::Manager::Part->delete_all(all => 1);
46   SL::DB::Manager::Customer->delete_all(all => 1);
47   SL::DB::Manager::Vendor->delete_all(all => 1);
48   SL::DB::Manager::SepaExportItem->delete_all(all => 1);
49   SL::DB::Manager::SepaExport->delete_all(all => 1);
50   SL::DB::Manager::BankAccount->delete_all(all => 1);
51   SL::DB::Manager::PaymentTerm->delete_all(all => 1);
52   SL::DB::Manager::Currency->delete_all(where => [ name => 'CUR' ]);
53 };
54
55 my $bt_controller;
56
57 sub save_btcontroller_to_string {
58   my $output;
59   open(my $outputFH, '>', \$output) or die;
60   my $oldFH = select $outputFH;
61
62   $bt_controller = SL::Controller::BankTransaction->new;
63   $bt_controller->action_save_invoices;
64
65   select $oldFH;
66   close $outputFH;
67   return $output;
68 }
69
70 # starting test:
71 Support::TestSetup::login();
72
73 clear_up();
74 reset_state(); # initialise customers/vendors/bank/currency/...
75
76 test1();
77
78 test_overpayment_with_partialpayment();
79 test_overpayment();
80 reset_state();
81 test_skonto_exact();
82 test_two_invoices();
83 test_partial_payment();
84 test_credit_note();
85 test_ap_transaction();
86 test_neg_ap_transaction(invoice => 0);
87 test_neg_ap_transaction(invoice => 1);
88 test_ap_payment_transaction();
89 test_ap_payment_part_transaction();
90 test_neg_sales_invoice();
91 test_two_neg_ap_transaction();
92 test_one_inv_and_two_invoices_with_skonto_exact();
93 test_bt_error();
94 test_full_workflow_ar_multiple_inv_skonto_reconciliate_and_undo();
95
96 reset_state();
97 test_sepa_export();
98
99 reset_state();
100 test_bt_rule1();
101 reset_state();
102 test_two_banktransactions();
103 # remove all created data at end of test
104 clear_up();
105
106 done_testing();
107
108 ###### functions for setting up data
109
110 sub reset_state {
111   my %params = @_;
112
113   $params{$_} ||= {} for qw(unit customer tax vendor);
114
115   clear_up();
116
117   $transdate1 = DateTime->today;
118   $transdate2 = DateTime->today->add(days => 5);
119
120   $tax             = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} }) || croak "No tax";
121   $tax7            = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07)                    || croak "No tax for 7\%";
122   $tax_9           = SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.19, %{ $params{tax} }) || croak "No tax for 19\%";
123   $tax0            = SL::DB::Manager::Tax->find_by(taxkey => 0, rate => 0.0)                     || croak "No tax for 0\%";
124
125   $currency_id     = $::instance_conf->get_currency_id;
126
127   $bank_account     =  SL::DB::BankAccount->new(
128     account_number  => '123',
129     bank_code       => '123',
130     iban            => '123',
131     bic             => '123',
132     bank            => '123',
133     chart_id        => SL::DB::Manager::Chart->find_by(description => 'Bank')->id,
134     name            => SL::DB::Manager::Chart->find_by(description => 'Bank')->description,
135   )->save;
136
137   $customer = new_customer(
138     name                      => 'Test Customer OLÉ S.L. Årdbärg AB',
139     iban                      => 'DE12500105170648489890',
140     bic                       => 'TESTBIC',
141     account_number            => '648489890',
142     mandate_date_of_signature => $transdate1,
143     mandator_id               => 'foobar',
144     bank                      => 'Geizkasse',
145     bank_code                 => 'G1235',
146     depositor                 => 'Test Customer',
147     customernumber            => 'CUST1704',
148   )->save;
149
150   $payment_terms = create_payment_terms();
151
152   $vendor = new_vendor(
153     name           => 'Test Vendor',
154     payment_id     => $payment_terms->id,
155     iban           => 'DE12500105170648489890',
156     bic            => 'TESTBIC',
157     account_number => '648489890',
158     bank           => 'Geizkasse',
159     bank_code      => 'G1235',
160     depositor      => 'Test Vendor',
161     vendornumber   => 'VEND1704',
162   )->save;
163
164   $ar_chart        = SL::DB::Manager::Chart->find_by( accno => '1400' ); # Forderungen
165   $ap_chart        = SL::DB::Manager::Chart->find_by( accno => '1600' ); # Verbindlichkeiten
166   $bank            = SL::DB::Manager::Chart->find_by( accno => '1200' ); # Bank
167   $ar_amount_chart = SL::DB::Manager::Chart->find_by( accno => '8400' ); # Erlöse
168   $ap_amount_chart = SL::DB::Manager::Chart->find_by( accno => '3400' ); # Wareneingang 19%
169
170 }
171
172 sub test_ar_transaction {
173   my (%params) = @_;
174   my $netamount = $params{amount} || 100;
175   my $amount    = $::form->round_amount($netamount * 1.19,2);
176   my $invoice   = SL::DB::Invoice->new(
177       invoice      => 0,
178       invnumber    => $params{invnumber} || undef, # let it use its own invnumber
179       amount       => $amount,
180       netamount    => $netamount,
181       transdate    => $transdate1,
182       taxincluded  => $params{taxincluded } || 0,
183       customer_id  => $customer->id,
184       taxzone_id   => $customer->taxzone_id,
185       currency_id  => $currency_id,
186       transactions => [],
187       payment_id   => $params{payment_id} || undef,
188       notes        => 'test_ar_transaction',
189   );
190   $invoice->add_ar_amount_row(
191     amount => $invoice->netamount,
192     chart  => $ar_amount_chart,
193     tax_id => $params{tax_id} || $tax->id,
194   );
195
196   $invoice->create_ar_row(chart => $ar_chart);
197   $invoice->save;
198
199   is($invoice->currency_id , $currency_id , 'currency_id has been saved');
200   is($invoice->netamount   , $netamount   , 'ar amount has been converted');
201   is($invoice->amount      , $amount      , 'ar amount has been converted');
202   is($invoice->taxincluded , 0            , 'ar transaction doesn\'t have taxincluded');
203
204   if ( $netamount == 100 ) {
205     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');
206     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');
207   }
208   return $invoice;
209 };
210
211 sub test_ap_transaction {
212   my (%params) = @_;
213   my $testname = 'test_ap_transaction';
214
215   my $netamount = 100;
216   my $amount    = $::form->round_amount($netamount * 1.19,2);
217   my $invoice   = SL::DB::PurchaseInvoice->new(
218     invoice      => 0,
219     invnumber    => $params{invnumber} || $testname,
220     amount       => $amount,
221     netamount    => $netamount,
222     transdate    => $transdate1,
223     taxincluded  => 0,
224     vendor_id    => $vendor->id,
225     taxzone_id   => $vendor->taxzone_id,
226     currency_id  => $currency_id,
227     transactions => [],
228     notes        => 'test_ap_transaction',
229   );
230   $invoice->add_ap_amount_row(
231     amount     => $invoice->netamount,
232     chart      => $ap_amount_chart,
233     tax_id     => $params{tax_id} || $tax_9->id,
234   );
235
236   $invoice->create_ap_row(chart => $ap_chart);
237   $invoice->save;
238
239   is($invoice->currency_id , $currency_id , "$testname: currency_id has been saved");
240   is($invoice->netamount   , 100          , "$testname: ap amount has been converted");
241   is($invoice->amount      , 119          , "$testname: ap amount has been converted");
242   is($invoice->taxincluded , 0            , "$testname: ap transaction doesn\'t have taxincluded");
243
244   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');
245   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');
246
247   return $invoice;
248 };
249
250 ###### test cases
251
252 sub test1 {
253
254   my $testname = 'test1';
255
256   $ar_transaction = test_ar_transaction(invnumber => 'salesinv1');
257
258   my $bt = create_bank_transaction(record => $ar_transaction) or die "Couldn't create bank_transaction";
259
260   $::form->{invoice_ids} = {
261     $bt->id => [ $ar_transaction->id ]
262   };
263
264   save_btcontroller_to_string();
265
266   $ar_transaction->load;
267   $bt->load;
268   is($ar_transaction->paid   , '119.00000' , "$testname: salesinv1 was paid");
269   is($ar_transaction->closed , 1           , "$testname: salesinv1 is closed");
270   is($bt->invoice_amount     , '119.00000' , "$testname: bt invoice amount was assigned");
271
272 };
273
274 sub test_skonto_exact {
275
276   my $testname = 'test_skonto_exact';
277
278   $ar_transaction = test_ar_transaction(invnumber => 'salesinv skonto',
279                                         payment_id => $payment_terms->id,
280                                        );
281
282   my $bt = create_bank_transaction(record        => $ar_transaction,
283                                    bank_chart_id => $bank->id,
284                                    amount        => $ar_transaction->amount_less_skonto
285                                   ) or die "Couldn't create bank_transaction";
286
287   $::form->{invoice_ids} = {
288     $bt->id => [ $ar_transaction->id ]
289   };
290   $::form->{invoice_skontos} = {
291     $bt->id => [ 'with_skonto_pt' ]
292   };
293
294   save_btcontroller_to_string();
295
296   $ar_transaction->load;
297   $bt->load;
298   is($ar_transaction->paid   , '119.00000' , "$testname: salesinv skonto was paid");
299   is($ar_transaction->closed , 1           , "$testname: salesinv skonto is closed");
300   is($bt->invoice_amount     , '113.05000' , "$testname: bt invoice amount was assigned");
301
302 };
303
304 sub test_bt_error {
305
306   my $testname = 'test_rollback_error';
307   # without type with_free_skonto the helper function (Payment.pm) looks ugly but not
308   # breakable
309
310   $ar_transaction = test_ar_transaction(invnumber   => 'salesinv skonto',
311                                         payment_id  => $payment_terms->id,
312                                         taxincluded => 0,
313                                         amount      => 168.58 / 1.19,
314                                        );
315
316   my $bt = create_bank_transaction(record        => $ar_transaction,
317                                    bank_chart_id => $bank->id,
318                                    amount        => 160.15,
319                                   ) or die "Couldn't create bank_transaction";
320   $::form->{invoice_ids} = {
321     $bt->id => [ $ar_transaction->id ]
322   };
323   $::form->{invoice_skontos} = {
324     $bt->id => [ 'with_skonto_pt' ]
325   };
326
327   is($ar_transaction->paid   , '0' , "$testname: salesinv is not paid");
328
329   # generate an error for testing rollback mechanism
330   my $saved_skonto_sales_chart_id = $tax->skonto_sales_chart_id;
331   $tax->skonto_sales_chart_id(undef);
332   $tax->save;
333
334   save_btcontroller_to_string();
335   my @bt_errors = @{ $bt_controller->problems };
336   is(substr($bt_errors[0]->{message},0,38), 'Kein Skontokonto für Steuerschlüssel 3', "$testname: Fehlermeldung ok");
337   # set original value
338   $tax->skonto_sales_chart_id($saved_skonto_sales_chart_id);
339   $tax->save;
340
341   $ar_transaction->load;
342   $bt->load;
343   is($ar_transaction->paid   , '0.00000' , "$testname: salesinv was not paid");
344   is($bt->invoice_amount     , '0.00000' , "$testname: bt invoice amount was not assigned");
345
346 };
347
348 sub test_two_invoices {
349
350   my $testname = 'test_two_invoices';
351
352   my $ar_transaction_1 = test_ar_transaction(invnumber => 'salesinv_1');
353   my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv_2');
354
355   my $bt = create_bank_transaction(record        => $ar_transaction_1,
356                                    amount        => ($ar_transaction_1->amount + $ar_transaction_2->amount),
357                                    purpose       => "Rechnungen " . $ar_transaction_1->invnumber . " und " . $ar_transaction_2->invnumber,
358                                    bank_chart_id => $bank->id,
359                                   ) or die "Couldn't create bank_transaction";
360
361   my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($ar_transaction_1);
362   is($agreement, 16, "points for ar_transaction_1 in test_two_invoices ok");
363
364   $::form->{invoice_ids} = {
365     $bt->id => [ $ar_transaction_1->id, $ar_transaction_2->id ]
366   };
367
368   save_btcontroller_to_string();
369
370   $ar_transaction_1->load;
371   $ar_transaction_2->load;
372   $bt->load;
373
374   is($ar_transaction_1->paid   , '119.00000' , "$testname: salesinv_1 wcsv_import_reportsas paid");
375   is($ar_transaction_1->closed , 1           , "$testname: salesinv_1 is closed");
376   is($ar_transaction_2->paid   , '119.00000' , "$testname: salesinv_2 was paid");
377   is($ar_transaction_2->closed , 1           , "$testname: salesinv_2 is closed");
378   is($bt->invoice_amount       , '238.00000' , "$testname: bt invoice amount was assigned");
379
380 }
381
382 sub test_one_inv_and_two_invoices_with_skonto_exact {
383
384   my $testname = 'test_two_invoices_with_skonto_exact';
385
386   my $ar_transaction_1 = test_ar_transaction(invnumber => 'salesinv 1 skonto',
387                                              payment_id => $payment_terms->id,
388                                             );
389   my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv 2 skonto',
390                                              payment_id => $payment_terms->id,
391                                             );
392   my $ar_transaction_3 = test_ar_transaction(invnumber => 'salesinv 3 no skonto');
393
394
395
396   my $bt = create_bank_transaction(record        => $ar_transaction_1,
397                                    bank_chart_id => $bank->id,
398                                    amount        => $ar_transaction_1->amount_less_skonto * 2 + $ar_transaction_3->amount
399                                   ) or die "Couldn't create bank_transaction";
400
401   $::form->{invoice_ids} = {
402     $bt->id => [ $ar_transaction_1->id, $ar_transaction_3->id, $ar_transaction_2->id]
403   };
404   $::form->{invoice_skontos} = {
405     $bt->id => [ 'with_skonto_pt', 'without_skonto', 'with_skonto_pt' ]
406   };
407
408   save_btcontroller_to_string();
409
410   $ar_transaction_1->load;
411   $ar_transaction_2->load;
412   $ar_transaction_3->load;
413   my $skonto_1 = SL::DB::Manager::AccTransaction->find_by(trans_id => $ar_transaction_1->id, chart_id => 162);
414   my $skonto_2 = SL::DB::Manager::AccTransaction->find_by(trans_id => $ar_transaction_2->id, chart_id => 162);
415   $bt->load;
416   is($skonto_1->amount   , '-5.95000' , "$testname: salesinv 1 skonto was booked");
417   is($skonto_2->amount   , '-5.95000' , "$testname: salesinv 2 skonto was booked");
418   is($ar_transaction_1->paid   , '119.00000' , "$testname: salesinv 1 was paid");
419   is($ar_transaction_2->paid   , '119.00000' , "$testname: salesinv 2 was paid");
420   is($ar_transaction_3->paid   , '119.00000' , "$testname: salesinv 3 was paid");
421   is($ar_transaction_1->closed , 1           , "$testname: salesinv 1 skonto is closed");
422   is($ar_transaction_2->closed , 1           , "$testname: salesinv 2 skonto is closed");
423   is($ar_transaction_3->closed , 1           , "$testname: salesinv 2 skonto is closed");
424   is($bt->invoice_amount     , '345.10000' , "$testname: bt invoice amount was assigned");
425
426 }
427
428 sub test_overpayment {
429
430   my $testname = 'test_overpayment';
431
432   $ar_transaction = test_ar_transaction(invnumber => 'salesinv overpaid');
433
434   # amount 135 > 119
435   my $bt = create_bank_transaction(record        => $ar_transaction,
436                                    bank_chart_id => $bank->id,
437                                    amount        => 135
438                                   ) or die "Couldn't create bank_transaction";
439
440   $::form->{invoice_ids} = {
441     $bt->id => [ $ar_transaction->id ]
442   };
443
444   save_btcontroller_to_string();
445
446   $ar_transaction->load;
447   $bt->load;
448
449   is($ar_transaction->paid                     , '119.00000' , "$testname: 'salesinv overpaid' was not overpaid");
450   is($bt->invoice_amount                       , '119.00000' , "$testname: bt invoice amount was not fully assigned with the overpaid amount");
451 { local $TODO = 'this currently fails because closed ignores over-payments, see commit d90966c7';
452   is($ar_transaction->closed                   , 0           , "$testname: 'salesinv overpaid' is open (via 'closed' method')");
453 }
454   is($ar_transaction->open_amount == 0 ? 1 : 0 , 1           , "$testname: 'salesinv overpaid is closed (via amount-paid)");
455
456 };
457
458 sub test_overpayment_with_partialpayment {
459
460   # two payments on different days, 10 and 119. If there is only one invoice we
461   # don't want it to be overpaid.
462   my $testname = 'test_overpayment_with_partialpayment';
463
464   $ar_transaction = test_ar_transaction(invnumber => 'salesinv overpaid partial');
465
466   my $bt_1 = create_bank_transaction(record        => $ar_transaction,
467                                      bank_chart_id => $bank->id,
468                                      amount        =>  10
469                                     ) or die "Couldn't create bank_transaction";
470   my $bt_2 = create_bank_transaction(record        => $ar_transaction,
471                                      amount        => 119,
472                                      transdate     => DateTime->today->add(days => 5),
473                                      bank_chart_id => $bank->id,
474                                     ) or die "Couldn't create bank_transaction";
475
476   $::form->{invoice_ids} = {
477     $bt_1->id => [ $ar_transaction->id ]
478   };
479   save_btcontroller_to_string();
480
481   $bt_1->load;
482   is($bt_1->invoice_amount ,  '10.00000' , "$testname: bt_1 invoice amount was fully assigned");
483   $::form->{invoice_ids} = {
484     $bt_2->id => [ $ar_transaction->id ]
485   };
486   save_btcontroller_to_string();
487
488   $ar_transaction->load;
489   $bt_2->load;
490
491   is($bt_1->invoice_amount ,  '10.00000' , "$testname: bt_1 invoice amount was fully assigned");
492   is($ar_transaction->paid , '119.00000' , "$testname: 'salesinv overpaid partial' was not overpaid");
493   is($bt_2->invoice_amount , '109.00000' , "$testname: bt_2 invoice amount was partly assigned");
494
495 };
496
497 sub test_partial_payment {
498
499   my $testname = 'test_partial_payment';
500
501   $ar_transaction = test_ar_transaction(invnumber => 'salesinv partial payment');
502
503   # amount 100 < 119
504   my $bt = create_bank_transaction(record        => $ar_transaction,
505                                    bank_chart_id => $bank->id,
506                                    amount        => 100
507                                   ) or die "Couldn't create bank_transaction";
508
509   $::form->{invoice_ids} = {
510     $bt->id => [ $ar_transaction->id ]
511   };
512
513   save_btcontroller_to_string();
514
515   $ar_transaction->load;
516   $bt->load;
517
518   is($ar_transaction->paid , '100.00000' , "$testname: 'salesinv partial payment' was partially paid");
519   is($bt->invoice_amount   , '100.00000' , "$testname: bt invoice amount was assigned partially paid amount");
520
521 };
522
523 sub test_full_workflow_ar_multiple_inv_skonto_reconciliate_and_undo {
524
525   my $testname = 'test_partial_payment';
526
527   $ar_transaction = test_ar_transaction(invnumber => 'salesinv partial payment two');
528   my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv 2 22d2', amount => 22);
529
530   # amount 299.29 > 119
531   my $bt = create_bank_transaction(record        => $ar_transaction,
532                                    bank_chart_id => $bank->id,
533                                    amount        => 299.29
534                                   ) or die "Couldn't create bank_transaction";
535
536   $::form->{invoice_ids} = {
537     $bt->id => [ $ar_transaction->id ]
538   };
539
540   save_btcontroller_to_string();
541
542   $ar_transaction->load;
543   $bt->load;
544
545   is($ar_transaction->paid , '119.00000' , "$testname: 'salesinv partial payment' was fully paid");
546   is($bt->invoice_amount   , '119.00000' , "$testname: bt invoice amount was assigned partially paid amount");
547   is($bt->amount           , '299.29000' , "$testname: bt amount is stil there");
548   # next invoice, same bank transaction
549   $::form->{invoice_ids} = {
550     $bt->id => [ $ar_transaction_2->id ]
551   };
552
553   save_btcontroller_to_string();
554
555   $ar_transaction_2->load;
556   $bt->load;
557   is($ar_transaction_2->paid , '26.18000' , "$testname: 'salesinv partial payment' was fully paid");
558   is($bt->invoice_amount   , '145.18000' , "$testname: bt invoice amount was assigned partially paid amount");
559   is($bt->amount           , '299.29000' , "$testname: bt amount is stil there");
560   is(scalar @{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )}, 4, "$testname 4 acc_trans entries created");
561
562   #  now check all 4 entries done so far and save paid acc_trans_ids for later use with reconcile
563   foreach my $acc_trans_id_entry (@{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )}) {
564     isnt($acc_trans_id_entry->ar_id, undef, "$testname: bt linked with acc_trans and trans_id set");
565     my $rl = SL::DB::Manager::RecordLink->get_all(where => [ from_id => $bt->id, from_table => 'bank_transactions', to_id => $acc_trans_id_entry->ar_id ]);
566     is (ref $rl->[0], 'SL::DB::RecordLink', "$testname record link created");
567     my $acc_trans = SL::DB::Manager::AccTransaction->get_all(where => [acc_trans_id => $acc_trans_id_entry->acc_trans_id]);
568     foreach my $entry (@{ $acc_trans }) {
569       like(abs($entry->amount), qr/(119|26.18)/, "$testname: abs amount correct");
570       like($entry->chart_link, qr/(paid|AR)/, "$testname chart_link correct");
571       push @{ $::form->{bb_ids} }, $entry->acc_trans_id if $entry->chart_link =~ m/paid/;
572     }
573   }
574   # great we need one last booking to clear the whole bank transaction - we include skonto
575   my $ar_transaction_skonto = test_ar_transaction(invnumber  => 'salesinv skonto last case',
576                                                   payment_id => $payment_terms->id,
577                                                   amount     => 136.32,
578                                                  );
579
580   $::form->{invoice_ids} = {
581     $bt->id => [ $ar_transaction_skonto->id ]
582   };
583   $::form->{invoice_skontos} = {
584     $bt->id => [ 'with_skonto_pt' ]
585   };
586
587   save_btcontroller_to_string();
588
589   $ar_transaction_skonto->load;
590   $bt->load;
591   is($ar_transaction_skonto->paid , '162.22000' , "$testname: 'salesinv skonto fully paid");
592   is($bt->invoice_amount   , '299.29000' , "$testname: bt invoice amount was assigned partially paid amount");
593   is($bt->amount           , '299.29000' , "$testname: bt amount is stil there");
594   is(scalar @{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )},
595        7, "$testname 7 acc_trans entries created");
596
597   # same loop as above, but only for the 3rd ar_id
598   foreach my $acc_trans_id_entry (@{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [ar_id => $ar_transaction_skonto->id ] )}) {
599     isnt($acc_trans_id_entry->ar_id, '', "$testname: bt linked with acc_trans and trans_id set");
600     my $rl = SL::DB::Manager::RecordLink->get_all(where => [ from_id => $bt->id, from_table => 'bank_transactions', to_id => $acc_trans_id_entry->ar_id ]);
601     is (ref $rl->[0], 'SL::DB::RecordLink', "$testname record link created");
602     my $acc_trans = SL::DB::Manager::AccTransaction->get_all(where => [acc_trans_id => $acc_trans_id_entry->acc_trans_id]);
603     foreach my $entry (@{ $acc_trans }) {
604       like($entry->chart_link, qr/(paid|AR)/, "$testname chart_link correct");
605       is ($entry->amount, '162.22000', "$testname full amont") if $entry->chart_link eq 'AR'; # full amount
606       like(abs($entry->amount), qr/(154.11|8.11)/, "$testname: abs amount correct") if $entry->chart_link =~ m/paid/;
607       push @{ $::form->{bb_ids} }, $entry->acc_trans_id if ($entry->chart_link =~ m/paid/ && $entry->amount == -154.11);
608     }
609   }
610   # done, now reconciliate all bookings
611   $::form->{bt_ids} = [ $bt->id ];
612   my $rec_controller = SL::Controller::Reconciliation->new;
613   my @errors = $rec_controller->_get_elements_and_validate;
614
615   is (scalar @errors, 0, "$testname unsuccesfull reconciliation with error: " . Dumper(@errors));
616   $rec_controller->_reconcile;
617   $bt->load;
618
619   # and check the cleared state of bt and the acc_transactions
620   is($bt->cleared, '1' , "$testname: bt cleared");
621   foreach (@{ $::form->{bb_ids} }) {
622     my $acc_trans = SL::DB::Manager::AccTransaction->find_by(acc_trans_id => $_);
623     is($acc_trans->cleared, '1' , "$testname: acc_trans entry cleared");
624   }
625   # now, this was a really bad idea and in general a major mistake. better undo and redo the whole bank transactions
626
627   $::form->{ids} = [ $bt->id ];
628   $bt_controller = SL::Controller::BankTransaction->new;
629   $bt_controller->action_unlink_bank_transaction('testcase' => 1);
630
631   $bt->load;
632
633   # and check the cleared state of bt and the acc_transactions
634   is($bt->cleared, '0' , "$testname: bt undo cleared");
635   is($bt->invoice_amount, '0.00000' , "$testname: bt undo invoice amount");
636   foreach (@{ $::form->{bb_ids} }) {
637     my $acc_trans = SL::DB::Manager::AccTransaction->find_by(acc_trans_id => $_);
638     is($acc_trans, undef , "$testname: cleared acc_trans entry completely removed");
639   }
640   # this was for data integrity for reconcile, now all the other options
641   is(scalar @{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )},
642        0, "$testname 7 acc_trans entries deleted");
643   my $rl = SL::DB::Manager::RecordLink->get_all(where => [ from_id => $bt->id, from_table => 'bank_transactions' ]);
644   is (ref $rl->[0], '', "$testname record link removed");
645   # double safety and check ar.paid
646   # load all three invoices and check for paid-link via acc_trans and paid in general
647
648   $ar_transaction->load;
649   $ar_transaction_2->load;
650   $ar_transaction_skonto->load;
651
652   is(scalar @{ SL::DB::Manager::AccTransaction->get_all(
653      where => [ trans_id => $ar_transaction->id, chart_link => { like => '%paid%' } ])},
654      0, "$testname no more paid entries in acc_trans for ar_transaction");
655   is(scalar @{ SL::DB::Manager::AccTransaction->get_all(
656      where => [ trans_id => $ar_transaction_2->id, chart_link => { like => '%paid%' } ])},
657      0, "$testname no more paid entries in acc_trans for ar_transaction_2");
658   is(scalar @{ SL::DB::Manager::AccTransaction->get_all(
659      where => [ trans_id => $ar_transaction_skonto->id, chart_link => { like => '%paid%' } ])},
660      0, "$testname no more paid entries in acc_trans for ar_transaction_skonto");
661
662   is($ar_transaction->paid , '0.00000' , "$testname: 'salesinv fully unpaid");
663   is($ar_transaction_2->paid , '0.00000' , "$testname: 'salesinv 2 fully unpaid");
664   is($ar_transaction_skonto->paid , '0.00000' , "$testname: 'salesinv skonto fully unpaid");
665
666   # whew. w(h)a(n)t a whole lotta test
667 }
668
669
670 sub test_credit_note {
671
672   my $testname = 'test_credit_note';
673
674   my $part1 = new_part(   partnumber => 'T4254')->save;
675   my $part2 = new_service(partnumber => 'Serv1')->save;
676   my $credit_note = create_credit_note(
677     invnumber    => 'cn 1',
678     customer     => $customer,
679     taxincluded  => 0,
680     invoiceitems => [ create_invoice_item(part => $part1, qty =>  3, sellprice => 70),
681                       create_invoice_item(part => $part2, qty => 10, sellprice => 50),
682                     ]
683   );
684   my $bt            = create_bank_transaction(record        => $credit_note,
685                                                                 amount        => $credit_note->amount,
686                                                                 bank_chart_id => $bank->id,
687                                                                 transdate     => DateTime->today->add(days => 10),
688                                                                );
689   my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($credit_note);
690   is($agreement, 13, "points for credit note ok");
691   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");
692
693   $::form->{invoice_ids} = {
694     $bt->id => [ $credit_note->id ]
695   };
696
697   save_btcontroller_to_string();
698
699   $credit_note->load;
700   $bt->load;
701   is($credit_note->amount   , '-844.90000', "$testname: amount ok");
702   is($credit_note->netamount, '-710.00000', "$testname: netamount ok");
703   is($credit_note->paid     , '-844.90000', "$testname: paid ok");
704 }
705
706 sub test_neg_ap_transaction {
707   my (%params) = @_;
708   my $testname = 'test_neg_ap_transaction' . $params{invoice} ? ' invoice booking' : ' credit booking';
709   my $netamount = -20;
710   my $amount    = $::form->round_amount($netamount * 1.19,2);
711   my $invoice   = SL::DB::PurchaseInvoice->new(
712     invoice      => $params{invoice} // 0,
713     invnumber    => $params{invnumber} || 'test_neg_ap_transaction',
714     amount       => $amount,
715     netamount    => $netamount,
716     transdate    => $transdate1,
717     taxincluded  => 0,
718     vendor_id    => $vendor->id,
719     taxzone_id   => $vendor->taxzone_id,
720     currency_id  => $currency_id,
721     transactions => [],
722     notes        => 'test_neg_ap_transaction',
723   );
724   $invoice->add_ap_amount_row(
725     amount     => $invoice->netamount,
726     chart      => $ap_amount_chart,
727     tax_id     => $tax_9->id,
728   );
729
730   $invoice->create_ap_row(chart => $ap_chart);
731   $invoice->save;
732
733   is($invoice->netamount, -20  , "$testname: netamount ok");
734   is($invoice->amount   , -23.8, "$testname: amount ok");
735
736   my $bt            = create_bank_transaction(record        => $invoice,
737                                               amount        => $invoice->amount,
738                                               bank_chart_id => $bank->id,
739                                               transdate     => DateTime->today->add(days => 10),
740                                                                );
741
742   my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($invoice);
743   is($agreement, 15, "points for negative ap transaction ok");
744
745   $::form->{invoice_ids} = {
746     $bt->id => [ $invoice->id ]
747   };
748
749   save_btcontroller_to_string();
750
751   $invoice->load;
752   $bt->load;
753
754   is($invoice->amount   , '-23.80000', "$testname: amount ok");
755   is($invoice->netamount, '-20.00000', "$testname: netamount ok");
756   is($invoice->paid     , '-23.80000', "$testname: paid ok");
757   is($bt->invoice_amount, '23.80000', "$testname: bt invoice amount for ap was assigned");
758   is($bt->amount,         '23.80000', "$testname: bt  amount for ap was assigned");
759
760   return $invoice;
761 };
762 sub test_two_neg_ap_transaction {
763   my $testname='test_two_neg_ap_transaction';
764   my $netamount = -20;
765   my $amount    = $::form->round_amount($netamount * 1.19,2);
766   my $invoice   = SL::DB::PurchaseInvoice->new(
767     invoice      =>  0,
768     invnumber    => 'test_neg_ap_transaction',
769     amount       => $amount,
770     netamount    => $netamount,
771     transdate    => $transdate1,
772     taxincluded  => 0,
773     vendor_id    => $vendor->id,
774     taxzone_id   => $vendor->taxzone_id,
775     currency_id  => $currency_id,
776     transactions => [],
777     notes        => 'test_neg_ap_transaction',
778   );
779   $invoice->add_ap_amount_row(
780     amount     => $invoice->netamount,
781     chart      => $ap_amount_chart,
782     tax_id     => $tax_9->id,
783   );
784
785   $invoice->create_ap_row(chart => $ap_chart);
786   $invoice->save;
787
788   is($invoice->netamount, -20  , "$testname: netamount ok");
789   is($invoice->amount   , -23.8, "$testname: amount ok");
790
791   my $netamount_two = -1.14;
792   my $amount_two    = $::form->round_amount($netamount_two * 1.19,2);
793   my $invoice_two   = SL::DB::PurchaseInvoice->new(
794     invoice      => 0,
795     invnumber    => 'test_neg_ap_transaction_two',
796     amount       => $amount_two,
797     netamount    => $netamount_two,
798     transdate    => $transdate1,
799     taxincluded  => 0,
800     vendor_id    => $vendor->id,
801     taxzone_id   => $vendor->taxzone_id,
802     currency_id  => $currency_id,
803     transactions => [],
804     notes        => 'test_neg_ap_transaction_two',
805   );
806   $invoice_two->add_ap_amount_row(
807     amount     => $invoice_two->netamount,
808     chart      => $ap_amount_chart,
809     tax_id     => $tax_9->id,
810   );
811
812   $invoice_two->create_ap_row(chart => $ap_chart);
813   $invoice_two->save;
814
815   is($invoice_two->netamount, -1.14  , "$testname: netamount ok");
816   is($invoice_two->amount   , -1.36, "$testname: amount ok");
817
818
819   my $bt            = create_bank_transaction(record        => $invoice_two,
820                                               amount        => $invoice_two->amount + $invoice->amount,
821                                               bank_chart_id => $bank->id,
822                                               transdate     => DateTime->today->add(days => 10),
823                                                                );
824   # my ($agreement, $rule_matches) = $bt->get_agreement_with_invoice($invoice_two);
825   # is($agreement, 15, "points for negative ap transaction ok");
826
827   $::form->{invoice_ids} = {
828     $bt->id => [ $invoice->id, $invoice_two->id ]
829   };
830
831   save_btcontroller_to_string();
832
833   $invoice->load;
834   $invoice_two->load;
835   $bt->load;
836
837   is($invoice->amount   , '-23.80000', "$testname: first inv amount ok");
838   is($invoice->netamount, '-20.00000', "$testname: first inv netamount ok");
839   is($invoice->paid     , '-23.80000', "$testname: first inv paid ok");
840   is($invoice_two->amount   , '-1.36000', "$testname: second inv amount ok");
841   is($invoice_two->netamount, '-1.14000', "$testname: second inv netamount ok");
842   is($invoice_two->paid     , '-1.36000', "$testname: second inv paid ok");
843   is($bt->invoice_amount, '25.16000', "$testname: bt invoice amount for both invoices were assigned");
844
845
846   return ($invoice, $invoice_two);
847 };
848
849 sub test_ap_payment_transaction {
850   my (%params) = @_;
851   my $testname = 'test_ap_payment_transaction';
852   my $netamount = 115;
853   my $amount    = $::form->round_amount($netamount * 1.19,2);
854   my $invoice   = SL::DB::PurchaseInvoice->new(
855     invoice      => 0,
856     invnumber    => $params{invnumber} || $testname,
857     amount       => $amount,
858     netamount    => $netamount,
859     transdate    => $transdate1,
860     taxincluded  => 0,
861     vendor_id    => $vendor->id,
862     taxzone_id   => $vendor->taxzone_id,
863     currency_id  => $currency_id,
864     transactions => [],
865     notes        => $testname,
866   );
867   $invoice->add_ap_amount_row(
868     amount     => $invoice->netamount,
869     chart      => $ap_amount_chart,
870     tax_id     => $tax_9->id,
871   );
872
873   $invoice->create_ap_row(chart => $ap_chart);
874   $invoice->save;
875
876   is($invoice->netamount, 115  , "$testname: netamount ok");
877   is($invoice->amount   , 136.85, "$testname: amount ok");
878
879   my $bt            = create_bank_transaction(record        => $invoice,
880                                               amount        => $invoice->amount,
881                                               bank_chart_id => $bank->id,
882                                               transdate     => DateTime->today->add(days => 10),
883                                              );
884   $::form->{invoice_ids} = {
885     $bt->id => [ $invoice->id ]
886   };
887
888   save_btcontroller_to_string();
889
890   $invoice->load;
891   $bt->load;
892
893   is($invoice->amount   , '136.85000', "$testname: amount ok");
894   is($invoice->netamount, '115.00000', "$testname: netamount ok");
895   is($bt->amount,         '-136.85000', "$testname: bt amount ok");
896   is($invoice->paid     , '136.85000', "$testname: paid ok");
897   is($bt->invoice_amount, '-136.85000', "$testname: bt invoice amount for ap was assigned");
898
899   return $invoice;
900 };
901
902 sub test_ap_payment_part_transaction {
903   my (%params) = @_;
904   my $testname = 'test_ap_payment_p_transaction';
905   my $netamount = 115;
906   my $amount    = $::form->round_amount($netamount * 1.19,2);
907   my $invoice   = SL::DB::PurchaseInvoice->new(
908     invoice      => 0,
909     invnumber    => $params{invnumber} || $testname,
910     amount       => $amount,
911     netamount    => $netamount,
912     transdate    => $transdate1,
913     taxincluded  => 0,
914     vendor_id    => $vendor->id,
915     taxzone_id   => $vendor->taxzone_id,
916     currency_id  => $currency_id,
917     transactions => [],
918     notes        => $testname,
919   );
920   $invoice->add_ap_amount_row(
921     amount     => $invoice->netamount,
922     chart      => $ap_amount_chart,
923     tax_id     => $tax_9->id,
924   );
925
926   $invoice->create_ap_row(chart => $ap_chart);
927   $invoice->save;
928
929   is($invoice->netamount, 115  , "$testname: netamount ok");
930   is($invoice->amount   , 136.85, "$testname: amount ok");
931
932   my $bt            = create_bank_transaction(record        => $invoice,
933                                               amount        => $invoice->amount-100,
934                                               bank_chart_id => $bank->id,
935                                               transdate     => DateTime->today->add(days => 10),
936                                              );
937   $::form->{invoice_ids} = {
938     $bt->id => [ $invoice->id ]
939   };
940
941   save_btcontroller_to_string();
942
943   $invoice->load;
944   $bt->load;
945
946   is($invoice->amount   , '136.85000', "$testname: amount ok");
947   is($invoice->netamount, '115.00000', "$testname: netamount ok");
948   is($bt->amount,         '-36.85000', "$testname: bt amount ok");
949   is($invoice->paid     ,  '36.85000', "$testname: paid ok");
950   is($bt->invoice_amount, '-36.85000', "$testname: bt invoice amount for ap was assigned");
951
952   my $bt2           = create_bank_transaction(record        => $invoice,
953                                               amount        => 100,
954                                               bank_chart_id => $bank->id,
955                                               transdate     => DateTime->today->add(days => 10),
956                                              );
957   $::form->{invoice_ids} = {
958     $bt2->id => [ $invoice->id ]
959   };
960
961   save_btcontroller_to_string();
962   $invoice->load;
963   $bt2->load;
964
965   is($invoice->amount   , '136.85000', "$testname: amount ok");
966   is($invoice->netamount, '115.00000', "$testname: netamount ok");
967   is($bt2->amount,        '-100.00000',"$testname: bt amount ok");
968   is($invoice->paid     , '136.85000', "$testname: paid ok");
969   is($bt2->invoice_amount,'-100.00000', "$testname: bt invoice amount for ap was assigned");
970
971   return $invoice;
972 };
973
974 sub test_neg_sales_invoice {
975
976   my $testname = 'test_neg_sales_invoice';
977
978   my $part1 = new_part(   partnumber => 'Funkenhaube öhm')->save;
979   my $part2 = new_service(partnumber => 'Service-Pauschale Pasch!')->save;
980
981   my $neg_sales_inv = create_sales_invoice(
982     invnumber    => '20172201',
983     customer     => $customer,
984     taxincluded  => 0,
985     invoiceitems => [ create_invoice_item(part => $part1, qty =>  3, sellprice => 70),
986                       create_invoice_item(part => $part2, qty => 10, sellprice => -50),
987                     ]
988   );
989   my $bt            = create_bank_transaction(record        => $neg_sales_inv,
990                                                                 amount        => $neg_sales_inv->amount,
991                                                                 bank_chart_id => $bank->id,
992                                                                 transdate     => DateTime->today,
993                                                                );
994   $::form->{invoice_ids} = {
995     $bt->id => [ $neg_sales_inv->id ]
996   };
997
998   save_btcontroller_to_string();
999
1000   $neg_sales_inv->load;
1001   $bt->load;
1002   is($neg_sales_inv->amount   , '-345.10000', "$testname: amount ok");
1003   is($neg_sales_inv->netamount, '-290.00000', "$testname: netamount ok");
1004   is($neg_sales_inv->paid     , '-345.10000', "$testname: paid ok");
1005   is($bt->amount              , '-345.10000', "$testname: bt amount ok");
1006   is($bt->invoice_amount      , '-345.10000', "$testname: bt invoice_amount ok");
1007 }
1008
1009 sub test_bt_rule1 {
1010
1011   my $testname = 'test_bt_rule1';
1012
1013   $ar_transaction = test_ar_transaction(invnumber => 'bt_rule1');
1014
1015   my $bt = create_bank_transaction(record => $ar_transaction) or die "Couldn't create bank_transaction";
1016
1017   $ar_transaction->load;
1018   $bt->load;
1019   is($ar_transaction->paid   , '0.00000' , "$testname: not paid");
1020   is($bt->invoice_amount     , '0.00000' , "$testname: bt invoice amount was not assigned");
1021
1022   my $bt_controller = SL::Controller::BankTransaction->new;
1023   $::form->{dont_render_for_test} = 1;
1024   $::form->{filter}{bank_account} = $bank_account->id;
1025   my ( $bt_transactions, $proposals ) = $bt_controller->action_list;
1026
1027   is(scalar(@$bt_transactions)         , 1  , "$testname: one bank_transaction");
1028   is($bt_transactions->[0]->{agreement}, 20 , "$testname: agreement == 20");
1029   my $match = join ( ' ',@{$bt_transactions->[0]->{rule_matches}});
1030   #print "rule_matches='".$match."'\n";
1031   is($match,
1032      "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) ",
1033      "$testname: rule_matches ok");
1034   $bt->invoice_amount($bt->amount);
1035   $bt->save;
1036   is($bt->invoice_amount     , '119.00000' , "$testname: bt invoice amount now set");
1037 };
1038
1039 sub test_sepa_export {
1040
1041   my $testname = 'test_sepa_export';
1042
1043   $ar_transaction = test_ar_transaction(invnumber => 'sepa1');
1044
1045   my $bt  = create_bank_transaction(record => $ar_transaction) or die "Couldn't create bank_transaction";
1046   my $se  = create_sepa_export();
1047   my $sei = create_sepa_export_item(
1048     chart_id       => $bank->id,
1049     ar_id          => $ar_transaction->id,
1050     sepa_export_id => $se->id,
1051     vc_iban        => $customer->iban,
1052     vc_bic         => $customer->bic,
1053     vc_mandator_id => $customer->mandator_id,
1054     vc_depositor   => $customer->depositor,
1055     amount         => $ar_transaction->amount,
1056   );
1057   require SL::SEPA::XML;
1058   my $sepa_xml   = SL::SEPA::XML->new('company'     => $customer->name,
1059                                       'creditor_id' => "id",
1060                                       'src_charset' => 'UTF-8',
1061                                       'message_id'  => "test",
1062                                       'grouped'     => 1,
1063                                       'collection'  => 1,
1064                                      );
1065   is($sepa_xml->{company}    , 'Test Customer OLE S.L. Ardbaerg AB');
1066
1067   $ar_transaction->load;
1068   $bt->load;
1069   $sei->load;
1070   is($ar_transaction->paid   , '0.00000' , "$testname: sepa1 not paid");
1071   is($bt->invoice_amount     , '0.00000' , "$testname: bt invoice amount was not assigned");
1072   is($bt->amount             , '119.00000' , "$testname: bt amount ok");
1073   is($sei->amount            , '119.00000' , "$testname: sepa export amount ok");
1074
1075   my $bt_controller = SL::Controller::BankTransaction->new;
1076   $::form->{dont_render_for_test} = 1;
1077   $::form->{filter}{bank_account} = $bank_account->id;
1078   my ( $bt_transactions, $proposals ) = $bt_controller->action_list;
1079
1080   is(scalar(@$bt_transactions)         , 1  , "$testname: one bank_transaction");
1081   is($bt_transactions->[0]->{agreement}, 25 , "$testname: agreement == 25");
1082   my $match = join ( ' ',@{$bt_transactions->[0]->{rule_matches}});
1083   is($match,
1084      "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) ",
1085      "$testname: rule_matches ok");
1086 };
1087
1088 sub test_two_banktransactions {
1089
1090   my $testname = 'two_banktransactions';
1091
1092   my $ar_transaction_1 = test_ar_transaction(invnumber => 'salesinv10000' , amount => 2912.00 );
1093   my $bt1 = create_bank_transaction(record        => $ar_transaction_1,
1094                                     amount        => $ar_transaction_1->amount,
1095                                     purpose       => "Rechnung10000 beinahe",
1096                                     bank_chart_id => $bank->id,
1097                                   ) or die "Couldn't create bank_transaction";
1098
1099   my $bt2 = create_bank_transaction(record        => $ar_transaction_1,
1100                                     amount        => $ar_transaction_1->amount + 0.01,
1101                                     purpose       => "sicher salesinv20000 vielleicht",
1102                                     bank_chart_id => $bank->id,
1103                                   ) or die "Couldn't create bank_transaction";
1104
1105   my ($agreement1, $rule_matches1) = $bt1->get_agreement_with_invoice($ar_transaction_1);
1106   is($agreement1, 19, "bt1 19 points for ar_transaction_1 in $testname ok");
1107   #print "rule_matches1=".$rule_matches1."\n";
1108   is($rule_matches1,
1109      "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) ",
1110      "$testname: rule_matches ok");
1111   my ($agreement2, $rule_matches2) = $bt2->get_agreement_with_invoice($ar_transaction_1);
1112   is($agreement2, 11, "bt2 11 points for ar_transaction_1 in $testname ok");
1113   is($rule_matches2,
1114      "remote_account_number(3) depositor_matches(2) remote_name(2) payment_within_30_days(1) datebonus0(3) ",
1115      "$testname: rule_matches ok");
1116
1117   my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv20000' , amount => 2912.01 );
1118   my $ar_transaction_3 = test_ar_transaction(invnumber => 'zweitemit10000', amount => 2912.00 );
1119      ($agreement1, $rule_matches1) = $bt1->get_agreement_with_invoice($ar_transaction_2);
1120
1121   is($agreement1, 11, "bt1 11 points for ar_transaction_2 in $testname ok");
1122
1123      ($agreement2, $rule_matches2) = $bt2->get_agreement_with_invoice($ar_transaction_2);
1124   is($agreement2, 20, "bt2 20 points for ar_transaction_2 in $testname ok");
1125
1126      ($agreement2, $rule_matches2) = $bt2->get_agreement_with_invoice($ar_transaction_1);
1127   is($agreement2, 11, "bt2 11 points for ar_transaction_1 in $testname ok");
1128
1129   my $bt3 = create_bank_transaction(record        => $ar_transaction_3,
1130                                     amount        => $ar_transaction_3->amount,
1131                                     purpose       => "sicher Rechnung10000 vielleicht",
1132                                     bank_chart_id => $bank->id,
1133                                   ) or die "Couldn't create bank_transaction";
1134
1135   my ($agreement3, $rule_matches3) = $bt3->get_agreement_with_invoice($ar_transaction_3);
1136   is($agreement3, 19, "bt3 19 points for ar_transaction_3 in $testname ok");
1137
1138   $bt2->delete;
1139   $ar_transaction_2->delete;
1140
1141   #nun sollten zwei gleichwertige Rechnungen $ar_transaction_1 und $ar_transaction_3 für $bt1 gefunden werden
1142   #aber es darf keine Proposals geben mit mehreren Rechnungen
1143   my $bt_controller = SL::Controller::BankTransaction->new;
1144   $::form->{dont_render_for_test} = 1;
1145   $::form->{filter}{bank_account} = $bank_account->id;
1146   my ( $bt_transactions, $proposals ) = $bt_controller->action_list;
1147
1148   is(scalar(@$bt_transactions)   , 2  , "$testname: two bank_transaction");
1149   is(scalar(@$proposals)         , 0  , "$testname: no proposals");
1150
1151   $ar_transaction_3->delete;
1152
1153   # Jetzt gibt es zwei Kontobewegungen mit gleichen Punkten für eine Rechnung.
1154   # hier darf es auch keine Proposals geben
1155
1156   ( $bt_transactions, $proposals ) = $bt_controller->action_list;
1157
1158   is(scalar(@$bt_transactions)   , 2  , "$testname: two bank_transaction");
1159   # odyn testfall - anforderungen so (noch) nicht in kivi
1160   # is(scalar(@$proposals)         , 0  , "$testname: no proposals");
1161
1162   # Jetzt gibt es zwei Kontobewegungen für eine Rechnung.
1163   # eine Bewegung bekommt mehr Punkte
1164   # hier darf es auch keine Proposals geben
1165   $bt3->update_attributes( purpose => "fuer Rechnung salesinv10000");
1166
1167   ( $bt_transactions, $proposals ) = $bt_controller->action_list;
1168
1169   is(scalar(@$bt_transactions)   , 2  , "$testname: two bank_transaction");
1170   # odyn testfall - anforderungen so (noch) nicht in kivi
1171   # is(scalar(@$proposals)         , 1  , "$testname: one proposal");
1172
1173 };
1174
1175
1176 1;