Feld auffüllen in eigene Funktion verlagert.
[kivitendo-erp.git] / SL / DATEV.pm
1 #=====================================================================
2 # Lx-Office ERP
3 # Copyright (c) 2004
4 #
5 #  Author: Philip Reetz
6 #   Email: p.reetz@linet-services.de
7 #     Web: http://www.lx-office.org
8 #
9 #
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #======================================================================
23 #
24 # Datev export module
25 #======================================================================
26
27 package DATEV;
28
29 use SL::DBUtils;
30
31 use Data::Dumper;
32
33 sub _fill {
34   $main::lxdebug->enter_sub();
35
36   my $text      = shift;
37   my $field_len = shift;
38   my $fill_char = shift;
39   my $alignment = shift || 'right';
40
41   my $text_len  = length $text;
42
43   if ($field_len < $text_len) {
44     $text = substr $text, 0, $field_len;
45
46   } elsif ($field_len > $text_len) {
47     my $filler = ($fill_char) x ($field_len - $text_len);
48     $text      = $alignment eq 'right' ? $filler . $text : $text . $filler;
49   }
50
51   $main::lxdebug->leave_sub();
52
53   return $text;
54 }
55
56 sub get_datev_stamm {
57   $main::lxdebug->enter_sub();
58
59   my ($self, $myconfig, $form) = @_;
60
61   # connect to database
62   my $dbh = $form->dbconnect($myconfig);
63
64   $query = qq|SELECT * FROM datev|;
65   $sth   = $dbh->prepare($query);
66   $sth->execute || $form->dberror($query);
67
68   my $ref = $sth->fetchrow_hashref(NAME_lc);
69
70   map { $form->{$_} = $ref->{$_} } keys %$ref;
71
72   $sth->finish;
73   $dbh->disconnect;
74   $main::lxdebug->leave_sub();
75 }
76
77 sub save_datev_stamm {
78   $main::lxdebug->enter_sub();
79
80   my ($self, $myconfig, $form) = @_;
81
82   # connect to database
83   my $dbh = $form->dbconnect_noauto($myconfig);
84
85   $query = qq|DELETE FROM datev|;
86   $dbh->do($query) || $form->dberror($query);
87
88   $query = qq|INSERT INTO datev
89               (beraternr, beratername, dfvkz, mandantennr, datentraegernr, abrechnungsnr) VALUES
90               (|
91     . $dbh->quote($form->{beraternr}) . qq|,|
92     . $dbh->quote($form->{beratername}) . qq|,|
93     . $dbh->quote($form->{dfvkz}) . qq|,
94               |
95     . $dbh->quote($form->{mandantennr}) . qq|,|
96     . $dbh->quote($form->{datentraegernr}) . qq|,|
97     . $dbh->quote($form->{abrechnungsnr}) . qq|)|;
98   $sth = $dbh->prepare($query);
99   $sth->execute || $form->dberror($query);
100   $sth->finish;
101
102   $dbh->commit;
103   $dbh->disconnect;
104   $main::lxdebug->leave_sub();
105 }
106
107 sub kne_export {
108   $main::lxdebug->enter_sub();
109
110   my ($self, $myconfig, $form) = @_;
111   my @rc;
112
113   if ($form->{exporttype} == 0) {
114     @rc = &kne_buchungsexport($myconfig, $form);
115   } else {
116     @rc = &kne_stammdatenexport($myconfig, $form);
117   }
118
119   $main::lxdebug->leave_sub();
120
121   return @rc;
122 }
123
124 sub obe_export {
125   $main::lxdebug->enter_sub();
126
127   my ($self, $myconfig, $form) = @_;
128
129   # connect to database
130   my $dbh = $form->dbconnect_noauto($myconfig);
131   $dbh->commit;
132   $dbh->disconnect;
133   $main::lxdebug->leave_sub();
134 }
135
136 sub get_dates {
137   $main::lxdebug->enter_sub();
138
139   my ($zeitraum, $monat, $quartal, $transdatefrom, $transdateto) = @_;
140
141   $fromto = "transdate >= ";
142
143   my @a = localtime;
144   $a[5] += 1900;
145   $jahr = $a[5];
146   if ($zeitraum eq "monat") {
147   SWITCH: {
148       $monat eq "1" && do {
149         $form->{fromdate} = "1.1.$jahr";
150         $form->{todate}   = "31.1.$jahr";
151         last SWITCH;
152       };
153       $monat eq "2" && do {
154         $form->{fromdate} = "1.2.$jahr";
155
156         #this works from 1901 to 2099, 1900 and 2100 fail.
157         $leap = ($jahr % 4 == 0) ? "29" : "28";
158         $form->{todate} = "$leap.2.$jahr";
159         last SWITCH;
160       };
161       $monat eq "3" && do {
162         $form->{fromdate} = "1.3.$jahr";
163         $form->{todate}   = "31.3.$jahr";
164         last SWITCH;
165       };
166       $monat eq "4" && do {
167         $form->{fromdate} = "1.4.$jahr";
168         $form->{todate}   = "30.4.$jahr";
169         last SWITCH;
170       };
171       $monat eq "5" && do {
172         $form->{fromdate} = "1.5.$jahr";
173         $form->{todate}   = "31.5.$jahr";
174         last SWITCH;
175       };
176       $monat eq "6" && do {
177         $form->{fromdate} = "1.6.$jahr";
178         $form->{todate}   = "30.6.$jahr";
179         last SWITCH;
180       };
181       $monat eq "7" && do {
182         $form->{fromdate} = "1.7.$jahr";
183         $form->{todate}   = "31.7.$jahr";
184         last SWITCH;
185       };
186       $monat eq "8" && do {
187         $form->{fromdate} = "1.8.$jahr";
188         $form->{todate}   = "31.8.$jahr";
189         last SWITCH;
190       };
191       $monat eq "9" && do {
192         $form->{fromdate} = "1.9.$jahr";
193         $form->{todate}   = "30.9.$jahr";
194         last SWITCH;
195       };
196       $monat eq "10" && do {
197         $form->{fromdate} = "1.10.$jahr";
198         $form->{todate}   = "31.10.$jahr";
199         last SWITCH;
200       };
201       $monat eq "11" && do {
202         $form->{fromdate} = "1.11.$jahr";
203         $form->{todate}   = "30.11.$jahr";
204         last SWITCH;
205       };
206       $monat eq "12" && do {
207         $form->{fromdate} = "1.12.$jahr";
208         $form->{todate}   = "31.12.$jahr";
209         last SWITCH;
210       };
211     }
212     $fromto .=
213       "'" . $form->{fromdate} . "' and transdate <= '" . $form->{todate} . "'";
214   }
215
216   elsif ($zeitraum eq "quartal") {
217     if ($quartal == 1) {
218       $fromto .=
219         "'01.01." . $jahr . "' and transdate <= '31.03." . $jahr . "'";
220     } elsif ($quartal == 2) {
221       $fromto .=
222         "'01.04." . $jahr . "' and transdate <= '30.06." . $jahr . "'";
223     } elsif ($quartal == 3) {
224       $fromto .=
225         "'01.07." . $jahr . "' and transdate <= '30.09." . $jahr . "'";
226     } elsif ($quartal == 4) {
227       $fromto .=
228         "'01.10." . $jahr . "' and transdate <= '31.12." . $jahr . "'";
229     }
230   }
231
232   elsif ($zeitraum eq "zeit") {
233     $fromto            .= "'" . $transdatefrom . "' and transdate <= '" . $transdateto . "'";
234     my ($yy, $mm, $dd)  = $main::locale->parse_date(\%main::myconfig, $transdatefrom);
235     $jahr               = $yy;
236   }
237
238   $main::lxdebug->leave_sub();
239
240   return ($fromto, $jahr);
241 }
242
243 sub _get_transactions {
244   $main::lxdebug->enter_sub();
245
246   my $fromto   =  shift;
247
248   my $myconfig =  \%main::myconfig;
249   my $form     =  $main::form;
250
251   my $dbh      =  $form->get_standard_dbh($myconfig);
252
253   my @errors   = ();
254
255   $fromto      =~ s/transdate/ac\.transdate/g;
256
257   my %taxes    =  selectall_as_map($form, $dbh, qq|SELECT id, rate FROM tax|, 'id', 'rate');
258
259   my $query    =
260     qq|SELECT ac.oid, ac.transdate, ac.trans_id,ar.id, ac.amount, ac.taxkey,
261          ar.invnumber, ar.duedate, ar.amount as umsatz,
262          ct.name,
263          c.accno, c.taxkey_id as charttax, c.datevautomatik, c.id,
264          t.chart_id, t.rate, t.id AS taxid, t.taxkey AS taxtaxkey
265        FROM acc_trans ac,ar ar, customer ct, chart c
266        LEFT JOIN tax t ON (t.chart_id = c.id)
267        WHERE $fromto
268          AND (ac.trans_id = ar.id)
269          AND (ac.trans_id = ar.id)
270          AND (ar.customer_id = ct.id)
271          AND (ac.chart_id = c.id)
272
273        UNION ALL
274
275        SELECT ac.oid, ac.transdate, ac.trans_id,ap.id, ac.amount, ac.taxkey,
276          ap.invnumber, ap.duedate, ap.amount as umsatz,
277          ct.name,
278          c.accno, c.taxkey_id as charttax, c.datevautomatik, c.id,
279          t.chart_id, t.rate, t.id AS taxid, t.taxkey AS taxtaxkey
280        FROM acc_trans ac, ap ap, vendor ct, chart c
281        LEFT JOIN tax t ON (t.chart_id = c.id)
282        WHERE $fromto
283          AND (ac.trans_id = ap.id)
284          AND (ap.vendor_id = ct.id)
285          AND (ac.chart_id = c.id)
286
287        UNION ALL
288
289        SELECT ac.oid, ac.transdate, ac.trans_id,gl.id, ac.amount, ac.taxkey,
290          gl.reference AS invnumber, gl.transdate AS duedate, ac.amount as umsatz,
291          gl.description AS name,
292          c.accno, c.taxkey_id as charttax, c.datevautomatik, c.id,
293          t.chart_id, t.rate, t.id AS taxid, t.taxkey AS taxtaxkey
294        FROM acc_trans ac, gl gl, chart c
295        LEFT JOIN tax t ON (t.chart_id = c.id)
296        WHERE $fromto
297          AND (ac.trans_id = gl.id)
298          AND (ac.chart_id = c.id)
299
300        ORDER BY trans_id, oid|;
301
302   my $sth     = prepare_execute_query($form, $dbh, $query);
303
304   my @splits;
305   my $counter = 0;
306   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
307     $counter++;
308     if (($counter % 500) == 0) {
309       print("$counter ");
310     }
311
312     my $trans    = [ $ref ];
313
314     my $count    = $ref->{amount};
315     my $firstrun = 1;
316
317     while (abs($count) > 0.01 || $firstrun) {
318       my $ref2 = $sth->fetchrow_hashref(NAME_lc);
319       last unless ($ref2);
320
321       push @{ $trans }, $ref2;
322
323       $count    += $ref2->{amount};
324       $firstrun  = 0;
325     }
326
327     my %taxid_taxkeys = ();
328     my $absumsatz     = 0;
329     if (scalar(@{$trans}) <= 2) {
330       push @{ $form->{DATEV} }, $trans;
331       next;
332     }
333
334     for my $j (0 .. (scalar(@{$trans}) - 1)) {
335       if (abs($trans->[$j]->{'amount'}) > abs($absumsatz)) {
336         $absumsatz     = $trans->[$j]->{'amount'};
337         $notsplitindex = $j;
338       }
339       if (($trans->[$j]->{'taxtaxkey'}) && ($trans->[$j]->{'taxid'})) {
340         $taxid_taxkeys{$trans->[$j]->{'taxtaxkey'}}     = $trans->[$j]->{'taxid'};
341       }
342     }
343
344     my $ml = ($trans->[0]->{'umsatz'} > 0) ? 1 : -1;
345     for my $j (0 .. (scalar(@{$trans}) - 1)) {
346       if (   ($j != $notsplitindex)
347           && ($trans->[$j]->{'chart_id'}  eq "")
348           && (   $trans->[$j]->{'taxkey'} eq ""
349               || $trans->[$j]->{'taxkey'} eq "0"
350               || $trans->[$j]->{'taxkey'} eq "1"
351               || $trans->[$j]->{'taxkey'} eq "10"
352               || $trans->[$j]->{'taxkey'} eq "11")) {
353         my %new_trans = ();
354         map { $new_trans{$_} = $trans->[$notsplitindex]->{$_}; } keys %{ $trans->[$notsplitindex] };
355
356         $absumsatz               += $trans->[$j]->{'amount'};
357         $new_trans{'amount'}      = $trans->[$j]->{'amount'} * (-1);
358         $new_trans{'umsatz'}      = abs($trans->[$j]->{'amount'}) * $ml;
359         $trans->[$j]->{'umsatz'}  = abs($trans->[$j]->{'amount'}) * $ml;
360
361         push @splits, [ \%new_trans, $trans->[$j] ];
362         push @{ $form->{DATEV} }, $splits[-1];
363
364       } elsif (($j != $notsplitindex) && ($trans->[$j]->{'chart_id'} eq "")) {
365         $absumsatz += ($trans->[$j]->{'amount'} * (1 + $taxes{ $taxid_taxkeys{$trans->[$j]->{'taxkey'}} }));
366
367         my %new_trans = ();
368         map { $new_trans{$_} = $trans->[$notsplitindex]->{$_}; } keys %{ $trans->[$notsplitindex] };
369
370         my $tax_rate             = 1 + $taxes{ $taxid_taxkeys{$trans->[$j]->{'taxkey'}} };
371         $new_trans{'amount'}     = $form->round_amount(($trans->[$j]->{'amount'} * $tax_rate * -1), 2);
372         $new_trans{'umsatz'}     = abs($form->round_amount(($trans->[$j]->{'amount'} * $tax_rate), 2)) * $ml;
373         $trans->[$j]->{'umsatz'} = abs($form->round_amount(($trans->[$j]->{'amount'} * $tax_rate), 2)) * $ml;
374
375         push @splits, [ \%new_trans, $trans->[$j] ];
376         push @{ $form->{DATEV} }, $splits[-1];
377       }
378     }
379
380     if (abs($absumsatz) > 0.01) {
381       push @errors, "Datev-Export fehlgeschlagen! Bei Transaktion $trans->[0]->{trans_id} ($absumsatz)\n";
382     }
383   }
384
385   $sth->finish();
386
387   $form->error(join("<br>\n", @errors)) if (@errors);
388
389   $main::lxdebug->leave_sub();
390 }
391
392 sub make_kne_data_header {
393   $main::lxdebug->enter_sub();
394
395   my ($myconfig, $form, $fromto, $start_jahr) = @_;
396
397   my $jahr = $start_jahr;
398   if (!$jahr) {
399     my @a = localtime;
400     $jahr = $a[5];
401   }
402
403   #Header
404   my $header  = "\x1D\x181";
405   $header    .= _fill($form->{datentraegernr}, 3, '0');
406   $header    .= ($fromto) ? "11" : "13"; # Anwendungsnummer
407   $header    .= _fill($form->{dfvkz}, 2, '0');
408   $header    .= _fill($form->{beraternr}, 7, '0');
409   $header    .= _fill($form->{mandantennr}, 5, '0');
410   $header    .= _fill($form->{abrechnungsnr} . $jahr, 6, '0');
411
412   $fromto         =~ s/transdate|>=|and|\'|<=//g;
413   my ($from, $to) =  split /   /, $fromto;
414   $from           =~ s/ //g;
415   $to             =~ s/ //g;
416
417   if ($from ne "") {
418     my ($fday, $fmonth, $fyear) = split(/\./, $from);
419     if (length($fmonth) < 2) {
420       $fmonth = "0" . $fmonth;
421     }
422     if (length($fday) < 2) {
423       $fday = "0" . $fday;
424     }
425     $from = $fday . $fmonth . substr($fyear, -2, 2);
426   } else {
427     $from = "";
428   }
429
430   $header .= $from;
431
432   if ($to ne "") {
433     my ($tday, $tmonth, $tyear) = split(/\./, $to);
434     if (length($tmonth) < 2) {
435       $tmonth = "0" . $tmonth;
436     }
437     if (length($tday) < 2) {
438       $tday = "0" . $tday;
439     }
440     $to = $tday . $tmonth . substr($tyear, -2, 2);
441   } else {
442     $to = "";
443   }
444   $header .= $to;
445
446   if ($fromto ne "") {
447     $primanota = "001";
448     $header .= $primanota;
449   }
450
451   $header .= _fill($form->{passwort}, 4, '0');
452   $header .= " " x 16;       # Anwendungsinfo
453   $header .= " " x 16;       # Inputinfo
454   $header .= "\x79";
455
456   #Versionssatz
457   my $versionssatz  = $form->{exporttype} == 0 ? "\xB5" . "1," : "\xB6" . "1,";
458
459   my $dbh           = $form->get_standard_dbh($myconfig);
460   my $query         = qq|SELECT accno FROM chart LIMIT 1|;
461   my $ref           = selectfirst_hashref_query($form, $dbh, $query);
462
463   $versionssatz    .= length $ref->{accno};
464   $versionssatz    .= ",";
465   $versionssatz    .= length $ref->{accno};
466   $versionssatz    .= ",SELF" . "\x1C\x79";
467
468   $header          .= $versionssatz;
469
470   $main::lxdebug->leave_sub();
471
472   return $header;
473 }
474
475 sub datetofour {
476   $main::lxdebug->enter_sub();
477
478   my ($date, $six) = @_;
479
480   ($day, $month, $year) = split(/\./, $date);
481
482   if ($day =~ /^0/) {
483     $day = substr($day, 1, 1);
484   }
485   if (length($month) < 2) {
486     $month = "0" . $month;
487   }
488   if (length($year) > 2) {
489     $year = substr($year, -2, 2);
490   }
491
492   if ($six) {
493     $date = $day . $month . $year;
494   } else {
495     $date = $day . $month;
496   }
497
498   $main::lxdebug->leave_sub();
499
500   return $date;
501 }
502
503 sub formatumsatz {
504   $main::lxdebug->enter_sub();
505
506   my ($umsatz, $stellen) = @_;
507
508   $umsatz =~ s/-//;
509   ($vorkomma, $nachkomma) = split(/\./, $umsatz);
510   $umsatz = "";
511   if ($stellen > 0) {
512     for ($i = $stellen; $i >= $stellen + 2 - length($vorkomma); $i--) {
513       $umsatz .= "0";
514     }
515   }
516   for ($i = 3; $i > length($nachkomma); $i--) {
517     $nachkomma .= "0";
518   }
519   $umsatz = $vorkomma . substr($nachkomma, 0, 2);
520
521   $main::lxdebug->leave_sub();
522
523   return $umsatz;
524 }
525
526 sub make_ed_versionset {
527   $main::lxdebug->enter_sub();
528
529   my ($header, $filename, $blockcount, $fromto) = @_;
530
531   my $versionset  = "V" . substr($filename, 2, 5);
532   $versionset    .= substr($header, 6, 22);
533
534   if ($fromto ne "") {
535     $versionset .= "0000" . substr($header, 28, 19);
536   } else {
537     $datum = " " x 16;
538     $versionset .= $datum . "001" . substr($header, 28, 4);
539   }
540
541   $versionset .= _fill($blockcount, 5, '0');
542   $versionset .= "001";
543   $versionset .= " 1";
544   $versionset .= substr($header, -12, 10) . "    ";
545   $versionset .= " " x 53;
546
547   $main::lxdebug->leave_sub();
548
549   return $versionset;
550 }
551
552 sub make_ev_header {
553   $main::lxdebug->enter_sub();
554
555   my ($form, $fileno) = @_;
556
557   my $ev_header  = _fill($form->{datentraegernr}, 3, ' ', 'left');
558   $ev_header    .= "   ";
559   $ev_header    .= _fill($form->{beraternr}, 7, ' ', 'left');
560   $ev_header    .= _fill($form->{beratername}, 9, ' ', 'left');
561   $ev_header    .= " ";
562   $ev_header    .= (_fill($fileno, 5, '0')) x 2;
563   $ev_header    .= " " x 95;
564
565   $main::lxdebug->leave_sub();
566
567   return $ev_header;
568 }
569
570 sub kne_buchungsexport {
571   $main::lxdebug->enter_sub();
572
573   my ($myconfig, $form) = @_;
574
575   my @filenames;
576
577   my $export_path = $main::userspath . "/";
578   my $filename    = "ED00000";
579   my $evfile      = "EV01";
580   my @ed_versionsets;
581   my $fileno = 0;
582
583   $form->header;
584   print qq|
585   <html>
586   <body>Export in Bearbeitung<br>
587   Buchungss&auml;tze verarbeitet:
588 |;
589
590   ($fromto, $start_jahr) =
591     &get_dates($form->{zeitraum}, $form->{monat},
592                $form->{quartal},  $form->{transdatefrom},
593                $form->{transdateto});
594   _get_transactions($fromto);
595   my $counter = 0;
596   print qq|<br>2. Durchlauf:|;
597   while (scalar(@{ $form->{DATEV} })) {
598     my $blockcount      = 1;
599     my $remaining_bytes = 256;
600     my $total_bytes     = 256;
601     my $umsatzsumme     = 0;
602     my $buchungssatz    = "";
603     $filename++;
604     my $ed_filename = $export_path . $filename;
605     push(@filenames, $filename);
606     open(ED, "> $ed_filename") or die "can't open outputfile: $!\n";
607     $header = &make_kne_data_header($myconfig, $form, $fromto, $start_jahr);
608     $remaining_bytes -= length($header);
609
610     while (scalar(@{ $form->{DATEV} }) > 0) {
611       $transaction = shift @{ $form->{DATEV} };
612       $trans_lines = scalar(@{$transaction});
613       $counter++;
614       if (($counter % 500) == 0) {
615         print("$counter ");
616       }
617
618       $umsatz         = 0;
619       $gegenkonto     = "";
620       $konto          = "";
621       $belegfeld1     = "";
622       $datum          = "";
623       $waehrung       = "";
624       $buchungstext   = "";
625       $belegfeld2     = "";
626       $datevautomatik = 0;
627       $taxkey         = 0;
628       $charttax       = 0;
629       %umlaute = ('ä' => 'ae',
630                   'ö' => 'oe',
631                   'ü' => 'ue',
632                   'Ä' => 'Ae',
633                   'Ö' => 'Oe',
634                   'Ü' => 'Ue',
635                   'ß' => 'sz');
636
637       for (my $i = 0; $i < $trans_lines; $i++) {
638         if ($trans_lines == 2) {
639           if (abs($transaction->[$i]->{'amount'}) > abs($umsatz)) {
640             $umsatz = $transaction->[$i]->{'amount'};
641           }
642         } else {
643           if (abs($transaction->[$i]->{'umsatz'}) > abs($umsatz)) {
644             $umsatz = $transaction->[$i]->{'umsatz'};
645           }
646         }
647         if ($transaction->[$i]->{'datevautomatik'}) {
648           $datevautomatik = 1;
649         }
650         if ($transaction->[$i]->{'taxkey'}) {
651           $taxkey = $transaction->[$i]->{'taxkey'};
652         }
653         if ($transaction->[$i]->{'charttax'}) {
654           $charttax = $transaction->[$i]->{'charttax'};
655         }
656         if (   ($transaction->[$i]->{'id'} eq $transaction->[$i]->{'chart_id'})
657             && ($trans_lines > 2)) {
658           undef($transaction->[$i]);
659             } elsif ($transaction->[$i]->{'amount'} > 0) {
660           $haben = $i;
661             } else {
662           $soll = $i;
663         }
664       }
665
666       $umsatzsumme += abs($umsatz);
667
668       # Umwandlung von Umlauten und Sonderzeichen in erlaubte Zeichen bei Textfeldern
669       foreach $umlaut (keys(%umlaute)) {
670         $transaction->[$haben]->{'invnumber'} =~
671           s/${umlaut}/${umlaute{$umlaut}}/g;
672         $transaction->[$haben]->{'name'} =~ s/${umlaut}/${umlaute{$umlaut}}/g;
673       }
674
675       $transaction->[$haben]->{'invnumber'} =~ s/[^0-9A-Za-z\$\%\&\*\+\-\/]//g;
676       $transaction->[$haben]->{'name'} =~ s/[^0-9A-Za-z\$\%\&\*\+\-\ \/]//g;
677
678       $transaction->[$haben]->{'invnumber'} =
679         substr($transaction->[$haben]->{'invnumber'}, 0, 12);
680       $transaction->[$haben]->{'name'} =
681         substr($transaction->[$haben]->{'name'}, 0, 30);
682       $transaction->[$haben]->{'invnumber'} =~ s/\ *$//;
683       $transaction->[$haben]->{'name'}      =~ s/\ *$//;
684
685       if ($trans_lines >= 2) {
686
687         $gegenkonto = "a" . $transaction->[$haben]->{'accno'};
688         $konto      = "e" . $transaction->[$soll]->{'accno'};
689         if ($transaction->[$haben]->{'invnumber'} ne "") {
690           $belegfeld1 =
691             "\xBD" . $transaction->[$haben]->{'invnumber'} . "\x1C";
692         }
693         $datum = "d";
694         $datum .= &datetofour($transaction->[$haben]->{'transdate'}, 0);
695         $waehrung = "\xB3" . "EUR" . "\x1C";
696         if ($transaction->[$haben]->{'name'} ne "") {
697           $buchungstext = "\x1E" . $transaction->[$haben]->{'name'} . "\x1C";
698         }
699         if ($transaction->[$haben]->{'duedate'} ne "") {
700           $belegfeld2 = "\xBE"
701             . &datetofour($transaction->[$haben]->{'duedate'}, 1) . "\x1C";
702         }
703       }
704
705       if (($remaining_bytes - length("+" . &formatumsatz($umsatz, 0))) <= 6) {
706         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
707         $buchungssatz .= "\x00" x $fuellzeichen;
708         $blockcount++;
709         $total_bytes = ($blockcount) * 256;
710       }
711       $umsatz = abs($umsatz);
712       $vorzeichen = ($umsatz > 0) ? "+" : "-";
713       $buchungssatz .= $vorzeichen . &formatumsatz($umsatz, 0);
714       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
715
716       if ( ($taxkey || $datevautomatik)
717         && (!$datevautomatik || ($datevautomatik && ($charttax ne $taxkey)))) {
718         if (($remaining_bytes - length("\x6C" . "11")) <= 6) {
719           $fuellzeichen =
720             ($blockcount * 256 - length($buchungssatz . $header));
721           $buchungssatz .= "\x00" x $fuellzeichen;
722           $blockcount++;
723           $total_bytes = ($blockcount) * 256;
724         }
725         if (!$datevautomatik) {
726           $buchungssatz .= "\x6C" . $taxkey;
727         } else {
728           $buchungssatz .= "\x6C" . "4";
729         }
730         $remaining_bytes = $total_bytes - length($buchungssatz . $header);
731       }
732
733       if (($remaining_bytes - length($gegenkonto)) <= 6) {
734         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
735         $buchungssatz .= "\x00" x $fuellzeichen;
736         $blockcount++;
737         $total_bytes = ($blockcount) * 256;
738       }
739       $buchungssatz .= $gegenkonto;
740       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
741
742       if (($remaining_bytes - length($belegfeld1)) <= 6) {
743         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
744         $buchungssatz .= "\x00" x $fuellzeichen;
745         $blockcount++;
746         $total_bytes = ($blockcount) * 256;
747       }
748       $buchungssatz .= $belegfeld1;
749       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
750
751       if (($remaining_bytes - length($belegfeld2)) <= 6) {
752         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
753         $buchungssatz .= "\x00" x $fuellzeichen;
754         $blockcount++;
755         $total_bytes = ($blockcount) * 256;
756       }
757       $buchungssatz .= $belegfeld2;
758       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
759
760       if (($remaining_bytes - length($datum)) <= 6) {
761         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
762         $buchungssatz .= "\x00" x $fuellzeichen;
763         $blockcount++;
764         $total_bytes = ($blockcount) * 256;
765       }
766       $buchungssatz .= $datum;
767       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
768
769       if (($remaining_bytes - length($konto)) <= 6) {
770         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
771         $buchungssatz .= "\x00" x $fuellzeichen;
772         $blockcount++;
773         $total_bytes = ($blockcount) * 256;
774       }
775       $buchungssatz .= $konto;
776       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
777
778       if (($remaining_bytes - length($buchungstext)) <= 6) {
779         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
780         $buchungssatz .= "\x00" x $fuellzeichen;
781         $blockcount++;
782         $total_bytes = ($blockcount) * 256;
783       }
784       $buchungssatz .= $buchungstext;
785       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
786
787       if (($remaining_bytes - (length($waehrung . "\x79"))) <= 6) {
788         $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
789         $buchungssatz .= "\x00" x $fuellzeichen;
790         $blockcount++;
791         $total_bytes = ($blockcount) * 256;
792       }
793       $buchungssatz .= $waehrung . "\x79";
794       $remaining_bytes = $total_bytes - length($buchungssatz . $header);
795
796     }
797
798     $mandantenendsumme =
799       "x" . &formatumsatz($umsatzsumme, 14) . "\x79" . "\x7a";
800     $fuellzeichen =
801       256 - (length($header . $buchungssatz . $mandantenendsumme) % 256);
802     $dateiende = "\x00" x $fuellzeichen;
803     print(ED $header);
804     print(ED $buchungssatz);
805     print(ED $mandantenendsumme);
806     print(ED $dateiende);
807     close(ED);
808
809     $ed_versionset[$fileno] =
810       &make_ed_versionset($header, $filename, $blockcount, $fromto);
811     $fileno++;
812   }
813
814   #Make EV Verwaltungsdatei
815   $ev_header = &make_ev_header($form, $fileno);
816   $ev_filename = $export_path . $evfile;
817   push(@filenames, $evfile);
818   open(EV, "> $ev_filename") or die "can't open outputfile: EV01\n";
819   print(EV $ev_header);
820
821   foreach $file (@ed_versionset) {
822     print(EV $ed_versionset[$file]);
823   }
824   close(EV);
825   print qq|<br>Done. <br>
826 |;
827   ###
828   $main::lxdebug->leave_sub();
829
830   return @filenames;
831 }
832
833 sub kne_stammdatenexport {
834   $main::lxdebug->enter_sub();
835
836   my ($myconfig, $form) = @_;
837   $form->{abrechnungsnr} = "99";
838
839   $form->header;
840   print qq|
841   <html>
842   <body>Export in Bearbeitung<br>
843 |;
844
845   my @filenames;
846
847   my $export_path = $main::userspath . "/";
848   my $filename    = "ED00000";
849   my $evfile      = "EV01";
850   my @ed_versionsets;
851   my $fileno          = 1;
852   my $i               = 0;
853   my $blockcount      = 1;
854   my $remaining_bytes = 256;
855   my $total_bytes     = 256;
856   my $buchungssatz    = "";
857   $filename++;
858   my $ed_filename = $export_path . $filename;
859   push(@filenames, $filename);
860   open(ED, "> $ed_filename") or die "can't open outputfile: $!\n";
861   $header = &make_kne_data_header($myconfig, $form, "");
862   $remaining_bytes -= length($header);
863
864   # connect to database
865   my $dbh = $form->dbconnect($myconfig);
866
867   $query =
868     qq|SELECT c.accno, c.description FROM chart c WHERE c.accno >=|
869     . $dbh->quote($form->{accnofrom}) . qq|
870            AND c.accno <= |
871     . $dbh->quote($form->{accnoto}) . qq| ORDER BY c.accno|;
872
873   $sth = $dbh->prepare($query);
874   $sth->execute || $form->dberror($query);
875
876   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
877     if (($remaining_bytes - length("t" . $ref->{'accno'})) <= 6) {
878       $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
879       $buchungssatz .= "\x00" x $fuellzeichen;
880       $blockcount++;
881       $total_bytes = ($blockcount) * 256;
882     }
883     $buchungssatz .= "t" . $ref->{'accno'};
884     $remaining_bytes = $total_bytes - length($buchungssatz . $header);
885     $ref->{'description'} =~ s/[^0-9A-Za-z\$\%\&\*\+\-\/]//g;
886     $ref->{'description'} = substr($ref->{'description'}, 0, 40);
887     $ref->{'description'} =~ s/\ *$//;
888
889     if (
890         ($remaining_bytes - length("\x1E" . $ref->{'description'} . "\x1C\x79")
891         ) <= 6
892       ) {
893       $fuellzeichen = ($blockcount * 256 - length($buchungssatz . $header));
894       $buchungssatz .= "\x00" x $fuellzeichen;
895       $blockcount++;
896       $total_bytes = ($blockcount) * 256;
897     }
898     $buchungssatz .= "\x1E" . $ref->{'description'} . "\x1C\x79";
899     $remaining_bytes = $total_bytes - length($buchungssatz . $header);
900   }
901
902   $sth->finish;
903   print(ED $header);
904   print(ED $buchungssatz);
905   $fuellzeichen = 256 - (length($header . $buchungssatz . "z") % 256);
906   $dateiende = "\x00" x $fuellzeichen;
907   print(ED "z");
908   print(ED $dateiende);
909   close(ED);
910
911   #Make EV Verwaltungsdatei
912   $ed_versionset[0] =
913     &make_ed_versionset($header, $filename, $blockcount, $fromto);
914
915   $ev_header = &make_ev_header($form, $fileno);
916   $ev_filename = $export_path . $evfile;
917   push(@filenames, $evfile);
918   open(EV, "> $ev_filename") or die "can't open outputfile: EV01\n";
919   print(EV $ev_header);
920
921   foreach $file (@ed_versionset) {
922     print(EV $ed_versionset[$file]);
923   }
924   close(EV);
925
926   $dbh->disconnect;
927   ###
928
929   print qq|<br>Done. <br>
930 |;
931
932   $main::lxdebug->leave_sub();
933
934   return @filenames;
935 }
936
937 1;