1 use Test::More tests => 38;
2 use Test::Deep qw(cmp_deeply);
9 use Support::TestSetup;
15 use SL::DB::GLTransaction;
17 use SL::DBUtils qw(selectall_hashref_query);
18 use SL::Dev::Record qw(:ALL);
19 use SL::Dev::CustomerVendor qw(new_customer new_vendor);
20 use SL::Dev::Part qw(new_part);
23 Support::TestSetup::login();
24 my $dbh = SL::DB->client->dbh;
26 my $test_kontenrahmen = 'skr03';
30 # TODOs: Storno muß noch korrekt funktionieren
31 # neue Konten für 5% anlegen
32 # Leistungszeitraum vs. Datum Zuord. Steuerperiodest
34 note('checking if all tax entries exist for Konjunkturprogramm');
36 # create dates to test on
37 my $date_2006 = DateTime->new(year => 2006, month => 6, day => 15);
38 my $date_2020_1 = DateTime->new(year => 2020, month => 6, day => 15);
39 my $date_2020_2 = DateTime->new(year => 2020, month => 7, day => 15);
40 my $date_2021 = DateTime->new(year => 2021, month => 1, day => 15);
42 # The only way to discern the pre-2007 16% tax from the 2020 16% tax is by
43 # their configured automatic tax charts, so look them up here:
45 my ($chart_vst_19, $chart_vst_16, $chart_vst_5, $chart_vst_7);
46 my ($chart_ust_19, $chart_ust_16, $chart_ust_5, $chart_ust_7);
47 my ($income_19_accno, $income_7_accno);
48 my ($ar_accno, $ap_accno);
49 my ($chart_reisekosten_accno, $chart_cash_accno, $chart_bank_accno);
52 if ( $test_kontenrahmen eq 'skr03' ) {
54 is(SL::DB::Default->get->coa, 'Germany-DATEV-SKR03EU', "coa SKR03 ok");
56 $chart_vst_19 = '1776';
57 $chart_vst_16 = '1775';
58 $chart_vst_5 = '1773';
59 $chart_vst_7 = '1771';
61 $chart_ust_19 = '1576';
62 $chart_ust_16 = '1575';
63 $chart_ust_5 = '1568';
64 $chart_ust_7 = '1571';
66 $income_19_accno = '8400';
67 $income_7_accno = '8300';
69 $chart_reisekosten_accno = 4660;
70 $chart_cash_accno = 1000;
75 } elsif ( $test_kontenrahmen eq 'skr04') { # skr04 - test can be ran manually by running t/000setup_database.t with coa for SKR04
76 is(SL::DB::Default->get->coa, 'Germany-DATEV-SKR04EU', "coa SKR04 ok");
77 $chart_ust_19 = '1406';
78 $chart_ust_16 = '1405';
79 $chart_ust_5 = '1403';
80 $chart_ust_7 = '1401';
82 $chart_vst_19 = '3806';
83 $chart_vst_16 = '3805';
84 $chart_vst_5 = '3803';
85 $chart_vst_7 = '3801';
87 $income_19_accno = '4400';
88 $income_7_accno = '4300';
90 $chart_reisekosten_accno = 6650;
91 $chart_cash_accno = 1600;
97 my $tax_vst_19 = SL::DB::Manager::Chart->find_by(accno => $chart_vst_19) or die; # 19%
98 my $tax_vst_16 = SL::DB::Manager::Chart->find_by(accno => $chart_vst_16) or die; # 16%
99 my $tax_vst_5 = SL::DB::Manager::Chart->find_by(accno => $chart_vst_5 ) or die; # 5%
100 my $tax_vst_7 = SL::DB::Manager::Chart->find_by(accno => $chart_vst_7 ) or die; # 7%
102 my $tax_ust_19 = SL::DB::Manager::Chart->find_by(accno => $chart_ust_19) or die; # 19%
103 my $tax_ust_16 = SL::DB::Manager::Chart->find_by(accno => $chart_ust_16) or die; # 16%
104 my $tax_ust_5 = SL::DB::Manager::Chart->find_by(accno => $chart_ust_5) or die; # 5%
105 my $tax_ust_7 = SL::DB::Manager::Chart->find_by(accno => $chart_ust_7) or die; # 7%
107 my $chart_income_19 = SL::DB::Manager::Chart->find_by(accno => $income_19_accno) or die;
108 my $chart_income_7 = SL::DB::Manager::Chart->find_by(accno => $income_7_accno) or die;
110 my $chart_reisekosten = SL::DB::Manager::Chart->find_by(accno => $chart_reisekosten_accno) or die;
111 my $chart_cash = SL::DB::Manager::Chart->find_by(accno => $chart_cash_accno) or die;
113 is(defined SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.05), 1, "tax for taxkey 2 with 5% was created ok");
114 is(defined SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.16, chart_id => $tax_vst_16->id), 1, "new sales tax for taxkey 3 with 16% exists ok");
115 is(defined SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, chart_id => $tax_vst_19->id), 1, "old sales tax for taxkey 3 with 19% exists ok");
116 is(defined SL::DB::Manager::Tax->find_by(taxkey => 5, rate => 0.16, chart_id => $tax_vst_16->id), 1, "new sales tax for taxkey 5 with 16% exists ok");
118 is(defined SL::DB::Manager::Tax->find_by(taxkey => 7, rate => 0.16, chart_id => $tax_ust_16->id), 1, "old purchase tax for taxkey 7 with 16% exists ok");
119 # is(defined SL::DB::Manager::Tax->find_by(taxkey => 8, rate => 0.07, chart_id => $tax_ust_16->id), 1, "old purchase tax for taxkey 7 with 16% exists ok");
120 is(defined SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.19, chart_id => $tax_ust_19->id), 1, "old purchase tax for taxkey 9 with 19% exists ok");
121 is(defined SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.16, chart_id => $tax_ust_16->id), 1, "new purchase tax for taxkey 9 with 16% exists ok");
123 my $vendor = new_vendor( name => 'Testvendor')->save;
124 my $customer = new_customer(name => 'Testcustomer')->save;
126 # cmp_ok($chart_income_7->get_active_taxkey($date_2020_1)->tax->rate, '==', 0.07, "get_active_taxkey rate for 8300 in 2020_1 ok");
127 # cmp_ok($chart_income_7->get_active_taxkey($date_2020_2)->tax->rate, '==', 0.05, "get_active_taxkey rate for 8300 in 2020_2 ok");
128 # cmp_ok($chart_income_7->get_active_taxkey($date_2021 )->tax->rate, '==', 0.07, "get_active_taxkey rate for 8300 in 2021 ok");
129 cmp_ok($chart_income_7->get_active_taxkey($date_2020_1)->tax->rate, '==', 0.07, "get_active_taxkey rate for $income_7_accno in 2020_1 ok");
130 cmp_ok($chart_income_7->get_active_taxkey($date_2020_2)->tax->rate, '==', 0.05, "get_active_taxkey rate for $income_7_accno in 2020_2 ok");
131 cmp_ok($chart_income_7->get_active_taxkey($date_2021 )->tax->rate, '==', 0.07, "get_active_taxkey rate for $income_7_accno in 2021 ok");
132 cmp_ok($chart_income_7->get_active_taxkey($date_2006 )->tax->rate, '==', 0.07, "get_active_taxkey rate for $income_7_accno in 2016 ok");
134 cmp_ok($chart_income_19->get_active_taxkey($date_2020_1)->tax->rate, '==', 0.19, "get_active_taxkey rate for $income_19_accno in 2020_1 ok");
135 cmp_ok($chart_income_19->get_active_taxkey($date_2020_2)->tax->rate, '==', 0.16, "get_active_taxkey rate for $income_19_accno in 2020_2 ok");
136 cmp_ok($chart_income_19->get_active_taxkey($date_2021 )->tax->rate, '==', 0.19, "get_active_taxkey rate for $income_19_accno in 2021 ok");
137 cmp_ok($chart_income_19->get_active_taxkey($date_2006 )->tax->rate, '==', 0.16, "get_active_taxkey rate for $income_19_accno in 2016 ok");
139 my $bugru19 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 19%') or die "Can't find bugru19";
140 my $bugru7 = SL::DB::Manager::Buchungsgruppe->find_by(description => 'Standard 7%' ) or die "Can't find bugru7";
142 my $part1 = new_part(partnumber => '1', description => 'part19', buchungsgruppen_id => $bugru19->id)->save;
143 my $part2 = new_part(partnumber => '2', description => 'part7', buchungsgruppen_id => $bugru7->id )->save;
145 note('sales invoices');
146 my $sales_invoice_2006 = create_invoice_for_date('2006', $date_2006);
147 my $sales_invoice_2020_1 = create_invoice_for_date('2020_1', $date_2020_1);
148 my $sales_invoice_2020_2 = create_invoice_for_date('2020_2', $date_2020_2);
149 my $sales_invoice_2021 = create_invoice_for_date('2021', $date_2021);
151 is($sales_invoice_2006->amount, 223, '2006 sales invoice has 16% and 7% tax ok' ); # 116 + 7
152 is($sales_invoice_2020_1->amount, 226, '2020_01 sales invoice has 19% and 7% tax ok'); # 119 + 7
153 is($sales_invoice_2020_2->amount, 221, '2020_02 sales invoice has 16% and 5% tax ok'); # 116 + 5
154 is($sales_invoice_2021->amount, 226, '2021 sales invoice has 19% and 7% tax ok' ); # 119 + 7
156 &datev_test($sales_invoice_2020_2,
159 'belegfeld1' => 'test is 2020_2',
160 'buchungstext' => 'Testcustomer',
161 'datum' => '15.07.2020',
162 'leistungsdatum' => '15.07.2020', # should leistungsdatum be empty if it doesn't exist?
163 'gegenkonto' => $income_7_accno,
164 'konto' => $ar_accno,
172 'belegfeld1' => 'test is 2020_2',
173 'buchungstext' => 'Testcustomer',
174 'datum' => '15.07.2020',
175 'leistungsdatum' => '15.07.2020',
176 'gegenkonto' => $income_19_accno,
177 'konto' => $ar_accno,
185 "datev check for 16/5 ok, no taxkey"
188 note('sales invoice with differing delivery dates');
189 my $sales_invoice_2020_1_with_delivery_date_2020_2 = create_invoice_for_date('deliverydate 2020_1', $date_2020_1, $date_2020_2);
190 is($sales_invoice_2020_1_with_delivery_date_2020_2->amount, 221, "sales_invoice from 2020_1 with future delivery_date 2020_2 tax ok");
192 my $sales_invoice_2020_2_with_delivery_date_2020_1 = create_invoice_for_date('deliverydate 2020_2', $date_2020_2, $date_2020_1);
193 is($sales_invoice_2020_2_with_delivery_date_2020_1->amount, 226, "sales_invoice from 2020_2 with past delivery_date 2020_1 tax ok");
195 &datev_test($sales_invoice_2020_2_with_delivery_date_2020_1,
198 'belegfeld1' => 'test is deliverydate 2020_2',
199 'buchungstext' => 'Testcustomer',
200 'datum' => '15.07.2020',
201 'gegenkonto' => $income_7_accno,
202 'konto' => $ar_accno,
205 'leistungsdatum' => '15.06.2020',
211 'belegfeld1' => 'test is deliverydate 2020_2',
212 'buchungstext' => 'Testcustomer',
213 'datum' => '15.07.2020',
214 'gegenkonto' => $income_19_accno,
215 'konto' => $ar_accno,
218 'leistungsdatum' => '15.06.2020',
224 "datev check for datev export with delivery_date 19/7 ok, no taxkey"
227 my $sales_invoice_2021_with_delivery_date_2020_2 = create_invoice_for_date('deliverydate 2020_2', $date_2021, $date_2020_2);
228 is($sales_invoice_2021_with_delivery_date_2020_2->amount, 221, "sales_invoice from 2021 with past delivery_date 2020_2 tax ok");
230 my $sales_invoice_2020_2_with_delivery_date_2021 = create_invoice_for_date('deliverydate 2021', $date_2020_2, $date_2021);
231 is($sales_invoice_2020_2_with_delivery_date_2021->amount, 226, "sales_invoice from 2020_2 with future delivery_date 2021 tax ok");
234 note('ap transactions');
235 # in the test we want to test for Reisekosten with 19% and 7%. Normally the user
236 # would select the entries from the dropdown, as they may differ from the
237 # default, so we have to pass the tax we want to create_ap_transaction
239 my $tax_9_16_old = SL::DB::Manager::Tax->find_by(taxkey => 7, rate => 0.16, chart_id => $tax_ust_16->id);
240 my $tax_9_19 = SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.19, chart_id => $tax_ust_19->id);
241 my $tax_9_16 = SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.16, chart_id => $tax_ust_16->id);
242 my $tax_8_7 = SL::DB::Manager::Tax->find_by(taxkey => 8, rate => 0.07, chart_id => $tax_ust_7->id);
243 my $tax_8_5 = SL::DB::Manager::Tax->find_by(taxkey => 8, rate => 0.05, chart_id => $tax_ust_5->id);
245 # simulate user selecting the "correct" taxes in dropdown:
246 my $ap_transaction_2006 = create_ap_transaction_for_date('2006', $date_2006, undef, $tax_9_16_old, $tax_8_7);
247 my $ap_transaction_2020_1 = create_ap_transaction_for_date('2020_1', $date_2020_1, undef, $tax_9_19, $tax_8_7);
248 my $ap_transaction_2020_2 = create_ap_transaction_for_date('2020_2', $date_2020_2, undef, $tax_9_16, $tax_8_5);
249 my $ap_transaction_2021 = create_ap_transaction_for_date('2021', $date_2021, undef, $tax_9_19, $tax_8_7);
252 is($ap_transaction_2006->amount, 223, '2006 ap transaction has 16% and 7% tax ok'); # 116 + 7
253 is($ap_transaction_2020_1->amount, 226, '2020_01 ap transaction has 19% and 7% tax ok'); # 119 + 7
254 is($ap_transaction_2020_2->amount, 221, '2020_02 ap transaction has 16% and 5% tax ok'); # 116 + 5
255 is($ap_transaction_2021->amount, 226, '2021 ap transaction has 19% and 7% tax ok'); # 119 + 7
257 # ap transaction in july, but use old tax
258 my $ap_transaction_2020_2_with_delivery_date_2020_1 = create_ap_transaction_for_date('2020_2 with delivery date 2020_1', $date_2020_2, $date_2020_1, $tax_9_19, $tax_8_7);
259 is($ap_transaction_2020_2_with_delivery_date_2020_1->amount, 226, 'ap transaction 2020_2 with delivery date 2020_1, 19% and 7% tax ok'); # 119 + 7
260 &datev_test($ap_transaction_2020_2_with_delivery_date_2020_1,
263 'belegfeld1' => 'test ap_transaction 2020_2 with delivery date 2020_1',
264 'buchungsschluessel' => 8,
265 'buchungstext' => 'Testvendor',
266 'datum' => '15.07.2020',
267 'gegenkonto' => $ap_accno,
268 'konto' => $chart_reisekosten_accno,
271 'leistungsdatum' => '15.06.2020',
277 'belegfeld1' => 'test ap_transaction 2020_2 with delivery date 2020_1',
278 'buchungsschluessel' => 9,
279 'buchungstext' => 'Testvendor',
280 'datum' => '15.07.2020',
281 'gegenkonto' => $ap_accno,
282 'konto' => $chart_reisekosten_accno,
285 'leistungsdatum' => '15.06.2020',
291 "datev check for ap transaction 2020_2 with delivery date 2020_1, 19% and 7% tax ok"
294 note('ar transactions');
296 my $ar_transaction_2006 = create_ar_transaction_for_date('2006', $date_2006);
297 my $ar_transaction_2020_1 = create_ar_transaction_for_date('2020_1', $date_2020_1);
298 my $ar_transaction_2020_2 = create_ar_transaction_for_date('2020_2', $date_2020_2);
299 my $ar_transaction_2021 = create_ar_transaction_for_date('2021', $date_2021);
301 is($ar_transaction_2006->amount, 223, '2006 ar transaction has 16% and 7% tax ok'); # 116 + 7
302 is($ar_transaction_2020_1->amount, 226, '2020_01 ar transaction has 19% and 7% tax ok'); # 119 + 7
303 is($ar_transaction_2020_2->amount, 221, '2020_02 ar transaction has 16% and 5% tax ok'); # 116 + 5
304 is($ar_transaction_2021->amount, 226, '2021 ar transaction has 19% and 7% tax ok'); # 119 + 7
306 note('gl transactions');
308 my $gl_2006 = create_gl_transaction_for_date('glincome 2006', $date_2006, 223);
309 my $gl_2020_1 = create_gl_transaction_for_date('glincome 2020_1', $date_2020_1, 226);
310 my $gl_2020_2 = create_gl_transaction_for_date('glincome 2020_2', $date_2020_2, 221);
311 my $gl_2021 = create_gl_transaction_for_date('glincome 2021', $date_2021, 226);
313 is(SL::DB::Manager::GLTransaction->get_all_count(), 4, "4 gltransactions created correctly");
315 my $result = &get_account_balances;
316 # print Dumper($result);
317 is_deeply( &get_account_balances,
321 # # 'description' => 'Kasse',
322 # 'sum' => '-896.00000'
326 # # 'description' => 'Ford. a.Lieferungen und Leistungen',
327 # 'sum' => '-2686.00000'
331 # 'description' => 'Abziehbare Vorsteuer 7%',
336 # 'description' => 'Abziehbare Vorsteuer 7%',
341 # 'description' => 'Abziehbare Vorsteuer 16%',
346 # 'description' => 'Abziehbare Vorsteuer 19 %',
351 # # 'description' => 'Verbindlichkeiten aus Lief.u.Leist.',
352 # 'sum' => '896.00000'
356 # 'description' => 'Umsatzsteuer 7%',
361 # 'description' => 'Umsatzsteuer 5 %',
366 # 'description' => 'Umsatzsteuer 16%',
371 # 'description' => 'Umsatzsteuer 19 %',
376 # # 'description' => 'Reisekosten Arbeitnehmer',
377 # 'sum' => '-800.00000'
380 # 'accno' => $income_7_accno,
381 # # 'description' => "Erl\x{f6}se 7%USt",
382 # 'sum' => '1600.00000'
385 # 'accno' => $income_19_accno,
386 # # 'description' => "Erl\x{f6}se 16%/19% USt.",
387 # 'sum' => '1600.00000'
390 'account balances after invoices'
397 ###### functions for setting up data
399 sub create_invoice_for_date {
400 my ($invnumber, $transdate, $deliverydate) = @_;
402 $deliverydate = $transdate unless defined $deliverydate;
404 my $sales_invoice = create_sales_invoice(
405 invnumber => 'test is ' . $invnumber,
406 transdate => $transdate,
407 customer => $customer,
408 deliverydate => $deliverydate,
410 invoiceitems => [ create_invoice_item(part => $part1, qty => 10, sellprice => 10),
411 create_invoice_item(part => $part2, qty => 10, sellprice => 10),
414 return $sales_invoice;
417 sub create_ar_transaction_for_date {
418 my ($invnumber, $transdate) = @_;
420 my $ar_transaction = create_ar_transaction(
421 customer => $customer,
422 invnumber => 'test ar' . $invnumber,
424 transdate => $transdate,
425 ar_chart => SL::DB::Manager::Chart->find_by(accno => $ar_accno), # pass ar_chart, as it is hardcoded for SKR03 in SL::Dev::Record
428 chart => $chart_income_19,
432 chart => $chart_income_7,
437 return $ar_transaction;
440 sub create_ap_transaction_for_date {
441 my ($invnumber, $transdate, $deliverydate, $tax_high, $tax_low) = @_;
443 # printf("invnumber = %s tax_high = %s tax_low = %s\n", $invnumber, $tax_high->accno , $tax_low->accno);
444 my $taxkey_ = $chart_reisekosten->get_active_taxkey($transdate);
446 my $ap_transaction = create_ap_transaction(
448 invnumber => 'test ap_transaction ' . $invnumber,
450 transdate => $transdate,
451 deliverydate => $deliverydate,
452 ap_chart => SL::DB::Manager::Chart->find_by(accno => $ap_accno), # pass ap_chart, as it is hardcoded for SKR03 in SL::Dev::Record
455 chart => $chart_reisekosten,
457 tax_id => $tax_high->id,
460 chart => $chart_reisekosten,
462 tax_id => $tax_low->id,
466 return $ap_transaction;
469 sub create_gl_transaction_for_date {
470 my ($reference, $transdate, $debitamount) = @_;
472 my $gl_transaction = create_gl_transaction(
473 reference => $reference,
475 transdate => $transdate,
478 chart => $chart_income_19,
484 chart => $chart_income_7,
490 chart => $chart_cash,
491 debit => $debitamount,
497 return $gl_transaction;
500 sub get_account_balances {
502 select c.accno, sum(a.amount)
504 left join chart c on (c.id = a.chart_id)
505 where c.accno ~ '^17' or c.accno ~ '^15'
506 group by c.accno, c.description
510 my $result = selectall_hashref_query($::form, $dbh, $query);
515 my ($invoice, $expected_data, $msg) = @_;
517 my $datev = SL::DATEV->new(
518 dbh => $invoice->db->dbh,
519 trans_id => $invoice->id,
522 $datev->generate_datev_data;
523 my @data_datev = sort { $a->{umsatz} <=> $b->{umsatz} } @{ $datev->generate_datev_lines() };
525 # print Dumper(\@data_datev);
527 cmp_deeply(\@data_datev, $expected_data, $msg);
531 SL::DB::Manager::OrderItem->delete_all(all => 1);
532 SL::DB::Manager::Order->delete_all(all => 1);
533 SL::DB::Manager::InvoiceItem->delete_all(all => 1);
534 SL::DB::Manager::Invoice->delete_all(all => 1);
535 SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
536 SL::DB::Manager::GLTransaction->delete_all(all => 1);
537 SL::DB::Manager::Part->delete_all(all => 1);
538 SL::DB::Manager::Customer->delete_all(all => 1);
539 SL::DB::Manager::Vendor->delete_all(all => 1);