Datenbankupgradescript für die Buchungsgruppen.
authorMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 11 Dec 2006 11:15:32 +0000 (11:15 +0000)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 11 Dec 2006 11:15:32 +0000 (11:15 +0000)
locale/de/Pg-upgrade-2.2.0.33-2.2.0.34 [new file with mode: 0644]
locale/de/all
sql/Pg-upgrade/Pg-upgrade-2.2.0.33-2.2.0.34.pl [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_footer_de.html [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_footer_master.html [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_header_de.html [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_header_master.html [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_parts_de.html [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_parts_master.html [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_services_de.html [new file with mode: 0644]
templates/webpages/dbupgrade/buchungsgruppen_services_master.html [new file with mode: 0644]

diff --git a/locale/de/Pg-upgrade-2.2.0.33-2.2.0.34 b/locale/de/Pg-upgrade-2.2.0.33-2.2.0.34
new file mode 100644 (file)
index 0000000..231c319
--- /dev/null
@@ -0,0 +1,21 @@
+$self->{texts} = {
+  'Database update error:'      => 'Fehler beim Datenbankupgrade:',
+};
+
+$self->{subs} = {
+  'create_buchungsgruppen'      => 'create_buchungsgruppen',
+  'display_create_bgs_dialog'   => 'display_create_bgs_dialog',
+  'do_update'                   => 'do_update',
+  'force_inventory_accno_id_for_parts' => 'force_inventory_accno_id_for_parts',
+  'mydberror'                   => 'mydberror',
+  'mydoquery'                   => 'mydoquery',
+  'retrieve_accounts'           => 'retrieve_accounts',
+  'retrieve_buchungsgruppen'    => 'retrieve_buchungsgruppen',
+  'retrieve_std_inventory_accno_id' => 'retrieve_std_inventory_accno_id',
+  'retrieve_unknown_accno_combinations' => 'retrieve_unknown_accno_combinations',
+  'set_ic_links'                => 'set_ic_links',
+  'set_taxzone_ids'             => 'set_taxzone_ids',
+  'update_known_buchungsgruppen' => 'update_known_buchungsgruppen',
+};
+
+1;
index 230e05b..d06699a 100644 (file)
@@ -16,6 +16,7 @@ $self->{texts} = {
   '2. Quarter'                  => '2. Quartal',
   '3. Quarter'                  => '3. Quartal',
   '4. Quarter'                  => '4. Quartal',
+  'A Buchungsgruppe consists of a descriptive name and the account numbers for the income and expense accounts for those four tax zones as well as the inventory account number.' => 'Eine Buchungsgruppe besteht aus einem deskriptiven Namen, den Erl&ouml;s- und Aufwandskonten f&uuml;r diese vier Steuerzonen sowie aus einem Inventarkonto.',
   'A unit with this name does already exist.' => 'Eine Einheit mit diesem Namen existiert bereits.',
   'AP'                          => 'Einkauf',
   'AP Aging'                    => 'Offene Verbindlichkeiten',
@@ -493,6 +494,7 @@ gestartet',
   'Interest Rate'               => 'Zinssatz',
   'Internal Notes'              => 'interne Bemerkungen',
   'Internet'                    => 'Internet',
+  'Introduction of Buchungsgruppen' => 'Einf&uuml;hrung von Buchungsgruppen',
   'Introduction of units'       => 'Einf&uuml;hrung von Einheiten',
   'Inv. Duedate'                => '',
   'Invdate'                     => 'Rechnungsdatum',
@@ -515,6 +517,7 @@ gestartet',
   'Invoices'                    => 'Rechnungen',
   'Is this a summary account to record' => 'Buchungskonto in',
   'Ist dies eine berichtigte Anmeldung? (Nr. 10/Zeile 15 Steuererklärung)' => 'Ist dies eine berichtigte Anmeldung? (Nr. 10/Zeile 15 Steuererklärung)',
+  'It is possible to do this automatically for some Buchungsgruppen, but not for all.' => 'Es ist m&ouml;glich, dies f&uuml;r einige, aber nicht f&uuml;r alle Buchungsgruppen automatisch zu erledigen.',
   'It is possible to do this automatically for some units, but for others the user has to chose the new unit.' => 'Das ist f&uuml;r einige Einheiten automatisch m&ouml;glich, aber bei anderen muss der Benutzer die neue Einheit ausw&auml;hlen.',
   'Item deleted!'               => 'Artikel gelöscht!',
   'Item not on file!'           => 'Dieser Artikel ist nicht in der Datenbank!',
@@ -586,6 +589,7 @@ gestartet',
   'Login name missing!'         => 'Loginname fehlt.',
   'Logout'                      => 'Abmeldung',
   'Long Description'            => 'Langtext',
+  'Lx-Office 2.4.0 introduces two new concepts: tax zones and Buchungsgruppen.' => 'Lx-Office 2.4.0 f&uuml;hrt zwei neue Konzepte ein: Steuerzonen und Buchungsgruppen.',
   'Make'                        => 'Hersteller',
   'Manager'                     => 'Manager',
   'Mandantennummer'             => 'Mandantennummer',
@@ -642,6 +646,7 @@ gestartet',
   'Nothing to transfer!'        => 'Es gibt nichts zum Umlagern!',
   'Nov'                         => 'Nov',
   'November'                    => 'November',
+  'Now the user must select a single Buchungsgruppe for each part instead of three distinct accounts.' => 'Der Benutzer muss nun f&uuml;r jeden Artikel nur noch die Buchungsgruppe anstelle der drei einzelnen Konten ausw&auml;hlen.',
   'Number'                      => 'Nummer',
   'Number Format'               => 'Zahlenformat',
   'Number missing in Row'       => 'Nummer fehlt in Zeile',
@@ -743,6 +748,7 @@ gestartet',
   'Printer saved!'              => 'Drucker gespeichert!',
   'Printing ... '               => 'Es wird gedruckt.',
   'Prior to Lx-Office v2.4.0 the user could enter arbitrary strings as units for parts, services and in invoices, sales quotations etc.' => 'Vor Lx-Office 2.4.0 konnte der Benutzer bei Artikeln, Dienstleistungen und Rechnungen, Angeboten etc beliebige Einheiten angeben.',
+  'Prior to Lx-Office v2.4.0 the user had to chose the accounts for each part and service.' => 'Vor Lx-Office 2.4.0 musste der Benutzer die Konten bei jeder Ware und jeder Dienstleistung einzeln ausw&auml;hlen.',
   'Private E-mail'              => 'Private eMail',
   'Private Phone'               => 'Privates Tel.',
   'Profit Center'               => 'Erfolgsbereich',
@@ -924,6 +930,7 @@ gestartet',
   'The base unit does not exist.' => 'Die Basiseinheit existiert nicht.',
   'The base unit relations must not contain loops (e.g. by saying that unit A\'s base unit is B, B\'s base unit is C and C\'s base unit is A) in row %d.' => 'Die Beziehungen der Einheiten d&uuml;rfen keine Schleifen beinhalten (z.B. wenn gesagt wird, dass Einheit As Basiseinheit B, Bs Basiseinheit C und Cs Basiseinheit A ist) in Zeile %d.',
   'The database update/creation did not succeed. The file <TMPL_VAR file ESCAPE=HTML> contained the following error:' => 'Die Datenbankaktualisierung/erstellung schlug fehl. Die Datei <TMPL_VAR file ESCAPE=HTML> enthielt den folgenden Fehler:',
+  'The database upgrade for the introduction of Buchungsgruppen is now complete.' => 'Das Datenbankupgrade f&uuml;r die Einf&uuml;hrung von Buchungsgruppen ist jetzt beendet.',
   'The database upgrade for the introduction of units is now complete.' => 'Das Datenbankupgrade zwecks Einf&uuml;hrung von Einheiten ist nun beendet.',
   'The factor is missing in row %d.' => 'Der Faktor fehlt in Zeile %d.',
   'The factor is missing.'      => 'Der Faktor fehlt.',
@@ -941,9 +948,12 @@ gestartet',
   'The unit in row %d has been deleted in the meantime.' => 'Die Einheit in Zeile %d ist in der Zwischentzeit gel&ouml;scht worden.',
   'The unit in row %d has been used in the meantime and cannot be changed anymore.' => 'Die Einheit in Zeile %d wurde in der Zwischenzeit benutzt und kann nicht mehr ge&auml;ndert werden.',
   'The units have been saved.'  => 'Die Einheiten wurden gespeichert.',
+  'There are four tax zones.'   => 'Es gibt vier Steuerzonen.',
   'There are still entries in the database for which no unit has been assigned.' => 'Es gibt noch Eintr&auml;ge in der Datenbank, f&uuml;r die keine Einheit zugeordnet ist.',
+  'Therefore there\'s no need to create the same article more than once if it is sold or bought in/from another tax zone.' => 'Deswegen muss man den gleichen Artikel nicht mehr mehrmals anlegen, wenn er in verschiedenen Steuerzonen gehandelt werden soll.',
   'These units can be based on other units so that Lx-Office can convert prices when the user switches from one unit to another.' => 'Diese Einheiten k&ouml;nnen auf anderen Einheiten basieren, sodass Lx-Office Preise umrechnen kann, wenn der Benutzer von einer Einheit zu einer anderen Wechselt.',
   'This is a preliminary check for existing sources. Nothing will be created or deleted at this stage!' => 'In diesem Schritt werden bestehende Datenbanken gesucht. Es werden noch keine Änderungen vorgenommen!',
+  'This upgrade script tries to map all existing parts in the database to the newly created Buchungsgruppen.' => 'Dieses Upgradescript versucht, bei allen bestehenden Artikeln neu erstellte Buchungsgruppen zuzuordnen.',
   'This upgrade script tries to map all existing units in the database to the newly created units.' => 'Dieses Update-Script versucht, alle bestehenden Einheiten automatisch in die neuen Einheiten umzuwandeln.',
   'Title'                       => 'Titel',
   'To'                          => 'An',
@@ -1026,6 +1036,7 @@ gestartet',
   'Update'                      => 'Erneuern',
   'Update Dataset'              => 'Datenbank aktualisieren',
   'Update Prices'               => 'Preise aktualisieren',
+  'Update complete'             => 'Update beendet.',
   'Update prices'               => 'Preise aktualisieren',
   'Updated'                     => 'Erneuert am',
   'Use Templates'               => 'benutze Vorlagen',
@@ -1078,6 +1089,7 @@ gestartet',
   'You did not enter a name!'   => 'Sie haben keinen Namen eingegeben!',
   'You have to chose a dimension unit and a service unit which will then be assigned to those entries.' => 'Sie m&uuml;ssen eine Ma&szlig;- und eine Dienstleistungseinheit ausw&auml;hlen, die diesen Waren und Dienstleistungen, denen noch keine Einheit zugeordnet ist, zugeordnet wird.',
   'You have to chose which unit to save for each of them.' => 'Sie m&uuml;ssen f&uuml;r jeden Artikel die neue Einheit ausw&auml;hlen.',
+  'You have to create new Buchungsgruppen for all the combinations of inventory, income and expense accounts that have been used already.' => 'Sie m&uuml;ssen neue Buchungsgruppen f&uuml;r alle Kombinationen aus Inventar-, Erl&ouml;s- und Aufwandskonto, die bereits benutzt wurden.',
   'You must enter a host and port for local and remote connections!' => '"Rechner" und "Port" müssen für lokale und externe Verbindungen eingetragen werden!',
   'Zeitraum'                    => 'Zeitraum',
   'Zipcode'                     => 'PLZ',
diff --git a/sql/Pg-upgrade/Pg-upgrade-2.2.0.33-2.2.0.34.pl b/sql/Pg-upgrade/Pg-upgrade-2.2.0.33-2.2.0.34.pl
new file mode 100644 (file)
index 0000000..8c3e9d2
--- /dev/null
@@ -0,0 +1,415 @@
+#!/usr/bin/perl
+
+die("This script cannot be run from the command line.") unless ($main::form);
+
+sub mydberror {
+  my ($msg) = @_;
+  die($dbup_locale->text("Database update error:") .
+      "<br>$msg<br>" . $DBI::errstr);
+}
+
+sub mydoquery {
+  my ($query, @values) = @_;
+
+  $dbh->do($query, undef, @values) ||
+    mydberror($query . " (" . join(", ", @values) . ")");
+}
+
+sub set_taxzone_ids {
+  foreach my $table (qw(customer vendor ar ap oe)) {
+    my $query = "UPDATE ${table} SET taxzone_id = 0";
+    $dbh->do($query) || mydberror($query);
+  }
+}
+
+sub set_ic_links {
+  my $query =
+    "SELECT id, link " .
+    "FROM chart " .
+    "WHERE id IN " .
+    "  (SELECT DISTINCT inventory_accno_id " .
+    "   FROM parts " .
+    "   WHERE (NOT inventory_accno_id ISNULL) AND (inventory_accno_id > 0))";
+
+  my $sth = $dbh->prepare($query);
+  $sth->execute() || mydberror($query);
+
+  my $query_update = "UPDATE chart SET link = ? WHERE id = ?";
+  my $sth_update = $dbh->prepare($query_update);
+
+  while (my $ref = $sth->fetchrow_hashref()) {
+    my %links;
+    map({ $links{$_} = 1 } split(/:/, $ref->{"link"}));
+    $links{"IC"} = 1;
+    my $new_link = join(":", keys(%links));
+    $sth_update->execute($new_link, $ref->{"id"}) ||
+      mydberror($query_update . " ($new_link, $ref->{id})");
+  }
+
+  $sth->finish();
+  $sth_update->finish();
+}
+
+sub force_inventory_accno_id_for_parts {
+  my $query =
+    "UPDATE parts SET inventory_accno_id = " .
+    "(SELECT bg.inventory_accno_id " .
+    " FROM buchungsgruppen bg " .
+    " WHERE bg.description = 'Standard 16%') " .
+    "WHERE (NOT inventory_accno_id ISNULL) AND (inventory_accno_id > 0)";
+
+  $dbh->do($query) || mydberror($query);
+}
+
+sub retrieve_accounts {
+  my $query =
+    "SELECT c.accno, c.description, c.link, c.id, " .
+    "d.inventory_accno_id, d.income_accno_id, d.expense_accno_id " .
+    "FROM chart c, defaults d " .
+    "WHERE c.link LIKE '%IC%' " .
+    "ORDER BY c.accno";
+
+  my $sth = $dbh->prepare($query);
+  $sth->execute() || mydberror($query);
+
+  my ($acc_inventory, $acc_income, $acc_expense) = ({}, {}, {});
+  my %key_map = (
+    "IC" => $acc_inventory,
+    "IC_income" => $acc_income,
+    "IC_sale" => $acc_income,
+    "IC_expense" => $acc_expense,
+    "IC_cogs" => $acc_expense,
+    );
+
+  while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+    foreach my $key (split(/:/, $ref->{link})) {
+      next unless ($key_map{$key});
+      $key_map{$key}->{$ref->{"id"}} = {
+        "accno" => $ref->{"accno"},
+        "description" => $ref->{"description"},
+        "id" => $ref->{"id"},
+        "selected" => ($ref->{id} eq $ref->{inventory_accno_id})
+          || ($ref->{id} eq $ref->{income_accno_id})
+          || ($ref->{id} eq $ref->{expense_accno_id}) ?
+          "selected" : "",
+      };
+    }
+  }
+  $sth->finish();
+
+  $acc_inventory =
+    [sort({ $a->{"accno"} cmp $b->{"accno"} } values(%{$acc_inventory}))];
+  $acc_income =
+    [sort({ $a->{"accno"} cmp $b->{"accno"} } values(%{$acc_income}))];
+  $acc_expense =
+    [sort({ $a->{"accno"} cmp $b->{"accno"} } values(%{$acc_expense}))];
+
+  return ($acc_inventory, $acc_income, $acc_expense);
+}
+
+sub retrieve_buchungsgruppen {
+  my @buchungsgruppen;
+
+  my $query =
+    "SELECT bg.*, " .
+    "  ci.accno AS inventory_accno, " .
+    "  ci0.accno AS income_accno_0, " .
+    "  ce0.accno AS expense_accno_0, " .
+    "  ci1.accno AS income_accno_1, " .
+    "  ce1.accno AS expense_accno_1, " .
+    "  ci2.accno AS income_accno_2, " .
+    "  ce2.accno AS expense_accno_2, " .
+    "  ci3.accno AS income_accno_3, " .
+    "  ce3.accno AS expense_accno_3 " .
+    "FROM buchungsgruppen bg " .
+    "LEFT JOIN chart ci ON bg.inventory_accno_id = ci.id " .
+    "LEFT JOIN chart ci0 ON bg.income_accno_id_0 = ci0.id " .
+    "LEFT JOIN chart ce0 ON bg.expense_accno_id_0 = ce0.id " .
+    "LEFT JOIN chart ci1 ON bg.income_accno_id_1 = ci1.id " .
+    "LEFT JOIN chart ce1 ON bg.expense_accno_id_1 = ce1.id " .
+    "LEFT JOIN chart ci2 ON bg.income_accno_id_2 = ci2.id " .
+    "LEFT JOIN chart ce2 ON bg.expense_accno_id_2 = ce2.id " .
+    "LEFT JOIN chart ci3 ON bg.income_accno_id_3 = ci3.id " .
+    "LEFT JOIN chart ce3 ON bg.expense_accno_id_3 = ce3.id";
+  my $sth = $dbh->prepare($query);
+  $sth->execute() || mydberror($query);
+
+  while (my $ref = $sth->fetchrow_hashref()) {
+    push(@buchungsgruppen, $ref);
+  }
+  $sth->finish();
+
+  return \@buchungsgruppen;
+}
+
+sub update_known_buchungsgruppen {
+  my ($buchungsgruppen) = @_;
+
+  my @updates;
+
+  my $query =
+    "SELECT id, inventory_accno_id, income_accno_id, expense_accno_id " .
+    "FROM parts " .
+    "WHERE NOT inventory_accno_id ISNULL AND (inventory_accno_id > 0)";
+  my $sth = $dbh->prepare($query);
+  $sth->execute() || mydberror($query);
+
+  my $query_update = "UPDATE parts SET buchungsgruppen_id = ? WHERE id = ?";
+  my $sth_update = $dbh->prepare($query_update);
+
+  while (my $ref = $sth->fetchrow_hashref()) {
+    foreach my $bg (@{$buchungsgruppen}) {
+      if (($ref->{"inventory_accno_id"} == $bg->{"inventory_accno_id"}) &&
+          ($ref->{"income_accno_id"} == $bg->{"income_accno_id_0"}) &&
+          ($ref->{"expense_accno_id"} == $bg->{"expense_accno_id_0"})) {
+        $sth_update->execute($bg->{"id"}, $ref->{"id"}) ||
+          mydberror($query_update . " ($bg->{id}, $ref->{id})");
+        last;
+      }
+    }
+  }
+  $sth->finish();
+
+  my $query =
+    "SELECT id, inventory_accno_id, income_accno_id, expense_accno_id " .
+    "FROM parts " .
+    "WHERE inventory_accno_id ISNULL OR (inventory_accno_id = 0)";
+  my $sth = $dbh->prepare($query);
+  $sth->execute() || mydberror($query);
+
+  while (my $ref = $sth->fetchrow_hashref()) {
+    foreach my $bg (@{$buchungsgruppen}) {
+      if (($ref->{"income_accno_id"} == $bg->{"income_accno_id_0"}) &&
+          ($ref->{"expense_accno_id"} == $bg->{"expense_accno_id_0"})) {
+        $sth_update->execute($bg->{"id"}, $ref->{"id"}) ||
+          mydberror($query_update . " ($bg->{id}, $ref->{id})");
+        last;
+      }
+    }
+  }
+  $sth->finish();
+  $sth_update->finish();
+}
+
+sub retrieve_unknown_accno_combinations {
+  my ($buchungsgruppen) = @_;
+
+  my (@parts, @services, $sth, $query, $ref);
+
+  $query =
+    "SELECT DISTINCT " .
+    "p.inventory_accno_id, p.income_accno_id, p.expense_accno_id, " .
+    "c1.accno AS inventory_accno, c1.description AS inventory_description, " .
+    "c2.accno AS income_accno, c2.description AS income_description, " .
+    "c3.accno AS expense_accno, c3.description AS expense_description " .
+    "FROM parts p " .
+    "LEFT JOIN chart c1 ON p.inventory_accno_id = c1.id " .
+    "LEFT JOIN chart c2 ON p.income_accno_id = c2.id " .
+    "LEFT JOIN chart c3 ON p.expense_accno_id = c3.id " .
+    "WHERE NOT inventory_accno_id ISNULL AND (inventory_accno_id > 0)";
+
+  $sth = $dbh->prepare($query);
+  $sth->execute() || mydberror($query);
+
+  while ($ref = $sth->fetchrow_hashref()) {
+    my $found = 0;
+
+    foreach my $bg (@{$buchungsgruppen}) {
+      if (($ref->{"inventory_accno_id"} == $bg->{"inventory_accno_id"}) &&
+          ($ref->{"income_accno_id"} == $bg->{"income_accno_id_0"}) &&
+          ($ref->{"expense_accno_id"} == $bg->{"expense_accno_id_0"})) {
+        $found = 1;
+        last;
+      }
+    }
+
+    push(@parts, $ref) unless ($found);
+  }
+  $sth->finish();
+
+  $query =
+    "SELECT DISTINCT " .
+    "p.income_accno_id, p.expense_accno_id, " .
+    "c2.accno AS income_accno, c2.description AS income_description, " .
+    "c3.accno AS expense_accno, c3.description AS expense_description " .
+    "FROM parts p " .
+    "LEFT JOIN chart c1 ON p.inventory_accno_id = c1.id " .
+    "LEFT JOIN chart c2 ON p.income_accno_id = c2.id " .
+    "LEFT JOIN chart c3 ON p.expense_accno_id = c3.id " .
+    "WHERE inventory_accno_id ISNULL OR (inventory_accno_id = 0)";
+
+  $sth = $dbh->prepare($query);
+  $sth->execute() || mydberror($query);
+
+  while ($ref = $sth->fetchrow_hashref()) {
+    my $found = 0;
+
+    foreach my $bg (@{$buchungsgruppen}) {
+      if (($ref->{"income_accno_id"} == $bg->{"income_accno_id_0"}) &&
+          ($ref->{"expense_accno_id"} == $bg->{"expense_accno_id_0"})) {
+        $found = 1;
+        last;
+      }
+    }
+
+    push(@services, $ref) unless ($found);
+  }
+  $sth->finish();
+
+  return (\@parts, \@services);
+}
+
+sub display_create_bgs_dialog {
+  my ($type, $list,
+      $acc_inventory, $acc_income, $acc_expense,
+      $buchungsgruppen) = @_;
+
+  foreach my $entry (@{$list}) {
+    $entry->{"ACC_INVENTORY"} = $acc_inventory;
+    $entry->{"ACC_INCOME"} = $acc_income;
+    $entry->{"ACC_EXPENSE"} = $acc_expense;
+    $entry->{"eur"} = $main::eur;
+  }
+
+  print($form->parse_html_template("dbupgrade/buchungsgruppen_${type}",
+                                   { "LIST" => $list,
+                                     "BUCHUNGSGRUPPEN" => $buchungsgruppen,
+                                   }));
+}
+
+sub create_buchungsgruppen {
+  my $form = $main::form;
+
+  $main::lxdebug->dump(0, "gaby", $form);
+  for (my $i = 1; $i <= $form->{"rowcount"}; $i++) {
+    next unless ($form->{"description_$i"} &&
+                 $form->{"inventory_accno_id_$i"} &&
+                 $form->{"income_accno_id_0_$i"} &&
+                 $form->{"expense_accno_id_0_$i"} &&
+                 $form->{"income_accno_id_1_$i"} &&
+                 $form->{"expense_accno_id_1_$i"} &&
+                 $form->{"income_accno_id_2_$i"} &&
+                 $form->{"expense_accno_id_2_$i"} &&
+                 $form->{"income_accno_id_3_$i"} &&
+                 $form->{"expense_accno_id_3_$i"});
+
+    my $query =
+      "INSERT INTO buchungsgruppen (" .
+      "description, inventory_accno_id, " .
+      "income_accno_id_0, expense_accno_id_0, " .
+      "income_accno_id_1, expense_accno_id_1, " .
+      "income_accno_id_2, expense_accno_id_2, " .
+      "income_accno_id_3, expense_accno_id_3) " .
+      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+    my @values = ($form->{"description_$i"});
+
+    foreach my $acc (qw(inventory_accno_id
+                        income_accno_id_0 expense_accno_id_0
+                        income_accno_id_1 expense_accno_id_1
+                        income_accno_id_2 expense_accno_id_2
+                        income_accno_id_3 expense_accno_id_3)) {
+      push(@values, (split(/--/, $form->{"${acc}_${i}"}))[0]);
+    }
+
+    $main::lxdebug->dump(0, "klaus$i", \@values);
+
+    mydoquery($query, @values);
+    $main::lxdebug->message(0, "nachklausi$i");
+  }
+
+  $main::lxdebug->message(0, "commit: " . $dbh->commit());
+  $main::lxdebug->message(0, "errstr: " . $dbh->errstr);
+  $dbh->begin_work();
+}
+
+sub retrieve_std_inventory_accno_id {
+  my $query;
+
+  $query = "SELECT coa FROM defaults";
+  my ($coa) = $dbh->selectrow_array($query);
+
+  my $inventory_accno;
+
+  if ($coa eq "Germany-DATEV-SKR03EU") {
+    $inventory_accno = "3980";
+
+  } elsif ($coa eq "Germany-DATEV-SKR04EU") {
+    $inventory_accno = "1140";
+  }
+
+  my $inventory_accno_id;
+  if ($inventory_accno) {
+    $query = "SELECT id FROM chart WHERE accno = $inventory_accno";
+    ($inventory_accno_id) = $dbh->selectrow_array($query);
+  }
+
+  if (!$inventory_accno_id) {
+    $query = "SELECT id, link FROM chart WHERE link LIKE '%IC%'";
+    my $sth = $dbh->prepare($query);
+    $sth->execute() || mydberror($query);
+
+    while (my $ref = $sth->fetchrow_hashref()) {
+      if (grep({ $_ eq "IC" } split(/:/, $ref->{"link"}))) {
+        $inventory_accno_id = $ref->{"id"};
+        last;
+      }
+    }
+    $sth->finish();
+  }
+
+  $form->{"std_inventory_accno_id"} = $inventory_accno_id;
+}
+
+sub do_update {
+  if ($main::form->{"action2"} eq "create_buchungsgruppen") {
+    create_buchungsgruppen();
+  }
+
+  retrieve_std_inventory_accno_id();
+
+  # Set all taxzone_id columns = 0.
+  set_taxzone_ids();
+
+  # If balancing is off then force parts.inventory_accno_id to
+  # a single value for parts.
+  force_inventory_accno_id_for_parts() if ($main::eur);
+
+  # Force "IC" to be present in chart.link for all accounts
+  # which have been used as inventory accounts in parts.
+  set_ic_links();
+
+  # Assign buchungsgruppen_ids in parts for known combinations
+  # of inventory_accno_id, income_accno_id, expense_accno_id.
+  my $buchungsgruppen = retrieve_buchungsgruppen();
+
+  update_known_buchungsgruppen($buchungsgruppen);
+
+  # Retrieve all distinct combinations of inventory_accno_id,
+  # income_accno_id and expense_accno_id for which there's no
+  # Buchungsgruppe. Then let the user create new ones.
+  ($parts, $services) = retrieve_unknown_accno_combinations($buchungsgruppen);
+
+  my ($acc_inventory, $acc_income, $acc_expense) = retrieve_accounts();
+
+  print($form->parse_html_template("dbupgrade/buchungsgruppen_header"));
+
+  if (scalar(@{$parts})) {
+    display_create_bgs_dialog("parts", $parts,
+                              $acc_inventory, $acc_income, $acc_expense,
+                              $buchungsgruppen);
+    return 2;
+  }
+
+  if (scalar(@{$services})) {
+    display_create_bgs_dialog("services", $services,
+                              $acc_inventory, $acc_income, $acc_expense,
+                              $buchungsgruppen);
+    return 2;
+  }
+
+  print($form->parse_html_template("dbupgrade/buchungsgruppen_footer"));
+
+  return 1;
+}
+
+return do_update();
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_footer_de.html b/templates/webpages/dbupgrade/buchungsgruppen_footer_de.html
new file mode 100644 (file)
index 0000000..7ca68e6
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="listtop">Update beendet.</div>
+
+<p>Das Datenbankupgrade f&uuml;r die Einf&uuml;hrung von Buchungsgruppen ist jetzt beendet.</p>
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_footer_master.html b/templates/webpages/dbupgrade/buchungsgruppen_footer_master.html
new file mode 100644 (file)
index 0000000..06a8139
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="listtop"><translate>Update complete</translate></div>
+
+<p><translate>The database upgrade for the introduction of Buchungsgruppen is now complete.</translate></p>
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_header_de.html b/templates/webpages/dbupgrade/buchungsgruppen_header_de.html
new file mode 100644 (file)
index 0000000..2851aa7
--- /dev/null
@@ -0,0 +1,16 @@
+<div class="listtop">Einf&uuml;hrung von Buchungsgruppen</div>
+
+<p>
+ Vor Lx-Office 2.4.0 musste der Benutzer die Konten bei jeder Ware und jeder Dienstleistung einzeln ausw&auml;hlen.
+ Lx-Office 2.4.0 f&uuml;hrt zwei neue Konzepte ein: Steuerzonen und Buchungsgruppen.
+ Es gibt vier Steuerzonen.
+ Eine Buchungsgruppe besteht aus einem deskriptiven Namen, den Erl&ouml;s- und Aufwandskonten f&uuml;r diese vier Steuerzonen sowie aus einem Inventarkonto.
+ Der Benutzer muss nun f&uuml;r jeden Artikel nur noch die Buchungsgruppe anstelle der drei einzelnen Konten ausw&auml;hlen.
+ Deswegen muss man den gleichen Artikel nicht mehr mehrmals anlegen, wenn er in verschiedenen Steuerzonen gehandelt werden soll.
+</p>
+
+<p>
+ Dieses Upgradescript versucht, bei allen bestehenden Artikeln neu erstellte Buchungsgruppen zuzuordnen.
+ Es ist m&ouml;glich, dies f&uuml;r einige, aber nicht f&uuml;r alle Buchungsgruppen automatisch zu erledigen.
+ Sie m&uuml;ssen neue Buchungsgruppen f&uuml;r alle Kombinationen aus Inventar-, Erl&ouml;s- und Aufwandskonto, die bereits benutzt wurden.
+</p>
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_header_master.html b/templates/webpages/dbupgrade/buchungsgruppen_header_master.html
new file mode 100644 (file)
index 0000000..f2066e3
--- /dev/null
@@ -0,0 +1,27 @@
+<div class="listtop"><translate>Introduction of Buchungsgruppen</translate></div>
+
+<p>
+ <translate>Prior to Lx-Office v2.4.0 the user had to chose the accounts
+  for each part and service.</translate>
+ <translate>Lx-Office 2.4.0 introduces two new concepts: tax zones and
+  Buchungsgruppen.</translate>
+ <translate>There are four tax zones.</translate>
+ <translate>A Buchungsgruppe consists of a descriptive name and the
+  account numbers for the income and expense accounts for those four
+  tax zones as well as the inventory account number.</translate>
+ <translate>Now the user must select a single Buchungsgruppe for each
+  part instead of three distinct accounts.</translate>
+ <translate>Therefore there's no need to create the same article more
+  than once if it is sold or bought in/from another tax
+  zone.</translate>
+</p>
+
+<p>
+ <translate>This upgrade script tries to map all existing parts in the
+  database to the newly created Buchungsgruppen.</translate>
+ <translate>It is possible to do this automatically for some
+  Buchungsgruppen, but not for all.</translate>
+ <translate>You have to create new Buchungsgruppen for all the
+  combinations of inventory, income and expense accounts that have
+  been used already.</translate>
+</p>
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_parts_de.html b/templates/webpages/dbupgrade/buchungsgruppen_parts_de.html
new file mode 100644 (file)
index 0000000..9c2185b
--- /dev/null
@@ -0,0 +1,145 @@
+<div class="listtop">Schritt 1 von 2: Waren</div>
+
+<form name="Form" method="post" action="login.pl">
+
+ <input type="hidden" name="path" value="<TMPL_VAR path ESCAPE=HTML>">
+ <input type="hidden" name="login" value="<TMPL_VAR login ESCAPE=HTML>">
+ <input type="hidden" name="hashed_password" value="<TMPL_VAR password ESCAPE=HTML>">
+ <input type="hidden" name="type" value="parts">
+ <input type="hidden" name="action" value="login">
+ <input type="hidden" name="action2" value="">
+
+ <TMPL_IF saved_message>
+  <p><TMPL_VAR saved_message></p>
+ </TMPL_IF>
+
+ <div class="subsubheading">Bestehende Buchungsgruppen</div>
+
+ <p>
+  Die folgenden Buchungsgruppen wurden bereits angelegt:
+  <br>
+  <ul>
+   <TMPL_LOOP BUCHUNGSGRUPPEN>
+    <li>
+     <TMPL_VAR description ESCAPE=HTML>:
+     Inventar: <TMPL_VAR inventory_accno>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     Inland: <TMPL_VAR income_accno_0>/<TMPL_VAR expense_accno_0>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     EU mit UstId-Nummer: <TMPL_VAR income_accno_1>/<TMPL_VAR expense_accno_1>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     EU ohne UstId-Nummer: <TMPL_VAR income_accno_2>/<TMPL_VAR expense_accno_2>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     Ausland: <TMPL_VAR income_accno_3>/<TMPL_VAR expense_accno_3>
+    </li>
+   </TMPL_LOOP>
+  </ul>
+ </p>
+
+ <TMPL_LOOP LIST>
+  <div class="subsubheading">Neue Buchungsgruppe <TMPL_VAR __counter__></div>
+
+  <table>
+   <tr>
+    <td>Beschreibung:</td>
+    <td><input name="description_<TMPL_VAR __counter__>"></td>
+   </tr>
+
+   <TMPL_IF eur>
+    <input type="hidden" name="inventory_accno_id_<TMPL_VAR __counter__>" value="<TMPL_VAR std_inventory_accno_id>">
+    <TMPL_ELSE>
+    <tr>
+     <td>Inventar:</td>
+     <td>
+      <input type="hidden" name="inventory_accno_id_<TMPL_VAR __counter__>" value="<TMPL_VAR inventory_accno_id ESCAPE=HTML>">
+      <TMPL_VAR inventory_accno ESCAPE=HTML>--<TMPL_VAR inventory_description ESCAPE=HTML>
+     </td>
+    </tr>
+   </TMPL_IF>
+
+   <tr>
+    <td>Erl&ouml;skonto Inland:</td>
+    <td>
+     <input type="hidden" name="income_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR income_accno_id ESCAPE=HTML>">
+     <TMPL_VAR income_accno ESCAPE=HTML>--<TMPL_VAR income_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto Inland:</td>
+    <td>
+     <input type="hidden" name="expense_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR expense_accno_id ESCAPE=HTML>">
+     <TMPL_VAR expense_accno ESCAPE=HTML>--<TMPL_VAR expense_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Erl&ouml;skonto EU mit UstId-Nummer:</td>
+    <td>
+     <select name="income_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto EU mit UstId-Nummer:</td>
+    <td>
+     <select name="expense_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Erl&ouml;skonto EU ohne UstId-Nummer:</td>
+    <td>
+     <select name="income_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto EU ohne UstId-Nummer:</td>
+    <td>
+     <select name="expense_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Erl&ouml;skonto Ausland:</td>
+    <td>
+     <select name="income_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto Ausland:</td>
+    <td>
+     <select name="expense_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+  </table>
+
+  <TMPL_IF __last__>
+   <input type="hidden" name="rowcount" value="<TMPL_VAR __counter__>">
+  </TMPL_IF>
+
+  <hr>
+ </TMPL_LOOP>
+
+ <input type="submit" onclick="document.Form.action2.value = 'create_buchungsgruppen'; document.Form.submit();" name="dummy" value="Buchungsgruppen erfassen">
+
+</form>
+
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_parts_master.html b/templates/webpages/dbupgrade/buchungsgruppen_parts_master.html
new file mode 100644 (file)
index 0000000..318b000
--- /dev/null
@@ -0,0 +1,145 @@
+<div class="listtop"><translate>Step 1 of 2: Parts</translate></div>
+
+<form name="Form" method="post" action="login.pl">
+
+ <input type="hidden" name="path" value="<TMPL_VAR path ESCAPE=HTML>">
+ <input type="hidden" name="login" value="<TMPL_VAR login ESCAPE=HTML>">
+ <input type="hidden" name="hashed_password" value="<TMPL_VAR password ESCAPE=HTML>">
+ <input type="hidden" name="type" value="parts">
+ <input type="hidden" name="action" value="login">
+ <input type="hidden" name="action2" value="">
+
+ <TMPL_IF saved_message>
+  <p><TMPL_VAR saved_message></p>
+ </TMPL_IF>
+
+ <div class="subsubheading"><translate>Existing Buchungsgruppen</translate></div>
+
+ <p>
+  <translate>The following Buchungsgruppen have already been created:</translate>
+  <br>
+  <ul>
+   <TMPL_LOOP BUCHUNGSGRUPPEN>
+    <li>
+     <TMPL_VAR description ESCAPE=HTML>:
+     <translate>Invetory</translate>: <TMPL_VAR inventory_accno>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>National</translate>: <TMPL_VAR income_accno_0>/<TMPL_VAR expense_accno_0>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>EU with VAT ID</translate>: <TMPL_VAR income_accno_1>/<TMPL_VAR expense_accno_1>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>EU without VAT ID</translate>: <TMPL_VAR income_accno_2>/<TMPL_VAR expense_accno_2>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>International</translate>: <TMPL_VAR income_accno_3>/<TMPL_VAR expense_accno_3>
+    </li>
+   </TMPL_LOOP>
+  </ul>
+ </p>
+
+ <TMPL_LOOP LIST>
+  <div class="subsubheading"><translate>New Buchungsgruppe <TMPL_VAR __counter__></translate></div>
+
+  <table>
+   <tr>
+    <td><translate>Description</translate>:</td>
+    <td><input name="description_<TMPL_VAR __counter__>"></td>
+   </tr>
+
+   <TMPL_IF eur>
+    <input type="hidden" name="inventory_accno_id_<TMPL_VAR __counter__>" value="<TMPL_VAR std_inventory_accno_id>">
+    <TMPL_ELSE>
+    <tr>
+     <td><translate>Inventory</translate>:</td>
+     <td>
+      <input type="hidden" name="inventory_accno_id_<TMPL_VAR __counter__>" value="<TMPL_VAR inventory_accno_id ESCAPE=HTML>">
+      <TMPL_VAR inventory_accno ESCAPE=HTML>--<TMPL_VAR inventory_description ESCAPE=HTML>
+     </td>
+    </tr>
+   </TMPL_IF>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>National</translate>:</td>
+    <td>
+     <input type="hidden" name="income_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR income_accno_id ESCAPE=HTML>">
+     <TMPL_VAR income_accno ESCAPE=HTML>--<TMPL_VAR income_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>National</translate>:</td>
+    <td>
+     <input type="hidden" name="expense_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR expense_accno_id ESCAPE=HTML>">
+     <TMPL_VAR expense_accno ESCAPE=HTML>--<TMPL_VAR expense_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>EU with VAT ID</translate>:</td>
+    <td>
+     <select name="income_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>EU with VAT ID</translate>:</td>
+    <td>
+     <select name="expense_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>EU without VAT ID</translate>:</td>
+    <td>
+     <select name="income_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>EU without VAT ID</translate>:</td>
+    <td>
+     <select name="expense_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>International</translate>:</td>
+    <td>
+     <select name="income_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>International</translate>:</td>
+    <td>
+     <select name="expense_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+  </table>
+
+  <TMPL_IF __last__>
+   <input type="hidden" name="rowcount" value="<TMPL_VAR __counter__>">
+  </TMPL_IF>
+
+  <hr>
+ </TMPL_LOOP>
+
+ <input type="submit" onclick="document.Form.action2.value = 'create_buchungsgruppen'; document.Form.submit();" name="dummy" value="<translate>Create Buchungsgruppen</translate>">
+
+</form>
+
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_services_de.html b/templates/webpages/dbupgrade/buchungsgruppen_services_de.html
new file mode 100644 (file)
index 0000000..b56ff43
--- /dev/null
@@ -0,0 +1,146 @@
+<div class="listtop">Schritt 2 von 2: Dienstleistungen</div>
+
+<form name="Form" method="post" action="login.pl">
+
+ <input type="hidden" name="path" value="<TMPL_VAR path ESCAPE=HTML>">
+ <input type="hidden" name="login" value="<TMPL_VAR login ESCAPE=HTML>">
+ <input type="hidden" name="hashed_password" value="<TMPL_VAR password ESCAPE=HTML>">
+ <input type="hidden" name="type" value="parts">
+ <input type="hidden" name="action" value="login">
+ <input type="hidden" name="action2" value="">
+
+ <TMPL_IF saved_message>
+  <p><TMPL_VAR saved_message></p>
+ </TMPL_IF>
+
+ <div class="subsubheading">Bestehende Buchungsgruppen</div>
+
+ <p>
+  Die folgenden Buchungsgruppen wurden bereits angelegt:
+  <br>
+  <ul>
+   <TMPL_LOOP BUCHUNGSGRUPPEN>
+    <li>
+     <TMPL_VAR description ESCAPE=HTML>:
+     Inventar: <TMPL_VAR inventory_accno>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     Inland: <TMPL_VAR income_accno_0>/<TMPL_VAR expense_accno_0>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     EU mit UstId-Nummer: <TMPL_VAR income_accno_1>/<TMPL_VAR expense_accno_1>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     EU ohne UstId-Nummer: <TMPL_VAR income_accno_2>/<TMPL_VAR expense_accno_2>;
+
+     Erl&ouml;skonto/Aufwandskonto
+     Ausland: <TMPL_VAR income_accno_3>/<TMPL_VAR expense_accno_3>
+    </li>
+   </TMPL_LOOP>
+  </ul>
+ </p>
+
+ <TMPL_LOOP LIST>
+  <div class="subsubheading">Neue Buchungsgruppe <TMPL_VAR __counter__></div>
+
+  <table>
+   <tr>
+    <td>Beschreibung:</td>
+    <td><input name="description_<TMPL_VAR __counter__>"></td>
+   </tr>
+
+   <TMPL_IF eur>
+    <input type="hidden" name="inventory_accno_id_<TMPL_VAR __counter__>" value="<TMPL_VAR std_inventory_accno_id>">
+    <TMPL_ELSE>
+    <tr>
+     <td>Inventar:</td>
+     <td>
+      <select name="inventory_accno_id_<TMPL_VAR __counter__>">
+       <TMPL_LOOP ACC_INVENTORY><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+      </select>
+     </td>
+    </tr>
+   </TMPL_IF>
+
+   <tr>
+    <td>Erl&ouml;skonto Inland:</td>
+    <td>
+     <input type="hidden" name="income_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR income_accno_id ESCAPE=HTML>">
+     <TMPL_VAR income_accno ESCAPE=HTML>--<TMPL_VAR income_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto Inland:</td>
+    <td>
+     <input type="hidden" name="expense_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR expense_accno_id ESCAPE=HTML>">
+     <TMPL_VAR expense_accno ESCAPE=HTML>--<TMPL_VAR expense_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Erl&ouml;skonto EU mit UstId-Nummer:</td>
+    <td>
+     <select name="income_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto EU mit UstId-Nummer:</td>
+    <td>
+     <select name="expense_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Erl&ouml;skonto EU ohne UstId-Nummer:</td>
+    <td>
+     <select name="income_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto EU ohne UstId-Nummer:</td>
+    <td>
+     <select name="expense_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Erl&ouml;skonto Ausland:</td>
+    <td>
+     <select name="income_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td>Aufwandskonto Ausland:</td>
+    <td>
+     <select name="expense_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+  </table>
+
+  <TMPL_IF __last__>
+   <input type="hidden" name="rowcount" value="<TMPL_VAR __counter__>">
+  </TMPL_IF>
+
+  <hr>
+ </TMPL_LOOP>
+
+ <input type="submit" onclick="document.Form.action2.value = 'create_buchungsgruppen'; document.Form.submit();" name="dummy" value="Buchungsgruppen erfassen">
+
+</form>
+
diff --git a/templates/webpages/dbupgrade/buchungsgruppen_services_master.html b/templates/webpages/dbupgrade/buchungsgruppen_services_master.html
new file mode 100644 (file)
index 0000000..3eade42
--- /dev/null
@@ -0,0 +1,146 @@
+<div class="listtop"><translate>Step 2 of 2: Services</translate></div>
+
+<form name="Form" method="post" action="login.pl">
+
+ <input type="hidden" name="path" value="<TMPL_VAR path ESCAPE=HTML>">
+ <input type="hidden" name="login" value="<TMPL_VAR login ESCAPE=HTML>">
+ <input type="hidden" name="hashed_password" value="<TMPL_VAR password ESCAPE=HTML>">
+ <input type="hidden" name="type" value="parts">
+ <input type="hidden" name="action" value="login">
+ <input type="hidden" name="action2" value="">
+
+ <TMPL_IF saved_message>
+  <p><TMPL_VAR saved_message></p>
+ </TMPL_IF>
+
+ <div class="subsubheading"><translate>Existing Buchungsgruppen</translate></div>
+
+ <p>
+  <translate>The following Buchungsgruppen have already been created:</translate>
+  <br>
+  <ul>
+   <TMPL_LOOP BUCHUNGSGRUPPEN>
+    <li>
+     <TMPL_VAR description ESCAPE=HTML>:
+     <translate>Invetory</translate>: <TMPL_VAR inventory_accno>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>National</translate>: <TMPL_VAR income_accno_0>/<TMPL_VAR expense_accno_0>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>EU with VAT ID</translate>: <TMPL_VAR income_accno_1>/<TMPL_VAR expense_accno_1>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>EU without VAT ID</translate>: <TMPL_VAR income_accno_2>/<TMPL_VAR expense_accno_2>;
+
+     <translate>Income accno</translate>/<translate>Expense accno</translate>
+     <translate>International</translate>: <TMPL_VAR income_accno_3>/<TMPL_VAR expense_accno_3>
+    </li>
+   </TMPL_LOOP>
+  </ul>
+ </p>
+
+ <TMPL_LOOP LIST>
+  <div class="subsubheading"><translate>New Buchungsgruppe <TMPL_VAR __counter__></translate></div>
+
+  <table>
+   <tr>
+    <td><translate>Description</translate>:</td>
+    <td><input name="description_<TMPL_VAR __counter__>"></td>
+   </tr>
+
+   <TMPL_IF eur>
+    <input type="hidden" name="inventory_accno_id_<TMPL_VAR __counter__>" value="<TMPL_VAR std_inventory_accno_id>">
+    <TMPL_ELSE>
+    <tr>
+     <td><translate>Inventory</translate>:</td>
+     <td>
+      <select name="inventory_accno_id_<TMPL_VAR __counter__>">
+       <TMPL_LOOP ACC_INVENTORY><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+      </select>
+     </td>
+    </tr>
+   </TMPL_IF>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>National</translate>:</td>
+    <td>
+     <input type="hidden" name="income_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR income_accno_id ESCAPE=HTML>">
+     <TMPL_VAR income_accno ESCAPE=HTML>--<TMPL_VAR income_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>National</translate>:</td>
+    <td>
+     <input type="hidden" name="expense_accno_id_0_<TMPL_VAR __counter__>" value="<TMPL_VAR expense_accno_id ESCAPE=HTML>">
+     <TMPL_VAR expense_accno ESCAPE=HTML>--<TMPL_VAR expense_description ESCAPE=HTML>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>EU with VAT ID</translate>:</td>
+    <td>
+     <select name="income_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>EU with VAT ID</translate>:</td>
+    <td>
+     <select name="expense_accno_id_1_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>EU without VAT ID</translate>:</td>
+    <td>
+     <select name="income_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>EU without VAT ID</translate>:</td>
+    <td>
+     <select name="expense_accno_id_2_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Income accno</translate> <translate>International</translate>:</td>
+    <td>
+     <select name="income_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_INCOME><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+
+   <tr>
+    <td><translate>Expense accno</translate> <translate>International</translate>:</td>
+    <td>
+     <select name="expense_accno_id_3_<TMPL_VAR __counter__>">
+      <TMPL_LOOP ACC_EXPENSE><option value="<TMPL_VAR id>" <TMPL_VAR selected>><TMPL_VAR accno ESCAPE=HTML>--<TMPL_VAR description ESCAPE=HTML></option></TMPL_LOOP>
+     </select>
+    </td>
+   </tr>
+  </table>
+
+  <TMPL_IF __last__>
+   <input type="hidden" name="rowcount" value="<TMPL_VAR __counter__>">
+  </TMPL_IF>
+
+  <hr>
+ </TMPL_LOOP>
+
+ <input type="submit" onclick="document.Form.action2.value = 'create_buchungsgruppen'; document.Form.submit();" name="dummy" value="<translate>Create Buchungsgruppen</translate>">
+
+</form>
+