67889587d855c2efb086d0c97197218482bc323e
[kivitendo-erp.git] / t / datev / datev_format_2018.t
1 use strict;
2 use Test::More;
3 use Test::Deep qw(cmp_deeply);
4
5 use lib 't';
6
7 use_ok 'Support::TestSetup';
8 use SL::DATEV qw(:CONSTANTS);
9 use SL::Dev::ALL qw(:ALL);
10 use List::Util qw(sum);
11 use SL::DB::Buchungsgruppe;
12 use SL::DB::Chart;
13 use DateTime;
14 use Data::Dumper;
15 use utf8;
16
17 Support::TestSetup::login();
18
19 my $dbh = SL::DB->client->dbh;
20
21 clear_up();
22
23 my $d = SL::DB::Default->get;
24 $d->update_attributes(datev_export_format => 'cp1252');
25
26 my $ustid           = 'DE123456788';
27 my $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%') || die "No accounting group for 7\%";
28 my $date            = DateTime->new(year => 2017, month =>  7, day => 19);
29 my $department      = create_department(description => 'Kästchenweiße heiße Preise');
30 my $project         = create_project(projectnumber => 2017, description => '299');
31 my $bank            = SL::DB::Manager::Chart->find_by(description => 'Bank') || die 'Can\'t find chart "Bank"';
32 my $customer        = new_customer(name => 'Test customer', ustid => $ustid)->save();
33 my $part1 = new_part(partnumber => '19', description => 'Part 19%')->save;
34 my $part2 = new_part(
35   partnumber         => '7',
36   description        => 'Part 7%',
37   buchungsgruppen_id => $buchungsgruppe7->id,
38 )->save;
39
40 my $invoice = create_sales_invoice(
41   invnumber    => "ݗݘݰݶ",
42   itime        => $date,
43   gldate       => $date,
44   taxincluded  => 0,
45   transdate    => $date,
46   invoiceitems => [ create_invoice_item(part => $part1, qty =>  3, sellprice => 550),
47                     create_invoice_item(part => $part2, qty => 10, sellprice => 50),
48                   ],
49   department_id    => $department->id,
50   globalproject_id => $project->id,
51   customer_id      => $customer->id,
52 );
53
54 # lets make a boom
55 # generate_datev_* doesn't care about encoding but
56 # csv_buchungsexport does! all arabic will be deleted
57 # and no string will be left as invnumber
58
59 my $datev1 = SL::DATEV->new(
60   dbh        => $dbh,
61   trans_id   => $invoice->id,
62 );
63
64 my $startdate = DateTime->new(year => 2017, month =>  1, day =>  1);
65 my $enddate   = DateTime->new(year => 2017, month => 12, day => 31);
66 my $today     = DateTime->new(year => 2017, month =>  3, day => 17);
67
68 $datev1->from($startdate);
69 $datev1->to($enddate);
70
71 $datev1->generate_datev_data;
72 $datev1->generate_datev_lines;
73
74 # check conversion to csv
75 $datev1->from($startdate);
76 $datev1->to($enddate);
77 my ($datev_csv, $die_message);
78 eval {
79   $datev_csv = SL::DATEV::CSV->new(datev_lines  => $datev1->generate_datev_lines,
80                                    from         => $startdate,
81                                    to           => $enddate,
82                                    locked       => $datev1->locked,
83                                   );
84   my $lines_aref = $datev_csv->lines; # dies only if we assign (do stuff with the data)
85   1;
86 } or do {
87   $die_message = $@;
88 };
89 ok($die_message =~ m/Falscher Feldwert 'ݗݘݰݶ' für Feld 'belegfeld1' bei der Transaktion mit dem Umsatz von/, 'wrong_encoding');
90
91
92 $invoice->invnumber('ݗݘݰݶmuh');
93 $invoice->save();
94
95 my $datev3 = SL::DATEV->new(
96   dbh        => $dbh,
97   trans_id   => $invoice->id,
98 );
99
100 $datev3->from($startdate);
101 $datev3->to($enddate);
102 $datev3->generate_datev_data;
103 $datev3->generate_datev_lines;
104 my ($datev_csv2, $die_message2);
105 eval {
106   $datev_csv2 = SL::DATEV::CSV->new(datev_lines  => $datev3->generate_datev_lines,
107                                     from         => $startdate,
108                                     to           => $enddate,
109                                     locked       => $datev3->locked,
110                                    );
111 my $lines_aref = $datev_csv2->lines; # dies only if we assign (do stuff with the data)
112
113   1;
114 } or do {
115   $die_message2 = $@;
116 };
117
118 # redefine invnumber, we have mixed encodings, should still fail
119 ok($die_message2 =~ m/Falscher Feldwert 'ݗݘݰݶmuh' für Feld 'belegfeld1' bei der Transaktion mit dem Umsatz von/, 'mixed_wrong_encoding');
120
121 # check with good number
122 $invoice->invnumber('meine muh');
123 $invoice->save();
124
125 $invoice->pay_invoice(chart_id      => $bank->id,
126                       amount        => $invoice->open_amount,
127                       transdate     => $invoice->transdate->clone->add(days => 10),
128                       memo          => 'foobar',
129                       source        => 'barfoo',
130                      );
131
132 my $datev4 = SL::DATEV->new(
133   dbh        => $dbh,
134   trans_id   => $invoice->id,
135 );
136
137 $datev4->from($startdate);
138 $datev4->to($enddate);
139 $datev4->generate_datev_data;
140 $datev4->generate_datev_lines;
141
142 my ($datev_csv4, $die_message3, $lines_aref);
143 eval {
144   $datev_csv4 = SL::DATEV::CSV->new(datev_lines  => $datev4->generate_datev_lines,
145                                     from         => $startdate,
146                                     to           => $enddate,
147                                     locked       => $datev4->locked,
148                                    );
149   $lines_aref = $datev_csv4->lines; # dies only if we assign (do stuff with the data)
150
151   1;
152 } or do {
153   $die_message3 = $@;
154 };
155 ok(!($die_message3), 'no die message');
156 ok(scalar @{ $datev_csv4->warnings } == 0, 'no warnings');
157
158
159 note('testing invoice without deliverydate');
160 my @sorted =  sort { $a->[0] cmp $b->[0] } @{ $lines_aref }; # sort by string-comparison of amount
161 cmp_deeply $sorted[0],
162            [ '1963,5', 'S', 'EUR', '', '', '',
163              '1400', '8400', '', '1907', 'meine muh',
164              '', '', 'Test customer', '', '', '', '', '', '',
165              '', '', '', '', '', '', '', '', '',
166              '', '', '', '', '', '', '', "K\x{e4}stchen",
167              '299', '', $ustid, '', '', '',
168              '', '', '', '', '', '', '', '', '',
169              '', '', '', '', '', '', '', '', '',
170              '', '', '', '', '', '', '', '', '',
171              '', '', '', '', '', '', '', '', '',
172              '', '', '', '', '', '', '', '', '',
173              '', '', '', '', '', '', '', '', '',
174              '', '', '', '', '', '', '', '', '',
175              '', '', '', '', '', '', '', '1', '',
176              '', '', '', '', '',
177            ],
178            'invoice without deliverydate 19% tax export ok';
179 cmp_deeply $sorted[2],
180            [ '535', 'S', 'EUR', '', '', '',
181              '1400', '8300', '', '1907','meine muh',
182              '', '', 'Test customer', '', '', '', '', '', '',
183              '', '', '', '', '', '', '', '', '',
184              '', '', '', '', '', '', '', "K\x{e4}stchen",
185              '299', '', $ustid, '', '', '',
186              '', '', '', '', '', '', '', '', '',
187              '', '', '', '', '', '', '', '', '',
188              '', '', '', '', '', '', '', '', '',
189              '', '', '', '', '', '', '', '', '',
190              '', '', '', '', '', '', '', '', '',
191              '', '', '', '', '', '', '', '', '',
192              '', '', '', '', '', '', '', '', '',
193              '', '', '', '', '', '', '', '1', '',
194              '', '', '', '', '',
195            ],
196            'invoice without deliverydate 16% tax export ok';
197 cmp_deeply $sorted[1],
198            [ '2498,5', 'S', 'EUR', '', '', '',
199              '1200', '1400', '', '2907','meine muh',
200              '', '', 'Test customer', '', '', '', '', '', '',
201              '', '', '', '', '', '', '', '', '',
202              '', '', '', '', '', '', '', "K\x{e4}stchen",
203              '299', '', $ustid, '', '', '',
204              '', '', '', '', '', '', '', '', '',
205              '', '', '', '', '', '', '', '', '',
206              '', '', '', '', '', '', '', '', '',
207              '', '', '', '', '', '', '', '', '',
208              '', '', '', '', '', '', '', '', '',
209              '', '', '', '', '', '', '', '', '',
210              '', '', '', '', '', '', '', '', '',
211              '', '', '', '', '', '', '', '1', '',
212              '', '', '', '', '',
213            ],
214            'invoice without deliverydate payment export ok';
215
216 # create one haben buchung with GLTransaction today
217
218 my $expense_chart = SL::DB::Manager::Chart->find_by(accno => '4660'); # Reisekosten
219 my $cash_chart    = SL::DB::Manager::Chart->find_by(accno => '1000'); # Kasse
220
221 note('testing gl transaction without deliverydate');
222 my $gl_transaction = create_gl_transaction(
223   reference      => "Reise März 2018",
224   description    => "Reisekosten März 2018 / Ma Schmidt",
225   transdate      => $today,
226   taxincluded    => 1,
227   type           => undef,
228   bookings       => [
229                       {
230                         chart  => $expense_chart,
231                         taxkey => 9,
232                         debit  => 100, # net 84.03
233                       },
234                       {
235                         chart  => $cash_chart,
236                         taxkey => 0,
237                         credit => 100,
238                       },
239                     ],
240 );
241
242 my $datev2 = SL::DATEV->new(
243   dbh        => $dbh,
244   trans_id   => $gl_transaction->id,
245 );
246
247 $datev2->from($startdate);
248 $datev2->to($enddate);
249 $datev2->generate_datev_data;
250
251 my $datev_csv3  = SL::DATEV::CSV->new(datev_lines  => $datev2->generate_datev_lines,
252                                       from         => $startdate,
253                                       to           => $enddate,
254                                       locked       => $datev2->locked,
255                                      );
256
257 my @data_csv    = sort { $a->[0] cmp $b->[0] } @{ $datev_csv3->lines };
258 cmp_deeply($data_csv[0],
259            [ '100', 'S', 'EUR', '', '', '', '4660', '1000', 9, '1703', 'Reise März 2',
260              '', '', 'Reisekosten März 2018 / Ma Schmidt', '', '', '', '', '', '', '', '',
261              '', '', '', '', '', '', '', '', '', '', '', '', '',
262              '', '', '', '', '', '', '', '', '', '', '',
263              '', '', '', '', '', '', '', '', '', '', '', '', '',
264              '', '', '', '', '', '', '', '', '', '', '', '', '',
265              '', '', '', '', '', '', '', '', '', '', '', '', '',
266              '', '', '', '', '', '', '', '', '', '', '', '', '',
267              '', '', '', '', '', '', '', '', '', '', '', '', '',
268              '', '', '1', '', '', '', '', '', '',
269            ],
270            'gl datev export without delivery date ok');
271
272
273 note('testing same invoice, but with deliverydate');
274 # 8400 and 8300 should have deliverydate in datev, payment should not
275 $invoice->deliverydate(DateTime->new(year => 2017, month =>  7, day => 18));
276 $invoice->save();
277
278 $datev1 = SL::DATEV->new(
279   dbh        => $dbh,
280   trans_id   => $invoice->id,
281 );
282
283 $datev1->from($startdate);
284 $datev1->to($enddate);
285 $datev1->generate_datev_data;
286 $datev1->generate_datev_lines;
287
288 $datev_csv = SL::DATEV::CSV->new(datev_lines  => $datev1->generate_datev_lines,
289                                  from         => $startdate,
290                                  to           => $enddate,
291                                  locked       => $datev1->locked,
292 );
293 @sorted    = sort { $a->[0] cmp $b->[0] } @{ $datev_csv->lines };
294 cmp_deeply $sorted[0],
295            [ '1963,5', 'S', 'EUR', '', '', '',
296              '1400', '8400', '', '1907', 'meine muh',
297              '', '', 'Test customer', '', '', '', '', '', '',
298              '', '', '', '', '', '', '', '', '',
299              '', '', '', '', '', '', '', "K\x{e4}stchen",
300              '299', '', $ustid, '', '', '',
301              '', '', '', '', '', '', '', '', '',
302              '', '', '', '', '', '', '', '', '',
303              '', '', '', '', '', '', '', '', '',
304              '', '', '', '', '', '', '', '', '',
305              '', '', '', '', '', '', '', '', '',
306              '', '', '', '', '', '', '', '', '',
307              '', '', '', '', '', '', '', '', '',
308              '', '', '', '', '', '', '', '1', '18072017',
309              '', '', '', '', '',
310            ],
311            'invoice with deliverydate 19% tax export ok';
312
313 cmp_deeply $sorted[2],
314            [ '535', 'S', 'EUR', '', '', '',
315              '1400', '8300', '', '1907','meine muh',
316              '', '', 'Test customer', '', '', '', '', '', '',
317              '', '', '', '', '', '', '', '', '',
318              '', '', '', '', '', '', '', "K\x{e4}stchen",
319              '299', '', $ustid, '', '', '',
320              '', '', '', '', '', '', '', '', '',
321              '', '', '', '', '', '', '', '', '',
322              '', '', '', '', '', '', '', '', '',
323              '', '', '', '', '', '', '', '', '',
324              '', '', '', '', '', '', '', '', '',
325              '', '', '', '', '', '', '', '', '',
326              '', '', '', '', '', '', '', '', '',
327              '', '', '', '', '', '', '', '1', '18072017',
328              '', '', '', '', '',
329            ],
330            'invoice with deliverydate 16% tax export ok';
331
332 cmp_deeply $sorted[1],
333            [ '2498,5', 'S', 'EUR', '', '', '',
334              '1200', '1400', '', '2907','meine muh',
335              '', '', 'Test customer', '', '', '', '', '', '',
336              '', '', '', '', '', '', '', '', '',
337              '', '', '', '', '', '', '', "K\x{e4}stchen",
338              '299', '', $ustid, '', '', '',
339              '', '', '', '', '', '', '', '', '',
340              '', '', '', '', '', '', '', '', '',
341              '', '', '', '', '', '', '', '', '',
342              '', '', '', '', '', '', '', '', '',
343              '', '', '', '', '', '', '', '', '',
344              '', '', '', '', '', '', '', '', '',
345              '', '', '', '', '', '', '', '', '',
346              '', '', '', '', '', '', '', '1', '',
347              '', '', '', '', '',
348            ],
349            'invoice with deliverydate payment export ok';
350
351 note('testing same gl transaction with deliverydate');
352 $gl_transaction->deliverydate(DateTime->new(year => 2017, month =>  7, day => 18));
353 $gl_transaction->save;
354
355 $datev1 = SL::DATEV->new(
356   dbh        => $dbh,
357   trans_id   => $gl_transaction->id,
358 );
359
360 $datev1->from($startdate);
361 $datev1->to($enddate);
362 $datev1->generate_datev_data;
363
364 $datev_csv   = SL::DATEV::CSV->new(datev_lines  => $datev1->generate_datev_lines,
365                                    from         => $startdate,
366                                    to           => $enddate,
367                                    locked       => $datev1->locked,
368 );
369
370 @sorted      = sort { $a->[0] cmp $b->[0] } @{ $datev_csv->lines };
371 cmp_deeply($sorted[0],
372            [ '100', 'S', 'EUR', '', '', '', '4660', '1000', 9, '1703', 'Reise März 2',
373              '', '', 'Reisekosten März 2018 / Ma Schmidt', '', '', '', '', '', '', '', '',
374              '', '', '', '', '', '', '', '', '', '', '', '', '',
375              '', '', '', '', '', '', '', '', '', '', '',
376              '', '', '', '', '', '', '', '', '', '', '', '', '',
377              '', '', '', '', '', '', '', '', '', '', '', '', '',
378              '', '', '', '', '', '', '', '', '', '', '', '', '',
379              '', '', '', '', '', '', '', '', '', '', '', '', '',
380              '', '', '', '', '', '', '', '', '', '', '', '', '',
381              '', '', '1', '18072017', '', '', '', '', '',
382            ],
383           'testing gl transaction with delivery date datev export ok');
384
385 # TODO warnings are not yet tested
386 # currently most of the valid_checks are senseless because of
387 # the strict input_checks before. Maybe something like encoding mismatch of invnumber,
388 # can be altered to just a warning (not a mandantory field!)
389
390 done_testing();
391 clear_up();
392
393
394 sub clear_up {
395   SL::DB::Manager::AccTransaction->delete_all( all => 1);
396   SL::DB::Manager::GLTransaction->delete_all(  all => 1);
397   SL::DB::Manager::InvoiceItem->delete_all(    all => 1);
398   SL::DB::Manager::Invoice->delete_all(        all => 1);
399   SL::DB::Manager::Customer->delete_all(       all => 1);
400   SL::DB::Manager::Part->delete_all(           all => 1);
401   SL::DB::Manager::Project->delete_all(        all => 1);
402   SL::DB::Manager::Department->delete_all(     all => 1);
403   SL::DATEV->clean_temporary_directories;
404 };
405
406 1;