Debitorenbuchungen als CSV importieren
[kivitendo-erp.git] / t / controllers / csvimport / artransactions.t
1 use Test::More tests => 70;
2
3 use strict;
4
5 use lib 't';
6
7 use Carp;
8 use Data::Dumper;
9 use Support::TestSetup;
10 use Test::Exception;
11
12 use List::MoreUtils qw(pairwise);
13 use SL::Controller::CsvImport;
14
15 my $DEBUG = 0;
16
17 use_ok 'SL::Controller::CsvImport::ARTransaction';
18
19 use SL::DB::Buchungsgruppe;
20 use SL::DB::Currency;
21 use SL::DB::Customer;
22 use SL::DB::Employee;
23 use SL::DB::Invoice;
24 use SL::DB::TaxZone;
25 use SL::DB::Chart;
26 use SL::DB::AccTransaction;
27
28 my ($customer, $currency_id, $employee, $taxzone, $project, $department);
29
30 sub reset_state {
31   # Create test data
32   my %params = @_;
33
34   $params{$_} ||= {} for qw(buchungsgruppe customer tax);
35
36   clear_up();
37   $employee        = SL::DB::Manager::Employee->current                          || croak "No employee";
38   $taxzone         = SL::DB::Manager::TaxZone->find_by( description => 'Inland') || croak "No taxzone";
39   $currency_id     = $::instance_conf->get_currency_id;
40
41   $customer     = SL::DB::Customer->new(
42     name        => 'Test Customer',
43     currency_id => $currency_id,
44     taxzone_id  => $taxzone->id,
45     %{ $params{customer} }
46   )->save;
47
48   $project     = SL::DB::Project->new(
49     projectnumber  => 'P1',
50     description    => 'Project X',
51     project_type   => SL::DB::Manager::ProjectType->find_by(description => 'Standard'),
52     project_status => SL::DB::Manager::ProjectStatus->find_by(name => 'running'),
53   )->save;
54
55   $department     = SL::DB::Department->new(
56     description    => 'Department 1',
57   )->save;
58 }
59
60 Support::TestSetup::login();
61
62 reset_state(customer => {id => 960, customernumber => 2});
63
64 #####
65 sub test_import {
66   my $file = shift;
67
68   my $controller = SL::Controller::CsvImport->new();
69
70   my $csv_artransactions_import = SL::Controller::CsvImport::ARTransaction->new(
71     settings    => {'ar_column'          => 'Rechnung',
72                     'transaction_column' => 'AccTransaction',
73                     'max_amount_diff'    => 0.02
74                   },
75     controller => $controller,
76     file       => $file,
77   );
78
79   # $csv_artransactions_import->init_vc_by;
80   $csv_artransactions_import->test_run(0);
81   $csv_artransactions_import->csv(SL::Helper::Csv->new(file                    => $csv_artransactions_import->file,
82                                                        profile                 => $csv_artransactions_import->profile,
83                                                        encoding                => 'utf-8',
84                                                        ignore_unknown_columns  => 1,
85                                                        strict_profile          => 1,
86                                                        case_insensitive_header => 1,
87                                                        sep_char                => ',',
88                                                        quote_char              => '"',
89                                                        ignore_unknown_columns  => 1,
90                                                      ));
91
92   $csv_artransactions_import->csv->parse;
93
94   $csv_artransactions_import->controller->errors([ $csv_artransactions_import->csv->errors ]) if $csv_artransactions_import->csv->errors;
95
96   return if ( !$csv_artransactions_import->csv->header || $csv_artransactions_import->csv->errors );
97
98   my $headers;
99   my $i = 0;
100   foreach my $header (@{ $csv_artransactions_import->csv->header }) {
101
102     my $profile   = $csv_artransactions_import->csv->profile->[$i]->{profile};
103     my $row_ident = $csv_artransactions_import->csv->profile->[$i]->{row_ident};
104
105     my $h = { headers => [ grep { $profile->{$_} } @{ $header } ] };
106     $h->{methods} = [ map { $profile->{$_} } @{ $h->{headers} } ];
107     $h->{used}    = { map { ($_ => 1) }      @{ $h->{headers} } };
108
109     $headers->{$row_ident} = $h;
110     $i++;
111   }
112
113   $csv_artransactions_import->controller->headers($headers);
114
115   my $raw_data_headers;
116   my $info_headers;
117   foreach my $p (@{ $csv_artransactions_import->csv->profile }) {
118     my $ident = $p->{row_ident};
119     $raw_data_headers->{$ident} = { used => { }, headers => [ ] };
120     $info_headers->{$ident}     = { used => { }, headers => [ ] };
121   }
122   $csv_artransactions_import->controller->raw_data_headers($raw_data_headers);
123   $csv_artransactions_import->controller->info_headers($info_headers);
124
125   my $objects  = $csv_artransactions_import->csv->get_objects;
126   my @raw_data = @{ $csv_artransactions_import->csv->get_data };
127
128   $csv_artransactions_import->controller->data([ pairwise { no warnings 'once'; { object => $a, raw_data => $b, errors => [], information => [], info_data => {} } } @$objects, @raw_data ]);
129   $csv_artransactions_import->check_objects;
130
131   # don't try and save objects that have errors
132   $csv_artransactions_import->save_objects unless scalar @{$csv_artransactions_import->controller->data->[0]->{errors}};
133
134  return $csv_artransactions_import->controller->data;
135 }
136
137 ##### manually create an ar transaction from scratch, testing the methods
138 $::myconfig{numberformat} = '1000.00';
139 my $old_locale = $::locale;
140 # set locale to en so we can match errors
141 $::locale = Locale->new('en');
142
143 my $amount = 10;
144
145 my $ar = SL::DB::Invoice->new(
146   invoice      => 0,
147   invnumber    => 'manual invoice',
148   taxzone_id   => $taxzone->id,
149   currency_id  => $currency_id,
150   taxincluded  => 'f',
151   customer_id  => $customer->id,
152   transdate    => DateTime->today,
153   employee_id  => SL::DB::Manager::Employee->current->id,
154   transactions => [],
155 );
156
157 my $tax3 = SL::DB::Manager::Tax->find_by(rate => 0.19, taxkey => 3) || die "can't find tax with taxkey 3";
158 my $income_chart = SL::DB::Manager::Chart->find_by(accno => '8400') || die "can't find income chart";
159
160 $ar->add_ar_amount_row(
161   amount => $amount,
162   chart  => $income_chart,
163   tax_id => $tax3->id,
164 );
165
166 $ar->recalculate_amounts; # set amount and netamount from transactions
167 is $ar->amount, '10', 'amount of manual invoice is 10';
168 is $ar->netamount, '8.4', 'netamount of manual invoice is 10';
169
170 $ar->create_ar_row( chart => SL::DB::Manager::Chart->find_by(accno => '1400', link => 'AR') );
171 my $result = $ar->validate_acc_trans(debug => 0);
172 is $result, 1, 'manual $ar validates';
173
174 $ar->save;
175 is ${ $ar->transactions }[0]->chart->accno, '8400', 'assigned income chart after save ok';
176 is ${ $ar->transactions }[2]->chart->accno, '1400', 'assigned receivable chart after save ok';
177 is scalar @{$ar->transactions}, 3, 'manual invoice has 3 acc_trans entries';
178
179 $ar->pay_invoice(  chart_id      => SL::DB::Manager::Chart->find_by(accno => '1200')->id, # bank
180                    amount        => $ar->open_amount,
181                    transdate     => DateTime->now->to_kivitendo,
182                    payment_type  => 'without_skonto',  # default if not specified
183                   );
184 $result = $ar->validate_acc_trans(debug => 0);
185 is $result, 1, 'manual invoice validates after payment';
186
187 reset_state(customer => {id => 960, customernumber => 2});
188
189 my ($entries, $entry, $file);
190
191 # starting test of csv imports
192 # to debug errors in certain tests, run after test_import:
193 #   die Dumper($entry->{errors});
194 ##### basic test
195 $file = \<<EOL;
196 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
197 datatype,accno,amount,taxkey
198 "Rechnung",960,4,1,"invoice 1",f,1400
199 "AccTransaction",8400,159.48,3
200 EOL
201 $entries = test_import($file);
202 $entry = $entries->[0];
203 $entry->{object}->validate_acc_trans;
204
205 is $entry->{object}->invnumber, 'invoice 1', 'simple invnumber ok (customer)';
206 is $entry->{object}->customer_id, '960', 'simple customer_id ok (customer)';
207 is scalar @{$entry->{object}->transactions}, 3, 'invoice 1 has 3 acc_trans entries';
208 is $::form->round_amount($entry->{object}->transactions->[0]->amount, 2), 159.48, 'invoice 1 ar amount is 159.48';
209 is $entry->{object}->direct_debit, '0', 'no direct debit';
210 is $entry->{object}->taxincluded, '0', 'taxincluded is false';
211 is $entry->{object}->amount, '189.78', 'ar amount tax not included is 189.78';
212 is $entry->{object}->netamount, '159.48', 'ar netamount tax not included is 159.48';
213
214 ##### test for duplicate invnumber
215 $file = \<<EOL;
216 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
217 datatype,accno,amount,taxkey
218 "Rechnung",960,4,1,"invoice 1",f,1400
219 "AccTransaction",8400,159.48,3
220 EOL
221 $entries = test_import($file);
222 $entry = $entries->[0];
223 $entry->{object}->validate_acc_trans;
224 is $entry->{errors}->[0], 'Error: invnumber already exists', 'detects verify_amount differences';
225
226 ##### test for no invnumber given
227 $file = \<<EOL;
228 datatype,customer_id,taxzone_id,currency_id,taxincluded,archart
229 datatype,accno,amount,taxkey
230 "Rechnung",960,4,1,f,1400
231 "AccTransaction",8400,159.48,3
232 EOL
233 $entries = test_import($file);
234 $entry = $entries->[0];
235 $entry->{object}->validate_acc_trans;
236 is $entry->{object}->invnumber =~ /^\d+$/, 1, 'invnumber assigned automatically';
237
238 ##### basic test without amounts in Rechnung, only specified in AccTransaction
239 $file = \<<EOL;
240 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
241 datatype,accno,amount,taxkey
242 "Rechnung",960,4,1,"invoice 1 no amounts",f,1400
243 "AccTransaction",8400,159.48,3
244 EOL
245 $entries = test_import($file);
246 $entry = $entries->[0];
247 $entry->{object}->validate_acc_trans;
248
249 is $entry->{object}->invnumber, 'invoice 1 no amounts', 'simple invnumber ok (customer)';
250 is $entry->{object}->customer_id, '960', 'simple customer_id ok (customer)';
251 is scalar @{$entry->{object}->transactions}, 3, 'invoice 1 has 3 acc_trans entries';
252 is $::form->round_amount($entry->{object}->amount, 2), '189.78', 'not taxincluded ar amount';
253 is $::form->round_amount($entry->{object}->transactions->[0]->amount, 2), '159.48', 'not taxincluded acc_trans netamount';
254 is $::form->round_amount($entry->{object}->transactions->[0]->amount, 2), 159.48, 'invoice 1 ar amount is 159.48';
255
256 ##### basic test: credit_note
257 $file = \<<EOL;
258 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
259 datatype,accno,amount,taxkey
260 "Rechnung",960,4,1,"credit note",f,1400
261 "AccTransaction",8400,-159.48,3
262 EOL
263 $entries = test_import($file);
264 $entry = $entries->[0];
265 $entry->{object}->validate_acc_trans;
266
267 is $entry->{object}->invnumber, 'credit note', 'simple credit note ok';
268 is scalar @{$entry->{object}->transactions}, 3, 'credit note has 3 acc_trans entries';
269 is $::form->round_amount($entry->{object}->amount, 2), '-189.78', 'taxincluded ar amount';
270 is $::form->round_amount($entry->{object}->netamount, 2), '-159.48', 'taxincluded ar net amount';
271 is $::form->round_amount($entry->{object}->transactions->[0]->amount, 2), -159.48, 'credit note ar amount is -159.48';
272 is $entry->{object}->amount, '-189.78', 'credit note amount tax not included is 189.78';
273 is $entry->{object}->netamount, '-159.48', 'credit note netamount tax not included is 159.48';
274
275 #### verify_amount differs: max_amount_diff = 0.02, 189.80 is ok, 189.81 is not
276 $file = \<<EOL;
277 datatype,customer_id,verify_amount,verify_netamount,taxzone_id,currency_id,invnumber,taxincluded,archart
278 datatype,accno,amount,taxkey
279 "Rechnung",960,189.81,159.48,4,1,"invoice amounts differing",f,1400
280 "AccTransaction",8400,159.48,3
281 EOL
282 $entries = test_import($file);
283 $entry = $entries->[0];
284 is $entry->{errors}->[0], 'Amounts differ too much', 'detects verify_amount differences';
285
286 #####  direct debit
287 $file = \<<EOL;
288 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,direct_debit,archart
289 datatype,accno,amount,taxkey
290 "Rechnung",960,4,1,"invoice with direct debit",f,t,1400
291 "AccTransaction",8400,159.48,3
292 EOL
293
294 $entries = test_import($file);
295 $entry = $entries->[0];
296 $entry->{object}->validate_acc_trans;
297 is $entry->{object}->direct_debit, '1', 'direct debit';
298
299 #### tax included
300 $file = \<<EOL;
301 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
302 datatype,accno,amount,taxkey
303 "Rechnung",960,4,1,"invoice 1 tax included no amounts",t,1400
304 "AccTransaction",8400,189.78,3
305 EOL
306
307 $entries = test_import($file);
308 $entry = $entries->[0];
309 $entry->{object}->validate_acc_trans(debug => 0);
310 is $entry->{object}->taxincluded, '1', 'taxincluded is true';
311 is $::form->round_amount($entry->{object}->amount, 2), '189.78', 'taxincluded ar amount';
312 is $::form->round_amount($entry->{object}->netamount, 2), '159.48', 'taxincluded ar net amount';
313 is $::form->round_amount($entry->{object}->transactions->[0]->amount, 2), '159.48', 'taxincluded acc_trans netamount';
314
315 #### multiple tax included
316 $file = \<<EOL;
317 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
318 datatype,accno,amount,taxkey
319 "Rechnung",960,4,1,"invoice multiple tax included",t,1400
320 "AccTransaction",8400,94.89,3
321 "AccTransaction",8400,94.89,3
322 EOL
323
324 $entries = test_import($file);
325 $entry = $entries->[0];
326 $entry->{object}->validate_acc_trans;
327 is $::form->round_amount($entry->{object}->amount, 2),    '189.78', 'taxincluded ar amount';
328 is $::form->round_amount($entry->{object}->netamount, 2), '159.48', 'taxincluded ar netamount';
329 is $::form->round_amount($entry->{object}->transactions->[0]->amount, 2), '79.74', 'taxincluded amount';
330 is $::form->round_amount($entry->{object}->transactions->[1]->amount, 2), '15.15', 'taxincluded tax';
331
332 # different receivables chart
333 $file = \<<EOL;
334 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
335 datatype,accno,amount,taxkey
336 "Rechnung",960,4,1,"invoice mit archart 1448",f,1448
337 "AccTransaction",8400,159.48,3
338 EOL
339 $entries = test_import($file);
340 $entry = $entries->[0];
341 $entry->{object}->validate_acc_trans;
342 is $entry->{object}->transactions->[2]->chart->accno, '1448', 'archart set to 1448';
343
344 # missing customer
345 $file = \<<EOL;
346 datatype,taxzone_id,currency_id,invnumber,taxincluded,archart
347 datatype,accno,amount,taxkey
348 "Rechnung",4,1,"invoice missing customer",f,1400
349 "AccTransaction",8400,159.48,3
350 EOL
351 $entries = test_import($file);
352 $entry = $entries->[0];
353 is $entry->{errors}->[0], 'Error: Customer/vendor missing', 'detects missing customer or vendor';
354
355
356 ##### customer by name
357 $file = \<<EOL;
358 datatype,customer,taxzone_id,currency_id,invnumber,taxincluded,archart
359 datatype,accno,amount,taxkey
360 "Rechnung","Test Customer",4,1,"invoice customer name",f,1400
361 "AccTransaction",8400,159.48,3
362 EOL
363 $entries = test_import($file);
364 $entry = $entries->[0];
365 $entry->{object}->validate_acc_trans;
366 is $entry->{object}->customer->name, "Test Customer", 'detects customer by name';
367
368 ##### detect missing chart
369 $file = \<<EOL;
370 datatype,taxzone_id,currency_id,invnumber,customer,archart
371 datatype,amount,taxkey
372 "Rechnung",4,1,"invoice missing chart","Test Customer",1400
373 "AccTransaction",4,3
374 EOL
375 $entries = test_import($file);
376 $entry = $entries->[1];
377 is $entry->{errors}->[0], 'Error: chart missing', 'detects missing chart (chart_id or accno)';
378
379 ##### detect illegal chart by accno
380 $file = \<<EOL;
381 datatype,taxzone_id,currency_id,invnumber,customer,archart
382 datatype,accno,amount,taxkey
383 "Rechnung",4,1,"invoice illegal chart accno","Test Customer",1400
384 "AccTransaction",9999,4,3
385 EOL
386 $entries = test_import($file);
387 $entry = $entries->[1];
388 is $entry->{errors}->[0], 'Error: invalid chart (accno)', 'detects invalid chart (chart_id or accno)';
389
390 # ##### detect illegal archart
391 $file = \<<EOL;
392 datatype,taxzone_id,currency_id,invnumber,customer,taxincluded,archart
393 datatype,accno,amount,taxkey
394 "Rechnung",4,1,"invoice illegal archart","Test Customer",f,11400
395 "AccTransaction",8400,159.48,3
396 EOL
397 $entries = test_import($file);
398 $entry = $entries->[0];
399 is $entry->{errors}->[0], "Error: can't find ar chart with accno 11400", 'detects illegal receivables chart (archart)';
400
401 ##### detect chart by id
402 $file = \<<EOL;
403 datatype,taxzone_id,currency_id,invnumber,customer,taxincluded,archart
404 datatype,amount,chart_id,taxkey
405 "Rechnung",4,1,"invoice chart_id","Test Customer",f,1400
406 "AccTransaction",159.48,184,3
407 EOL
408 $entries = test_import($file);
409 $entry = $entries->[1]; # acc_trans entry is at entry array pos 1
410 $entries->[0]->{object}->validate_acc_trans;
411 is $entry->{object}->chart->id, "184", 'detects chart by id';
412
413 ##### detect chart by accno
414 $file = \<<EOL;
415 datatype,taxzone_id,currency_id,invnumber,customer,taxincluded,archart
416 datatype,amount,accno,taxkey
417 "Rechnung",4,1,"invoice by chart accno","Test Customer",f,1400
418 "AccTransaction",159.48,8400,3
419 EOL
420 $entries = test_import($file);
421 $entry = $entries->[1];
422 $entries->[0]->{object}->validate_acc_trans;
423 is $entry->{object}->chart->accno, "8400", 'detects chart by accno';
424
425 ##### detect chart isn't an ar_chart
426 $file = \<<EOL;
427 datatype,taxzone_id,currency_id,invnumber,customer,taxincluded,archart
428 datatype,amount,accno,taxkey
429 "Rechnung",4,1,"invoice by chart accno","Test Customer",f,1400
430 "AccTransaction",159.48,1400,3
431 EOL
432 $entries = test_import($file);
433 $entry = $entries->[1];
434 $entries->[0]->{object}->validate_acc_trans;
435 is $entry->{errors}->[0], 'Error: chart isn\'t an ar_amount chart', 'detects valid chart that is not an ar_amount chart';
436
437 # missing taxkey
438 $file = \<<EOL;
439 datatype,taxzone_id,currency_id,invnumber,customer,archart
440 datatype,amount,accno
441 "Rechnung",4,1,"invoice missing taxkey chart accno","Test Customer",1400
442 "AccTransaction",159.48,8400
443 EOL
444 $entries = test_import($file);
445 $entry = $entries->[1];
446 is $entry->{errors}->[0], 'Error: taxkey missing', 'detects missing taxkey (DATEV Steuerschlüssel)';
447
448 # illegal taxkey
449 $file = \<<EOL;
450 datatype,taxzone_id,currency_id,invnumber,customer,archart
451 datatype,amount,accno,taxkey
452 "Rechnung",4,1,"invoice illegal taxkey","Test Customer",1400
453 "AccTransaction",4,8400,123
454 EOL
455 $entries = test_import($file);
456 $entry = $entries->[1];
457 is $entry->{errors}->[0], 'Error: invalid taxkey', 'detects invalid taxkey (DATEV Steuerschlüssel)';
458
459 # taxkey
460 $file = \<<EOL;
461 datatype,customer_id,taxzone_id,currency_id,invnumber,archart
462 datatype,accno,amount,taxkey
463 "Rechnung",960,4,1,"invoice by taxkey",1400
464 "AccTransaction",8400,4,3
465 EOL
466
467 $entries = test_import($file);
468 $entry = $entries->[1];
469 is $entry->{object}->taxkey, 3, 'detects taxkey';
470
471 # acc_trans project
472 $file = \<<EOL;
473 datatype,customer_id,taxzone_id,currency_id,invnumber,archart,taxincluded
474 datatype,accno,amount,taxkey,projectnumber
475 "Rechnung",960,4,1,"invoice with acc_trans project",1400,f
476 "AccTransaction",8400,159.48,3,P1
477 EOL
478
479 $entries = test_import($file);
480 $entry = $entries->[1];
481 # die Dumper($entries->[0]->{errors}) if scalar @{$entries->[0]->{errors}};
482 is $entry->{object}->project->projectnumber, 'P1', 'detects acc_trans project';
483
484 #####  various tests
485 $file = \<<EOL;
486 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart,transdate,duedate,globalprojectnumber,department
487 datatype,accno,amount,taxkey,projectnumber
488 "Rechnung",960,4,1,"invoice various",t,1400,21.04.2016,30.04.2016,P1,Department 1
489 "AccTransaction",8400,119,3,P1
490 "AccTransaction",8300,107,2,P1
491 "AccTransaction",8200,100,0,P1
492 EOL
493
494 $entries = test_import($file);
495 $entry = $entries->[0];
496 $entry->{object}->validate_acc_trans;
497 is $entry->{object}->duedate->to_kivitendo,      '30.04.2016',    'duedate';
498 is $entry->{object}->transdate->to_kivitendo,    '21.04.2016',    'transdate';
499 is $entry->{object}->globalproject->description, 'Project X',     'project';
500 is $entry->{object}->department->description,    'Department 1',  'department';
501 # 8300 is third entry after 8400 and tax for 8400
502 is $::form->round_amount($entry->{object}->transactions->[2]->amount),     '100',        '8300 net amount: 100';
503 is $::form->round_amount($entry->{object}->transactions->[2]->taxkey),     '2',          '8300 has taxkey 2';
504 is $::form->round_amount($entry->{object}->transactions->[2]->project_id), $project->id, 'AccTrans project';
505
506 #####  ar amount test
507 $file = \<<EOL;
508 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart,transdate,duedate,globalprojectnumber,department
509 datatype,accno,amount,taxkey,projectnumber
510 "Rechnung",960,4,1,"invoice various 1",t,1400,21.04.2016,30.04.2016,P1,Department 1
511 "AccTransaction",8400,119,3,P1
512 "AccTransaction",8300,107,2,P1
513 "AccTransaction",8200,100,0,P1
514 "Rechnung",960,4,1,"invoice various 2",t,1400,21.04.2016,30.04.2016,P1,Department 1
515 "AccTransaction",8400,119,3,P1
516 "AccTransaction",8300,107,2,P1
517 "AccTransaction",8200,100,0,P1
518 EOL
519
520 $entries = test_import($file);
521 $entry = $entries->[0];
522 $entry->{object}->validate_acc_trans;
523 is $entry->{object}->duedate->to_kivitendo,      '30.04.2016',    'duedate';
524 is $entry->{info_data}->{amount}, '326', "First invoice amount displayed in info data";
525 is $entries->[4]->{info_data}->{amount}, '326', "Second invoice amount displayed in info data";
526
527 # multiple entries, taxincluded = f
528 $file = \<<EOL;
529 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
530 datatype,accno,amount,taxkey
531 "Rechnung",960,4,1,"invoice 4 acc_trans",f,1400
532 "AccTransaction",8400,39.87,3
533 "AccTransaction",8400,39.87,3
534 "AccTransaction",8400,39.87,3
535 "AccTransaction",8400,39.87,3
536 "Rechnung",960,4,1,"invoice 4 acc_trans 2",f,1400
537 "AccTransaction",8400,39.87,3
538 "AccTransaction",8400,39.87,3
539 "AccTransaction",8400,39.87,3
540 "AccTransaction",8400,39.87,3
541 "Rechnung",960,4,1,"invoice 4 acc_trans 3",f,1400
542 "AccTransaction",8400,39.87,3
543 "AccTransaction",8400,39.87,3
544 "AccTransaction",8400,39.87,3
545 "AccTransaction",8400,39.87,3
546 "Rechnung",960,4,1,"invoice 4 acc_trans 4",f,1448
547 "AccTransaction",8400,39.87,3
548 "AccTransaction",8400,39.87,3
549 "AccTransaction",8400,39.87,3
550 "AccTransaction",8400,39.87,3
551 EOL
552 $entries = test_import($file);
553
554 my $i = 0;
555 foreach my $entry ( @$entries ) {
556   next unless $entry->{object}->isa('SL::DB::Invoice');
557   $i++;
558   is scalar @{$entry->{object}->transactions}, 9, "invoice $i: 'invoice 4 acc_trans' has 9 acc_trans entries";
559   $entry->{object}->validate_acc_trans;
560 };
561
562 ##### missing acc_trans
563 $file = \<<EOL;
564 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart,transdate,duedate,globalprojectnumber,department
565 datatype,accno,amount,taxkey,projectnumber
566 "Rechnung",960,4,1,"invoice acc_trans missing",t,1400,21.04.2016,30.04.2016,P1,Department 1
567 "Rechnung",960,4,1,"invoice various a",t,1400,21.04.2016,30.04.2016,P1,Department 1
568 "AccTransaction",8400,119,3,P1
569 "AccTransaction",8300,107,2,P1
570 EOL
571
572 $entries = test_import($file);
573 $entry = $entries->[0];
574 is $entry->{errors}->[0], "Error: ar transaction doesn't validate", 'detects invalid ar, maybe acc_trans entry missing';
575
576 my $number_of_imported_invoices = SL::DB::Manager::Invoice->get_all_count;
577 is $number_of_imported_invoices, 19, 'All invoices saved';
578
579 #### taxkey differs from active_taxkey
580 $file = \<<EOL;
581 datatype,customer_id,taxzone_id,currency_id,invnumber,taxincluded,archart
582 datatype,accno,amount,taxkey
583 "Rechnung",960,4,1,"invoice 1 tax included no amounts",t,1400
584 "AccTransaction",8400,189.78,2
585 EOL
586
587 $entries = test_import($file);
588 $entry = $entries->[0];
589 $entry->{object}->validate_acc_trans(debug => 0);
590
591 clear_up(); # remove all data at end of tests
592 # end of tests
593
594
595 sub clear_up {
596   SL::DB::Manager::AccTransaction->delete_all(all => 1);
597   SL::DB::Manager::Invoice->delete_all       (all => 1);
598   SL::DB::Manager::Customer->delete_all      (all => 1);
599   SL::DB::Manager::Project->delete_all       (all => 1);
600   SL::DB::Manager::Department->delete_all    (all => 1);
601 };
602
603
604 1;
605
606 #####
607 # vim: ft=perl
608 # set emacs to perl mode
609 # Local Variables:
610 # mode: perl
611 # End: