Merge branch 'b-3.6.1' of ../kivitendo-erp_20220811
[kivitendo-erp.git] / SL / USTVA.pm
index a80372b..ee2d21f 100644 (file)
 # GNU General Public License for more details.
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1335, USA.
 #======================================================================
 # Utilities for ustva
 #=====================================================================
 
 package USTVA;
 
+use Carp;
+use Data::Dumper;
 use List::Util qw(first);
 
+use SL::DB;
 use SL::DBUtils;
+use SL::DB::Default;
+use SL::DB::Finanzamt;
+use SL::Locale::String qw(t8);
 
 use utf8;
 use strict;
 
 my @tax_office_information = (
-  { 'id' =>  8, 'name' => 'Baden-Württemberg',      'taxbird_nr' => '0',  'elster_format' => 'FF/BBB/UUUUP',  },
-  { 'id' =>  9, 'name' => 'Bayern',                 'taxbird_nr' => '1',  'elster_format' => 'FFF/BBB/UUUUP', },
-  { 'id' => 11, 'name' => 'Berlin',                 'taxbird_nr' => '2',  'elster_format' => 'FF/BBB/UUUUP',  },
-  { 'id' => 12, 'name' => 'Brandenburg',            'taxbird_nr' => '3',  'elster_format' => 'FFF/BBB/UUUUP', },
-  { 'id' =>  4, 'name' => 'Bremen',                 'taxbird_nr' => '4',  'elster_format' => 'FF BBB UUUUP',  },
-  { 'id' =>  2, 'name' => 'Hamburg',                'taxbird_nr' => '5',  'elster_format' => 'FF/BBB/UUUUP',  },
-  { 'id' =>  6, 'name' => 'Hessen',                 'taxbird_nr' => '6',  'elster_format' => '0FF BBB UUUUP', },
-  { 'id' => 13, 'name' => 'Mecklenburg-Vorpommern', 'taxbird_nr' => '7',  'elster_format' => 'FFF/BBB/UUUUP', },
-  { 'id' =>  3, 'name' => 'Niedersachsen',          'taxbird_nr' => '8',  'elster_format' => 'FF/BBB/UUUUP',  },
-  { 'id' =>  5, 'name' => 'Nordrhein-Westfalen',    'taxbird_nr' => '9',  'elster_format' => 'FFF/BBBB/UUUP', },
-  { 'id' =>  7, 'name' => 'Rheinland-Pfalz',        'taxbird_nr' => '10', 'elster_format' => 'FF/BBB/UUUU/P', },
-  { 'id' => 10, 'name' => 'Saarland',               'taxbird_nr' => '11', 'elster_format' => 'FFF/BBB/UUUUP', },
-  { 'id' => 14, 'name' => 'Sachsen',                'taxbird_nr' => '12', 'elster_format' => 'FFF/BBB/UUUUP', },
-  { 'id' => 15, 'name' => 'Sachsen-Anhalt',         'taxbird_nr' => '13', 'elster_format' => 'FFF/BBB/UUUUP', },
-  { 'id' =>  1, 'name' => 'Schleswig-Holstein',     'taxbird_nr' => '14', 'elster_format' => 'FF BBB UUUUP',  },
-  { 'id' => 16, 'name' => 'Thüringen',              'taxbird_nr' => '15', 'elster_format' => 'FFF/BBB/UUUUP', },
+  { 'id' =>  8, 'name' => 'Baden-Württemberg',      'taxbird_nr' => '1',  'elster_format' => 'FFBBB/UUUUP',  },
+  { 'id' =>  9, 'name' => 'Bayern',                 'taxbird_nr' => '2',  'elster_format' => 'FFF/BBB/UUUUP', },
+  { 'id' => 11, 'name' => 'Berlin',                 'taxbird_nr' => '3',  'elster_format' => 'FF/BBB/UUUUP',  },
+  { 'id' => 12, 'name' => 'Brandenburg',            'taxbird_nr' => '4',  'elster_format' => 'FFF/BBB/UUUUP', },
+  { 'id' =>  4, 'name' => 'Bremen',                 'taxbird_nr' => '5',  'elster_format' => 'FF BBB UUUUP',  },
+  { 'id' =>  2, 'name' => 'Hamburg',                'taxbird_nr' => '6',  'elster_format' => 'FF/BBB/UUUUP',  },
+  { 'id' =>  6, 'name' => 'Hessen',                 'taxbird_nr' => '7',  'elster_format' => '0FF BBB UUUUP', },
+  { 'id' => 13, 'name' => 'Mecklenburg-Vorpommern', 'taxbird_nr' => '8',  'elster_format' => 'FFF/BBB/UUUUP', },
+  { 'id' =>  3, 'name' => 'Niedersachsen',          'taxbird_nr' => '9',  'elster_format' => 'FF/BBB/UUUUP',  },
+  { 'id' =>  5, 'name' => 'Nordrhein-Westfalen',    'taxbird_nr' => '10', 'elster_format' => 'FFF/BBBB/UUUP', },
+  { 'id' =>  7, 'name' => 'Rheinland-Pfalz',        'taxbird_nr' => '11', 'elster_format' => 'FF/BBB/UUUUP', },
+  { 'id' => 10, 'name' => 'Saarland',               'taxbird_nr' => '12', 'elster_format' => 'FFF/BBB/UUUUP', },
+  { 'id' => 14, 'name' => 'Sachsen',                'taxbird_nr' => '13', 'elster_format' => 'FFF/BBB/UUUUP', },
+  { 'id' => 15, 'name' => 'Sachsen-Anhalt',         'taxbird_nr' => '14', 'elster_format' => 'FFF/BBB/UUUUP', },
+  { 'id' =>  1, 'name' => 'Schleswig-Holstein',     'taxbird_nr' => '15', 'elster_format' => 'FF BBB UUUUP',  },
+  { 'id' => 16, 'name' => 'Thüringen',              'taxbird_nr' => '16', 'elster_format' => 'FFF/BBB/UUUUP', },
   );
 
+  my @fiamt_config = qw(taxnumber fa_bufa_nr fa_dauerfrist fa_steuerberater_city fa_steuerberater_name
+  fa_steuerberater_street fa_steuerberater_tel fa_voranmeld);
+
+  my @fiamt_finanzamt = qw(
+    fa_land_nr          fa_bufa_nr            fa_name             fa_strasse
+    fa_plz              fa_ort                fa_telefon          fa_fax
+    fa_plz_grosskunden  fa_plz_postfach       fa_postfach
+    fa_blz_1 fa_kontonummer_1 fa_bankbezeichnung_1
+    fa_blz_2 fa_kontonummer_2 fa_bankbezeichnung_2 fa_oeffnungszeiten
+    fa_email fa_internet);
+
+
 sub new {
   my $type = shift;
 
@@ -114,63 +133,25 @@ sub report_variables {
     $where_dcp
   |;
 
-  my $dbh = $form->dbconnect($myconfig);
-  my $sth = $dbh->prepare($query);
-
-  $sth->execute() || $form->dberror($query);
-
   my @positions;
 
-  while ( my $row_ref = $sth->fetchrow_arrayref() ) {
-    push @positions, @$row_ref;  # Copy the array contents
-  }
+  SL::DB->client->with_transaction(sub {
+    my $dbh = SL::DB->client->dbh;
+    my $sth = $dbh->prepare($query);
 
-  $sth->finish;
+    $sth->execute() || $form->dberror($query);
 
-  $dbh->disconnect;
+    while ( my $row_ref = $sth->fetchrow_arrayref() ) {
+      push @positions, @$row_ref;  # Copy the array contents
+    }
 
-  return @positions;
+    $sth->finish;
+    1;
+  }) or do { die SL::DB->client->error };
 
+  return @positions;
 }
 
-sub create_steuernummer {
-  $main::lxdebug->enter_sub();
-
-  my $form = $main::form;
-
-  our ($elster_FFFF);
-
-  my $part           = $form->{part};
-  my $patterncount   = $form->{patterncount};
-  my $delimiter      = $form->{delimiter};
-  my $elster_pattern = $form->{elster_pattern};
-
-  # rebuild steuernummer and elstersteuernummer
-  # es gibt eine gespeicherte steuernummer $form->{steuernummer}
-  # und die parts und delimiter
-
-  my $h = 0;
-  my $i = 0;
-
-  my $steuernummer_new        = $part;
-  my $elstersteuernummer_new  = $elster_FFFF;
-  $elstersteuernummer_new    .= '0';
-
-  for ($h = 1; $h < $patterncount; $h++) {
-    $steuernummer_new .= qq|$delimiter|;
-    for ($i = 1; $i <= length($elster_pattern); $i++) {
-      $steuernummer_new       .= $form->{"part_$h\_$i"};
-      $elstersteuernummer_new .= $form->{"part_$h\_$i"};
-    }
-  }
-  if ($form->{steuernummer} ne $steuernummer_new) {
-    $form->{steuernummer}       = $steuernummer_new;
-    $form->{elstersteuernummer} = $elstersteuernummer_new;
-    $form->{steuernummer_new}   = $steuernummer_new;
-  }
-  $main::lxdebug->leave_sub();
-  return ($steuernummer_new, $elstersteuernummer_new);
-}
 
 sub steuernummer_input {
   $main::lxdebug->enter_sub();
@@ -191,16 +172,27 @@ sub steuernummer_input {
   #Pattern description Elstersteuernummer
 
   #split the pattern
-  my $tax_office     = first { $_->{name} eq $elster_land } @{ $self->{tax_office_information} };
+  my $tax_office     = first { $_->{id} eq $elster_land } @{ $self->{tax_office_information} };
   my $elster_pattern = $tax_office->{elster_format};
+ # $::lxdebug->message(LXDebug->DEBUG2, "stnr=".$stnr." elster_FFFF=".$elster_FFFF.
+ #                     " pattern=".$elster_pattern." land=".$elster_land);
   my @elster_pattern = split(' ', $elster_pattern);
-  my $delimiter      = '&nbsp;';
+  my $delimiter1      = '&nbsp;';
+  my $delimiter2      = '&nbsp;';
   my $patterncount   = @elster_pattern;
   if ($patterncount < 2) {
     @elster_pattern = ();
     @elster_pattern = split('/', $elster_pattern);
-    $delimiter      = '/';
+    $delimiter1      = '/';
+    $delimiter2      = '/';
     $patterncount   = @elster_pattern;
+    if ($patterncount < 2) {
+        @elster_pattern = ();
+        @elster_pattern = split(' ', $elster_pattern);
+        $delimiter1      = ' ';
+        $delimiter2      = ' ';
+        $patterncount   = @elster_pattern;
+    }
   }
 
   # no we have an array of patternparts and a delimiter
@@ -208,6 +200,7 @@ sub steuernummer_input {
 
   $steuernummer_input .= qq|<b><font size="+1">|;
   my $part = '';
+#  $::lxdebug->message(LXDebug->DEBUG2, "pattern0=".$elster_pattern[0]);
 SWITCH: {
     $elster_pattern[0] eq 'FFF' && do {
       $part = substr($elster_FFFF, 1, 4);
@@ -219,6 +212,15 @@ SWITCH: {
       $steuernummer_input .= qq|$part|;
       last SWITCH;
     };
+    $elster_pattern[0] eq 'FFBBB' && do {
+      $part = substr($elster_FFFF, 2, 4);
+      $steuernummer_input .= qq|$part|;
+      $delimiter1 = '';
+      $patterncount++ ;
+      # Sonderfall BW
+      @elster_pattern = ('FF','BBB','UUUUP');
+      last SWITCH;
+    };
     $elster_pattern[0] eq 'FF' && do {
       $part = substr($elster_FFFF, 2, 4);
       $steuernummer_input .= qq|$part|;
@@ -231,19 +233,22 @@ SWITCH: {
   }
 
   #now the rest of the Steuernummer ...
-  $steuernummer_input .= qq|</b></font>|;
+  $steuernummer_input .= qq|</font></b>|;
   $steuernummer_input .= qq|\n
            <input type=hidden name="elster_pattern" value="$elster_pattern">
            <input type=hidden name="patterncount" value="$patterncount">
            <input type=hidden name="patternlength" value="$patterncount">
-           <input type=hidden name="delimiter" value="$delimiter">
+           <input type=hidden name="delimiter1" value="$delimiter1">
+           <input type=hidden name="delimiter2" value="$delimiter2">
            <input type=hidden name="part" value="$part">
   |;
 
   my $k = 0;
 
   for (my $h = 1; $h < $patterncount; $h++) {
+    my $delimiter = ( $h==1?$delimiter1:$delimiter2);
     $steuernummer_input .= qq|&nbsp;$delimiter&nbsp;\n|;
+#  $::lxdebug->message(LXDebug->DEBUG2, "pattern[$h]=".$elster_pattern[$h]);
     for (my $i = 1; $i <= length($elster_pattern[$h]); $i++) {
       $steuernummer_input .= qq|<select name="part_$h\_$i">\n|;
 
@@ -269,42 +274,46 @@ SWITCH: {
 sub fa_auswahl {
   $main::lxdebug->enter_sub();
 
-#  use SL::Form;
-
   # Referenz wird übergeben, hash of hash wird nicht
   # in neues  Hash kopiert, sondern direkt über die Referenz verändert
   # Prototyp für diese Konstruktion
 
   my ($self, $land, $elsterFFFF, $elster_init) = @_;
 
+#  $::lxdebug->message(LXDebug->DEBUG2,"land=".$land." amt=".$elsterFFFF);
   my $terminal = '';
   my $FFFF     = $elsterFFFF;
   my $ffff     = '';
   my $checked  = '';
   $checked = 'checked' if ($elsterFFFF eq '' and $land eq '');
   my %elster_land_fa;
+  my %elster_land_name = ();
 
   my $fa_auswahl = qq|
         <script language="Javascript">
         function update_auswahl()
         {
-                var elsterBLAuswahl = document.verzeichnis.elsterland_new;
-                var elsterFAAuswahl = document.verzeichnis.elsterFFFF_new;
+                var elsterBLAuswahl = document.verzeichnis.fa_land_nr_new;
+                var elsterFAAuswahl = document.verzeichnis.fa_bufa_nr_new;
 
                 elsterFAAuswahl.options.length = 0; // dropdown aufräumen
                 |;
 
   foreach my $elster_land (sort keys %$elster_init) {
     $fa_auswahl .= qq|
-               if (elsterBLAuswahl.options[elsterBLAuswahl.selectedIndex].
-               value == "$elster_land")
+               if (elsterBLAuswahl.options[elsterBLAuswahl.selectedIndex].value == "$elster_land")
                {
                |;
     my $j              = 0;
     %elster_land_fa = ();
     $FFFF = '';
     for $FFFF (keys %{ $elster_init->{$elster_land} }) {
-      $elster_land_fa{$FFFF} = $elster_init->{$elster_land}->{$FFFF}->[0];
+        if ( $FFFF eq 'name' ) {
+            $elster_land_name{$elster_land} = $elster_init->{$elster_land}{$FFFF};
+            delete $elster_init->{$elster_land}{$FFFF};
+        } else {
+            $elster_land_fa{$FFFF} = $elster_init->{$elster_land}{$FFFF}->fa_name;
+       }
     }
     foreach $ffff (sort { $elster_land_fa{$a} cmp $elster_land_fa{$b} }
                    keys(%elster_land_fa)
@@ -326,20 +335,22 @@ sub fa_auswahl {
                Bundesland
             </td>
             <td>
-              <select size="1" name="elsterland_new" onchange="update_auswahl()">|;
+              <select size="1" name="fa_land_nr_new" onchange="update_auswahl()">|;
   if ($land eq '') {
     $fa_auswahl .= qq|<option value="Auswahl" $checked>| . $main::locale->text('Select federal state...') . qq|</option>\n|;
   }
   foreach my $elster_land (sort keys %$elster_init) {
     $fa_auswahl .= qq|
                   <option value="$elster_land"|;
+#  $::lxdebug->message(LXDebug->DEBUG2,"land=".$land." elster_land=".$elster_land." lname=".$elster_land_name{$elster_land});
     if ($elster_land eq $land and $checked eq '') {
       $fa_auswahl .= qq| selected|;
     }
-    $fa_auswahl .= qq|>$elster_land</option>
+    $fa_auswahl .= qq|>$elster_land_name{$elster_land}</option>
              |;
   }
   $fa_auswahl .= qq|
+              </select>
             </td>
           </tr>
           |;
@@ -348,7 +359,7 @@ sub fa_auswahl {
   $elster_land = ($land ne '') ? $land : '';
   %elster_land_fa = ();
   for $FFFF (keys %{ $elster_init->{$elster_land} }) {
-    $elster_land_fa{$FFFF} = $elster_init->{$elster_land}->{$FFFF}->[0];
+    $elster_land_fa{$FFFF} = $elster_init->{$elster_land}{$FFFF}->fa_name;
   }
 
   $fa_auswahl .= qq|
@@ -356,7 +367,7 @@ sub fa_auswahl {
               <td>Finanzamt
               </td>
               <td>
-                 <select size="1" name="elsterFFFF_new">|;
+                 <select size="1" name="fa_bufa_nr_new">|;
   if ($elsterFFFF eq '') {
     $fa_auswahl .= qq|<option value="Auswahl" $checked>| . $main::locale->text('Select tax office...') . qq|</option>|;
   } else {
@@ -373,10 +384,10 @@ sub fa_auswahl {
     }
   }
   $fa_auswahl .= qq|
-                 </td>
-              </tr>
-            </table>
-            </select>|;
+                 </select>
+              </td>
+          </tr>
+        </table>|;
 
   $main::lxdebug->leave_sub();
 
@@ -401,7 +412,7 @@ sub info {
     </body>
     |;
 
-    ::end_of_request();
+    $::dispatcher->end_request;
 
   } else {
 
@@ -411,95 +422,12 @@ sub info {
   $main::lxdebug->leave_sub();
 }
 
-# 20.10.2009 sschoeling: this sub seems to be orphaned.
-sub stichtag {
-  $main::lxdebug->enter_sub();
-
-  # noch nicht fertig
-  # soll mal eine Erinnerungsfunktion für USTVA Abgaben werden, die automatisch
-  # den Termin der nächsten USTVA anzeigt.
-  #
-  #
-  my ($today, $FA_dauerfrist, $FA_voranmeld) = @_;
-
-  #$today zerlegen:
-
-  #$today =today * 1;
-  $today =~ /(\d\d\d\d)(\d\d)(\d\d)/;
-  my $year     = $1;
-  my $month    = $2;
-  my $day      = $3;
-  my $yy       = $year;
-  my $mm       = $month;
-  my $yymmdd   = "$year$month$day" * 1;
-  my $mmdd     = "$month$day" * 1;
-  my $stichtag = '';
-
-  #$tage_bis = '1234';
-  #$ical = '...vcal format';
-
-  #if ($FA_voranmeld eq 'month'){
-
-  my %liste = (
-    "0110" => 'December',
-    "0210" => 'January',
-    "0310" => 'February',
-    "0410" => 'March',
-    "0510" => 'April',
-    "0610" => 'May',
-    "0710" => 'June',
-    "0810" => 'July',
-    "0910" => 'August',
-    "1010" => 'September',
-    "1110" => 'October',
-    "1210" => 'November',
-  );
-
-  #$mm += $dauerfrist
-  #$month *= 1;
-  $month += 1 if ($day > 10);
-  $month    = sprintf("%02d", $month);
-  $stichtag = $year . $month . "10";
-  my $ust_va   = $month . "10";
-
-  foreach my $date (%liste) {
-    $ust_va = $liste{$date} if ($date eq $stichtag);
-  }
-
-  #} elsif ($FA_voranmeld eq 'quarter'){
-  #1;
-
-  #}
-
-  #@stichtag = ('10.04.2004', '10.05.2004');
-
-  #@liste = ['0110', '0210', '0310', '0410', '0510', '0610', '0710', '0810', '0910',
-  #          '1010', '1110', '1210', ];
-  #
-  #foreach $key (@liste){
-  #  #if ($ddmm < ('0110' * 1));
-  #  if ($ddmm ){}
-  #  $stichtag = $liste[$key - 1] if ($ddmm > $key);
-  #
-  #}
-  #
-  #$stichtag =~ /([\d]\d)(\d\d)$/
-  #$stichtag = "$1.$2.$yy"
-  #$stichtag=$1;
-  our $description; # most probably not existent.
-  our $tage_bis;    # most probably not existent.
-  our $ical;        # most probably not existent.
-
-  $main::lxdebug->leave_sub();
-  return ($stichtag, $description, $tage_bis, $ical);
-}
-
 sub query_finanzamt {
   $main::lxdebug->enter_sub();
 
   my ($self, $myconfig, $form) = @_;
 
-  my $dbh = $form->dbconnect($myconfig) or $self->error(DBI->errstr);
+  my $dbh = SL::DB->client->dbh;
 
   #Test, if table finanzamt exist
   my $table    = 'finanzamt';
@@ -510,77 +438,23 @@ sub query_finanzamt {
     #There is no table, read the table from sql/finanzamt.sql
     print qq|<p>Bitte warten, Tabelle $table wird einmalig in Datenbank:
     $myconfig->{dbname} als Benutzer: $myconfig->{dbuser} hinzugefügt...</p>|;
-    process_query($form, $dbh, $filename) || $self->error(DBI->errstr);
-
-    #execute second last call
-    my $dbh = $form->dbconnect($myconfig) or $self->error(DBI->errstr);
-    $dbh->disconnect();
+    SL::DB->client->with_transaction(sub {
+      process_query($form, $dbh, $filename) || $self->error(DBI->errstr);
+      1;
+    }) or do { die SL::DB->client->error };
   };
   $tst->finish();
 
-  #$dbh->disconnect();
-
-  my @vars = (
-    'FA_Land_Nr',             #  0
-    'FA_BUFA_Nr',             #  1
-                              #'FA_Verteiler',                             #  2
-    'FA_Name',                #  3
-    'FA_Strasse',             #  4
-    'FA_PLZ',                 #  5
-    'FA_Ort',                 #  6
-    'FA_Telefon',             #  7
-    'FA_Fax',                 #  8
-    'FA_PLZ_Grosskunden',     #  9
-    'FA_PLZ_Postfach',        # 10
-    'FA_Postfach',            # 11
-    'FA_BLZ_1',               # 12
-    'FA_Kontonummer_1',       # 13
-    'FA_Bankbezeichnung_1',   # 14
-                              #'FA_BankIBAN_1',                            # 15
-                              #'FA_BankBIC_1',                             # 16
-                              #'FA_BankInhaber_BUFA_Nr_1',                 # 17
-    'FA_BLZ_2',               # 18
-    'FA_Kontonummer_2',       # 19
-    'FA_Bankbezeichnung_2',   # 20
-                              #'FA_BankIBAN_2',                            # 21
-                              #'FA_BankBIC_2',                             # 22
-                              #'FA_BankInhaber_BUFA_Nr_2',                 # 23
-    'FA_Oeffnungszeiten',     # 24
-    'FA_Email',               # 25
-    'FA_Internet'             # 26
-                              #'FA_zustaendige_Hauptstelle_BUFA_Nr',       # 27
-                              #'FA_zustaendige_vorgesetzte_Finanzbehoerde' # 28
-  );
 
-  my $field = join(', ', @vars);
-
-  my $query = "SELECT $field FROM finanzamt ORDER BY FA_Land_nr";
-  my $sth = $dbh->prepare($query) or $self->error($dbh->errstr);
-  $sth->execute || $form->dberror($query);
-  my $array_ref = $sth->fetchall_arrayref();
-  my $land      = '';
+  my $fiamt =  SL::DB::Finanzamt->_get_manager_class->get_all(sort => 'fa_land_nr');
+  my $land      = 0;
   my %finanzamt;
-  foreach my $row (@$array_ref) {
-    my $FA_finanzamt = $row;
-    my $tax_office   = first { $_->{id} == $FA_finanzamt->[0] } @{ $self->{tax_office_information} };
-    $land            = $tax_office->{name};
-
-    # $land = $main::locale->{iconv}->convert($land);
-
-    my $ffff = @$FA_finanzamt[1];
-
-    my $rec = {};
-    $rec->{$land} = $ffff;
-
-    shift @$row;
-    shift @$row;
-
-    $finanzamt{$land}{$ffff} = [@$FA_finanzamt];
+  foreach my $row (@$fiamt) {
+    my $tax_office   = first { $_->{id} == $row->fa_land_nr } @{ $self->{tax_office_information} };
+    $land            = $tax_office->{id};
+    $finanzamt{$land}{$row->fa_bufa_nr}  = $row;
+    $finanzamt{$land}{'name'} ||= $tax_office->{name};
   }
-
-  $sth->finish();
-  $dbh->disconnect();
-
   $main::lxdebug->leave_sub();
 
   return \%finanzamt;
@@ -589,11 +463,8 @@ sub query_finanzamt {
 sub process_query {
   $main::lxdebug->enter_sub();
 
-  # Copyright D. Simander -> SL::Form under Gnu GPL.
   my ($form, $dbh, $filename) = @_;
 
-  #  return unless (-f $filename);
-
   open my $FH, "<", "$filename" or $form->error("$filename : $!\n");
   my $query = "";
   my $sth;
@@ -648,12 +519,16 @@ sub ustva {
 
   my ($self, $myconfig, $form) = @_;
 
-  # connect to database
-  my $dbh = $form->get_standard_dbh;
+  my $dbh = SL::DB->client->dbh;
 
   my $last_period     = 0;
   my $category        = "pos_ustva";
 
+  $form->{coa} = $::instance_conf->get_coa;
+
+  unless ($form->{coa} eq 'Germany-DATEV-SKR03EU' or $form->{coa} eq 'Germany-DATEV-SKR04EU') {
+    croak t8("Advance turnover tax return only valid for SKR03 or SKR04");
+  }
   my @category_cent = USTVA->report_variables({
       myconfig    => $myconfig,
       form        => $form,
@@ -661,9 +536,10 @@ sub ustva {
       attribute   => 'position',
       dec_places  => '2',
   });
-
-  push @category_cent, qw(83  Z43  Z45  Z53  Z62  Z65  Z67);
-
+  push @category_cent, ("pos_ustva_811b_kivi", "pos_ustva_861b_kivi");
+  if ( $form->{coa} eq 'Germany-DATEV-SKR03EU' or $form->{coa} eq 'Germany-DATEV-SKR04EU') {
+      push @category_cent, qw(Z43  Z45  Z53  Z54  Z62  Z65  Z67);
+  }
   my @category_euro = USTVA->report_variables({
       myconfig    => $myconfig,
       form        => $form,
@@ -671,15 +547,9 @@ sub ustva {
       attribute   => 'position',
       dec_places  => '0',
   });
-
-  push @category_euro, USTVA->report_variables({
-      myconfig    => $myconfig,
-      form        => $form,
-      type        => '',
-      attribute   => 'position',
-      dec_places  => '0',
-  });
-
+  push @category_euro, ("pos_ustva_81b_kivi", "pos_ustva_86b_kivi");
+  @{$form->{category_cent}} = @category_cent;
+  @{$form->{category_euro}} = @category_euro;
   $form->{decimalplaces} *= 1;
 
   foreach my $item (@category_cent) {
@@ -688,14 +558,11 @@ sub ustva {
   foreach my $item (@category_euro) {
     $form->{"$item"} = 0;
   }
-  my $coa_name = $::instance_conf->get_coa;
-  $form->{coa} = $coa_name;
 
   # Controlvariable for templates
+  my $coa_name = $form->{coa};
   $form->{"$coa_name"} = '1';
 
-  $main::lxdebug->message(LXDebug->DEBUG2(), "COA: '$form->{coa}',  \$form->{$coa_name} = 1");
-
   &get_accounts_ustva($dbh, $last_period, $form->{fromdate}, $form->{todate},
                       $form, $category);
 
@@ -707,7 +574,7 @@ sub ustva {
 
   # Germany
 
-  if ( $form->{coa} eq 'Germany-DATEV-SKR03EU' or $form->{coa} eq 'Germany-DATEV-SKR04EU'){
+  if ( $form->{coa} eq 'Germany-DATEV-SKR03EU' or $form->{coa} eq 'Germany-DATEV-SKR04EU') {
 
     # 16%/19% Umstellung
     # Umordnen der Kennziffern
@@ -730,7 +597,7 @@ sub ustva {
 
   # Fixme: Wird auch noch für Oesterreich gebraucht,
   # weil kein eigenes Ausgabeformular
-  # sotte aber aus der allgeméinen Steuerberechnung verschwinden
+  # sollte aber aus der allgemeinen Steuerberechnung verschwinden
   #
   # Berechnung der USTVA Formularfelder laut Bogen 207
   #
@@ -757,8 +624,6 @@ sub ustva {
   $form->{"Z65"} = $form->{"Z62"}     - $form->{"69"};
   $form->{"83"}  = $form->{"Z65"}     - $form->{"39"};
 
-  $dbh->disconnect;
-
   $main::lxdebug->leave_sub();
 }
 
@@ -777,10 +642,10 @@ sub get_accounts_ustva {
   my $arwhere  = "";
   my $item;
 
-    my $gltaxkey_where = "((tk.pos_ustva = 46) OR (tk.pos_ustva>=59 AND tk.pos_ustva<=67) or (tk.pos_ustva>=89 AND tk.pos_ustva<=93))";
+  my $gltaxkey_where = "((tk.pos_ustva = 46) OR (tk.pos_ustva>=59 AND tk.pos_ustva<=67) or (tk.pos_ustva>=89 AND tk.pos_ustva<=93))";
 
   if ($fromdate) {
-    if ($form->{method} eq 'cash') {
+    if ($form->{accounting_method} eq 'cash') {
       $subwhere .= " AND transdate >= '$fromdate'";
       $glwhere = " AND ac.transdate >= '$fromdate'";
       $ARwhere .= " AND acc.transdate >= '$fromdate'";
@@ -816,7 +681,7 @@ sub get_accounts_ustva {
   #
   ############################################
 
-  if ($form->{method} eq 'cash') {
+  if ($form->{accounting_method} eq 'cash') {
 
     $query = qq|
        SELECT
@@ -836,16 +701,16 @@ sub get_accounts_ustva {
               1=1
               $ARwhere
               AND acc.trans_id = ac.trans_id
-              )
-           /
+              )           /
            (
             SELECT amount FROM ar WHERE id = ac.trans_id
            )
          ) AS amount,
-         tk.pos_ustva
+         tk.pos_ustva,  t.rate, c.accno
        FROM acc_trans ac
        LEFT JOIN chart c ON (c.id  = ac.chart_id)
        LEFT JOIN ar      ON (ar.id = ac.trans_id)
+       LEFT JOIN tax t   ON (t.id = ac.tax_id)
        LEFT JOIN taxkeys tk ON (
          tk.id = (
            SELECT id FROM taxkeys
@@ -857,10 +722,10 @@ sub get_accounts_ustva {
        )
        WHERE
        $acc_trans_where
-       GROUP BY tk.pos_ustva
+       GROUP BY tk.pos_ustva, t.rate, c.accno
     |;
 
-  } elsif ($form->{method} eq 'accrual') {
+  } elsif ($form->{accounting_method} eq 'accrual') {
     #########################################
     # Method eq 'accrual' = Soll Versteuerung
     #########################################
@@ -869,10 +734,11 @@ sub get_accounts_ustva {
        -- Alle Einnahmen AR und pos_ustva erfassen
        SELECT
          - sum(ac.amount) AS amount,
-         tk.pos_ustva
+         tk.pos_ustva, t.rate, c.accno
        FROM acc_trans ac
        JOIN chart c ON (c.id = ac.chart_id)
        JOIN ar ON (ar.id = ac.trans_id)
+       JOIN tax t ON (t.id = ac.tax_id)
        JOIN taxkeys tk ON (
          tk.id = (
            SELECT id FROM taxkeys
@@ -884,12 +750,12 @@ sub get_accounts_ustva {
        $dpt_join
        WHERE 1 = 1
        $where
-       GROUP BY tk.pos_ustva
+       GROUP BY tk.pos_ustva, t.rate, c.accno
   |;
 
   } else {
 
-    $form->error("Unknown tax method: $form->{method}")
+    $form->error("Unknown tax method: $form->{accounting_method}")
 
   }
 
@@ -902,10 +768,11 @@ sub get_accounts_ustva {
 
        SELECT
          sum(ac.amount) AS amount,
-         tk.pos_ustva
+         tk.pos_ustva, t.rate, c.accno
        FROM acc_trans ac
        JOIN ap ON (ap.id = ac.trans_id )
        JOIN chart c ON (c.id = ac.chart_id)
+       JOIN tax t ON (t.id = ac.tax_id)
        LEFT JOIN taxkeys tk ON (
            tk.id = (
              SELECT id FROM taxkeys
@@ -919,16 +786,17 @@ sub get_accounts_ustva {
        WHERE
        1=1
        $where
-       GROUP BY tk.pos_ustva
+       GROUP BY tk.pos_ustva, t.rate, c.accno
 
      UNION -- Einnahmen direkter gl Buchungen erfassen
 
        SELECT sum
          ( - ac.amount) AS amount,
-         tk.pos_ustva
+         tk.pos_ustva, t.rate, c.accno
        FROM acc_trans ac
        JOIN chart c ON (c.id = ac.chart_id)
        JOIN gl a ON (a.id = ac.trans_id)
+       JOIN tax t ON (t.id = ac.tax_id)
        LEFT JOIN taxkeys tk ON (
          tk.id = (
            SELECT id FROM taxkeys
@@ -942,17 +810,18 @@ sub get_accounts_ustva {
        $dpt_join
        WHERE 1 = 1
        $where
-       GROUP BY tk.pos_ustva
+       GROUP BY tk.pos_ustva, t.rate, c.accno
 
 
      UNION -- Ausgaben direkter gl Buchungen erfassen
 
        SELECT sum
          (ac.amount) AS amount,
-         tk.pos_ustva
+         tk.pos_ustva, t.rate, c.accno
        FROM acc_trans ac
        JOIN chart c ON (c.id = ac.chart_id)
        JOIN gl a ON (a.id = ac.trans_id)
+       JOIN tax t ON (t.id = ac.tax_id)
        LEFT JOIN taxkeys tk ON (
          tk.id = (
            SELECT id FROM taxkeys
@@ -966,14 +835,10 @@ sub get_accounts_ustva {
        $dpt_join
        WHERE 1 = 1
        $where
-       GROUP BY tk.pos_ustva
+       GROUP BY tk.pos_ustva, t.rate, c.accno
 
   |;
 
-  my @accno;
-  my $accno;
-  my $ref;
-
   # Show all $query in Debuglevel LXDebug::QUERY
   my $callingdetails = (caller (0))[3];
   $main::lxdebug->message(LXDebug->QUERY(), "$callingdetails \$query=\n $query");
@@ -981,11 +846,53 @@ sub get_accounts_ustva {
   my $sth = $dbh->prepare($query);
 
   $sth->execute || $form->dberror($query);
+  # ugly, but we need to use static accnos
+  my ($accno_five, $accno_sixteen, $corr);
+
+  if ($form->{coa} eq 'Germany-DATEV-SKR03EU') {
+    $accno_five     = 1773;
+    $accno_sixteen  = 1775;
+  } elsif (($form->{coa} eq 'Germany-DATEV-SKR04EU')) {
+    $accno_five     = 3803; # SKR04
+    $accno_sixteen  = 3805; # SKR04
+  } else {die "wrong call"; }
 
   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
-    # Bug 365 solved?!
+    next unless $ref->{$category};
+    $corr = 0;
     $ref->{amount} *= -1;
-    $form->{ $ref->{$category} } += $ref->{amount};
+    # USTVA Pos 35
+    if ($ref->{pos_ustva} eq '35') {
+      if ($ref->{rate} == 0.16) {
+        $form->{"pos_ustva_81b_kivi"} += $ref->{amount};
+      } elsif ($ref->{rate} == 0.05) {
+        $form->{"pos_ustva_86b_kivi"} += $ref->{amount};
+      } elsif ($ref->{rate} == 0.19) {
+        # pos_ustva says 16, but rate says 19
+        # (pos_ustva should be tax dependent and not taxkeys dependent)
+        # correction hotfix for this case:
+        # bookings exists with 19% ->
+        # move 19% bookings to the 19% position
+        # Dont rely on dates of taxkeys
+        $corr = 1;
+        $form->{"81"} += $ref->{amount};
+      }  elsif ($ref->{rate} == 0.07) {
+        # pos_ustva says 5, but rate says 7
+        # see comment above:
+        # Dont rely on dates of taxkeys
+        $corr = 1;
+        $form->{"86"} += $ref->{amount};
+      } else {die ("No valid tax rate for pos 35" . Dumper($ref)); }
+    }
+    # USTVA Pos 36 (Steuerkonten)
+    if ($ref->{pos_ustva} eq '36') {
+      if ($ref->{accno} =~ /^$accno_sixteen/) {
+        $form->{"pos_ustva_811b_kivi"} += $ref->{amount};
+      } elsif ($ref->{accno} =~ /^$accno_five/) {
+        $form->{"pos_ustva_861b_kivi"} += $ref->{amount};
+      } else { die ("No valid accno for pos 36" . Dumper($ref)); }
+    }
+  $form->{ $ref->{$category} } += $ref->{amount} unless $corr;
   }
 
   $sth->finish;
@@ -994,27 +901,173 @@ sub get_accounts_ustva {
 
 }
 
-sub get_config {
+sub set_FromTo {
   $main::lxdebug->enter_sub();
 
-  my ($self, $userspath, $filename) = @_;
+  my ($self, $form) = @_;
 
-  my $form = $main::form;
+  # init some form vars
+  my @anmeldungszeitraum =
+    qw('0401' '0402' '0403'
+       '0404' '0405' '0406'
+       '0407' '0408' '0409'
+       '0410' '0411' '0412'
+       '0441' '0442' '0443' '0444');
 
-  $form->error("Missing Parameter: @_") if !$userspath || !$filename;
+  foreach my $item (@anmeldungszeitraum) {
+    $form->{$item} = "";
+  }
 
-  $filename = "$::myconfig{login}_$filename";
-  $filename =~ s|.*/||;
-  $filename = "$userspath/$filename";
-  open my $FACONF, "<", $filename or do {# Annon Sub
-    # catch open error
-    # create file if file does not exist
-    open my $FANEW, ">", $filename  or $form->error("CREATE: $filename : $!");
-    close $FANEW                    or $form->error("CLOSE: $filename : $!");
+  #forgotten the year --> thisyear
+  if ($form->{year} !~ m/^\d\d\d\d$/) {
+      $form->{year} = substr(
+          $form->datetonum(
+              $form->current_date(\%::myconfig), \%::myconfig
+          ),
+          0, 4);
+      $::lxdebug->message(LXDebug->DEBUG1,
+                          qq|Actual year from Database: $form->{year}\n|);
+  }
 
-    #try again open file
-    open my $FACONF, "<", $filename or $form->error("OPEN: $filename : $!");
-  };
+  #
+  # using dates in ISO-8601 format: yyyymmmdd  for Postgres...
+  #
+
+  #yearly report
+  if ($form->{period} eq "13") {
+      $form->{fromdate} = "$form->{year}0101";
+      $form->{todate}   = "$form->{year}1231";
+  }
+
+  #quarter reports
+  if ($form->{period} eq "41") {
+      $form->{fromdate} = "$form->{year}0101";
+      $form->{todate}   = "$form->{year}0331";
+      $form->{'0441'}   = "X";
+  }
+  if ($form->{period} eq "42") {
+      $form->{fromdate} = "$form->{year}0401";
+      $form->{todate}   = "$form->{year}0630";
+      $form->{'0442'}   = "X";
+  }
+  if ($form->{period} eq "43") {
+      $form->{fromdate} = "$form->{year}0701";
+      $form->{todate}   = "$form->{year}0930";
+      $form->{'0443'}   = "X";
+  }
+  if ($form->{period} eq "44") {
+      $form->{fromdate} = "$form->{year}1001";
+      $form->{todate}   = "$form->{year}1231";
+      $form->{'0444'}   = "X";
+  }
+
+   #Monthly reports
+  SWITCH: {
+      $form->{period} eq "01" && do {
+        $form->{fromdate} = "$form->{year}0101";
+        $form->{todate}   = "$form->{year}0131";
+        $form->{'0401'}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "02" && do {
+        $form->{fromdate} = "$form->{year}0201";
+
+        #this works from 1901 to 2099, 1900 and 2100 fail.
+        my $leap = ($form->{year} % 4 == 0) ? "29" : "28";
+        $form->{todate} = "$form->{year}02$leap";
+        $form->{"0402"} = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "03" && do {
+        $form->{fromdate} = "$form->{year}0301";
+        $form->{todate}   = "$form->{year}0331";
+        $form->{"0403"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "04" && do {
+        $form->{fromdate} = "$form->{year}0401";
+        $form->{todate}   = "$form->{year}0430";
+        $form->{"0404"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "05" && do {
+        $form->{fromdate} = "$form->{year}0501";
+        $form->{todate}   = "$form->{year}0531";
+        $form->{"0405"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "06" && do {
+        $form->{fromdate} = "$form->{year}0601";
+        $form->{todate}   = "$form->{year}0630";
+        $form->{"0406"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "07" && do {
+        $form->{fromdate} = "$form->{year}0701";
+        $form->{todate}   = "$form->{year}0731";
+        $form->{"0407"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "08" && do {
+        $form->{fromdate} = "$form->{year}0801";
+        $form->{todate}   = "$form->{year}0831";
+        $form->{"0408"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "09" && do {
+        $form->{fromdate} = "$form->{year}0901";
+        $form->{todate}   = "$form->{year}0930";
+        $form->{"0409"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "10" && do {
+        $form->{fromdate} = "$form->{year}1001";
+        $form->{todate}   = "$form->{year}1031";
+        $form->{"0410"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "11" && do {
+        $form->{fromdate} = "$form->{year}1101";
+        $form->{todate}   = "$form->{year}1130";
+        $form->{"0411"}   = "X";
+        last SWITCH;
+      };
+      $form->{period} eq "12" && do {
+        $form->{fromdate} = "$form->{year}1201";
+        $form->{todate}   = "$form->{year}1231";
+        $form->{"0412"}   = "X";
+        last SWITCH;
+      };
+    }
+
+  # Kontrollvariablen für die Templates
+  $form->{"year$_"} = ($form->{year} >= $_ ) ? "1":"0" for 2007..2107;
+
+  $main::lxdebug->leave_sub();
+}
+
+sub get_fiamt_vars {
+    return @fiamt_finanzamt;
+}
+
+sub get_oldconfig {
+  $main::lxdebug->enter_sub();
+
+  my $ret = 0;
+  my %oldkeys = (
+      'steuernummer' => 'taxnumber',
+      'elsterFFFF' => 'fa_bufa_nr',
+      'FA_dauerfrist' => 'fa_dauerfrist',
+      'FA_steuerberater_city' => 'fa_steuerberater_city',
+      'FA_steuerberater_name' => 'fa_steuerberater_name',
+      'FA_steuerberater_street' => 'fa_steuerberater_street',
+      'FA_steuerberater_tel' => 'fa_steuerberater_tel',
+      'FA_voranmeld' => 'fa_voranmeld',
+      );
+
+  my $filename = $::lx_office_conf{paths}{userspath}."/finanzamt.ini";
+  my $FACONF;
+  return unless (open( $FACONF, "<", $filename));
 
   while (<$FACONF>) {
     last if (/^\[/);
@@ -1027,14 +1080,61 @@ sub get_config {
     s/^\s*(.*?)\s*$/$1/;
     my ($key, $value) = split(/=/, $_, 2);
 
-    $form->{$key} = "$value";
-
+    $main::lxdebug->message(LXDebug->DEBUG2(), "oldkey: ".$key." val=".$value." newkey=".
+                          $oldkeys{$key}." oval=".$::form->{$oldkeys{$key}});
+    if ( $oldkeys{$key} && $::form->{$oldkeys{$key}} eq '' ) {
+        $::form->{$oldkeys{$key}} = $::locale->{iconv_utf8}->convert($value);
+        $main::lxdebug->message(LXDebug->DEBUG2(), "set ".$oldkeys{$key}."=".$::form->{$oldkeys{$key}});
+        $ret = 1;
+    }
   }
+  $main::lxdebug->leave_sub();
+  return $ret;
+}
+
+sub get_config {
+    $main::lxdebug->enter_sub();
+    my $defaults   = SL::DB::Default->get;
+    my @rd_config =  @fiamt_config;
+    push @rd_config ,qw(accounting_method coa company address co_ustid duns);
+    $::form->{$_} = $defaults->$_ for @rd_config;
+
+    if ( $::form->{taxnumber} eq '' || $::form->{fa_bufa_nr} eq '') {
+        #alte finanzamt.ini lesen, ggf abspeichern
+        if ( get_oldconfig() ) {
+            get_finanzamt();
+            save_config();
+        }
+    }
 
-  close $FACONF;
+    my $coa = $::form->{coa};
+    $::form->{"COA_$coa"} = '1';
+    $::form->{COA_Germany} = '1' if ($coa =~ m/^germany/i);
+    $main::lxdebug->leave_sub();
+}
 
-  $main::lxdebug->leave_sub();
+sub get_finanzamt {
+    $main::lxdebug->enter_sub();
+    if ( $::form->{fa_bufa_nr} && $::form->{fa_bufa_nr} ne '' ) {
+        my $fiamt =  SL::DB::Finanzamt->_get_manager_class->get_first(
+                 query => [ fa_bufa_nr => $::form->{fa_bufa_nr} ]);
+        $::form->{$_} = $fiamt->$_ for @fiamt_finanzamt;
+    }
+    $main::lxdebug->leave_sub();
 }
 
+sub save_config {
+    $main::lxdebug->enter_sub();
+    my $defaults  = SL::DB::Default->get;
+    $defaults->$_($::form->{$_}) for @fiamt_config;
+    $defaults->save;
+    if ( $defaults->fa_bufa_nr ) {
+        my $fiamt =  SL::DB::Finanzamt->_get_manager_class->get_first(
+                 query => [ fa_bufa_nr => $defaults->fa_bufa_nr ]);
+        $fiamt->$_($::form->{$_}) for @fiamt_finanzamt;
+        $fiamt->save;
+    }
+    $main::lxdebug->leave_sub();
+}
 
 1;