Codecleanup UStVA & Bugfixes bei Verwendung von UTF-8
[kivitendo-erp.git] / SL / USTVA.pm
1 #=====================================================================
2 # Lx-Office ERP
3 # Copyright (c) 2004 by Udo Spallek, Aachen
4 #
5 #  Author: Udo Spallek
6 #   Email: udono@gmx.net
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 # Utilities for ustva
24 #=====================================================================
25
26 package USTVA;
27
28 use List::Util qw(first);
29
30 use SL::DBUtils;
31
32 my @tax_office_information = (
33   { 'id' =>  8, 'name' => 'Baden Württemberg',      'taxbird_nr' => '0',  'elster_format' => 'FF/BBB/UUUUP',  },
34   { 'id' =>  9, 'name' => 'Bayern',                 'taxbird_nr' => '1',  'elster_format' => 'FFF/BBB/UUUUP', },
35   { 'id' => 11, 'name' => 'Berlin',                 'taxbird_nr' => '2',  'elster_format' => 'FF/BBB/UUUUP',  },
36   { 'id' => 12, 'name' => 'Brandenburg',            'taxbird_nr' => '3',  'elster_format' => 'FFF/BBB/UUUUP', },
37   { 'id' =>  4, 'name' => 'Bremen',                 'taxbird_nr' => '4',  'elster_format' => 'FF BBB UUUUP',  },
38   { 'id' =>  2, 'name' => 'Hamburg',                'taxbird_nr' => '5',  'elster_format' => 'FF/BBB/UUUUP',  },
39   { 'id' =>  6, 'name' => 'Hessen',                 'taxbird_nr' => '6',  'elster_format' => '0FF BBB UUUUP', },
40   { 'id' => 13, 'name' => 'Mecklenburg Vorpommern', 'taxbird_nr' => '7',  'elster_format' => 'FFF/BBB/UUUUP', },
41   { 'id' =>  3, 'name' => 'Niedersachsen',          'taxbird_nr' => '8',  'elster_format' => 'FF/BBB/UUUUP',  },
42   { 'id' =>  5, 'name' => 'Nordrhein Westfalen',    'taxbird_nr' => '9',  'elster_format' => 'FFF/BBBB/UUUP', },
43   { 'id' =>  7, 'name' => 'Rheinland Pfalz',        'taxbird_nr' => '10', 'elster_format' => 'FF/BBB/UUUU/P', },
44   { 'id' => 10, 'name' => 'Saarland',               'taxbird_nr' => '11', 'elster_format' => 'FFF/BBB/UUUUP', },
45   { 'id' => 14, 'name' => 'Sachsen',                'taxbird_nr' => '12', 'elster_format' => 'FFF/BBB/UUUUP', },
46   { 'id' => 15, 'name' => 'Sachsen Anhalt',         'taxbird_nr' => '13', 'elster_format' => 'FFF/BBB/UUUUP', },
47   { 'id' =>  1, 'name' => 'Schleswig Holstein',     'taxbird_nr' => '14', 'elster_format' => 'FF BBB UUUUP',  },
48   { 'id' => 16, 'name' => 'Thüringen',              'taxbird_nr' => '15', 'elster_format' => 'FFF/BBB/UUUUP', },
49   );
50
51 sub new {
52   my $type = shift;
53
54   my $self = {};
55
56   bless $self, $type;
57
58   $self->_init(@_);
59
60   return $self;
61 }
62
63 sub _init {
64   my $self = shift;
65
66   $self->{tax_office_information} = [];
67
68   foreach (@tax_office_information) {
69     my $entry      = \%{ $_ };
70     $entry->{name} = $main::locale->{iconv_iso8859}->convert($entry->{name});
71     push @{ $self->{tax_office_information} }, $entry;
72   }
73 }
74
75 sub get_coa {
76
77   my ( $self, $form, $myconfig) = @_;
78
79   my $query = q{ SELECT coa FROM defaults };
80
81   my $dbh = $form->dbconnect($myconfig);
82   my $sth = $dbh->prepare($query);
83   $sth->execute() || $form->dberror($query);
84
85   my ($coa) = selectrow_query($form, $dbh, $query);
86
87   $sth->finish;
88   $dbh->disconnect;
89
90   $form->{coa} = $coa;
91   $form->{"COA_$coa"} = '1';
92   $form->{COA_Germany} = '1' if ($coa =~ m/^germany/i);
93
94   return;
95 }
96
97
98 sub report_variables {
99   # Get all positions for taxreport out of the database
100   # Needs Databaseupdate Pg-upgrade2/USTVA_abstraction.pl
101
102   return unless defined wantarray;
103
104   my ( $self,
105        $arg_ref) = @_;
106
107   my $myconfig   = $arg_ref->{myconfig};
108   my $form       = $arg_ref->{form};
109   my $type       = $arg_ref->{type}; # 'paied' || 'received' || ''
110   my $attribute  = $arg_ref->{attribute}; #
111   my $dec_places = (defined $arg_ref->{dec_places}) ? $arg_ref->{dec_places}:undef;
112
113   my $where_type = "AND tax.report_headings.type = '$type'" if ( $type );
114   my $where_dcp  = "AND tax.report_variables.dec_places = '$dec_places'" if ( defined $dec_places );
115
116   my $query = qq|
117     SELECT $attribute
118     FROM tax.report_variables
119     LEFT JOIN tax.report_headings
120       ON (tax.report_variables.heading_id = tax.report_headings.id)
121     WHERE 1=1
122     $where_type
123     $where_dcp
124   |;
125
126   my $dbh = $form->dbconnect($myconfig);
127   my $sth = $dbh->prepare($query);
128
129   $sth->execute() || $form->dberror($query);
130
131   my @positions;
132
133   while ( my $row_ref = $sth->fetchrow_arrayref() ) {
134     push @positions, @$row_ref;  # Copy the array contents
135   }
136
137   $sth->finish;
138
139   $dbh->disconnect;
140
141   return @positions;
142
143 }
144
145 sub create_steuernummer {
146   $main::lxdebug->enter_sub();
147
148   $part           = $form->{part};
149   $patterncount   = $form->{patterncount};
150   $delimiter      = $form->{delimiter};
151   $elster_pattern = $form->{elster_pattern};
152
153   # rebuild steuernummer and elstersteuernummer
154   # es gibt eine gespeicherte steuernummer $form->{steuernummer}
155   # und die parts und delimiter
156
157   my $h = 0;
158   my $i = 0;
159
160   $steuernummer_new        = $part;
161   $elstersteuernummer_new  = $elster_FFFF;
162   $elstersteuernummer_new .= '0';
163
164   for ($h = 1; $h < $patterncount; $h++) {
165     $steuernummer_new .= qq|$delimiter|;
166     for ($i = 1; $i <= length($elster_pattern); $i++) {
167       $steuernummer_new       .= $form->{"part_$h\_$i"};
168       $elstersteuernummer_new .= $form->{"part_$h\_$i"};
169     }
170   }
171   if ($form->{steuernummer} ne $steuernummer_new) {
172     $form->{steuernummer}       = $steuernummer_new;
173     $form->{elstersteuernummer} = $elstersteuernummer_new;
174     $form->{steuernummer_new}   = $steuernummer_new;
175   }
176   $main::lxdebug->leave_sub();
177   return ($steuernummer_new, $elstersteuernummer_new);
178 }
179
180 sub steuernummer_input {
181   $main::lxdebug->enter_sub();
182
183   my ($self, $elsterland, $elsterFFFF, $steuernummer) = @_;
184
185   my $steuernummer_input = '';
186
187   $elster_land  = $elsterland;
188   $elster_FFFF  = $elsterFFFF;
189   $steuernummer = '0000000000' if ($steuernummer eq '');
190
191   # $steuernummer formatieren (nur Zahlen) -> $stnr
192   my $stnr = $steuernummer;
193   $stnr =~ s/\D+//g;
194
195   #Pattern description Elstersteuernummer
196
197   #split the pattern
198   my $tax_office     = first { $_->{name} eq $elster_land } @{ $self->{tax_office_information} };
199   my $elster_pattern = $tax_office->{elster_format};
200   my @elster_pattern = split(' ', $elster_pattern);
201   my $delimiter      = '&nbsp;';
202   my $patterncount   = @elster_pattern;
203   if ($patterncount < 2) {
204     @elster_pattern = ();
205     @elster_pattern = split('/', $elster_pattern);
206     $delimiter      = '/';
207     $patterncount   = @elster_pattern;
208   }
209
210   # no we have an array of patternparts and a delimiter
211   # create the first automated and fixed part and delimiter
212
213   $steuernummer_input .= qq|<b><font size="+1">|;
214   my $part = '';
215 SWITCH: {
216     $elster_pattern[0] eq 'FFF' && do {
217       $part = substr($elster_FFFF, 1, 4);
218       $steuernummer_input .= qq|$part|;
219       last SWITCH;
220     };
221     $elster_pattern[0] eq '0FF' && do {
222       $part = '0' . substr($elster_FFFF, 2, 4);
223       $steuernummer_input .= qq|$part|;
224       last SWITCH;
225     };
226     $elster_pattern[0] eq 'FF' && do {
227       $part = substr($elster_FFFF, 2, 4);
228       $steuernummer_input .= qq|$part|;
229       last SWITCH;
230     };
231     1 == 1 && do {
232       $steuernummer_input .= qq|Fehler!|;
233       last SWITCH;
234     };
235   }
236
237   #now the rest of the Steuernummer ...
238   $steuernummer_input .= qq|</b></font>|;
239   $steuernummer_input .= qq|\n
240            <input type=hidden name="elster_pattern" value="$elster_pattern">
241            <input type=hidden name="patterncount" value="$patterncount">
242            <input type=hidden name="patternlength" value="$patterncount">
243            <input type=hidden name="delimiter" value="$delimiter">
244            <input type=hidden name="part" value="$part">
245   |;
246
247   my $k = 0;
248
249   for (my $h = 1; $h < $patterncount; $h++) {
250     $steuernummer_input .= qq|&nbsp;$delimiter&nbsp;\n|;
251     for (my $i = 1; $i <= length($elster_pattern[$h]); $i++) {
252       $steuernummer_input .= qq|<select name="part_$h\_$i">\n|;
253
254       for (my $j = 0; $j <= 9; $j++) {
255         $steuernummer_input .= qq|      <option value="$j"|;
256         if ($steuernummer ne '') {
257           if ($j eq substr($stnr, length($part) + $k, 1)) {
258             $steuernummer_input .= qq| selected|;
259           }
260         }
261         $steuernummer_input .= qq|>$j</option>\n|;
262       }
263       $k++;
264       $steuernummer_input .= qq|</select>\n|;
265     }
266   }
267
268   $main::lxdebug->leave_sub();
269
270   return $steuernummer_input;
271 }
272
273 sub fa_auswahl {
274   $main::lxdebug->enter_sub();
275
276 #  use SL::Form;
277
278   # Referenz wird übergeben, hash of hash wird nicht
279   # in neues  Hash kopiert, sondern direkt über die Referenz verändert
280   # Prototyp für diese Konstruktion
281
282   my ($self, $land, $elsterFFFF, $elster_init) = @_;
283
284   my $terminal = '';
285   my $FFFF     = $elsterFFFF;
286   my $ffff     = '';
287   my $checked  = '';
288   $checked = 'checked' if ($elsterFFFF eq '' and $land eq '');
289
290   my $fa_auswahl = qq|
291         <script language="Javascript">
292         function update_auswahl()
293         {
294                 var elsterBLAuswahl = document.verzeichnis.elsterland_new;
295                 var elsterFAAuswahl = document.verzeichnis.elsterFFFF_new;
296
297                 elsterFAAuswahl.options.length = 0; // dropdown aufräumen
298                 |;
299
300   foreach $elster_land (sort keys %$elster_init) {
301     $fa_auswahl .= qq|
302                if (elsterBLAuswahl.options[elsterBLAuswahl.selectedIndex].
303                value == "$elster_land")
304                {
305                |;
306     my $j              = 0;
307     my %elster_land_fa = ();
308     $FFFF = '';
309     for $FFFF (keys %{ $elster_init->{$elster_land} }) {
310       $elster_land_fa{$FFFF} = $elster_init->{$elster_land}->{$FFFF}->[0];
311     }
312     foreach $ffff (sort { $elster_land_fa{$a} cmp $elster_land_fa{$b} }
313                    keys(%elster_land_fa)
314       ) {
315       $fa_auswahl .= qq|
316                    elsterFAAuswahl.options[$j] = new Option("$elster_land_fa{$ffff} ($ffff)","$ffff");|;
317       $j++;
318     }
319     $fa_auswahl .= qq|
320                }|;
321   }
322   $fa_auswahl .= qq|
323         }
324         </script>
325
326         <table width="100%">
327           <tr>
328             <td>
329                Bundesland
330             </td>
331             <td>
332               <select size="1" name="elsterland_new" onchange="update_auswahl()">|;
333   if ($land eq '') {
334     $fa_auswahl .= qq|<option value="Auswahl" $checked>| . $main::locale->text('Select federal state...') . qq|</option>\n|;
335   }
336   foreach $elster_land (sort keys %$elster_init) {
337     $fa_auswahl .= qq|
338                   <option value="$elster_land"|;
339     if ($elster_land eq $land and $checked eq '') {
340       $fa_auswahl .= qq| selected|;
341     }
342     $fa_auswahl .= qq|>$elster_land</option>
343              |;
344   }
345   $fa_auswahl .= qq|
346             </td>
347           </tr>
348           |;
349
350   my $elster_land = '';
351   $elster_land = ($land ne '') ? $land : '';
352   %elster_land_fa = ();
353   for $FFFF (keys %{ $elster_init->{$elster_land} }) {
354     $elster_land_fa{$FFFF} = $elster_init->{$elster_land}->{$FFFF}->[0];
355   }
356
357   $fa_auswahl .= qq|
358            <tr>
359               <td>Finanzamt
360               </td>
361               <td>
362                  <select size="1" name="elsterFFFF_new">|;
363   if ($elsterFFFF eq '') {
364     $fa_auswahl .= qq|<option value="Auswahl" $checked>| . $main::locale->text('Select tax office...') . qq|</option>|;
365   } else {
366     foreach $ffff (sort { $elster_land_fa{$a} cmp $elster_land_fa{$b} }
367                    keys(%elster_land_fa)
368       ) {
369
370       $fa_auswahl .= qq|
371                         <option value="$ffff"|;
372       if ($ffff eq $elsterFFFF and $checked eq '') {
373         $fa_auswahl .= qq| selected|;
374       }
375       $fa_auswahl .= qq|>$elster_land_fa{$ffff} ($ffff)</option>|;
376     }
377   }
378   $fa_auswahl .= qq|
379                  </td>
380               </tr>
381             </table>
382             </select>|;
383
384   $main::lxdebug->leave_sub();
385
386   return $fa_auswahl;
387 }
388
389 sub info {
390   $main::lxdebug->enter_sub();
391
392   my $msg = $_[0];
393
394   if ($ENV{HTTP_USER_AGENT}) {
395     $msg =~ s/\n/<br>/g;
396
397     print qq|<body><h2 class=info>Hinweis</h2>
398
399     <p><b>$msg</b>
400     <br>
401     <br>
402     <hr>
403     <input type=button value="| . $main::locale->text('Back') . qq|" onClick="history.go(-1)">
404     </body>
405     |;
406
407     exit;
408
409   } else {
410
411     die "Hinweis: $msg\n";
412   }
413
414   $main::lxdebug->leave_sub();
415 }
416
417 sub stichtag {
418   $main::lxdebug->enter_sub();
419
420   # noch nicht fertig
421   # soll mal eine Erinnerungsfunktion für USTVA Abgaben werden, die automatisch
422   # den Termin der nächsten USTVA anzeigt.
423   #
424   #
425   my ($today, $FA_dauerfrist, $FA_voranmeld) = @_;
426
427   #$today zerlegen:
428
429   #$today =today * 1;
430   $today =~ /(\d\d\d\d)(\d\d)(\d\d)/;
431   $year     = $1;
432   $month    = $2;
433   $day      = $3;
434   $yy       = $year;
435   $mm       = $month;
436   $yymmdd   = "$year$month$day" * 1;
437   $mmdd     = "$month$day" * 1;
438   $stichtag = '';
439
440   #$tage_bis = '1234';
441   #$ical = '...vcal format';
442
443   #if ($FA_voranmeld eq 'month'){
444
445   %liste = ("0110" => 'December',
446             "0210" => 'January',
447             "0310" => 'February',
448             "0410" => 'March',
449             "0510" => 'April',
450             "0610" => 'May',
451             "0710" => 'June',
452             "0810" => 'July',
453             "0910" => 'August',
454             "1010" => 'September',
455             "1110" => 'October',
456             "1210" => 'November');
457
458   #$mm += $dauerfrist
459   #$month *= 1;
460   $month += 1 if ($day > 10);
461   $month    = sprintf("%02d", $month);
462   $stichtag = $year . $month . "10";
463   $ust_va   = $month . "10";
464
465   foreach $date (%liste) {
466     $ust_va = $liste{$date} if ($date eq $stichtag);
467   }
468
469   #} elsif ($FA_voranmeld eq 'quarter'){
470   #1;
471
472   #}
473
474   #@stichtag = ('10.04.2004', '10.05.2004');
475
476   #@liste = ['0110', '0210', '0310', '0410', '0510', '0610', '0710', '0810', '0910',
477   #          '1010', '1110', '1210', ];
478   #
479   #foreach $key (@liste){
480   #  #if ($ddmm < ('0110' * 1));
481   #  if ($ddmm ){}
482   #  $stichtag = $liste[$key - 1] if ($ddmm > $key);
483   #
484   #}
485   #
486   #$stichtag =~ /([\d]\d)(\d\d)$/
487   #$stichtag = "$1.$2.$yy"
488   #$stichtag=$1;
489   $main::lxdebug->leave_sub();
490   return ($stichtag, $description, $tage_bis, $ical);
491 }
492
493 sub query_finanzamt {
494   $main::lxdebug->enter_sub();
495
496   my ($self, $myconfig, $form) = @_;
497
498   my $dbh = $form->dbconnect($myconfig) or $self->error(DBI->errstr);
499
500   #Test, if table finanzamt exist
501   my $table    = 'finanzamt';
502   my $filename = "sql/$table.sql";
503
504   my $tst = $dbh->prepare("SELECT * FROM $table");
505   $tst->execute;
506   if ($DBI::err) {
507
508     #There is no table, read the table from sql/finanzamt.sql
509     print qq|<p>Bitte warten, Tabelle $table wird einmalig in Datenbank:
510     $myconfig->{dbname} als Benutzer: $myconfig->{dbuser} hinzugefügt...</p>|;
511     process_query($form, $dbh, $filename) || $self->error(DBI->errstr);
512
513     #execute second last call
514     my $dbh = $form->dbconnect($myconfig) or $self->error(DBI->errstr);
515     $dbh->disconnect();
516   }
517   $tst->finish();
518
519   #$dbh->disconnect();
520
521   my @vars = (
522     'FA_Land_Nr',             #  0
523     'FA_BUFA_Nr',             #  1
524                               #'FA_Verteiler',                          #  2
525     'FA_Name',                #  3
526     'FA_Strasse',             #  4
527     'FA_PLZ',                 #  5
528     'FA_Ort',                 #  6
529     'FA_Telefon',             #  7
530     'FA_Fax',                 #  8
531     'FA_PLZ_Grosskunden',     #  9
532     'FA_PLZ_Postfach',        # 10
533     'FA_Postfach',            # 11
534     'FA_BLZ_1',               # 12
535     'FA_Kontonummer_1',       # 13
536     'FA_Bankbezeichnung_1',   # 14
537                               #'FA_BankIBAN_1',                         # 15
538                               #'FA_BankBIC_1',                          # 16
539                               #'FA_BankInhaber_BUFA_Nr_1',                      # 17
540     'FA_BLZ_2',               # 18
541     'FA_Kontonummer_2',       # 19
542     'FA_Bankbezeichnung_2',   # 20
543                               #'FA_BankIBAN_2',                         # 21
544                               #'FA_BankBIC_2',                          # 22
545                               #'FA_BankInhaber_BUFA_Nr_2',                      # 23
546     'FA_Oeffnungszeiten',     # 24
547     'FA_Email',               # 25
548     'FA_Internet'             # 26
549                               #'FA_zustaendige_Hauptstelle_BUFA_Nr',            # 27
550                               #'FA_zustaendige_vorgesetzte_Finanzbehoerde'      # 28
551   );
552
553   my $field = join(', ', @vars);
554
555   my $query = "SELECT $field FROM finanzamt ORDER BY FA_Land_nr";
556   my $sth = $dbh->prepare($query) or $self->error($dbh->errstr);
557   $sth->execute || $form->dberror($query);
558   my $array_ref = $sth->fetchall_arrayref();
559   my $land      = '';
560   foreach my $row (@$array_ref) {
561     my $FA_finanzamt = $row;
562     my $tax_office   = first { $_->{id} == $FA_finanzamt->[0] } @{ $self->{tax_office_information} };
563     $land            = $tax_office->{name};
564
565     # $land = $main::locale->{iconv}->convert($land);
566
567     my $ffff = @$FA_finanzamt[1];
568
569     my $rec = {};
570     $rec->{$land} = $ffff;
571
572     shift @$row;
573     shift @$row;
574
575     $finanzamt{$land}{$ffff} = [@$FA_finanzamt];
576   }
577
578   $sth->finish();
579   $dbh->disconnect();
580
581   $main::lxdebug->leave_sub();
582
583   return \%finanzamt;
584 }
585
586 sub process_query {
587   $main::lxdebug->enter_sub();
588
589   # Copyright D. Simander -> SL::Form under Gnu GPL.
590   my ($form, $dbh, $filename) = @_;
591
592   #  return unless (-f $filename);
593
594   open my $FH, "<", "$filename" or $form->error("$filename : $!\n");
595   my $query = "";
596   my $sth;
597   my @quote_chars;
598
599   while (<$FH>) {
600
601     # Remove DOS and Unix style line endings.
602     s/[\r\n]//g;
603
604     # don't add comments or empty lines
605     next if /^(--.*|\s+)$/;
606
607     for (my $i = 0; $i < length($_); $i++) {
608       my $char = substr($_, $i, 1);
609
610       # Are we inside a string?
611       if (@quote_chars) {
612         if ($char eq $quote_chars[-1]) {
613           pop(@quote_chars);
614         }
615         $query .= $char;
616
617       } else {
618         if (($char eq "'") || ($char eq "\"")) {
619           push(@quote_chars, $char);
620
621         } elsif ($char eq ";") {
622
623           # Query is complete. Send it.
624
625           $sth = $dbh->prepare($query);
626           $sth->execute || $form->dberror($query);
627           $sth->finish;
628
629           $char  = "";
630           $query = "";
631         }
632
633         $query .= $char;
634       }
635     }
636   }
637
638   close $FH;
639
640   $main::lxdebug->leave_sub();
641 }
642
643 sub ustva {
644   $main::lxdebug->enter_sub();
645
646   my ($self, $myconfig, $form) = @_;
647
648   # connect to database
649   my $dbh = $form->dbconnect($myconfig);
650
651   my $last_period     = 0;
652   my $category        = "pos_ustva";
653
654   my @category_cent = USTVA->report_variables({
655       myconfig    => $myconfig,
656       form        => $form,
657       type        => '',
658       attribute   => 'position',
659       dec_places  => '2',
660   });
661
662   push @category_cent, qw(83  Z43  Z45  Z53  Z62  Z65  Z67);
663
664   my @category_euro = USTVA->report_variables({
665       myconfig    => $myconfig,
666       form        => $form,
667       type        => '',
668       attribute   => 'position',
669       dec_places  => '0',
670   });
671
672   push @category_euro, USTVA->report_variables({
673       myconfig    => $myconfig,
674       form        => $form,
675       type        => '',
676       attribute   => 'position',
677       dec_places  => '0',
678   });
679
680   $form->{decimalplaces} *= 1;
681
682   foreach $item (@category_cent) {
683     $form->{"$item"} = 0;
684   }
685   foreach $item (@category_euro) {
686     $form->{"$item"} = 0;
687   }
688   my $coa_name = coa_get($dbh);
689   $form->{coa} = $coa_name;
690
691   # Controlvariable for templates
692   $form->{"$coa_name"} = '1';
693
694   $main::lxdebug->message(LXDebug::DEBUG2, "COA: '$form->{coa}',  \$form->{$coa_name} = 1");
695
696   &get_accounts_ustva($dbh, $last_period, $form->{fromdate}, $form->{todate},
697                       $form, $category);
698
699   ###########################################
700   #
701   # Nationspecific Modfications
702   #
703   ###########################################
704
705   # Germany
706
707   if ( $form->{coa} eq 'Germany-DATEV-SKR03EU' or $form->{coa} eq 'Germany-DATEV-SKR04EU'){
708
709     # 16%/19% Umstellung
710     # Umordnen der Kennziffern
711     if ( $form->{year} < 2007) {
712       $form->{35} += $form->{81};
713       $form->{36} += $form->{811};
714       $form->{95} += $form->{89};
715       $form->{98} += $form->{891};
716       map { delete $form->{$_} } qw(81 811 89 891);
717     } else {
718       $form->{35} += $form->{51};
719       $form->{36} += $form->{511};
720       $form->{95} += $form->{97};
721       $form->{98} += $form->{971};
722       map { delete $form->{$_} } qw(51 511 97 971);
723     }
724
725   }
726
727
728   # Fixme: Wird auch noch für Oesterreich gebraucht,
729   # weil kein eigenes Ausgabeformular
730   # sotte aber aus der allgeméinen Steuerberechnung verschwinden
731   #
732   # Berechnung der USTVA Formularfelder laut Bogen 207
733   #
734
735   $form->{"51r"} = $form->{"511"};
736   $form->{"86r"} = $form->{"861"};
737   $form->{"97r"} = $form->{"971"};
738   $form->{"93r"} = $form->{"931"};
739
740   $form->{"Z43"} = $form->{"511"}     + $form->{"811"} + $form->{"861"}
741                      + $form->{"36"}  + $form->{"80"}  + $form->{"971"}
742                      + $form->{"891"} + $form->{"931"} + $form->{"96"}
743                      + $form->{"98"};
744
745   $form->{"Z45"} = $form->{"Z43"};
746
747   $form->{"Z53"} = $form->{"Z45"}     + $form->{"53"}  + $form->{"74"}
748                      + $form->{"85"}  + $form->{"65"};
749
750   $form->{"Z62"} = $form->{"Z43"}     - $form->{"66"}  - $form->{"61"}
751                      - $form->{"62"}  - $form->{"67"}  - $form->{"63"}
752                      - $form->{"64"}  - $form->{"59"};
753
754   $form->{"Z65"} = $form->{"Z62"}     - $form->{"69"};
755   $form->{"83"}  = $form->{"Z65"}     - $form->{"39"};
756
757   $dbh->disconnect;
758
759   $main::lxdebug->leave_sub();
760 }
761
762 sub coa_get {
763
764   my ($dbh) = @_;
765
766   my $query= qq|SELECT coa FROM defaults|;
767
768   my $sth = $dbh->prepare($query);
769
770   $sth->execute || $form->dberror($query);
771
772   ($ref) = $sth->fetchrow_array;
773
774   return $ref;
775
776 };
777
778 sub get_accounts_ustva {
779   $main::lxdebug->enter_sub();
780
781   my ($dbh, $last_period, $fromdate, $todate, $form, $category) = @_;
782
783   my $query;
784   my $where    = "";
785   my $glwhere  = "";
786   my $subwhere = "";
787   my $ARwhere  = "";
788   my $APwhere  = '';
789   my $arwhere  = "";
790   my $item;
791
792     my $gltaxkey_where = "(tk.pos_ustva>=59 AND tk.pos_ustva<=66)";
793
794   if ($fromdate) {
795     if ($form->{method} eq 'cash') {
796       $subwhere .= " AND transdate >= '$fromdate'";
797       $glwhere = " AND ac.transdate >= '$fromdate'";
798       $ARwhere .= " AND acc.transdate >= '$fromdate'";
799     }
800     $APwhere .= " AND AP.transdate >= '$fromdate'";
801     $where .= " AND ac.transdate >= '$fromdate'";
802   }
803
804   if ($todate) {
805     $where    .= " AND ac.transdate <= '$todate'";
806     $ARwhere  .= " AND acc.transdate <= '$todate'";
807   }
808
809   my $acc_trans_where = '1=1';
810   if ($fromdate || $todate) {
811     $acc_trans_where = "ac.trans_id IN (SELECT DISTINCT trans_id FROM acc_trans WHERE ";
812
813     if ($fromdate) {
814       $acc_trans_where .= "transdate >= '$fromdate'";
815     }
816     if ($todate) {
817       $acc_trans_where .= " AND " if ($fromdate);
818       $acc_trans_where .= "transdate <= '$todate'";
819     }
820
821     $acc_trans_where .= ")";
822   }
823
824   ############################################
825   # Method eq 'cash' = IST Versteuerung
826   ############################################
827   # Betrifft nur die eingenommene Umsatzsteuer
828   #
829   ############################################
830
831   if ($form->{method} eq 'cash') {
832
833     $query = qq|
834        SELECT
835          -- USTVA IST-Versteuerung
836          --
837          -- Alle tatsaechlichen _Zahlungseingaenge_
838          -- im Voranmeldezeitraum erfassen
839          -- (Teilzahlungen werden prozentual auf verschiedene Steuern aufgeteilt)
840          SUM( ac.amount *
841             -- Bezahlt / Rechnungssumme
842            (
843              SELECT SUM(acc.amount)
844              FROM acc_trans acc
845              INNER JOIN chart c ON (acc.chart_id   =   c.id
846                                     AND c.link   like  '%AR_paid%')
847              WHERE
848               1=1
849               $ARwhere
850               AND acc.trans_id = ac.trans_id
851               )
852            /
853            (
854             SELECT amount FROM ar WHERE id = ac.trans_id
855            )
856          ) AS amount,
857          tk.pos_ustva
858        FROM acc_trans ac
859        LEFT JOIN chart c ON (c.id  = ac.chart_id)
860        LEFT JOIN ar      ON (ar.id = ac.trans_id)
861        LEFT JOIN taxkeys tk ON (
862          tk.id = (
863            SELECT id FROM taxkeys
864            WHERE chart_id   = ac.chart_id
865              -- AND taxkey_id  = ac.taxkey
866              AND startdate <= COALESCE(ar.deliverydate,ar.transdate)
867            ORDER BY startdate DESC LIMIT 1
868          )
869        )
870        WHERE
871        $acc_trans_where
872        GROUP BY tk.pos_ustva
873     |;
874
875   } elsif ($form->{method} eq 'accrual') {
876     #########################################
877     # Method eq 'accrual' = Soll Versteuerung
878     #########################################
879
880     $query = qq|
881        -- Alle Einnahmen AR und pos_ustva erfassen
882        SELECT
883          - sum(ac.amount) AS amount,
884          tk.pos_ustva
885        FROM acc_trans ac
886        JOIN chart c ON (c.id = ac.chart_id)
887        JOIN ar ON (ar.id = ac.trans_id)
888        JOIN taxkeys tk ON (
889          tk.id = (
890            SELECT id FROM taxkeys
891            WHERE chart_id   = ac.chart_id
892              AND startdate <= COALESCE(ar.deliverydate,ar.transdate)
893            ORDER BY startdate DESC LIMIT 1
894          )
895        )
896        $dpt_join
897        WHERE 1 = 1
898        $where
899        GROUP BY tk.pos_ustva
900   |;
901
902   } else {
903
904     $form->error("Unknown tax method: $form->{method}")
905
906   }
907
908   #########################################
909   # Ausgaben und Gl Buchungen sind gleich
910   # für Ist- und Soll-Versteuerung
911   #########################################
912   $query .= qq|
913      UNION -- alle Ausgaben AP erfassen
914
915        SELECT
916          sum(ac.amount) AS amount,
917          tk.pos_ustva
918        FROM acc_trans ac
919        JOIN ap ON (ap.id = ac.trans_id )
920        JOIN chart c ON (c.id = ac.chart_id)
921        LEFT JOIN taxkeys tk ON (
922            tk.id = (
923              SELECT id FROM taxkeys
924              WHERE 1=1
925                AND chart_id=ac.chart_id
926                --AND taxkey_id = ac.taxkey
927                AND startdate <= COALESCE(AP.transdate)
928              ORDER BY startdate DESC LIMIT 1
929            )
930        )
931        WHERE
932        1=1
933        $where
934        GROUP BY tk.pos_ustva
935
936      UNION -- Einnahmen direkter gl Buchungen erfassen
937
938        SELECT sum
939          ( - ac.amount) AS amount,
940          tk.pos_ustva
941        FROM acc_trans ac
942        JOIN chart c ON (c.id = ac.chart_id)
943        JOIN gl a ON (a.id = ac.trans_id)
944        LEFT JOIN taxkeys tk ON (
945          tk.id = (
946            SELECT id FROM taxkeys
947            WHERE chart_id=ac.chart_id
948              AND NOT $gltaxkey_where
949              AND startdate <= COALESCE(ac.transdate)
950            ORDER BY startdate DESC LIMIT 1
951          )
952        )
953
954        $dpt_join
955        WHERE 1 = 1
956        $where
957        GROUP BY tk.pos_ustva
958
959
960      UNION -- Ausgaben direkter gl Buchungen erfassen
961
962        SELECT sum
963          (ac.amount) AS amount,
964          tk.pos_ustva
965        FROM acc_trans ac
966        JOIN chart c ON (c.id = ac.chart_id)
967        JOIN gl a ON (a.id = ac.trans_id)
968        LEFT JOIN taxkeys tk ON (
969          tk.id = (
970            SELECT id FROM taxkeys
971            WHERE chart_id=ac.chart_id
972              AND $gltaxkey_where
973              AND startdate <= COALESCE(ac.transdate)
974            ORDER BY startdate DESC LIMIT 1
975          )
976        )
977
978        $dpt_join
979        WHERE 1 = 1
980        $where
981        GROUP BY tk.pos_ustva
982
983   |;
984
985   my @accno;
986   my $accno;
987   my $ref;
988
989   # Show all $query in Debuglevel LXDebug::QUERY
990   $callingdetails = (caller (0))[3];
991   $main::lxdebug->message(LXDebug::QUERY, "$callingdetails \$query=\n $query");
992
993   my $sth = $dbh->prepare($query);
994
995   $sth->execute || $form->dberror($query);
996
997   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
998     # Bug 365 solved?!
999     $ref->{amount} *= -1;
1000     $form->{ $ref->{$category} } += $ref->{amount};
1001   }
1002
1003   $sth->finish;
1004
1005   $main::lxdebug->leave_sub();
1006
1007 }
1008
1009 sub get_config {
1010   $main::lxdebug->enter_sub();
1011
1012   my ($self, $userspath, $filename) = @_;
1013
1014   $form->error("Missing Parameter: @_") if !$userspath || !$filename;
1015
1016   my $form = $main::form;
1017
1018   $filename = "$form->{login}_$filename";
1019   $filename =~ s|.*/||;
1020   $filename = "$userspath/$filename";
1021   open my $FACONF, "<", $filename or sub {# Annon Sub
1022     # catch open error
1023     # create file if file does not exist
1024     open my $FANEW, ">", $filename  or $form->error("CREATE: $filename : $!");
1025     close $FANEW                    or $form->error("CLOSE: $filename : $!");
1026
1027     #try again open file
1028     open my $FACONF, "<", $filename or $form->error("OPEN: $filename : $!");
1029   };
1030
1031   while (<$FACONF>) {
1032     last if (/^\[/);
1033     next if (/^(\#|\s)/);
1034
1035     # remove comments
1036     s/\s#.*//g;
1037
1038     # remove any trailing whitespace
1039     s/^\s*(.*?)\s*$/$1/;
1040     my ($key, $value) = split(/=/, $_, 2);
1041
1042     $form->{$key} = "$value";
1043
1044   }
1045
1046   close $FACONF;
1047
1048   $main::lxdebug->leave_sub();
1049 }
1050
1051
1052 1;