3b2d4af57ac385441d4a1a74a856d6defc4afa33
[kivitendo-erp.git] / t / datev / invoices.t
1 use strict;
2 use Test::More;
3 use Test::Deep qw(cmp_deeply 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_deeply \@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                                            'locked'       => undef,
77                                            'umsatz'       => '249.9',
78                                            'waehrung'     => 'EUR',
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                                            'locked'       => undef,
89                                            'umsatz'       => 535,
90                                            'waehrung'     => 'EUR',
91                                          },
92                                          {
93                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
94                                            'buchungstext' => 'Testcustomer',
95                                            'buchungstext' => 'Testcustomer',
96                                            'datum'        => '05.01.2017',
97                                            'gegenkonto'   => '1400',
98                                            'konto'        => '1200',
99                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
100                                            'kost2'        => 'Crowd-Funding September 2017',
101                                            'umsatz'       => '784.9',
102                                            'locked'       => undef,
103                                            'waehrung'     => 'EUR',
104                                          },
105                                        ], "trans_id datev check ok";
106
107 $datev1->use_pk(1);
108 $datev1->generate_datev_data;
109 # TODO for cmp_deeply we need to sort the incoming data structure (see below)
110 cmp_bag $datev1->generate_datev_lines, [
111                                          {
112                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
113                                            'buchungstext' => 'Testcustomer',
114                                            'datum'        => '01.01.2017',
115                                            'gegenkonto'   => '8400',
116                                            'konto'        => $customer->customernumber,
117                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
118                                            'kost2'        => 'Crowd-Funding September 2017',
119                                            'umsatz'       => '249.9',
120                                            'locked'       => undef,
121                                            'waehrung'     => 'EUR',
122                                          },
123                                          {
124                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
125                                            'buchungstext' => 'Testcustomer',
126                                            'datum'        => '01.01.2017',
127                                            'gegenkonto'   => '8300',
128                                            'konto'        => $customer->customernumber,
129                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
130                                            'kost2'        => 'Crowd-Funding September 2017',
131                                            'umsatz'       => 535,
132                                            'locked'       => undef,
133                                            'waehrung'     => 'EUR',
134                                          },
135                                          {
136                                            'belegfeld1'   => "\x{de} sales \x{a5}& inv\x{f6}ice",
137                                            'buchungstext' => 'Testcustomer',
138                                            'datum'        => '05.01.2017',
139                                            'gegenkonto'   => $customer->customernumber,
140                                            'konto'        => '1200',
141                                            'kost1'        => 'Kostenstelle DATEV-Schnittstelle 2018',
142                                            'kost2'        => 'Crowd-Funding September 2017',
143                                            'umsatz'       => '784.9',
144                                            'locked'       => undef,
145                                            'waehrung'     => 'EUR',
146                                          },
147                                        ], "trans_id datev check use_pk ok";
148
149
150 my $startdate = DateTime->new(year => 2017, month =>  1, day =>  1);
151 my $enddate   = DateTime->new(year => 2017, month => 12, day => 31);
152
153 # check conversion to csv
154 $datev1->from($startdate);
155 $datev1->to($enddate);
156 # reset use_pk for csv_buchungsexport
157 $datev1->use_pk(0);
158 $datev1->generate_datev_data;
159
160
161 my $datev_csv = SL::DATEV::CSV->new(datev_lines  => $datev1->generate_datev_lines,
162                                     from         => $startdate,
163                                     to           => $enddate,
164                                     locked       => $datev1->locked,
165                                    );
166 $datev_csv->lines;
167
168
169 # we need sort, because pay_invoice is not acc_trans_id order safe
170 my @data_csv    = sort { $a->[0] cmp $b->[0] } @{ $datev_csv->lines };
171 # warnings should be undef -> no array elements at all
172 is(scalar @{ $datev_csv->warnings }, 0);
173
174
175 cmp_deeply($data_csv[1], [ '535', 'S', 'EUR', '', '', '', '1400', '8300', '', '0101', "\x{de} sales \x{a5}& i",
176                      '', '', 'Testcustomer', '', '', '', '', '', '', '', '',
177                      '', '', '', '', '', '', '', '', '', '', '', '', '',
178                      '', 'Kostenst', 'Crowd-Fu', '', '', '', '', '', '', '', '',
179                      '', '', '', '', '', '', '', '', '', '', '', '', '',
180                      '', '', '', '', '', '', '', '', '', '', '', '', '',
181                      '', '', '', '', '', '', '', '', '', '', '', '', '',
182                      '', '', '', '', '', '', '', '', '', '', '', '', '',
183                      '', '', '', '', '', '', '', '', '', '', '', '', '',
184                      '', '', '1', '', '', '', '', '', '' ]
185        );
186
187 cmp_deeply($data_csv[0], [ '249,9', 'S', 'EUR', '', '', '', '1400', '8400', '', '0101', "\x{de} sales \x{a5}& i",
188                      '', '', 'Testcustomer', '', '', '', '', '', '', '', '',
189                      '', '', '', '', '', '', '', '', '', '', '', '', '',
190                      '', 'Kostenst', 'Crowd-Fu', '', '', '', '', '', '', '', '',
191                      '', '', '', '', '', '', '', '', '', '', '', '', '',
192                      '', '', '', '', '', '', '', '', '', '', '', '', '',
193                      '', '', '', '', '', '', '', '', '', '', '', '', '',
194                      '', '', '', '', '', '', '', '', '', '', '', '', '',
195                      '', '', '', '', '', '', '', '', '', '', '', '', '',
196                      '', '', '1', '', '', '', '', '', '' ]
197        );
198 cmp_deeply($data_csv[2], [ '784,9', 'S', 'EUR', '', '', '', '1200', '1400', '', '0501', "\x{de} sales \x{a5}& i",
199                      '', '', 'Testcustomer', '', '', '', '', '', '', '', '',
200                      '', '', '', '', '', '', '', '', '', '', '', '', '',
201                      '', 'Kostenst', 'Crowd-Fu', '', '', '', '', '', '', '', '',
202                      '', '', '', '', '', '', '', '', '', '', '', '', '',
203                      '', '', '', '', '', '', '', '', '', '', '', '', '',
204                      '', '', '', '', '', '', '', '', '', '', '', '', '',
205                      '', '', '', '', '', '', '', '', '', '', '', '', '',
206                      '', '', '', '', '', '', '', '', '', '', '', '', '',
207                      '', '', '1', '', '', '', '', '', '' ]
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 = create_ap_transaction(
251   vendor      => $vendor,
252   invnumber   => 'ap1',
253   amount      => '226',
254   netamount   => '200',
255   transdate   => $date,
256   gldate      => $date,
257   itime       => $date, # make sure itime is 1.1., as gldatefrom tests for itime!
258   taxincluded => 0,
259   bookings    => [
260                    {
261                      chart  => SL::DB::Manager::Chart->find_by(accno => '3400'),
262                      amount => 100,
263                    },
264                    {
265                      chart  => SL::DB::Manager::Chart->find_by(accno => '3300'),
266                      amount => 100,
267                    },
268                  ],
269 );
270
271 $datev1 = SL::DATEV->new(
272   dbh        => $purchase_invoice->db->dbh,
273   trans_id   => $purchase_invoice->id,
274 );
275
276 $datev1->generate_datev_data;
277 cmp_deeply $datev1->generate_datev_lines, [
278                                         {
279                                           'belegfeld1'             => 'ap1',
280                                           'buchungstext'           => 'Testvendor',
281                                           'datum'                  => '01.01.2017',
282                                           'gegenkonto'             => '1600',
283                                           'konto'                  => '3400',
284                                           'kost1'                  => undef,
285                                           'kost2'                  => undef,
286                                           'umsatz'                 => 119,
287                                           'locked'                 => undef,
288                                           'waehrung'               => 'EUR'
289                                         },
290                                         {
291                                           'belegfeld1'             => 'ap1',
292                                           'buchungstext'           => 'Testvendor',
293                                           'datum'                  => '01.01.2017',
294                                           'gegenkonto'             => '1600',
295                                           'konto'                  => '3300',
296                                           'kost1'                  => undef,
297                                           'kost2'                  => undef,
298                                           'umsatz'                 => 107,
299                                           'locked'                 => undef,
300                                           'waehrung'               => 'EUR'
301                                         }
302                                        ], "trans_id datev check purchase_invoice ok";
303 $datev1->use_pk(1);
304 $datev1->generate_datev_data;
305 cmp_deeply $datev1->generate_datev_lines, [
306                                         {
307                                           'belegfeld1'             => 'ap1',
308                                           'buchungstext'           => 'Testvendor',
309                                           'datum'                  => '01.01.2017',
310                                           'gegenkonto'             => $vendor->vendornumber,
311                                           'konto'                  => '3400',
312                                           'kost1'                  => undef,
313                                           'kost2'                  => undef,
314                                           'umsatz'                 => 119,
315                                           'locked'                 => undef,
316                                           'waehrung'               => 'EUR'
317                                         },
318                                         {
319                                           'belegfeld1'             => 'ap1',
320                                           'buchungstext'           => 'Testvendor',
321                                           'datum'                  => '01.01.2017',
322                                           'gegenkonto'             => $vendor->vendornumber,
323                                           'konto'                  => '3300',
324                                           'kost1'                  => undef,
325                                           'kost2'                  => undef,
326                                           'umsatz'                 => 107,
327                                           'locked'                 => undef,
328                                           'waehrung'               => 'EUR'
329                                         }
330                                        ], "trans_id datev check purchase_invoice use_pk ok";
331
332 note('testing gldatefrom');
333 # test an order with transdate in january, but that was booked in march
334 # gldatefrom in DATEV.pm checks for itime, not gldate!!!
335 $datev = SL::DATEV->new(
336   dbh        => $dbh,
337   from       => $startdate,
338   to         => DateTime->new(year => 2017, month => 01, day => 31),
339 );
340
341 $::form               = Support::TestSetup->create_new_form;
342 $::form->{gldatefrom} = DateTime->new(year => 2017, month => 3, day => 1)->to_kivitendo;
343
344 $datev->generate_datev_data(from_to => $datev->fromto);
345 $datev_lines = $datev->generate_datev_lines;
346 $umsatzsumme = sum map { $_->{umsatz} } @{ $datev_lines };
347 cmp_ok($umsatzsumme, '==', 1569.8, "Sum of bookings made after March 1st (only invoice2) ok");
348
349 $::form->{gldatefrom} = DateTime->new(year => 2017, month => 5, day => 1)->to_kivitendo;
350 $datev->generate_datev_data(from_to => $datev->fromto);
351 cmp_deeply $datev->generate_datev_lines, [], "no bookings for January made after May 1st: ok";
352
353 done_testing();
354 clear_up();
355
356 sub clear_up {
357   SL::DB::Manager::AccTransaction->delete_all(all => 1);
358   SL::DB::Manager::InvoiceItem->delete_all(   all => 1);
359   SL::DB::Manager::Invoice->delete_all(       all => 1);
360   SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
361   SL::DB::Manager::Customer->delete_all(      all => 1);
362   SL::DB::Manager::Part->delete_all(          all => 1);
363   SL::DB::Manager::Project->delete_all(       all => 1);
364   SL::DB::Manager::Department->delete_all(    all => 1);
365   SL::DATEV->clean_temporary_directories;
366 };
367
368 1;