a1cae03170c1eb30875f26245146e15a88e8c75d
[kivitendo-erp.git] / t / datev / invoices.t
1 use strict;
2 use Test::More;
3 use Test::Deep qw(cmp_bag);
4
5 use lib 't';
6 use utf8;
7
8 use_ok 'Support::TestSetup';
9 use SL::DATEV qw(:CONSTANTS);
10 use SL::Dev::ALL qw(:ALL);
11 use List::Util qw(sum);
12 use SL::DB::Buchungsgruppe;
13 use SL::DB::Chart;
14 use DateTime;
15
16 Support::TestSetup::login();
17
18 clear_up();
19
20 my $dbh = SL::DB->client->dbh;
21
22 my $buchungsgruppe7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%') || die "No accounting group for 7\%";
23 my $bank            = SL::DB::Manager::Chart->find_by(description => 'Bank')                 || die 'Can\'t find chart "Bank"';
24 my $date            = DateTime->new(year => 2017, month =>  1, day => 1);
25 my $payment_date    = DateTime->new(year => 2017, month =>  1, day => 5);
26 my $gldate          = DateTime->new(year => 2017, month =>  2, day => 9); # simulate bookings for Jan being made in Feb
27 my $department      = create_department(description => 'Kostenstelle DATEV-Schnittstelle 2018');
28 my $project         = create_project(projectnumber => 2017, description => 'Crowd-Funding September 2017');
29 my $customer        = new_customer(customernumber => '10001', name => 'Testcustomer')->save;
30 my $vendor          = new_vendor(vendornumber => '70001', name => 'Testvendor')->save;
31
32 my $part1 = new_part(partnumber => '19', description => 'Part 19%')->save;
33 my $part2 = new_part(
34   partnumber         => '7',
35   description        => 'Part 7%',
36   buchungsgruppen_id => $buchungsgruppe7->id,
37 )->save;
38
39 my $invoice = create_sales_invoice(
40   invnumber    => "Þ sales ¥& invöice",
41   customer     => $customer,
42   itime        => $gldate,
43   gldate       => $gldate,
44   intnotes     => 'booked in February',
45   taxincluded  => 0,
46   transdate    => $date,
47   invoiceitems => [ create_invoice_item(part => $part1, qty =>  3, sellprice => 70),
48                     create_invoice_item(part => $part2, qty => 10, sellprice => 50),
49                   ],
50   department_id    => $department->id,
51   globalproject_id => $project->id,
52 );
53 $invoice->pay_invoice(chart_id      => $bank->id,
54                       amount        => $invoice->open_amount,
55                       transdate     => $payment_date->to_kivitendo,
56                       memo          => 'foobar',
57                       source        => 'barfoo',
58                      );
59 my $datev1 = SL::DATEV->new(
60   dbh        => $invoice->db->dbh,
61   trans_id   => $invoice->id,
62 );
63
64 $datev1->generate_datev_data;
65
66 my @data_datev   = sort { $a->{umsatz} <=> $b->{umsatz} } @{ $datev1->generate_datev_lines() };
67 cmp_bag \@data_datev, [
68                                          {
69                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
70                                            'buchungstext' => 'Testcustomer',
71                                            'datum'        => '01.01.2017',
72                                            'gegenkonto'   => '8400',
73                                            'konto'        => '1400',
74                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
75                                            'kost2'        => 'Crowd-Funding September 2017',
76                                            'umsatz'       => '249.9',
77                                            'waehrung'     => 'EUR',
78                                            'soll_haben_kennzeichen' => 'S',
79                                          },
80                                          {
81                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
82                                            'buchungstext' => 'Testcustomer',
83                                            'datum'        => '01.01.2017',
84                                            'gegenkonto'   => '8300',
85                                            'konto'        => '1400',
86                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
87                                            'kost2'        => 'Crowd-Funding September 2017',
88                                            'umsatz'       => 535,
89                                            'waehrung'     => 'EUR',
90                                            'soll_haben_kennzeichen' => 'S',
91                                          },
92                                          {
93                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
94
95
96 'buchungstext' => 'Testcustomer',
97                                            'buchungstext' => 'Testcustomer',
98                                            'datum'        => '05.01.2017',
99                                            'gegenkonto'   => '1400',
100                                            'konto'        => '1200',
101                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
102                                            'kost2'        => 'Crowd-Funding September 2017',
103                                            'umsatz'       => '784.9',
104                                            'waehrung'     => 'EUR',
105                                            'soll_haben_kennzeichen' => 'S',
106                                          },
107                                        ], "trans_id datev check ok";
108
109 $datev1->use_pk(1);
110 $datev1->generate_datev_data;
111 cmp_bag $datev1->generate_datev_lines, [
112                                          {
113                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
114                                            'buchungstext' => 'Testcustomer',
115                                            'datum'        => '01.01.2017',
116                                            'gegenkonto'   => '8400',
117                                            'konto'        => $customer->customernumber,
118                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
119                                            'kost2'        => 'Crowd-Funding September 2017',
120                                            'umsatz'       => '249.9',
121                                            'waehrung'     => 'EUR',
122                                            'soll_haben_kennzeichen' => 'S',
123                                          },
124                                          {
125                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
126                                            'buchungstext' => 'Testcustomer',
127                                            'datum'        => '01.01.2017',
128                                            'gegenkonto'   => '8300',
129                                            'konto'        => $customer->customernumber,
130                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
131                                            'kost2'        => 'Crowd-Funding September 2017',
132                                            'umsatz'       => 535,
133                                            'waehrung'     => 'EUR',
134                                            'soll_haben_kennzeichen' => 'S',
135                                          },
136                                          {
137                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
138                                            'buchungstext' => 'Testcustomer',
139                                            'datum'        => '05.01.2017',
140                                            'gegenkonto'   => $customer->customernumber,
141                                            'konto'        => '1200',
142                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
143                                            'kost2'        => 'Crowd-Funding September 2017',
144                                            'umsatz'       => '784.9',
145                                            'waehrung'     => 'EUR',
146                                            'soll_haben_kennzeichen' => 'S',
147                                          },
148                                        ], "trans_id datev check use_pk ok";
149
150
151 my $startdate = DateTime->new(year => 2017, month =>  1, day =>  1);
152 my $enddate   = DateTime->new(year => 2017, month => 12, day => 31);
153
154 # check conversion to csv
155 $datev1->from($startdate);
156 $datev1->to($enddate);
157 # reset use_pk for csv_buchungsexport
158 $datev1->use_pk(0);
159 $datev1->generate_datev_data;
160
161
162 my ($datev_ref, $w_ref) = SL::DATEV::CSV->new(datev_lines  => $datev1->generate_datev_lines,
163                                               from         => $startdate,
164                                               to           => $enddate,
165                                               locked       => $datev1->locked,
166                                    );
167 # warnings should be undef -> no array elements at all
168 is(scalar @{ $w_ref }, 0);
169
170 # splice away the header, because sort won't do
171 # we need sort, because pay_invoice is not acc_trans_id order safe
172 my @data_csv = splice @{ $datev_ref }, 2, 5;
173 @data_csv    = sort { $a->[0] cmp $b->[0] } @data_csv;
174
175 cmp_bag($data_csv[1], [ 535, 'S', 'EUR', '', '', '', '1400', '8300', '', '0101', "\x{de} sales \x{a5}& i",
176                      '', '', '', '', '', '', '', '', '', '', '',
177                      '', '', '', '', '', '', '', '', '', '', '', '', '',
178                      '', 'Crowd-Fu', 'Kostenst', '', '', '', '', '', '', '', '',
179                      '', '', '', '', '', '', '', '', '', '', '', '', '',
180                      '', '', '', '', '', '', '', '', '', '', '', '', '',
181                      '', '', '', '', '', '', '', '', '', '', '', '', '',
182                      '', '', '', '', '', '', '', '', '', '', '', '', '',
183                      '', '', '', '', '', '', '', '', '', '', '', '', '',
184                      '', '', '', '', '' ]
185        );
186
187 cmp_bag($data_csv[0], [ '249,9', 'S', 'EUR', '', '', '', '1400', '8400', '', '0101', "\x{de} sales \x{a5}& i",
188                      '', '', '', '', '', '', '', '', '', '', '',
189                      '', '', '', '', '', '', '', '', '', '', '', '', '',
190                      '', 'Crowd-Fu', 'Kostenst', '', '', '', '', '', '', '', '',
191                      '', '', '', '', '', '', '', '', '', '', '', '', '',
192                      '', '', '', '', '', '', '', '', '', '', '', '', '',
193                      '', '', '', '', '', '', '', '', '', '', '', '', '',
194                      '', '', '', '', '', '', '', '', '', '', '', '', '',
195                      '', '', '', '', '', '', '', '', '', '', '', '', '',
196                      '', '', '', '', '' ]
197        );
198 cmp_bag($data_csv[2], [ '784,9', 'S', 'EUR', '', '', '', '1200', '1400', '', '0501', "\x{de} sales \x{a5}& i",
199                      '', '', '', '', '', '', '', '', '', '', '',
200                      '', '', '', '', '', '', '', '', '', '', '', '', '',
201                      '', 'Crowd-Fu', 'Kostenst', '', '', '', '', '', '', '', '',
202                      '', '', '', '', '', '', '', '', '', '', '', '', '',
203                      '', '', '', '', '', '', '', '', '', '', '', '', '',
204                      '', '', '', '', '', '', '', '', '', '', '', '', '',
205                      '', '', '', '', '', '', '', '', '', '', '', '', '',
206                      '', '', '', '', '', '', '', '', '', '', '', '', '',
207                      '', '', '', '', '' ]
208         );
209 my $march_9 = DateTime->new(year => 2017, month =>  3, day => 9);
210 my $invoice2 = create_sales_invoice(
211   invnumber    => "2 sales invoice",
212   customer     => $customer,
213   itime        => $march_9,
214   gldate       => $march_9,
215   intnotes     => 'booked in March',
216   taxincluded  => 0,
217   transdate    => $date,
218   invoiceitems => [ create_invoice_item(part => $part1, qty =>  6, sellprice => 70),
219                     create_invoice_item(part => $part2, qty => 20, sellprice => 50),
220                   ]
221 );
222
223 my $credit_note = create_credit_note(
224   invnumber    => 'Gutschrift 34',
225   customer     => $customer,
226   itime        => $gldate,
227   gldate       => $gldate,
228   intnotes     => 'booked in February',
229   taxincluded  => 0,
230   transdate    => $date,
231   invoiceitems => [ create_invoice_item(part => $part1, qty =>  3, sellprice => 70),
232                     create_invoice_item(part => $part2, qty => 10, sellprice => 50),
233                   ]
234 );
235
236 my $datev = SL::DATEV->new(
237   dbh        => $dbh,
238   from       => $startdate,
239   to         => $enddate,
240 );
241 $datev->generate_datev_data(from_to => $datev->fromto);
242 my $datev_lines = $datev->generate_datev_lines;
243 my $umsatzsumme = sum map { $_->{umsatz} } @{ $datev_lines };
244 cmp_ok($::form->round_amount($umsatzsumme,2), '==', 3924.5, "Sum of all bookings ok");
245
246 $datev->generate_datev_data(use_pk => 1, from_to => $datev->fromto);
247 $datev_lines = $datev->generate_datev_lines;
248
249 note('testing purchase invoice');
250 my $purchase_invoice = new_purchase_invoice();
251 $datev1 = SL::DATEV->new(
252   dbh        => $purchase_invoice->db->dbh,
253   trans_id   => $purchase_invoice->id,
254 );
255
256 $datev1->generate_datev_data;
257 cmp_bag $datev1->generate_datev_lines, [
258                                         {
259                                           'belegfeld1'             => 'ap1',
260                                           'buchungstext'           => 'Testvendor',
261                                           'datum'                  => '01.01.2017',
262                                           'gegenkonto'             => '1600',
263                                           'konto'                  => '3400',
264                                           'kost1'                  => undef,
265                                           'kost2'                  => undef,
266                                           'soll_haben_kennzeichen' => 'H',
267                                           'umsatz'                 => 119,
268                                           'waehrung'               => 'EUR'
269                                         },
270                                         {
271                                           'belegfeld1'             => 'ap1',
272                                           'buchungstext'           => 'Testvendor',
273                                           'datum'                  => '01.01.2017',
274                                           'gegenkonto'             => '1600',
275                                           'konto'                  => '3300',
276                                           'kost1'                  => undef,
277                                           'kost2'                  => undef,
278                                           'soll_haben_kennzeichen' => 'H',
279                                           'umsatz'                 => 107,
280                                           'waehrung'               => 'EUR'
281                                         }
282                                        ], "trans_id datev check purchase_invoice ok";
283 $datev1->use_pk(1);
284 $datev1->generate_datev_data;
285 cmp_bag $datev1->generate_datev_lines, [
286                                         {
287                                           'belegfeld1'             => 'ap1',
288                                           'buchungstext'           => 'Testvendor',
289                                           'datum'                  => '01.01.2017',
290                                           'gegenkonto'             => $vendor->vendornumber,
291                                           'konto'                  => '3400',
292                                           'kost1'                  => undef,
293                                           'kost2'                  => undef,
294                                           'soll_haben_kennzeichen' => 'H',
295                                           'umsatz'                 => 119,
296                                           'waehrung'               => 'EUR'
297                                         },
298                                         {
299                                           'belegfeld1'             => 'ap1',
300                                           'buchungstext'           => 'Testvendor',
301                                           'datum'                  => '01.01.2017',
302                                           'gegenkonto'             => $vendor->vendornumber,
303                                           'konto'                  => '3300',
304                                           'kost1'                  => undef,
305                                           'kost2'                  => undef,
306                                           'soll_haben_kennzeichen' => 'H',
307                                           'umsatz'                 => 107,
308                                           'waehrung'               => 'EUR'
309                                         }
310                                        ], "trans_id datev check purchase_invoice use_pk ok";
311
312 note('testing gldatefrom');
313 $datev = SL::DATEV->new(
314   dbh        => $dbh,
315   from       => $startdate,
316   to         => DateTime->new(year => 2017, month => 01, day => 31),
317 );
318
319 $::form               = Support::TestSetup->create_new_form;
320 $::form->{gldatefrom} = DateTime->new(year => 2017, month => 3, day => 1)->to_kivitendo;
321
322 $datev->generate_datev_data(from_to => $datev->fromto);
323 $datev_lines = $datev->generate_datev_lines;
324 $umsatzsumme = sum map { $_->{umsatz} } @{ $datev_lines };
325 cmp_ok($umsatzsumme, '==', 1569.8, "Sum of bookings made after March 1st (only invoice2) ok");
326
327 $::form->{gldatefrom} = DateTime->new(year => 2017, month => 5, day => 1)->to_kivitendo;
328 $datev->generate_datev_data(from_to => $datev->fromto);
329 cmp_bag $datev->generate_datev_lines, [], "no bookings for January made after May 1st: ok";
330
331 done_testing();
332 # clear_up();
333
334 sub new_purchase_invoice {
335   # manually create a Kreditorenbuchung from scratch, ap + acc_trans bookings, as no helper exists yet, like $invoice->post.
336   # arap-Booking must come last in the acc_trans order
337   # this function was essentially copied from t/db_helper/payment.t, refactor once $purchase_invoice->post exists
338   my $currency_id = $::instance_conf->get_currency_id;
339   my $employee    = SL::DB::Manager::Employee->current                          || die "No employee";
340   my $taxzone     = SL::DB::Manager::TaxZone->find_by( description => 'Inland') || die "No taxzone";
341
342   my $purchase_invoice = SL::DB::PurchaseInvoice->new(
343     amount      => '226',
344     currency_id => $currency_id,
345     employee_id => $employee->id,
346     gldate      => $date,
347     invnumber   => "ap1",
348     invoice     => 0,
349     itime       => $date,
350     mtime       => $date,
351     netamount   => '200',
352     paid        => '0',
353     taxincluded => 0,
354     taxzone_id  => $taxzone->id,
355     transdate   => $date,
356     type        => 'invoice',
357     vendor_id   => $vendor->id,
358   )->save;
359
360   my $expense_chart  = SL::DB::Manager::Chart->find_by(accno => '3400');
361   my $expense_chart_booking= SL::DB::AccTransaction->new(
362     amount     => '-100',
363     chart_id   => $expense_chart->id,
364     chart_link => $expense_chart->link,
365     itime      => $date,
366     mtime      => $date,
367     source     => '',
368     tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 9)->id,
369     taxkey     => 9,
370     transdate  => $date,
371     trans_id   => $purchase_invoice->id,
372   );
373   $expense_chart_booking->save;
374
375   my $tax_chart  = SL::DB::Manager::Chart->find_by(accno => '1576');
376   my $tax_chart_booking= SL::DB::AccTransaction->new(
377     amount     => '-19',
378     chart_id   => $tax_chart->id,
379     chart_link => $tax_chart->link,
380     itime      => $date,
381     mtime      => $date,
382     source     => '',
383     tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 9)->id,
384     taxkey     => 0,
385     transdate  => $date,
386     trans_id   => $purchase_invoice->id,
387   );
388   $tax_chart_booking->save;
389   $expense_chart  = SL::DB::Manager::Chart->find_by(accno => '3300');
390   $expense_chart_booking= SL::DB::AccTransaction->new(
391     amount     => '-100',
392     chart_id   => $expense_chart->id,
393     chart_link => $expense_chart->link,
394     itime      => $date,
395     mtime      => $date,
396     source     => '',
397     tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 8)->id,
398     taxkey     => 8,
399     transdate  => $date,
400     trans_id   => $purchase_invoice->id,
401   );
402   $expense_chart_booking->save;
403
404   $tax_chart  = SL::DB::Manager::Chart->find_by(accno => '1571');
405   $tax_chart_booking= SL::DB::AccTransaction->new(
406     trans_id   => $purchase_invoice->id,
407     chart_id   => $tax_chart->id,
408     chart_link => $tax_chart->link,
409     amount     => '-7',
410     transdate  => $date,
411     itime      => $date,
412     mtime      => $date,
413     source     => '',
414     taxkey     => 0,
415     tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 8)->id,
416   );
417   $tax_chart_booking->save;
418   my $arap_chart  = SL::DB::Manager::Chart->find_by(accno => '1600');
419   my $arap_booking= SL::DB::AccTransaction->new(
420     trans_id   => $purchase_invoice->id,
421     chart_id   => $arap_chart->id,
422     chart_link => $arap_chart->link,
423     amount     => '226',
424     transdate  => $date,
425     itime      => $date,
426     mtime      => $date,
427     source     => '',
428     taxkey     => 0,
429     tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 0)->id,
430   );
431   $arap_booking->save;
432
433   return $purchase_invoice;
434 }
435
436 sub clear_up {
437   SL::DB::Manager::AccTransaction->delete_all(all => 1);
438   SL::DB::Manager::InvoiceItem->delete_all(   all => 1);
439   SL::DB::Manager::Invoice->delete_all(       all => 1);
440   SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
441   SL::DB::Manager::Customer->delete_all(      all => 1);
442   SL::DB::Manager::Part->delete_all(          all => 1);
443   SL::DB::Manager::Project->delete_all(       all => 1);
444   SL::DB::Manager::Department->delete_all(    all => 1);
445   SL::DATEV->clean_temporary_directories;
446 };
447
448 1;