commit bde667c235b2347bdd1322f118b032a2f0d93367
Author: Moritz Bunkus <m.bunkus@linet.de>
Date:   Wed Feb 21 10:27:30 2007 +0000

    Einkaufs-, Verkaufs-, Debitoren- und Kreditorenrechnungen können als Entwurf gespeichert und später weiter bearbeitet werden. Dabei werden sie nicht gebucht.

diff --git a/SL/Drafts.pm b/SL/Drafts.pm
new file mode 100644
index 000000000..2ff3df86c
--- /dev/null
+++ b/SL/Drafts.pm
@@ -0,0 +1,164 @@
+#======================================================================
+# LX-Office ERP
+#
+#======================================================================
+#
+# Saving and loading drafts
+#
+#======================================================================
+
+package Drafts;
+
+use YAML;
+
+use SL::Common;
+use SL::DBUtils;
+
+sub get_module {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $form) = @_;
+
+  my ($module, $submodule);
+
+  $module = $form->{"script"};
+  $module =~ s/\.pl$//;
+  if (grep({ $module eq $_ } qw(is ir ar ap))) {
+    $submodule = "invoice";
+  } else {
+    $submodule = "unknown";
+  }
+
+  $main::lxdebug->leave_sub();
+
+  return ($module, $submodule);
+}
+
+sub save {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $myconfig, $form, $draft_id, $draft_description) = @_;
+
+  my ($dbh, $sth, $query, %saved, @dont_save, $dumped);
+
+  $dbh = $form->dbconnect_noauto($myconfig);
+
+  my ($module, $submodule) = $self->get_module($form);
+
+  $query = "SELECT COUNT(*) FROM drafts WHERE id = ?";
+  my ($res) = selectrow_query($form, $dbh, $query, $draft_id);
+  if (!$res) {
+    $draft_id = $module . "-" . $submodule . "-" . Common::unique_id();
+    $query = "INSERT INTO drafts (id, module, submodule) VALUES (?, ?, ?)";
+    do_query($form, $dbh, $query, $draft_id, $module, $submodule);
+  }
+
+  @dont_save = qw(login password path action);
+  map({ $saved{$_} = $form->{$_};
+        delete($form->{$_}); } @dont_save);
+  $dumped = YAML::Dump($form);
+  map({ $form->{$_} = $saved{$_}; } @dont_save);
+
+  $query =
+    qq|UPDATE drafts SET description = ?, form = ?, employee_id = | .
+    qq|  (SELECT id FROM employee WHERE login = ?) | .
+    qq|WHERE id = ?|;
+
+  do_query($form, $dbh, $query, $draft_description, $dumped,
+           $form->{login}, $draft_id);
+
+  $dbh->commit();
+  $dbh->disconnect();
+
+  $form->{draft_id} = $draft_id;
+  $form->{draft_description} = $draft_description;
+
+  $main::lxdebug->leave_sub();
+}
+
+sub load {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $myconfig, $form, $draft_id) = @_;
+
+  my ($dbh, $sth, $query, @values);
+
+  $dbh = $form->dbconnect($myconfig);
+
+  $query = qq|SELECT id, description, form FROM drafts WHERE id = ?|;
+
+  $sth = $dbh->prepare($query);
+  $sth->execute($draft_id) || $form->dberror("$query ($draft_id)");
+
+  my @values;
+  if (my $ref = $sth->fetchrow_hashref()) {
+    @values = ($ref->{form}, $ref->{id}, $ref->{description});
+  }
+  $sth->finish();
+
+  do_query($form, $dbh, "DELETE FROM drafts WHERE id = ?", $draft_id);
+
+  $dbh->disconnect();
+
+  $main::lxdebug->leave_sub();
+
+  return @values;
+}
+
+sub remove {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $myconfig, $form, $draft_id) = @_;
+
+  return $main::lxdebug->leave_sub() unless ($draft_id);
+
+  my ($dbh, $sth, $query, @values);
+
+  $dbh = $form->dbconnect($myconfig);
+
+  $query = qq|DELETE FROM drafts WHERE id = ?|;
+  do_query($form, $dbh, $query, $draft_id);
+
+  $dbh->disconnect();
+
+  $main::lxdebug->leave_sub();
+}
+
+sub list {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $myconfig, $form) = @_;
+
+  my ($dbh, $sth, $query, @values);
+
+  $dbh = $form->dbconnect($myconfig);
+
+  my ($module, $submodule) = $self->get_module($form);
+
+  my @list = ();
+  $query =
+    qq|SELECT d.id, d.description, d.itime::timestamp(0) AS itime, | .
+    qq|  e.name AS employee_name | .
+    qq|FROM drafts d | .
+    qq|LEFT JOIN employee e ON d.employee_id = e.id | .
+    qq|WHERE (d.module = ?) AND (d.submodule = ?) | .
+    qq|ORDER BY d.itime|;
+  my @values = ($module, $submodule);
+
+  $sth = $dbh->prepare($query);
+  $sth->execute(@values) ||
+    $form->dberror($query . " (" . join(", ", @values) . ")");
+
+  while (my $ref = $sth->fetchrow_hashref()) {
+    push(@list, $ref);
+  }
+  $sth->finish();
+
+  $dbh->disconnect();
+
+  $main::lxdebug->leave_sub();
+
+  return @list;
+}
+
+1;
diff --git a/bin/mozilla/ap.pl b/bin/mozilla/ap.pl
index f5c660952..54a9c94b4 100644
--- a/bin/mozilla/ap.pl
+++ b/bin/mozilla/ap.pl
@@ -37,6 +37,7 @@ use SL::PE;
 
 require "$form->{path}/arap.pl";
 require "bin/mozilla/common.pl";
+require "bin/mozilla/drafts.pl";
 
 1;
 
@@ -73,6 +74,8 @@ require "bin/mozilla/common.pl";
 sub add {
   $lxdebug->enter_sub();
 
+  return $lxdebug->leave_sub() if (load_draft_maybe());
+
   $form->{title} = "Add";
 
   $form->{callback} =
@@ -459,6 +462,8 @@ sub form_header {
 <input type=hidden name=locked value=$form->{locked}>
 <input type=hidden name=title value="$title">
 
+| . ($form->{saved_message} ? qq|<p>$form->{saved_message}</p>| : "") . qq|
+
 <table width=100%>
   <tr class=listtop>
     <th class=listtop>$form->{title}</th>
@@ -757,6 +762,10 @@ sub form_footer {
 <input type=hidden name=path value=$form->{path}>
 <input type=hidden name=login value=$form->{login}>
 <input type=hidden name=password value=$form->{password}>
+|
+. $cgi->hidden('-name' => 'draft_id', '-default' => [$form->{draft_id}])
+. $cgi->hidden('-name' => 'draft_description', '-default' => [$form->{draft_description}])
+. qq|
 
 <br>
 |;
@@ -789,7 +798,9 @@ sub form_footer {
   } elsif (($transdate > $closedto) && !$form->{id}) {
     print qq|
       <input class=submit type=submit name=action value="|
-      . $locale->text('Post') . qq|">|;
+      . $locale->text('Post') . qq|"> | .
+      NTI($cgi->submit('-name' => 'action', '-value' => $locale->text('Save draft'),
+                       '-class' => 'submit'));
   }
   # button for saving history
   if($form->{id} ne "") {
@@ -1000,15 +1011,17 @@ sub post {
   $form->{taxkey}       = $taxkey;
 
   $form->{id} = 0 if $form->{postasnew};
-  # saving the history
-  if(!exists $form->{addition} && $form->{id} ne "") {
-  	$form->{addition} = "POSTED";
-  	$form->save_history($form->dbconnect(\%myconfig));
-  }
-  # /saving the history 
 
-  $form->redirect($locale->text('Transaction posted!'))
-    if (AP->post_transaction(\%myconfig, \%$form));
+  if (AP->post_transaction(\%myconfig, \%$form)) {
+    # saving the history
+    if(!exists $form->{addition} && $form->{id} ne "") {
+      $form->{addition} = "POSTED";
+      $form->save_history($form->dbconnect(\%myconfig));
+    }
+    # /saving the history 
+    remove_draft();
+    $form->redirect($locale->text('Transaction posted!'));
+  }
   $form->error($locale->text('Cannot post transaction!'));
 
   $lxdebug->leave_sub();
diff --git a/bin/mozilla/ar.pl b/bin/mozilla/ar.pl
index 1e5aa98f2..af47235a9 100644
--- a/bin/mozilla/ar.pl
+++ b/bin/mozilla/ar.pl
@@ -38,6 +38,7 @@ use Data::Dumper;
 
 require "$form->{path}/arap.pl";
 require "bin/mozilla/common.pl";
+require "bin/mozilla/drafts.pl";
 
 1;
 
@@ -73,7 +74,9 @@ require "bin/mozilla/common.pl";
 
 sub add {
   $lxdebug->enter_sub();
-  
+
+  return $lxdebug->leave_sub() if (load_draft_maybe());
+
   # saving the history
   if(!exists $form->{addition} && ($form->{id} ne "")) {
   	$form->{addition} = "ADDED";
@@ -494,6 +497,8 @@ sub form_header {
 <input type=hidden name=locked value=$form->{locked}>
 <input type=hidden name=title value="$title">
 
+| . ($form->{saved_message} ? qq|<p>$form->{saved_message}</p>| : "") . qq|
+
 <table width=100%>
   <tr class=listtop>
     <th class=listtop>$form->{title}</th>
@@ -789,6 +794,10 @@ sub form_footer {
 <input type=hidden name=path value=$form->{path}>
 <input type=hidden name=login value=$form->{login}>
 <input type=hidden name=password value=$form->{password}>
+|
+. $cgi->hidden('-name' => 'draft_id', '-default' => [$form->{draft_id}])
+. $cgi->hidden('-name' => 'draft_description', '-default' => [$form->{draft_description}])
+. qq|
 
 <br>
 |;
@@ -822,7 +831,9 @@ sub form_footer {
   } else {
     if ($transdate > $closedto) {
       print qq|<input class=submit type=submit name=action value="|
-        . $locale->text('Post') . qq|">|;
+        . $locale->text('Post') . qq|"> | .
+        NTI($cgi->submit('-name' => 'action', '-value' => $locale->text('Save draft'),
+                         '-class' => 'submit'));
     }
   }
 
@@ -1049,6 +1060,7 @@ sub post {
   	  $form->save_history($form->dbconnect(\%myconfig));
     }
     # /saving the history 
+    remove_draft();
     $form->redirect($locale->text('Transaction posted!'));
   }
   $form->error($locale->text('Cannot post transaction!'));
diff --git a/bin/mozilla/common.pl b/bin/mozilla/common.pl
index 86f797bb5..1c4719aaf 100644
--- a/bin/mozilla/common.pl
+++ b/bin/mozilla/common.pl
@@ -38,7 +38,8 @@ sub restore_form {
   $old_form =~ s|!r|\r|g;
   $old_form =~ s|!n|\n|g;
   $old_form =~ s|!!|!|g;
-  $form = YAML::Load($old_form);
+  my $new_form = YAML::Load($old_form);
+  map({ $form->{$_} = $new_form->{$_}; } keys(%{$new_form}));
 
   $lxdebug->leave_sub();
 }
diff --git a/bin/mozilla/drafts.pl b/bin/mozilla/drafts.pl
new file mode 100644
index 000000000..3f5e527e1
--- /dev/null
+++ b/bin/mozilla/drafts.pl
@@ -0,0 +1,109 @@
+#======================================================================
+# LX-Office ERP
+#
+#======================================================================
+#
+# Saving and loading drafts
+#
+#======================================================================
+
+use SL::Drafts;
+
+require "bin/mozilla/common.pl";
+
+sub save_draft {
+  $lxdebug->enter_sub();
+
+  if (!$form->{draft_id} && !$form->{draft_description}) {
+    restore_form($form->{SAVED_FORM}, 1) if ($form->{SAVED_FORM});
+    $form->{SAVED_FORM} = save_form();
+
+    $form->header();
+    print($form->parse_html_template("drafts/save_new"));
+    return $lxdebug->leave_sub();
+  }
+
+  my ($draft_id, $draft_description) =
+    ($form->{draft_id}, $form->{draft_description});
+
+  restore_form($form->{SAVED_FORM}, 1);
+  delete($form->{SAVED_FORM});
+
+  Drafts->save(\%myconfig, $form, $draft_id, $draft_description);
+
+  $form->{saved_message} = $locale->text("Draft saved.");
+
+  update();
+
+  $lxdebug->leave_sub();
+}
+
+sub remove_draft {
+  $lxdebug->enter_sub();
+
+  Drafts->remove(\%myconfig, $form, $form->{draft_id}) if ($form->{draft_id});
+
+  delete($form->{draft_id});
+  delete($form->{draft_description});
+
+  $lxdebug->leave_sub();
+}
+
+sub load_draft_maybe {
+  $lxdebug->enter_sub();
+
+  $lxdebug->leave_sub() and return 0 if ($form->{DONT_LOAD_DRAFT});
+
+  my ($draft_nextsub) = @_;
+
+  my @drafts = Drafts->list(\%myconfig, $form);
+
+  $lxdebug->leave_sub() and return 0 unless (@drafts);
+
+  $draft_nextsub = "add" unless ($draft_nextsub);
+
+  delete($form->{action});
+  my $saved_form = save_form();
+
+  $form->header();
+  print($form->parse_html_template("drafts/load",
+                                   { "DRAFTS" => \@drafts,
+                                     "SAVED_FORM" => $saved_form,
+                                     "draft_nextsub" => $draft_nextsub }));
+
+  $lxdebug->leave_sub();
+
+  return 1;
+}
+
+sub dont_load_draft {
+  $lxdebug->enter_sub();
+
+  my $draft_nextsub = $form->{draft_nextsub};
+  $draft_nextsub = "add" unless ($form->{draft_nextsub});
+  restore_form($form->{SAVED_FORM}, 1);
+  delete($form->{action});
+  $form->{DONT_LOAD_DRAFT} = 1;
+
+  &{ $draft_nextsub }();
+
+  $lxdebug->leave_sub();
+}
+
+sub load_draft {
+  $lxdebug->enter_sub();
+
+  my ($old_form, $id, $description) = Drafts->load(\%myconfig, $form, $form->{id});
+  if ($old_form) {
+    restore_form($old_form, 1);
+    $form->{draft_id} = $id;
+    $form->{draft_description} = $description;
+    $lxdebug->dump(0, "of", $old_form);
+  }
+
+  update();
+
+  $lxdebug->leave_sub();
+}
+
+1;
diff --git a/bin/mozilla/ir.pl b/bin/mozilla/ir.pl
index 11bb82c4b..bb4198956 100644
--- a/bin/mozilla/ir.pl
+++ b/bin/mozilla/ir.pl
@@ -37,6 +37,7 @@ use SL::PE;
 require "$form->{path}/io.pl";
 require "$form->{path}/arap.pl";
 require "$form->{path}/common.pl";
+require "bin/mozilla/drafts.pl";
 
 1;
 
@@ -45,6 +46,8 @@ require "$form->{path}/common.pl";
 sub add {
   $lxdebug->enter_sub();
 
+  return $lxdebug->leave_sub() if (load_draft_maybe());
+
   $form->{title} = $locale->text('Add Vendor Invoice');
 
   &invoice_links;
@@ -399,6 +402,8 @@ sub form_header {
 <input type=hidden name=storno value=$form->{storno}>
 <input type=hidden name=storno_id value=$form->{storno_id}>
 
+| . ($form->{saved_message} ? qq|<p>$form->{saved_message}</p>| : "") . qq|
+
 <table width=100%>
   <tr class=listtop>
     <th class=listtop>$form->{title}</th>
@@ -803,7 +808,9 @@ sub form_footer {
 
   if (!$form->{id} && ($invdate > $closedto)) {
     print qq| <input class=submit type=submit name=action value="|
-      . $locale->text('Post') . qq|">|;
+      . $locale->text('Post') . qq|"> | .
+      NTI($cgi->submit('-name' => 'action', '-value' => $locale->text('Save draft'),
+                       '-class' => 'submit'));
   }
 
   print $form->write_trigger(\%myconfig, scalar(@triggers) / 3, @triggers) .
@@ -816,7 +823,10 @@ sub form_footer {
 <input type=hidden name=path value=$form->{path}>
 <input type=hidden name=login value=$form->{login}>
 <input type=hidden name=password value=$form->{password}>
-|;
+|
+  . $cgi->hidden('-name' => 'draft_id', '-default' => [$form->{draft_id}])
+  . $cgi->hidden('-name' => 'draft_description', '-default' => [$form->{draft_description}]);
+
   # button for saving history
   if($form->{id} ne "") {
     print qq|
@@ -1070,7 +1080,7 @@ sub post {
 
 
   relink_accounts();
-  if (IR->post_invoice(\%myconfig, \%$form)){ 
+  if (IR->post_invoice(\%myconfig, \%$form)){
   	# saving the history
   	if(!exists $form->{addition} && $form->{id} ne "") {
   		$form->{addition} = "POSTED";
@@ -1078,6 +1088,7 @@ sub post {
   		$form->save_history($form->dbconnect(\%myconfig));
   	}
 	# /saving the history
+    remove_draft();
   	$form->redirect(  $locale->text('Invoice')
                   . " $form->{invnumber} "
                   . $locale->text('posted!'));
diff --git a/bin/mozilla/is.pl b/bin/mozilla/is.pl
index b1258f83c..b05c8fddd 100644
--- a/bin/mozilla/is.pl
+++ b/bin/mozilla/is.pl
@@ -37,6 +37,7 @@ use Data::Dumper;
 
 require "$form->{path}/io.pl";
 require "$form->{path}/arap.pl";
+require "bin/mozilla/drafts.pl";
 
 1;
 
@@ -44,7 +45,9 @@ require "$form->{path}/arap.pl";
 
 sub add {
   $lxdebug->enter_sub();
-  
+
+  return $lxdebug->leave_sub() if (load_draft_maybe());
+
   if ($form->{type} eq "credit_note") {
     $form->{title} = $locale->text('Add Credit Note');
 
@@ -621,7 +624,7 @@ sub form_header {
 <input type=hidden name=storno value=$form->{storno}>
 <input type=hidden name=storno_id value=$form->{storno_id}>
 
-
+| . ($form->{saved_message} ? qq|<p>$form->{saved_message}</p>| : "") . qq|
 
 <table width=100%>
   <tr class=listtop>
@@ -1150,7 +1153,9 @@ if ($form->{type} eq "credit_note") {
       <input class=submit type=submit name=action value="|
         . $locale->text('Print and Post') . qq|">
       <input class=submit type=submit name=action value="|
-        . $locale->text('Post') . qq|">|;
+        . $locale->text('Post') . qq|"> | .
+        NTI($cgi->submit('-name' => 'action', '-value' => $locale->text('Save draft'),
+                         '-class' => 'submit'));
     }
   }
 
@@ -1172,7 +1177,10 @@ if ($form->{type} eq "credit_note") {
 <input type=hidden name=rowcount value=$form->{rowcount}>
 
 <input name=callback type=hidden value="$form->{callback}">
-
+|
+. $cgi->hidden('-name' => 'draft_id', '-default' => [$form->{draft_id}])
+. $cgi->hidden('-name' => 'draft_description', '-default' => [$form->{draft_description}])
+. qq|
 <input type=hidden name=path value=$form->{path}>
 <input type=hidden name=login value=$form->{login}>
 <input type=hidden name=password value=$form->{password}>
@@ -1445,6 +1453,7 @@ sub post {
     if (!(IS->post_invoice(\%myconfig, \%$form))) {
       $form->error($locale->text('Cannot post invoice!'));
     }
+    remove_draft();
     # saving the history
   	if(!exists $form->{addition}) {
   	  $form->{addition} = "PRINTED AND POSTED";
@@ -1453,9 +1462,10 @@ sub post {
     # /saving the history
     
   } else {
-      if (IS->post_invoice(\%myconfig, \%$form)){
+    if (IS->post_invoice(\%myconfig, \%$form)){
+      remove_draft();
     	# saving the history
-  		if(!exists $form->{addition}) {
+        if(!exists $form->{addition}) {
   	  		if($form->{storno}) {
   	  			$form->{addition} = "STORNO";
   	  		}
diff --git a/doc/changelog b/doc/changelog
index dedcd2a3c..2c2157e86 100644
--- a/doc/changelog
+++ b/doc/changelog
@@ -3,6 +3,9 @@
 ####################################
 2007-02-?? - Version 2.4.2
 
+  - Einkaufs-, Verkaufs-, Debitoren- und Kreditorenrechnungen k�nnen
+    als Entwurf gespeichert und sp�ter weiter bearbeitet werden. Dabei
+    werden sie nicht gebucht.
   - Vorlagenausdruck: Variablen "fax", "phone" und "email" bei
     Kundenstammdaten werden nun auch als "customerfax",
     "customerphone" und "customeremail" zur Verf�gung gestellt.
diff --git a/locale/de/all b/locale/de/all
index 3519b7ef9..6b3674c84 100644
--- a/locale/de/all
+++ b/locale/de/all
@@ -368,6 +368,7 @@ aktualisieren wollen?',
   'Directory'                   => 'Verzeichnis',
   'Discount'                    => 'Rabatt',
   'Done'                        => 'Fertig',
+  'Draft saved.'                => 'Entwurf gespeichert.',
   'Drawing'                     => 'Zeichnung',
   'Driver'                      => 'Treiber',
   'Dropdown Limit'              => 'Auswahllistenbegrenzung',
@@ -447,6 +448,7 @@ gestartet',
   'Employee'                    => 'Bearbeiter',
   'Empty transaction!'          => 'Buchung ist leer!',
   'Enforce transaction reversal for all dates' => 'Gegenbuchungen f�r jeden Zeitraum aktualisieren',
+  'Enter a description for this new draft.' => 'Geben Sie eine Beschreibung f&uuml;r diesen Entwurf ein.',
   'Enter longdescription'       => 'Langtext eingeben',
   'Enter up to 3 letters separated by a colon (i.e CAD:USD:EUR) for your native and foreign currencies' => 'Geben Sie Ihre und weitere W�hrungen mit bis zu drei Buchstaben pro W�hrung und W�hrungen durch Doppelpunkte getrennt ein (z.B. EUR:USD:CAD)',
   'Equity'                      => 'Passiva',
@@ -627,6 +629,8 @@ gestartet',
   'List Pricegroups'            => 'Preisgruppen anzeigen',
   'List Printer'                => 'Drucker anzeigen',
   'List Transactions'           => 'Buchungsliste',
+  'Load draft'                  => 'Entwurf laden',
+  'Loading a draft will remove it from this list until you click the \'Save Draft\' button again.' => 'Das Laden eines Entwurfs wird ihn aus dieser Liste entfernen, bis Sie erneut auf \'Entwurf Speichern\' klicken.',
   'Local Tax Office Preferences' => 'Angaben zum Finanzamt',
   'Lock System'                 => 'System sperren',
   'Lockfile created!'           => 'System gesperrt!',
@@ -903,6 +907,7 @@ gestartet',
   'Save and Quotation'          => 'Speichern und Angebot',
   'Save and RFQ'                => 'Speichern und Lieferantenanfrage',
   'Save as new'                 => 'als neu speichern',
+  'Save draft'                  => 'Entwurf speichern',
   'Screen'                      => 'Bildschirm',
   'Search Dunning'              => 'Mahnung suchen',
   'Select'                      => 'ausw�hlen',
@@ -946,6 +951,7 @@ gestartet',
   'Show details'                => 'Details anzeigen',
   'Show old dunnings'           => 'Alte Mahnungen anzeigen',
   'Signature'                   => 'Unterschrift',
+  'Skip'                        => '�berspringen',
   'Skonto'                      => 'Skonto',
   'Skonto Terms'                => 'Zahlungsziel Skonto',
   'Sold'                        => 'Verkauft',
@@ -1014,6 +1020,7 @@ gestartet',
   'The following Buchungsgruppen have already been created:' => 'Die folgenden Buchungsgruppen wurden bereits 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 following drafts have been saved and can be loaded.' => 'Die folgenden Entw&uuml;rfe wurden gespeichert und k&ouml;nnen geladen werden.',
   'The following units are unknown.' => 'Die folgenden Einheiten sind unbekannt.',
   'The following units exist already:' => 'Die folgenden Einheiten existieren bereits:',
   'The following warnings occured during an upgrade to the document templates:' => 'Die folgenden Warnungen traten w&auml;hrend einer Aktualisierung der Dokumentenvorlagen auf:',
diff --git a/locale/de/ap b/locale/de/ap
index 73d722e34..9fe0d4c30 100644
--- a/locale/de/ap
+++ b/locale/de/ap
@@ -35,6 +35,7 @@ $self->{texts} = {
   'Delete'                      => 'L�schen',
   'Department'                  => 'Abteilung',
   'Description'                 => 'Beschreibung',
+  'Draft saved.'                => 'Entwurf gespeichert.',
   'Due Date'                    => 'F�lligkeitsdatum',
   'Due Date missing!'           => 'F�lligkeitsdatum fehlt!',
   'ELSE'                        => 'Zusatz',
@@ -103,6 +104,7 @@ $self->{texts} = {
   'SAVED'                       => 'Gespeichert',
   'SAVED FOR DUNNING'           => 'Gespeichert',
   'SCREENED'                    => 'Angezeigt',
+  'Save draft'                  => 'Entwurf speichern',
   'Select a Customer'           => 'Endkunde ausw�hlen',
   'Select a part'               => 'Artikel ausw&auml;hlen',
   'Select a project'            => 'Projekt ausw&auml;hlen',
@@ -162,12 +164,15 @@ $self->{subs} = {
   'delete'                      => 'delete',
   'delivery_customer_selection' => 'delivery_customer_selection',
   'display_form'                => 'display_form',
+  'dont_load_draft'             => 'dont_load_draft',
   'edit'                        => 'edit',
   'employee_selection_internal' => 'employee_selection_internal',
   'form_footer'                 => 'form_footer',
   'form_header'                 => 'form_header',
   'format_dates'                => 'format_dates',
   'gl_transaction'              => 'gl_transaction',
+  'load_draft'                  => 'load_draft',
+  'load_draft_maybe'            => 'load_draft_maybe',
   'name_selected'               => 'name_selected',
   'part_selection_internal'     => 'part_selection_internal',
   'post'                        => 'post',
@@ -176,8 +181,10 @@ $self->{subs} = {
   'project_selected'            => 'project_selected',
   'project_selection_internal'  => 'project_selection_internal',
   'reformat_numbers'            => 'reformat_numbers',
+  'remove_draft'                => 'remove_draft',
   'restore_form'                => 'restore_form',
   'sales_invoice'               => 'sales_invoice',
+  'save_draft'                  => 'save_draft',
   'save_form'                   => 'save_form',
   'search'                      => 'search',
   'select_employee'             => 'select_employee',
@@ -200,6 +207,8 @@ $self->{subs} = {
   'kreditorenbuchung_bearbeiten' => 'edit_accounts_payables_transaction',
   'buchen'                      => 'post',
   'zahlung_buchen'              => 'post_payment',
+  'entwurf_speichern'           => 'save_draft',
+  '�berspringen'                => 'skip',
   'erneuern'                    => 'update',
   'als_vorlage_verwenden'       => 'use_as_template',
   'einkaufsrechnung'            => 'vendor_invoice',
diff --git a/locale/de/ar b/locale/de/ar
index de2902ea0..ef7d19b65 100644
--- a/locale/de/ar
+++ b/locale/de/ar
@@ -39,6 +39,7 @@ $self->{texts} = {
   'Delete'                      => 'L�schen',
   'Department'                  => 'Abteilung',
   'Description'                 => 'Beschreibung',
+  'Draft saved.'                => 'Entwurf gespeichert.',
   'Due Date'                    => 'F�lligkeitsdatum',
   'Due Date missing!'           => 'F�lligkeitsdatum fehlt!',
   'ELSE'                        => 'Zusatz',
@@ -109,6 +110,7 @@ $self->{texts} = {
   'SCREENED'                    => 'Angezeigt',
   'Sales Invoice'               => 'Rechnung',
   'Salesperson'                 => 'Verk�ufer',
+  'Save draft'                  => 'Entwurf speichern',
   'Select a Customer'           => 'Endkunde ausw�hlen',
   'Select a part'               => 'Artikel ausw&auml;hlen',
   'Select a project'            => 'Projekt ausw&auml;hlen',
@@ -171,12 +173,15 @@ $self->{subs} = {
   'delivery_customer_selection' => 'delivery_customer_selection',
   'display'                     => 'display',
   'display_form'                => 'display_form',
+  'dont_load_draft'             => 'dont_load_draft',
   'edit'                        => 'edit',
   'employee_selection_internal' => 'employee_selection_internal',
   'form_footer'                 => 'form_footer',
   'form_header'                 => 'form_header',
   'format_dates'                => 'format_dates',
   'gl_transaction'              => 'gl_transaction',
+  'load_draft'                  => 'load_draft',
+  'load_draft_maybe'            => 'load_draft_maybe',
   'name_selected'               => 'name_selected',
   'part_selection_internal'     => 'part_selection_internal',
   'post'                        => 'post',
@@ -185,8 +190,10 @@ $self->{subs} = {
   'project_selected'            => 'project_selected',
   'project_selection_internal'  => 'project_selection_internal',
   'reformat_numbers'            => 'reformat_numbers',
+  'remove_draft'                => 'remove_draft',
   'restore_form'                => 'restore_form',
   'sales_invoice'               => 'sales_invoice',
+  'save_draft'                  => 'save_draft',
   'save_form'                   => 'save_form',
   'search'                      => 'search',
   'section_menu'                => 'section_menu',
@@ -209,6 +216,8 @@ $self->{subs} = {
   'buchen'                      => 'post',
   'zahlung_buchen'              => 'post_payment',
   'rechnung'                    => 'sales_invoice',
+  'entwurf_speichern'           => 'save_draft',
+  '�berspringen'                => 'skip',
   'erneuern'                    => 'update',
   'als_vorlage_verwenden'       => 'use_as_template',
   'ja'                          => 'yes',
diff --git a/locale/de/drafts b/locale/de/drafts
new file mode 100644
index 000000000..13272f41c
--- /dev/null
+++ b/locale/de/drafts
@@ -0,0 +1,79 @@
+$self->{texts} = {
+  'ADDED'                       => 'Hinzugef�gt',
+  'Address'                     => 'Adresse',
+  'Customer Number'             => 'Kundennummer',
+  'DELETED'                     => 'Gel�scht',
+  'DUNNING STARTED'             => 'DUNNING STARTED',
+  'Draft saved.'                => 'Entwurf gespeichert.',
+  'ELSE'                        => 'Zusatz',
+  'Enter longdescription'       => 'Langtext eingeben',
+  'History'                     => 'Historie',
+  'MAILED'                      => 'Gesendet',
+  'Name'                        => 'Name',
+  'No Customer was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Endkunde gefunden',
+  'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein H�ndler gefunden',
+  'No employee was found matching the search parameters.' => 'Es wurde kein Angestellter gefunden, auf den die Suchparameter zutreffen.',
+  'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
+  'No project was found matching the search parameters.' => 'Es wurde kein Projekt gefunden, auf das die Suchparameter zutreffen.',
+  'PAYMENT POSTED'              => 'Rechung gebucht',
+  'POSTED'                      => 'Gebucht',
+  'POSTED AS NEW'               => 'Als neu gebucht',
+  'PRINTED'                     => 'Gedruckt',
+  'Part Number'                 => 'Artikelnummer',
+  'Part description'            => 'Artikelbeschreibung',
+  'Please enter values'         => 'Bitte Werte eingeben',
+  'Project Number'              => 'Projektnummer',
+  'Project description'         => 'Projektbeschreibung',
+  'SAVED'                       => 'Gespeichert',
+  'SAVED FOR DUNNING'           => 'Gespeichert',
+  'SCREENED'                    => 'Angezeigt',
+  'Select a Customer'           => 'Endkunde ausw�hlen',
+  'Select a part'               => 'Artikel ausw&auml;hlen',
+  'Select a project'            => 'Projekt ausw&auml;hlen',
+  'Select an employee'          => 'Angestellten ausw&auml;hlen',
+  'Unit'                        => 'Einheit',
+  'Value'                       => 'Wert',
+  'Variable'                    => 'Variable',
+  'bin_list'                    => 'Lagerliste',
+  'invoice'                     => 'Rechnung',
+  'packing_list'                => 'Versandliste',
+  'pick_list'                   => 'Entnahmeliste',
+  'proforma'                    => 'Proforma',
+  'purchase_order'              => 'Auftrag',
+  'request_quotation'           => 'Angebotsanforderung',
+  'sales_order'                 => 'Kundenauftrag',
+  'sales_quotation'             => 'Verkaufsangebot',
+};
+
+$self->{subs} = {
+  'E'                           => 'E',
+  'H'                           => 'H',
+  'NTI'                         => 'NTI',
+  'Q'                           => 'Q',
+  'build_std_url'               => 'build_std_url',
+  'calculate_qty'               => 'calculate_qty',
+  'delivery_customer_selection' => 'delivery_customer_selection',
+  'dont_load_draft'             => 'dont_load_draft',
+  'employee_selection_internal' => 'employee_selection_internal',
+  'format_dates'                => 'format_dates',
+  'load_draft'                  => 'load_draft',
+  'load_draft_maybe'            => 'load_draft_maybe',
+  'part_selection_internal'     => 'part_selection_internal',
+  'project_selection_internal'  => 'project_selection_internal',
+  'reformat_numbers'            => 'reformat_numbers',
+  'remove_draft'                => 'remove_draft',
+  'restore_form'                => 'restore_form',
+  'save_draft'                  => 'save_draft',
+  'save_form'                   => 'save_form',
+  'select_employee'             => 'select_employee',
+  'select_employee_internal'    => 'select_employee_internal',
+  'select_part'                 => 'select_part',
+  'select_part_internal'        => 'select_part_internal',
+  'set_longdescription'         => 'set_longdescription',
+  'show_history'                => 'show_history',
+  'vendor_selection'            => 'vendor_selection',
+  'entwurf_speichern'           => 'save_draft',
+  '�berspringen'                => 'skip',
+};
+
+1;
diff --git a/locale/de/ir b/locale/de/ir
index 6aec944b5..169da9463 100644
--- a/locale/de/ir
+++ b/locale/de/ir
@@ -53,6 +53,7 @@ $self->{texts} = {
   'Department'                  => 'Abteilung',
   'Description'                 => 'Beschreibung',
   'Discount'                    => 'Rabatt',
+  'Draft saved.'                => 'Entwurf gespeichert.',
   'Due Date'                    => 'F�lligkeitsdatum',
   'E-mail'                      => 'eMail',
   'E-mail address missing!'     => 'E-Mail-Adresse fehlt!',
@@ -162,6 +163,7 @@ $self->{texts} = {
   'SAVED FOR DUNNING'           => 'Gespeichert',
   'SCREENED'                    => 'Angezeigt',
   'Sales Order'                 => 'Kundenauftrag',
+  'Save draft'                  => 'Entwurf speichern',
   'Screen'                      => 'Bildschirm',
   'Select a Customer'           => 'Endkunde ausw�hlen',
   'Select a part'               => 'Artikel ausw&auml;hlen',
@@ -242,6 +244,7 @@ $self->{subs} = {
   'delivery_customer_selection' => 'delivery_customer_selection',
   'display_form'                => 'display_form',
   'display_row'                 => 'display_row',
+  'dont_load_draft'             => 'dont_load_draft',
   'e_mail'                      => 'e_mail',
   'edit'                        => 'edit',
   'employee_selection_internal' => 'employee_selection_internal',
@@ -252,6 +255,8 @@ $self->{subs} = {
   'invoice_links'               => 'invoice_links',
   'invoicetotal'                => 'invoicetotal',
   'item_selected'               => 'item_selected',
+  'load_draft'                  => 'load_draft',
+  'load_draft_maybe'            => 'load_draft_maybe',
   'name_selected'               => 'name_selected',
   'new_item'                    => 'new_item',
   'new_license'                 => 'new_license',
@@ -269,9 +274,11 @@ $self->{subs} = {
   'quotation'                   => 'quotation',
   'reformat_numbers'            => 'reformat_numbers',
   'relink_accounts'             => 'relink_accounts',
+  'remove_draft'                => 'remove_draft',
   'request_for_quotation'       => 'request_for_quotation',
   'restore_form'                => 'restore_form',
   'sales_invoice'               => 'sales_invoice',
+  'save_draft'                  => 'save_draft',
   'save_form'                   => 'save_form',
   'select_employee'             => 'select_employee',
   'select_employee_internal'    => 'select_employee_internal',
@@ -298,6 +305,8 @@ $self->{subs} = {
   'l�schen'                     => 'delete',
   'buchen'                      => 'post',
   'zahlung_buchen'              => 'post_payment',
+  'entwurf_speichern'           => 'save_draft',
+  '�berspringen'                => 'skip',
   'storno'                      => 'storno',
   'erneuern'                    => 'update',
   'als_vorlage_verwenden'       => 'use_as_template',
diff --git a/locale/de/is b/locale/de/is
index 148e5236c..c32c46971 100644
--- a/locale/de/is
+++ b/locale/de/is
@@ -64,6 +64,7 @@ $self->{texts} = {
   'Department'                  => 'Abteilung',
   'Description'                 => 'Beschreibung',
   'Discount'                    => 'Rabatt',
+  'Draft saved.'                => 'Entwurf gespeichert.',
   'Due Date'                    => 'F�lligkeitsdatum',
   'Dunning Amount'              => 'gemahnter Betrag',
   'E-mail'                      => 'eMail',
@@ -185,6 +186,7 @@ $self->{texts} = {
   'SCREENED'                    => 'Angezeigt',
   'Sales Order'                 => 'Kundenauftrag',
   'Salesperson'                 => 'Verk�ufer',
+  'Save draft'                  => 'Entwurf speichern',
   'Screen'                      => 'Bildschirm',
   'Select a Customer'           => 'Endkunde ausw�hlen',
   'Select a part'               => 'Artikel ausw&auml;hlen',
@@ -267,6 +269,7 @@ $self->{subs} = {
   'delivery_customer_selection' => 'delivery_customer_selection',
   'display_form'                => 'display_form',
   'display_row'                 => 'display_row',
+  'dont_load_draft'             => 'dont_load_draft',
   'e_mail'                      => 'e_mail',
   'edit'                        => 'edit',
   'employee_selection_internal' => 'employee_selection_internal',
@@ -277,6 +280,8 @@ $self->{subs} = {
   'invoice_links'               => 'invoice_links',
   'invoicetotal'                => 'invoicetotal',
   'item_selected'               => 'item_selected',
+  'load_draft'                  => 'load_draft',
+  'load_draft_maybe'            => 'load_draft_maybe',
   'name_selected'               => 'name_selected',
   'new_item'                    => 'new_item',
   'new_license'                 => 'new_license',
@@ -296,9 +301,11 @@ $self->{subs} = {
   'quotation'                   => 'quotation',
   'reformat_numbers'            => 'reformat_numbers',
   'relink_accounts'             => 'relink_accounts',
+  'remove_draft'                => 'remove_draft',
   'request_for_quotation'       => 'request_for_quotation',
   'restore_form'                => 'restore_form',
   'sales_invoice'               => 'sales_invoice',
+  'save_draft'                  => 'save_draft',
   'save_form'                   => 'save_form',
   'select_employee'             => 'select_employee',
   'select_employee_internal'    => 'select_employee_internal',
@@ -331,7 +338,9 @@ $self->{subs} = {
   'druckvorschau'               => 'preview',
   'drucken'                     => 'print',
   'drucken_und_buchen'          => 'print_and_post',
+  'entwurf_speichern'           => 'save_draft',
   'lieferadresse'               => 'ship_to',
+  '�berspringen'                => 'skip',
   'storno'                      => 'storno',
   'erneuern'                    => 'update',
   'als_vorlage_verwenden'       => 'use_as_template',
diff --git a/sql/Pg-upgrade2/drafts.sql b/sql/Pg-upgrade2/drafts.sql
new file mode 100644
index 000000000..fac0c912c
--- /dev/null
+++ b/sql/Pg-upgrade2/drafts.sql
@@ -0,0 +1,15 @@
+-- @tag: drafts
+-- @description: Neue Tabelle zum Speichern von Entw&uuml;rfen
+-- @depends: release_2_4_1
+CREATE TABLE drafts (
+       id varchar(50) NOT NULL,
+       module varchar(50) NOT NULL,
+       submodule varchar(50) NOT NULL,
+       description text,
+       itime timestamp DEFAULT now(),
+       form text,
+       employee_id integer,
+
+       PRIMARY KEY (id),
+       FOREIGN KEY (employee_id) REFERENCES employee (id)
+);
