]> wagnertech.de Git - kivitendo-erp.git/commitdiff
Neuer Datenbankupgrademechanismus: Die Upgradedateien im neuen Verzeichnis sql/Pg...
authorMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 22 Dec 2006 15:13:00 +0000 (15:13 +0000)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 22 Dec 2006 15:13:00 +0000 (15:13 +0000)
19 files changed:
SL/DBUpgrade2.pm [new file with mode: 0644]
SL/User.pm
doc/sql-upgrade-dateien.txt [new file with mode: 0644]
locale/de/admin
locale/de/all
locale/de/am
locale/de/locales.pl
locale/de/login
locale/de/ustva
scripts/dbupgrade2_tool.pl [new file with mode: 0755]
sql/Pg-upgrade/Pg-upgrade-2.4.0.0-2.4.0.1.sql [deleted file]
sql/Pg-upgrade/Pg-upgrade-2.4.0.1-2.4.0.2.sql [deleted file]
sql/Pg-upgrade/Pg-upgrade-2.4.0.2-2.4.0.3.sql [deleted file]
sql/Pg-upgrade2/README [new file with mode: 0644]
sql/Pg-upgrade2/language_output_formatting.sql [new file with mode: 0644]
sql/Pg-upgrade2/tax_id_if_taxkey_is_0.sql [new file with mode: 0644]
sql/Pg-upgrade2/units_translations_and_singular_plural_distinction.sql [new file with mode: 0644]
templates/webpages/dbupgrade/upgrade_message2_de.html [new file with mode: 0644]
templates/webpages/dbupgrade/upgrade_message2_master.html [new file with mode: 0644]

diff --git a/SL/DBUpgrade2.pm b/SL/DBUpgrade2.pm
new file mode 100644 (file)
index 0000000..514448f
--- /dev/null
@@ -0,0 +1,157 @@
+package SL::DBUpgrade2;
+
+require Exporter;
+@ISA = qw(Exporter);
+
+@EXPORT = qw(parse_dbupdate_controls sort_dbupdate_controls);
+
+sub parse_dbupdate_controls {
+  $main::lxdebug->enter_sub();
+
+  my ($form, $dbdriver) = @_;
+
+  my $locale = $main::locale;
+
+  local *IN;
+  my %all_controls;
+
+  my $path = "sql/${dbdriver}-upgrade2";
+
+  foreach my $file_name (<$path/*.sql>, <$path/*.pl>) {
+    next unless (open(IN, $file_name));
+
+    my $file = $file_name;
+    $file =~ s|.*/||;
+
+    my $control = {
+      "priority" => 1000,
+      "depends" => [],
+    };
+
+    while (<IN>) {
+      chomp();
+      next unless (/^(--|\#)\s*\@/);
+      s/^(--|\#)\s*\@//;
+      s/\s*$//;
+      next if ($_ eq "");
+
+      my @fields = split(/\s*:\s*/, $_, 2);
+      next unless (scalar(@fields) == 2);
+
+      if ($fields[0] eq "depends") {
+        push(@{$control->{"depends"}}, split(/\s+/, $fields[1]));
+      } else {
+        $control->{$fields[0]} = $fields[1];
+      }
+    }
+
+    _control_error($form, $file_name,
+                   $locale->text("Missing 'tag' field."))
+      unless ($control->{"tag"});
+
+    _control_error($form, $file_name,
+                   $locale->text("The 'tag' field must only consist of " .
+                                 "alphanumeric characters or the carachters " .
+                                 "- _ ( )"))
+      if ($control->{"tag"} =~ /[^a-zA-Z0-9_\(\)\-]/);
+
+    _control_error($form, $file_name,
+                   sprintf($locale->text("More than one control file " .
+                                         "with the tag '%s' exist."),
+                           $control->{"tag"}))
+      if (defined($all_controls{$control->{"tag"}}));
+
+    _control_error($form, $file_name,
+                   sprintf($locale->text("Missing 'description' field.")))
+      unless ($control->{"description"});
+
+    $control->{"priority"} *= 1;
+    $control->{"priority"} = 1000 unless ($control->{"priority"});
+
+    $control->{"file"} = $file;
+
+    map({ delete($control->{$_}); } qw(depth applied));
+
+    $all_controls{$control->{"tag"}} = $control;
+
+    close(IN);
+  }
+
+  foreach my $control (values(%all_controls)) {
+    foreach my $dependency (@{$control->{"depends"}}) {
+      _control_error($form, $control->{"file"},
+                     sprintf($locale->text("Unknown dependency '%s'."),
+                             $dependency))
+        if (!defined($all_controls{$dependency}));
+    }
+
+    map({ $_->{"loop"} = 0; } values(%all_controls));
+    _check_for_loops($form, $control->{"file"}, \%all_controls,
+                     $control->{"tag"});
+  }
+
+  map({ _dbupdate2_calculate_depth(\%all_controls, $_->{"tag"}) }
+      values(%all_controls));
+
+  $main::lxdebug->leave_sub();
+
+  return \%all_controls;
+}
+
+sub _check_for_loops {
+  my ($form, $file_name, $controls, $tag, @path) = @_;
+
+  push(@path, $tag);
+
+  _control_error($form, $file_name,
+                 $main::locale->text("Dependency loop detected:") .
+                 " " . join(" -> ", @path))
+    if ($controls->{$tag}->{"loop"});
+
+  $controls->{$tag}->{"loop"} = 1;
+  map({ _check_for_loops($form, $file_name, $controls, $_, @path); }
+      @{$controls->{$tag}->{"depends"}});
+}
+
+sub _control_error {
+  my ($form, $file_name, $message) = @_;
+
+  my $form = $main::form;
+  my $locale = $main::locale;
+
+  $form->error(sprintf($locale->text("Error in database control file '%s': %s"),
+                       $file_name, $message));
+}
+
+sub _dbupdate2_calculate_depth {
+  $main::lxdebug->enter_sub();
+
+  my ($tree, $tag) = @_;
+
+  my $node = $tree->{$tag};
+
+  return $main::lxdebug->leave_sub() if (defined($node->{"depth"}));
+
+  my $max_depth = 0;
+
+  foreach $tag (@{$node->{"depends"}}) {
+    _dbupdate2_calculate_depth($tree, $tag);
+    my $value = $tree->{$tag}->{"depth"};
+    $max_depth = $value if ($value > $max_depth);
+  }
+
+  $node->{"depth"} = $max_depth + 1;
+
+  $main::lxdebug->leave_sub();
+}
+
+sub sort_dbupdate_controls {
+  return
+    sort({ $a->{"depth"} != $b->{"depth"} ? $a->{"depth"} <=> $b->{"depth"} :
+             $a->{"priority"} != $b->{"priority"} ?
+             $a->{"priority"} <=> $b->{"priority"} :
+             $a->{"tag"} cmp $b->{"tag"} } values(%{$_[0]}));
+}
+
+
+1;
index f331ca4af15f491e3b79946cee539165bfec0270..88deb0b1f1ff8857f4685dd38d05ea0fb2f558a2 100644 (file)
@@ -34,6 +34,8 @@
 
 package User;
 
 
 package User;
 
+use SL::DBUpgrade2;
+
 sub new {
   $main::lxdebug->enter_sub();
 
 sub new {
   $main::lxdebug->enter_sub();
 
@@ -162,14 +164,21 @@ sub login {
                  '$myconfig{tel}', 'user')|;
       $dbh->do($query);
     }
                  '$myconfig{tel}', 'user')|;
       $dbh->do($query);
     }
+
+    $self->create_schema_info_table($form, $dbh);
+
     $dbh->disconnect;
 
     $rc = 0;
 
     $dbh->disconnect;
 
     $rc = 0;
 
-    if (&update_available($myconfig{"dbdriver"}, $dbversion)) {
+    my $controls =
+      parse_dbupdate_controls($form, $myconfig{"dbdriver"});
 
 
-      map { $form->{$_} = $myconfig{$_} }
-        qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect);
+    map({ $form->{$_} = $myconfig{$_} }
+        qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect));
+
+    if (update_available($myconfig{"dbdriver"}, $dbversion) ||
+        update2_available($form, $controls)) {
 
       $form->{"stylesheet"} = "lx-office-erp.css";
       $form->{"title"} = $main::locale->text("Dataset upgrade");
 
       $form->{"stylesheet"} = "lx-office-erp.css";
       $form->{"title"} = $main::locale->text("Dataset upgrade");
@@ -185,8 +194,7 @@ sub login {
       }
 
       # update the tables
       }
 
       # update the tables
-      open FH, ">$userspath/nologin" or die "
-$!";
+      open(FH, ">$userspath/nologin") or die("$!");
 
       # required for Oracle
       $form->{dbdefault} = $sid;
 
       # required for Oracle
       $form->{dbdefault} = $sid;
@@ -196,9 +204,10 @@ $!";
       $SIG{QUIT} = 'IGNORE';
 
       $self->dbupdate($form);
       $SIG{QUIT} = 'IGNORE';
 
       $self->dbupdate($form);
+      $self->dbupdate2($form, $controls);
 
       # remove lock file
 
       # remove lock file
-      unlink "$userspath/nologin";
+      unlink("$userspath/nologin");
 
       print($form->parse_html_template("dbupgrade/footer"));
 
 
       print($form->parse_html_template("dbupgrade/footer"));
 
@@ -453,7 +462,7 @@ sub process_perl_script {
 sub process_query {
   $main::lxdebug->enter_sub();
 
 sub process_query {
   $main::lxdebug->enter_sub();
 
-  my ($self, $form, $dbh, $filename, $version) = @_;
+  my ($self, $form, $dbh, $filename, $version_or_control) = @_;
 
   #  return unless (-f $filename);
 
 
   #  return unless (-f $filename);
 
@@ -510,7 +519,11 @@ sub process_query {
     }
   }
 
     }
   }
 
-  if ($version) {
+  if (ref($version_or_control) eq "HASH") {
+    $dbh->do("INSERT INTO schema_info (tag, login) VALUES (" .
+             $dbh->quote($version_or_control->{"tag"}) . ", " .
+             $dbh->quote($form->{"login"}) . ")");
+  } elsif ($version_or_control) {
     $dbh->do("UPDATE defaults SET version = " . $dbh->quote($version));
   }
   $dbh->commit();
     $dbh->do("UPDATE defaults SET version = " . $dbh->quote($version));
   }
   $dbh->commit();
@@ -725,6 +738,25 @@ sub update_available {
   return ($#upgradescripts > -1);
 }
 
   return ($#upgradescripts > -1);
 }
 
+sub create_schema_info_table {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $form, $dbh) = @_;
+
+  my $query = "SELECT tag FROM schema_info LIMIT 1";
+  if (!$dbh->do($query)) {
+    $query =
+      "CREATE TABLE schema_info (" .
+      "  tag text, " .
+      "  login text, " .
+      "  itime timestamp DEFAULT now(), " .
+      "  PRIMARY KEY (tag))";
+    $dbh->do($query) || $form->dberror($query);
+  }
+
+  $main::lxdebug->leave_sub();
+}
+
 sub dbupdate {
   $main::lxdebug->enter_sub();
 
 sub dbupdate {
   $main::lxdebug->enter_sub();
 
@@ -794,7 +826,7 @@ sub dbupdate {
       last if ($version < $mindb);
 
       # apply upgrade
       last if ($version < $mindb);
 
       # apply upgrade
-      $main::lxdebug->message(DEBUG2, "Appliying Update $upgradescript");
+      $main::lxdebug->message(DEBUG2, "Applying Update $upgradescript");
       if ($file_type eq "sql") {
         $self->process_query($form, $dbh, "sql/" . $form->{"dbdriver"} . "-upgrade/$upgradescript", $str_maxdb);
       } else {
       if ($file_type eq "sql") {
         $self->process_query($form, $dbh, "sql/" . $form->{"dbdriver"} . "-upgrade/$upgradescript", $str_maxdb);
       } else {
@@ -815,6 +847,112 @@ sub dbupdate {
   return $rc;
 }
 
   return $rc;
 }
 
+sub dbupdate2 {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $form, $controls) = @_;
+
+  $form->{sid} = $form->{dbdefault};
+
+  my @upgradescripts = ();
+  my ($query, $sth, $tag);
+  my $rc = -2;
+
+  @upgradescripts = sort_dbupdate_controls($controls);
+
+  foreach my $db (split / /, $form->{dbupdate}) {
+
+    next unless $form->{$db};
+
+    # strip db from dataset
+    $db =~ s/^db//;
+    &dbconnect_vars($form, $db);
+
+    my $dbh =
+      DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
+      or $form->dberror;
+
+    map({ $_->{"applied"} = 0; } @upgradescripts);
+
+    $query = "SELECT tag FROM schema_info";
+    $sth = $dbh->prepare($query);
+    $sth->execute() || $form->dberror($query);
+    while (($tag) = $sth->fetchrow_array()) {
+      $controls->{$tag}->{"applied"} = 1 if (defined($controls->{$tag}));
+    }
+    $sth->finish();
+
+    my $all_applied = 1;
+    foreach (@upgradescripts) {
+      if (!$_->{"applied"}) {
+        $all_applied = 0;
+        last;
+      }
+    }
+
+    next if ($all_applied);
+
+    foreach my $control (@upgradescripts) {
+      next if ($control->{"applied"});
+
+      $control->{"file"} =~ /\.(sql|pl)$/;
+      my $file_type = $1;
+
+      # apply upgrade
+      $main::lxdebug->message(DEBUG2, "Applying Update $control->{file}");
+      print($form->parse_html_template("dbupgrade/upgrade_message2",
+                                       $control));
+
+      if ($file_type eq "sql") {
+        $self->process_query($form, $dbh, "sql/" . $form->{"dbdriver"} .
+                             "-upgrade2/$control->{file}", $control);
+      } else {
+        $self->process_perl_script($form, $dbh, "sql/" . $form->{"dbdriver"} .
+                                   "-upgrade2/$control->{file}", $control);
+      }
+    }
+
+    $rc = 0;
+    $dbh->disconnect;
+
+  }
+
+  $main::lxdebug->leave_sub();
+
+  return $rc;
+}
+
+sub update2_available {
+  $main::lxdebug->enter_sub();
+
+  my ($form, $controls) = @_;
+
+  map({ $_->{"applied"} = 0; } values(%{$controls}));
+
+  dbconnect_vars($form, $form->{"dbname"});
+
+  my $dbh =
+    DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) ||
+    $form->dberror;
+
+  my ($query, $tag, $sth);
+
+  $query = "SELECT tag FROM schema_info";
+  $sth = $dbh->prepare($query);
+  $sth->execute() || $form->dberror($query);
+  while (($tag) = $sth->fetchrow_array()) {
+    $controls->{$tag}->{"applied"} = 1 if (defined($controls->{$tag}));
+  }
+  $sth->finish();
+  $dbh->disconnect();
+
+  map({ $main::lxdebug->leave_sub() and return 1 if (!$_->{"applied"}) }
+      values(%{$controls}));
+
+  $main::lxdebug->leave_sub();
+  return 0;
+}
+
 sub create_config {
   $main::lxdebug->enter_sub();
 
 sub create_config {
   $main::lxdebug->enter_sub();
 
diff --git a/doc/sql-upgrade-dateien.txt b/doc/sql-upgrade-dateien.txt
new file mode 100644 (file)
index 0000000..5b9ae18
--- /dev/null
@@ -0,0 +1,142 @@
+Neuer Mechanismus für SQL-Upgradedateien
+----------------------------------------
+
+Der alte Mechanismus für SQL-Upgradescripte, der auf einer
+Versionsnummer beruht und dann in sql/Pg-upgrade nach einem Script für
+diese Versionsnummer sucht, schränkt sehr ein, z.B. was die parallele
+Entwicklung im stable- und unstable-Baum betrifft.
+
+Dieser Mechanismus wurde für Lx-Office 2.4.1 deutlich erweitert. Es
+werden weiterhin alle Scripte aus sql/Pg-upgrade
+ausgeführt. Zusätzlich gibt es aber ein zweites Verzeichnis,
+sql/Pg-upgrade2. In diesem Verzeichnis muss pro Datenbankupgrade eine
+Datei existieren, die neben den eigentlich auszuführenden SQL- oder
+Perl-Befehlen einige Kontrollinformationen enthält.
+
+Neu sind die Kontrollinformationen, die Abhängigkeiten und Prioritäten
+definieren können werden, sodass Datenbankscripte zwar in einer
+sicheren Reihenfolge ausgeführt werden (z.B. darf ein "ALTER TABLE"
+erst ausgeführt werden, wenn die Tabelle mit "CREATE TABLE" angelegt
+wurde), diese Reihenfolge aber so flexibel ist, dass man keine
+Versionsnummern mehr braucht.
+
+Lx-Office merkt sich dabei, welches der Upgradescripte in
+sql/Pg-upgrade2 bereits durchgeführt wurde und führt diese nicht
+erneut aus. Dazu dient die Tabelle "schema_info", die bei der
+Anmeldung automatisch angelegt wird.
+
+Format der Kontrollinformationen
+--------------------------------
+
+Die Kontrollinformationen sollten sich am Anfang der jeweiligen
+Upgradedatei befinden. Jede Zeile, die Kontrollinformationen enthält,
+hat dabei das folgende Format:
+
+Für SQL-Upgradedateien:
+
+-- @key: value
+
+
+Für Perl-Upgradedateien:
+
+# @key: value
+
+
+Leerzeichen vor "value" werden entfern.
+
+Die folgenden Schlüsselworte werden verarbeitet:
+
+* tag: Wird zwingend benötigt. Dies ist der "Name" des
+  Upgrades. Dieser "tag" kann von anderen Kontrolldateien in ihren
+  Abhängigkeiten verwendet werden (Schlüsselwort "depends"). Der "tag"
+  ist auch der Name, der in der Datenbank eingetragen wird.
+
+  Normalerweise sollte die Kontrolldatei genau so heißen wie der
+  "tag", nur mit der Endung ".sql" bzw. "pl".
+
+  Ein Tag darf nur aus alphanumerischen Zeichen sowie den Zeichen _ -
+  ( ) bestehen. Insbesondere sind Leerzeichen nicht erlaubt und
+  sollten stattdessen mit Unterstrichen ersetzt werden.
+
+* description: Benötigt. Eine Beschreibung, was in diesem Update
+  passiert. Diese wird dem Benutzer beim eigentlichen Datenbankupdate
+  angezeigt. Während der Tag in englisch gehalten sein sollte, sollte
+  die Beschreibung auf Deutsch erfolgen.
+
+* depends: Optional. Eine mit Leerzeichen getrennte Liste von "tags",
+  von denen dieses Upgradescript abhängt. Lx-Office stellt sicher,
+  dass die in dieser Liste aufgeführten Scripte bereits durchgeführt
+  wurden, bevor dieses Script ausgeführt wird.
+
+  Abhängigkeiten werden rekursiv betrachtet. Wenn also ein Script "b"
+  existiert, das von Änderungen in "a" abhängt, und eine neue
+  Kontrolldatei für "c" erstellt wird, die von Änderungen in "a" und
+  "b" abhängt, so genügt es, in "c" nur den Tag "b" als Abhängigkeit
+  zu definieren.
+
+  Es ist nicht erlaubt, sich selbst referenzierende Abhängigkeiten zu
+  definieren (z.B. "a" -> "b", "b" -> "c" und "c" -> "a").
+
+* priority: Optional. Ein Zahlenwert, der die Reihenfolge bestimmt, in
+  der Scripte ausgeführt werden, die die gleichen Abhängigkeitstiefen
+  besitzen. Fehlt dieser Parameter, so wird der Wert 1000 benutzt.
+
+  Dies ist reine Kosmetik. Für echte Reihenfolgen muss "depends"
+  benutzt werden. Lx-Office sortiert die auszuführenden Scripte zuerst
+  nach der Abhängigkeitstiefe (wenn "z" von "y" abhängt und "y" von
+  "x", so hat "z" eine Abhängigkeitstiefe von 2, "y" von 1 und "x" von
+  0. "x" würde hier zuerst ausgeführt, dann "y", dann "z"), dann nach
+  der Priorität und bei gleicher Priorität alphabetisch nach dem
+  "tag".
+
+Hilfsscript dbupgrade2_tool.pl
+------------------------------
+
+Um die Arbeit mit den Abhängigkeiten etwas zu erleichtern, existiert
+ein Hilfsscript namens "scripts/dbupgrade2_tool.pl". Es muss aus dem
+Lx-Office-ERP-Basisverzeichnis heraus aufgerufen werden. Dieses Tool
+liest alle Datenbankupgradescripte aus dem Verzeichnis sql/Pg-upgrade2
+aus. Es benutzt dafür die gleichen Methoden wie Lx-Office selber,
+sodass alle Fehlersituationen von der Kommandozeile überprüft werden
+können.
+
+Wird dem Script kein weiterer Parameter übergeben, so wird nur eine
+Überprüfung der Felder und Abhängigkeiten vorgenommen. Man kann sich
+aber auch Informationen auf verschiedene Art ausgeben lassen:
+
+1. Listenform: "./scripts/dbupgrade2_tool.pl --list"
+
+   Gibt eine Liste aller Scripte aus. Die Liste ist in der Reihenfolge
+   sortiert, in der Lx-Office die Scripte ausführen würde. Es werden
+   neben der Listenposition der Tag, die Abhängigkeitstiefe und die
+   Priorität ausgegeben.
+
+2. Baumform: "./scripts/dbupgrade2_tool.pl --tree"
+
+   Listet alle Tags in Baumform basierend auf den Abhängigkeiten
+   auf. Die "Wurzelknoten" sind dabei die Scripte, von denen keine
+   anderen abhängen. Die Unterknoten sind Scripte, die beim
+   übergeordneten Script als Abhängigkeit eingetragen sind.
+
+3. Umgekehrte Baumform: "./scripts/dbupgrade2_tool.pl --rtree"
+
+   Listet alle Tags in Baumform basierend auf den Abhängigkeiten auf.
+   Die "Wurzelknoten" sind dabei die Scripte mit der geringsten
+   Abhängigkeitstiefe. Die Unterknoten sind Scripte, die das
+   übergeordnete Script als Abhängigkeit eingetragen haben.
+
+4. Baumform mit Postscriptausgabe: "./scripts/dbupgrade2_tool.pl --graphviz"
+
+   Benötigt das Tool "graphviz", um mit seiner Hilfe die Baumform aus
+   3. in eine Postscriptdatei namens "db_dependencies.ps"
+   auszugeben. Dies ist vermutlich die übersichtlichste Form, weil
+   hierbei jeder Knoten nur einmal ausgegeben wird. Bei den
+   Textmodusbaumformen hingegen können Knoten und all ihre
+   Abhängigkeiten mehrfach ausgegeben werden.
+
+5. Scripte, von denen kein anderes Script abhängt:
+   "./scripts/dbupgrade2_tool.pl --nodeps"
+
+   Listet die Tags aller Scripte auf, von denen keine anderen Scripte
+   abhängen.
+
index 0ebbd1755c9dc7c958249647b6021a9f15886a16..99ba1546a47731c49bfbe04ef75c6d48db5db287 100644 (file)
@@ -29,11 +29,13 @@ $self->{texts} = {
   'Date Format'                 => 'Datumsformat',
   'Delete'                      => 'Löschen',
   'Delete Dataset'              => 'Datenbank löschen',
   'Date Format'                 => 'Datumsformat',
   'Delete'                      => 'Löschen',
   'Delete Dataset'              => 'Datenbank löschen',
+  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
   'Directory'                   => 'Verzeichnis',
   'Driver'                      => 'Treiber',
   'Dropdown Limit'              => 'Auswahllistenbegrenzung',
   'E-mail'                      => 'eMail',
   'Edit User'                   => 'Benutzerdaten bearbeiten',
   'Directory'                   => 'Verzeichnis',
   'Driver'                      => 'Treiber',
   'Dropdown Limit'              => 'Auswahllistenbegrenzung',
   'E-mail'                      => 'eMail',
   'Edit User'                   => 'Benutzerdaten bearbeiten',
+  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
   'Existing Datasets'           => 'existierende Datenbanken',
   'Fax'                         => 'Fax',
   'File locked!'                => 'Datei gesperrt!',
   'Existing Datasets'           => 'existierende Datenbanken',
   'Fax'                         => 'Fax',
   'File locked!'                => 'Datei gesperrt!',
@@ -48,6 +50,9 @@ $self->{texts} = {
   'Login'                       => 'Anmeldung',
   'Login name missing!'         => 'Loginname fehlt.',
   'Manager'                     => 'Manager',
   'Login'                       => 'Anmeldung',
   'Login name missing!'         => 'Loginname fehlt.',
   'Manager'                     => 'Manager',
+  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
+  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
+  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
   'Multibyte Encoding'          => 'Schriftsatz',
   'Name'                        => 'Name',
   'New Templates'               => 'neue Vorlagen',
   'Multibyte Encoding'          => 'Schriftsatz',
   'Name'                        => 'Name',
   'New Templates'               => 'neue Vorlagen',
@@ -72,11 +77,13 @@ $self->{texts} = {
   'Stylesheet'                  => 'Stilvorlage',
   'Supervisor'                  => 'Supervisor',
   'Templates'                   => 'Vorlagen',
   'Stylesheet'                  => 'Stilvorlage',
   'Supervisor'                  => 'Supervisor',
   'Templates'                   => 'Vorlagen',
+  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
   'The following Datasets are not in use and can be deleted' => 'Die folgenden Datenbanken sind nicht in Verwendung und können gelöscht werden',
   'The following Datasets need to be updated' => 'Folgende Datenbanken müssen aktualisiert werden',
   'The passwords do not match.' => 'Die Passw&ouml;rter stimmen nicht &uuml;berein.',
   '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!',
   'To add a user to a group edit a name, change the login name and save.  A new user with the same variables will then be saved under the new login name.' => 'Um einer Gruppe einen neuen Benutzer hinzuzufügen, ändern und speichern Sie am einfachsten einen bestehen den Zugriffsnamen. Unter dem neuen Namen wird dann ein Benutzer mit denselben Einstellungen angelegt.',
   'The following Datasets are not in use and can be deleted' => 'Die folgenden Datenbanken sind nicht in Verwendung und können gelöscht werden',
   'The following Datasets need to be updated' => 'Folgende Datenbanken müssen aktualisiert werden',
   'The passwords do not match.' => 'Die Passw&ouml;rter stimmen nicht &uuml;berein.',
   '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!',
   'To add a user to a group edit a name, change the login name and save.  A new user with the same variables will then be saved under the new login name.' => 'Um einer Gruppe einen neuen Benutzer hinzuzufügen, ändern und speichern Sie am einfachsten einen bestehen den Zugriffsnamen. Unter dem neuen Namen wird dann ein Benutzer mit denselben Einstellungen angelegt.',
+  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
   'Unlock System'               => 'System entsperren',
   'Update Dataset'              => 'Datenbank aktualisieren',
   'Use Templates'               => 'benutze Vorlagen',
   'Unlock System'               => 'System entsperren',
   'Update Dataset'              => 'Datenbank aktualisieren',
   'Use Templates'               => 'benutze Vorlagen',
index 7597d93b6c3022b67a988f52a0ea094f2bcd1e86..bd9fd60f3732d8954c4fab4307963961b29794bd 100644 (file)
@@ -96,6 +96,7 @@ $self->{texts} = {
   'Ansprechpartner'             => '',
   'Application Error. No Format given!' => 'Fehler in der Anwendung. Das Format fehlt.',
   'Application Error. Wrong Format: ' => 'Fehler in der Anwendung. Falsches Format: ',
   'Ansprechpartner'             => '',
   'Application Error. No Format given!' => 'Fehler in der Anwendung. Das Format fehlt.',
   'Application Error. Wrong Format: ' => 'Fehler in der Anwendung. Falsches Format: ',
+  'Applying <TMPL_VAR file ESCAPE=HTML>:' => 'F&uuml;hre <TMPL_VAR file ESCAPE=HTML> aus:',
   'Apr'                         => 'Apr',
   'April'                       => 'April',
   'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gelöscht werden:',
   'Apr'                         => 'Apr',
   'April'                       => 'April',
   'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gelöscht werden:',
@@ -322,6 +323,7 @@ aktualisieren wollen?',
   'Department deleted!'         => 'Abteilung gelöscht.',
   'Department saved!'           => 'Abteilung gespeichert.',
   'Departments'                 => 'Abteilungen',
   'Department deleted!'         => 'Abteilung gelöscht.',
   'Department saved!'           => 'Abteilung gespeichert.',
   'Departments'                 => 'Abteilungen',
+  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
   'Deposit'                     => 'Gutschrift',
   'Description'                 => 'Beschreibung',
   'Description missing!'        => 'Beschreibung fehlt.',
   'Deposit'                     => 'Gutschrift',
   'Description'                 => 'Beschreibung',
   'Description missing!'        => 'Beschreibung fehlt.',
@@ -416,6 +418,7 @@ gestartet',
   'Erlöse EU o. UStId'          => 'Erl&ouml;se EU o. UStId',
   'Erlöse Inland'               => 'Erl&ouml;se Inland',
   'Error'                       => 'Fehler',
   'Erlöse EU o. UStId'          => 'Erl&ouml;se EU o. UStId',
   'Erlöse Inland'               => 'Erl&ouml;se Inland',
   'Error'                       => 'Fehler',
+  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
   'Error!'                      => 'Fehler!',
   'Exch'                        => 'Wechselkurs.',
   'Exchangerate'                => 'Wechselkurs',
   'Error!'                      => 'Fehler!',
   'Exch'                        => 'Wechselkurs.',
   'Exchangerate'                => 'Wechselkurs',
@@ -621,6 +624,8 @@ gestartet',
   'Method'                      => 'Verfahren',
   'Microfiche'                  => 'Mikrofilm',
   'Minimum Amount'              => 'Mindestbetrag',
   'Method'                      => 'Verfahren',
   'Microfiche'                  => 'Mikrofilm',
   'Minimum Amount'              => 'Mindestbetrag',
+  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
+  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
   'Missing Method!'             => 'Fehlender Voranmeldungszeitraum',
   'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
   'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
   'Missing Method!'             => 'Fehlender Voranmeldungszeitraum',
   'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
   'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
@@ -630,6 +635,7 @@ gestartet',
   'Model'                       => 'Modell',
   'Monat'                       => 'Monat',
   'Monthly'                     => 'monatlich',
   'Model'                       => 'Modell',
   'Monat'                       => 'Monat',
   'Monthly'                     => 'monatlich',
+  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
   'Multibyte Encoding'          => 'Schriftsatz',
   'MwSt. inkl.'                 => 'MwSt. inkl.',
   'N/A'                         => 'N.Z.',
   'Multibyte Encoding'          => 'Schriftsatz',
   'MwSt. inkl.'                 => 'MwSt. inkl.',
   'N/A'                         => 'N.Z.',
@@ -945,6 +951,7 @@ gestartet',
   'Templates'                   => 'Vorlagen',
   'Terms missing in row '       => '+Tage fehlen in Zeile ',
   'Terms: Net'                  => 'Zahlungsziel',
   'Templates'                   => 'Vorlagen',
   'Terms missing in row '       => '+Tage fehlen in Zeile ',
   'Terms: Net'                  => 'Zahlungsziel',
+  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
   'The base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gel&ouml;scht werden.',
   '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 base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gel&ouml;scht werden.',
   '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.',
@@ -1054,6 +1061,7 @@ gestartet',
   'Unit'                        => 'Einheit',
   'Unit of measure'             => 'Maßeinheit',
   'Units'                       => 'Einheiten',
   'Unit'                        => 'Einheit',
   'Unit of measure'             => 'Maßeinheit',
   'Units'                       => 'Einheiten',
+  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
   'Unlock System'               => 'System entsperren',
   'Until'                       => 'Bis',
   'Update'                      => 'Erneuern',
   'Unlock System'               => 'System entsperren',
   'Until'                       => 'Bis',
   'Update'                      => 'Erneuern',
index 6c5829e07e41cdbb19b157fb73cc51ed41037de3..d643edd7ad6e2f1a11e28210a02e86bc67cc59c2 100644 (file)
@@ -71,6 +71,7 @@ $self->{texts} = {
   'Department deleted!'         => 'Abteilung gelöscht.',
   'Department saved!'           => 'Abteilung gespeichert.',
   'Departments'                 => 'Abteilungen',
   'Department deleted!'         => 'Abteilung gelöscht.',
   'Department saved!'           => 'Abteilung gespeichert.',
   'Departments'                 => 'Abteilungen',
+  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
   'Description'                 => 'Beschreibung',
   'Description missing!'        => 'Beschreibung fehlt.',
   'Discount'                    => 'Rabatt',
   'Description'                 => 'Beschreibung',
   'Description missing!'        => 'Beschreibung fehlt.',
   'Discount'                    => 'Rabatt',
@@ -99,6 +100,7 @@ $self->{texts} = {
   'Erlöse EU m. UStId'          => 'Erl&ouml;se EU m. UStId',
   'Erlöse EU o. UStId'          => 'Erl&ouml;se EU o. UStId',
   'Erlöse Inland'               => 'Erl&ouml;se Inland',
   'Erlöse EU m. UStId'          => 'Erl&ouml;se EU m. UStId',
   'Erlöse EU o. UStId'          => 'Erl&ouml;se EU o. UStId',
   'Erlöse Inland'               => 'Erl&ouml;se Inland',
+  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
   'Expense'                     => 'Aufwandskonto',
   'Expense Account'             => 'Aufwandskonto',
   'Expense/Asset'               => 'Aufwand/Anlagen',
   'Expense'                     => 'Aufwandskonto',
   'Expense Account'             => 'Aufwandskonto',
   'Expense/Asset'               => 'Aufwand/Anlagen',
@@ -138,6 +140,9 @@ $self->{texts} = {
   'Link'                        => 'Verknüpfungen',
   'Long Dates'                  => 'Lange Monatsnamen',
   'Long Description'            => 'Langtext',
   'Link'                        => 'Verknüpfungen',
   'Long Dates'                  => 'Lange Monatsnamen',
   'Long Description'            => 'Langtext',
+  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
+  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
+  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
   'Name'                        => 'Name',
   'Netto Terms'                 => 'Zahlungsziel netto',
   'No'                          => 'Nein',
   'Name'                        => 'Name',
   'Netto Terms'                 => 'Zahlungsziel netto',
   'No'                          => 'Nein',
@@ -197,6 +202,7 @@ $self->{texts} = {
   'Template Code'               => 'Vorlagenkürzel',
   'Template Code missing!'      => 'Vorlagenkürzel fehlt!',
   'Template saved!'             => 'Schablone gespeichert!',
   'Template Code'               => 'Vorlagenkürzel',
   'Template Code missing!'      => 'Vorlagenkürzel fehlt!',
   'Template saved!'             => 'Schablone gespeichert!',
+  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
   'The base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gel&ouml;scht werden.',
   '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 base unit does not exist or it is about to be deleted in row %d.' => 'Die Basiseinheit in Zeile %d existiert nicht oder soll gel&ouml;scht werden.',
   '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.',
@@ -256,6 +262,7 @@ $self->{texts} = {
   'UStVA-Nr. 98'                => 'Kz. 98',
   'Umsatzsteuervoranmeldung'    => 'Umsatzsteuervoranmeldung',
   'Unit'                        => 'Einheit',
   'UStVA-Nr. 98'                => 'Kz. 98',
   'Umsatzsteuervoranmeldung'    => 'Umsatzsteuervoranmeldung',
   'Unit'                        => 'Einheit',
+  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
   'Value'                       => 'Wert',
   'Variable'                    => 'Variable',
   'Warehouse deleted!'          => 'Das Lager wurde gelöscht.',
   'Value'                       => 'Wert',
   'Variable'                    => 'Variable',
   'Warehouse deleted!'          => 'Das Lager wurde gelöscht.',
index 7a73120e82e727da35a315f17c33adb2cf86cedd..6415370443d90466fb5f152c90b3ec8ef8d7bc7c 100755 (executable)
@@ -15,6 +15,7 @@ $| = 1;
 $basedir  = "../..";
 $bindir   = "$basedir/bin/mozilla";
 $dbupdir  = "$basedir/sql/Pg-upgrade";
 $basedir  = "../..";
 $bindir   = "$basedir/bin/mozilla";
 $dbupdir  = "$basedir/sql/Pg-upgrade";
+$dbupdir2 = "$basedir/sql/Pg-upgrade2";
 $menufile = "menu.ini";
 $submitsearch = qr/type\s*=\s*[\"\']?submit/i;
 
 $menufile = "menu.ini";
 $submitsearch = qr/type\s*=\s*[\"\']?submit/i;
 
@@ -45,6 +46,10 @@ opendir DIR, $dbupdir or die "$!";
 @dbplfiles = grep { /\.pl$/ } readdir DIR;
 closedir DIR;
 
 @dbplfiles = grep { /\.pl$/ } readdir DIR;
 closedir DIR;
 
+opendir DIR, $dbupdir2 or die "$!";
+@dbplfiles2 = grep { /\.pl$/ } readdir DIR;
+closedir DIR;
+
 # slurp the translations in
 if (-f 'all') {
   require "all";
 # slurp the translations in
 if (-f 'all') {
   require "all";
@@ -59,6 +64,7 @@ if (-f 'all') {
 
 map({ handle_file($_, $bindir); } @progfiles);
 map({ handle_file($_, $dbupdir); } @dbplfiles);
 
 map({ handle_file($_, $bindir); } @progfiles);
 map({ handle_file($_, $dbupdir); } @dbplfiles);
+map({ handle_file($_, $dbupdir2); } @dbplfiles2);
 
 sub handle_file {
   my ($file, $dir) = @_;
 
 sub handle_file {
   my ($file, $dir) = @_;
index 52d2f65aea7c3b6a7df672d7cac93a379331f806..d9b989487d49e8d1d7fe422c758041980ee7e3e8 100644 (file)
@@ -3,11 +3,18 @@ $self->{texts} = {
   'Database Host'               => 'Datenbankcomputer',
   'Dataset'                     => 'Datenbank',
   'Dataset upgrade'             => 'Datenbankaktualisierung',
   'Database Host'               => 'Datenbankcomputer',
   'Dataset'                     => 'Datenbank',
   'Dataset upgrade'             => 'Datenbankaktualisierung',
+  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
+  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
   'Incorrect username or password!' => 'Ungültiger Benutzername oder falsches Passwort!',
   'Licensed to'                 => 'Lizensiert für',
   'Login'                       => 'Anmeldung',
   'Login Name'                  => 'Benutzername',
   'Incorrect username or password!' => 'Ungültiger Benutzername oder falsches Passwort!',
   'Licensed to'                 => 'Lizensiert für',
   'Login'                       => 'Anmeldung',
   'Login Name'                  => 'Benutzername',
+  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
+  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
+  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
   'Password'                    => 'Passwort',
   'Password'                    => 'Passwort',
+  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
+  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
   'User'                        => 'Benutzer',
   'Version'                     => 'Version',
   'You are logged out!'         => 'Auf Wiedersehen!',
   'User'                        => 'Benutzer',
   'Version'                     => 'Version',
   'You are logged out!'         => 'Auf Wiedersehen!',
index f4a7f8ee39bfd7bc13dae5bff3cbbd6db918ecfd..4252558fb082b1d93cfd2b4b595ed0f7f83d0945 100644 (file)
@@ -32,10 +32,12 @@ $self->{texts} = {
   'Dauerfristverlängerung'      => 'Dauerfristverlängerung',
   'Dec'                         => 'Dez',
   'December'                    => 'Dezember',
   'Dauerfristverlängerung'      => 'Dauerfristverlängerung',
   'Dec'                         => 'Dez',
   'December'                    => 'Dezember',
+  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
   'Description'                 => 'Beschreibung',
   'ELSTER Export nach Taxbird'  => 'ELSTER-Export nach Taxbird',
   'ELSTER Export nach Winston'  => 'ELSTER Export nach Winston',
   'ELSTER-Steuernummer: '       => 'ELSTER-Steuernummer: ',
   'Description'                 => 'Beschreibung',
   'ELSTER Export nach Taxbird'  => 'ELSTER-Export nach Taxbird',
   'ELSTER Export nach Winston'  => 'ELSTER Export nach Winston',
   'ELSTER-Steuernummer: '       => 'ELSTER-Steuernummer: ',
+  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
   'Fax'                         => 'Fax',
   'Fax. : '                     => 'Fax. : ',
   'Fax.: '                      => 'Fax.: ',
   'Fax'                         => 'Fax',
   'Fax. : '                     => 'Fax. : ',
   'Fax.: '                      => 'Fax.: ',
@@ -69,9 +71,12 @@ $self->{texts} = {
   'May'                         => 'Mai',
   'May '                        => 'Mai',
   'Method'                      => 'Verfahren',
   'May'                         => 'Mai',
   'May '                        => 'Mai',
   'Method'                      => 'Verfahren',
+  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
+  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
   'Missing Method!'             => 'Fehlender Voranmeldungszeitraum',
   'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
   'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
   'Missing Method!'             => 'Fehlender Voranmeldungszeitraum',
   'Missing Preferences: Outputroutine disabled' => 'Die Ausgabefunktionen sind wegen unzureichender Voreinstellungen deaktiviert!',
   'Missing Tax Authoritys Preferences' => 'Fehlende Angaben zum Finanzamt!',
+  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
   'Name'                        => 'Name',
   'Nov'                         => 'Nov',
   'November'                    => 'November',
   'Name'                        => 'Name',
   'Nov'                         => 'Nov',
   'November'                    => 'November',
@@ -93,10 +98,12 @@ $self->{texts} = {
   'Tel. : '                     => 'Tel. : ',
   'Tel.: '                      => 'Tel.: ',
   'Telefon'                     => 'Telefon',
   'Tel. : '                     => 'Tel. : ',
   'Tel.: '                      => 'Tel.: ',
   'Telefon'                     => 'Telefon',
+  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
   'USTVA-Hint: Method'          => 'Wenn Sie Ist-Versteuert sind, wählen Sie die Einnahmen-/Überschuß-Rechnung aus. Sind Sie Soll-Versteuert und bilanzverpflichtet, dann wählen Sie Bilanz aus.',
   'USTVA-Hint: Tax Authoritys'  => 'Bitte das Bundesland UND die Stadt bzw. den Einzugsbereich Ihres zuständigen Finanzamts auswählen.',
   'UStVA'                       => 'UStVA',
   'UStVA als PDF-Dokument'      => 'UStVa als PDF-Dokument',
   'USTVA-Hint: Method'          => 'Wenn Sie Ist-Versteuert sind, wählen Sie die Einnahmen-/Überschuß-Rechnung aus. Sind Sie Soll-Versteuert und bilanzverpflichtet, dann wählen Sie Bilanz aus.',
   'USTVA-Hint: Tax Authoritys'  => 'Bitte das Bundesland UND die Stadt bzw. den Einzugsbereich Ihres zuständigen Finanzamts auswählen.',
   'UStVA'                       => 'UStVA',
   'UStVA als PDF-Dokument'      => 'UStVa als PDF-Dokument',
+  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
   'Vendor not on file!'         => 'Lieferant ist nicht in der Datenbank!',
   'Verfahren'                   => 'Verfahren',
   'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)' => 'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)',
   'Vendor not on file!'         => 'Lieferant ist nicht in der Datenbank!',
   'Verfahren'                   => 'Verfahren',
   'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)' => 'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)',
diff --git a/scripts/dbupgrade2_tool.pl b/scripts/dbupgrade2_tool.pl
new file mode 100755 (executable)
index 0000000..850ef8d
--- /dev/null
@@ -0,0 +1,192 @@
+#!/usr/bin/perl
+
+BEGIN {
+  if (! -d "bin" || ! -d "SL") {
+    print("This tool must be run from the Lx-Office ERP base directory.\n");
+    exit(1);
+  }
+}
+
+use DBI;
+use Data::Dumper;
+use Getopt::Long;
+
+use SL::LXDebug;
+
+$lxdebug = LXDebug->new();
+
+use SL::Form;
+use SL::DBUpgrade2;
+
+#######
+#######
+#######
+
+sub show_help {
+  print("dbupgrade2_tool.pl [--list] [--tree] [--rtree] [--graphviz]\n" .
+        "                   [--nodepds] [--help]\n");
+}
+
+sub calc_rev_depends {
+  map({ $_->{"rev_depends"} = []; } values(%{$controls}));
+  foreach my $control (values(%{$controls})) {
+    map({ push(@{$controls->{$_}{"rev_depends"}}, $control->{"tag"}) }
+        @{$control->{"depends"}});
+  }
+}
+
+sub dump_list {
+  my @sorted_controls = sort_dbupdate_controls($controls);
+
+  print("LIST VIEW\n\n");
+  print("number tag depth priority\n");
+  $i = 0;
+  foreach (@sorted_controls) {
+    print("$i $_->{tag} $_->{depth} $_->{priority}\n");
+    $i++;
+  }
+
+  print("\n");
+}
+
+sub dump_node {
+  my ($tag, $depth) = @_;
+
+  print(" " x $depth . $tag . "\n");
+
+  my $c = $controls->{$tag};
+  my $num = scalar(@{$c->{"depends"}});
+  for (my $i = 0; $i < $num; $i++) {
+    dump_node($c->{"depends"}[$i], $depth + 1);
+  }
+}
+
+sub dump_tree {
+  print("TREE VIEW\n\n");
+
+  calc_rev_depends();
+
+  my @sorted_controls = sort_dbupdate_controls($controls);
+
+  foreach my $control (@sorted_controls) {
+    dump_node($control->{"tag"}, "") unless (@{$control->{"rev_depends"}});
+  }
+
+  print("\n");
+}
+
+sub dump_node_reverse {
+  my ($tag, $depth) = @_;
+
+  print(" " x $depth . $tag . "\n");
+
+  my $c = $controls->{$tag};
+  my $num = scalar(@{$c->{"rev_depends"}});
+  for (my $i = 0; $i < $num; $i++) {
+    dump_node_reverse($c->{"rev_depends"}[$i], $depth + 1);
+  }
+}
+
+sub dump_tree_reverse {
+  print("REVERSE TREE VIEW\n\n");
+
+  calc_rev_depends();
+
+  my @sorted_controls = sort_dbupdate_controls($controls);
+
+  foreach my $control (@sorted_controls) {
+    last if ($control->{"depth"} > 1);
+    dump_node_reverse($control->{"tag"}, "");
+  }
+
+  print("\n");
+}
+
+sub dump_graphviz {
+  print("GRAPHVIZ POSTCRIPT\n\n");
+  print("Output will be written to db_dependencies.ps\n");
+  $dot = "|dot -Tps ";
+  open(OUT, "${dot}> db_dependencies.ps");
+  print(OUT
+        "digraph db_dependencies {\n" .
+        "node [shape=box];\n");
+  my %ranks;
+  foreach my $c (values(%{$controls})) {
+    $ranks{$c->{"depth"}} = [] unless ($ranks{$c->{"depth"}});
+    push(@{$ranks{$c->{"depth"}}}, $c->{"tag"});
+  }
+  foreach (sort(keys(%ranks))) {
+    print(OUT "{ rank = same; " .
+          join("", map({ '"' . $_ . '"; ' } @{$ranks{$_}})) .
+          " }\n");
+  }
+  foreach my $c (values(%{$controls})) {
+    print(OUT "$c->{tag};\n");
+    foreach my $d (@{$c->{"depends"}}) {
+      print(OUT "$c->{tag} -> $d;\n");
+    }
+  }
+  print(OUT "}\n");
+  close(OUT);
+}
+
+sub dump_nodeps {
+  calc_rev_depends();
+
+  print("SCRIPTS NO OTHER SCRIPTS DEPEND ON\n\n" .
+        join("\n",
+             map({ $_->{"tag"} }
+                 grep({ !@{$_->{"rev_depends"}} }
+                      values(%{$controls})))) .
+        "\n\n");
+}
+
+#######
+#######
+#######
+
+eval { require "lx-erp.conf"; };
+
+$form = Form->new();
+$locale = Locale->new("de", "login");
+
+#######
+#######
+#######
+
+my ($opt_list, $opt_tree, $opt_rtree, $opt_nodeps, $opt_graphviz, $opt_help);
+
+GetOptions("list" => \$opt_list,
+           "tree" => \$opt_tree,
+           "rtree" => \$opt_rtree,
+           "nodeps" => \$opt_nodeps,
+           "graphviz" => \$opt_graphviz,
+           "help" => \$opt_help,
+  );
+
+if ($opt_help) {
+  show_help();
+  exit(0);
+}
+
+$controls = parse_dbupdate_controls($form, "Pg");
+
+if ($opt_list) {
+  dump_list();
+}
+
+if ($opt_tree) {
+  dump_tree();
+}
+
+if ($opt_rtree) {
+  dump_tree_reverse();
+}
+
+if ($opt_graphviz) {
+  dump_graphviz();
+}
+
+if ($opt_nodeps) {
+  dump_nodeps();
+}
diff --git a/sql/Pg-upgrade/Pg-upgrade-2.4.0.0-2.4.0.1.sql b/sql/Pg-upgrade/Pg-upgrade-2.4.0.0-2.4.0.1.sql
deleted file mode 100644 (file)
index b55199e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE language ADD COLUMN output_numberformat text;
-ALTER TABLE language ADD COLUMN output_dateformat text;
-ALTER TABLE language ADD COLUMN output_longdates boolean;
diff --git a/sql/Pg-upgrade/Pg-upgrade-2.4.0.1-2.4.0.2.sql b/sql/Pg-upgrade/Pg-upgrade-2.4.0.1-2.4.0.2.sql
deleted file mode 100644 (file)
index ed2c2cd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-CREATE TABLE units_language (
-       unit varchar (20) NOT NULL,
-       language_id integer NOT NULL,
-       localized varchar (20),
-       localized_plural varchar (20),
-
-       FOREIGN KEY (unit) REFERENCES units (name),
-       FOREIGN KEY (language_id) REFERENCES language (id)
-);
-CREATE INDEX units_name_idx ON units (name);
-CREATE INDEX units_language_unit_idx ON units_language (unit);
diff --git a/sql/Pg-upgrade/Pg-upgrade-2.4.0.2-2.4.0.3.sql b/sql/Pg-upgrade/Pg-upgrade-2.4.0.2-2.4.0.3.sql
deleted file mode 100644 (file)
index 36d291a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-update tax set id=0 WHERE taxkey=0;
diff --git a/sql/Pg-upgrade2/README b/sql/Pg-upgrade2/README
new file mode 100644 (file)
index 0000000..3a53151
--- /dev/null
@@ -0,0 +1,3 @@
+Bitte lesen Sie die Datei doc/sql-upgrade-dateien.txt, bevor
+Sie hier Dateien anlegen.
+
diff --git a/sql/Pg-upgrade2/language_output_formatting.sql b/sql/Pg-upgrade2/language_output_formatting.sql
new file mode 100644 (file)
index 0000000..4183c49
--- /dev/null
@@ -0,0 +1,6 @@
+-- @tag: language_output_formatting
+-- @description: Speichern des Ausgabeformates f&uuml;r Zahlen und Datumsangaben bei jeder Sprache.
+-- @depends:
+ALTER TABLE language ADD COLUMN output_numberformat text;
+ALTER TABLE language ADD COLUMN output_dateformat text;
+ALTER TABLE language ADD COLUMN output_longdates boolean;
diff --git a/sql/Pg-upgrade2/tax_id_if_taxkey_is_0.sql b/sql/Pg-upgrade2/tax_id_if_taxkey_is_0.sql
new file mode 100644 (file)
index 0000000..3df3414
--- /dev/null
@@ -0,0 +1,4 @@
+-- @tag: tax_id_if_taxkey_is_0
+-- @description: Aktualisierung der Spalte tax.id, wenn tax.taxkey = 0 ist.
+-- @depends:
+UPDATE tax SET id = 0 WHERE taxkey = 0;
diff --git a/sql/Pg-upgrade2/units_translations_and_singular_plural_distinction.sql b/sql/Pg-upgrade2/units_translations_and_singular_plural_distinction.sql
new file mode 100644 (file)
index 0000000..c1603e6
--- /dev/null
@@ -0,0 +1,14 @@
+-- @tag: units_translations_and_singular_plural_distinction
+-- @description: F&uuml;r jede Einheit kann f&uuml;r jede Sprache eine &Uuml;bersetzung sowie eine Unterscheidung zwischen Singular und Plural gespeichert werden.
+-- @depends:
+CREATE TABLE units_language (
+       unit varchar (20) NOT NULL,
+       language_id integer NOT NULL,
+       localized varchar (20),
+       localized_plural varchar (20),
+
+       FOREIGN KEY (unit) REFERENCES units (name),
+       FOREIGN KEY (language_id) REFERENCES language (id)
+);
+CREATE INDEX units_name_idx ON units (name);
+CREATE INDEX units_language_unit_idx ON units_language (unit);
diff --git a/templates/webpages/dbupgrade/upgrade_message2_de.html b/templates/webpages/dbupgrade/upgrade_message2_de.html
new file mode 100644 (file)
index 0000000..685a391
--- /dev/null
@@ -0,0 +1 @@
+F&uuml;hre <TMPL_VAR file ESCAPE=HTML> aus: <TMPL_VAR description ESCAPE=HTML><br>
diff --git a/templates/webpages/dbupgrade/upgrade_message2_master.html b/templates/webpages/dbupgrade/upgrade_message2_master.html
new file mode 100644 (file)
index 0000000..f0cc573
--- /dev/null
@@ -0,0 +1 @@
+<translate>Applying <TMPL_VAR file ESCAPE=HTML>:</translate> <TMPL_VAR description ESCAPE=HTML><br>