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