Mahnungen: Status-Bericht nach Mahnlauf mit evtl. Fehlermeldungen.
authorBernd Bleßmann <bernd@kivitendo-premium.de>
Mon, 22 Mar 2021 15:47:27 +0000 (16:47 +0100)
committerBernd Bleßmann <bernd@kivitendo-premium.de>
Thu, 25 Mar 2021 10:22:24 +0000 (11:22 +0100)
Das Erzeugen der Mahnungen erfolgt je nach ausgewählten Rechnungen in mehreren
Schritten (Zusammenfassen je Kunde und Mahnlevel oder auch einzeln für jede
Rechnung).
Hierbei können in einem Schritt durchaus Mahnungen für einen Kunden oder einen
Mahnlevel erfolgreich erzeugt und per Mail verschickt werden. In einem
folgenden Schritt kann aber ein Fehler auftreten, der dann zum Abbruch und
einer Fehlermeldung führt.
Dabei gab es bisher keinen Hinweis, ob einzelne Schritte erfolgreich waren und
Mahnungen erzeugt wurden.
Dieser commit sammelt die Ergebnisse der einzelnen Schritte und zeigt am Ende
aller Schritte einen Status-Bericht an.

SL/DN.pm
bin/mozilla/dn.pl
templates/webpages/dunning/status.html [new file with mode: 0644]

index a4eb127..ea47209 100644 (file)
--- a/SL/DN.pm
+++ b/SL/DN.pm
@@ -54,6 +54,7 @@ use SL::DB;
 use SL::Webdav;
 
 use File::Copy;
+use File::Slurp qw(read_file);
 
 use strict;
 
@@ -319,7 +320,16 @@ sub save_dunning {
 
   $form->{DUNNING_PDFS_STORAGE} = [];
 
-  my $rc = SL::DB->client->with_transaction(\&_save_dunning, $self, $myconfig, $form, $rows);
+  # Catch any error, either exception or a call to form->error
+  # and return it to the calling function.
+  my ($error, $rc);
+  eval {
+    local $form->{__ERROR_HANDLER} = sub { die @_ };
+    $rc = SL::DB->client->with_transaction(\&_save_dunning, $self, $myconfig, $form, $rows);
+    1;
+  } or do {
+    $error = $@;
+  };
 
   # Save PDFs in filemanagement and webdav after transation succeeded,
   # because otherwise files in the storage may exists if the transaction
@@ -329,9 +339,9 @@ sub save_dunning {
     _store_pdf_to_webdav_and_filemanagement($_->{dunning_id}, $_->{path}, $_->{name}) for @{ $form->{DUNNING_PDFS_STORAGE} };
   }
 
-  if (!$rc) {
-    die SL::DB->client->error
-  }
+  $error       = 'unknown errror' if !$error && !$rc;
+  $rc->{error} = $error           if $error;
+
   $::lxdebug->leave_sub;
 
   return $rc;
@@ -413,7 +423,7 @@ sub _save_dunning {
   }
   # die this transaction, because for this customer only credit notes are
   # selected ...
-  return unless $customer_id;
+  die "only credit notes are selected for this customer\n" unless $customer_id;
 
   $h_update_ar->finish();
   $h_insert_dunning->finish();
@@ -435,7 +445,7 @@ sub _save_dunning {
     $self->send_email($myconfig, $form, $dunning_id, $dbh);
   }
 
-  return 1;
+  return ({dunning_id => $dunning_id, print_original_invoice => $print_invoice, send_email => $send_email});
 }
 
 sub send_email {
@@ -826,7 +836,7 @@ sub melt_pdfs {
 
   $main::lxdebug->enter_sub();
 
-  my ($self, $myconfig, $form, $copies) = @_;
+  my ($self, $myconfig, $form, $copies, %params) = @_;
 
   # Don't allow access outside of $spool.
   map { $_ =~ s|.*/||; } @{ $form->{DUNNING_PDFS} };
@@ -842,23 +852,30 @@ sub melt_pdfs {
   my $in = IO::File->new($::lx_office_conf{applications}->{ghostscript} . " -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=- $inputfiles |");
   $form->error($main::locale->text('Could not spawn ghostscript.')) unless $in;
 
-  if ($form->{media} eq 'printer') {
-    $form->get_printer_code($myconfig);
-    my $out;
-    if ($form->{printer_command}) {
-      $out = IO::File->new("| $form->{printer_command}");
-    }
+  my $dunning_filename    = $form->get_formname_translation('dunning');
+  my $attachment_filename = "${dunning_filename}_${dunning_id}.pdf";
+  my $content;
+  if ($params{return_content}) {
+    $content = read_file($in);
 
-    $form->error($main::locale->text('Could not spawn the printer command.')) unless $out;
+  } else {
+    if ($form->{media} eq 'printer') {
+      $form->get_printer_code($myconfig);
+      my $out;
+      if ($form->{printer_command}) {
+        $out = IO::File->new("| $form->{printer_command}");
+      }
 
-    $::locale->with_raw_io($out, sub { $out->print($_) while <$in> });
+      $form->error($main::locale->text('Could not spawn the printer command.')) unless $out;
 
-  } else {
-    my $dunning_filename = $form->get_formname_translation('dunning');
-    print qq|Content-Type: Application/PDF\n| .
-          qq|Content-Disposition: attachment; filename="${dunning_filename}_${dunning_id}.pdf"\n\n|;
+      $::locale->with_raw_io($out, sub { $out->print($_) while <$in> });
+
+    } else {
+      print qq|Content-Type: Application/PDF\n| .
+            qq|Content-Disposition: attachment; filename=$attachment_filename\n\n|;
 
-    $::locale->with_raw_io(\*STDOUT, sub { print while <$in> });
+      $::locale->with_raw_io(\*STDOUT, sub { print while <$in> });
+    }
   }
 
   $in->close();
@@ -866,6 +883,7 @@ sub melt_pdfs {
   map { unlink("$spool/$_") } @{ $form->{DUNNING_PDFS} };
 
   $main::lxdebug->leave_sub();
+  return ($attachment_filename, $content) if $params{return_content};
 }
 
 sub print_dunning {
@@ -1014,13 +1032,6 @@ sub print_dunning {
 
   delete $form->{tmpfile};
 
-  push @{ $form->{DUNNING_PDFS} }        , $filename;
-  push @{ $form->{DUNNING_PDFS_EMAIL} }  , { 'path'       => "${spool}/$filename",
-                                             'name'       => $form->get_formname_translation('dunning') . "_${dunning_id}.pdf" };
-  push @{ $form->{DUNNING_PDFS_STORAGE} }, { 'dunning_id' => $dunning_id,
-                                             'path'       => "${spool}/$filename",
-                                             'name'       => $form->get_formname_translation('dunning') . "_${dunning_id}.pdf" };
-
   my $employee_id = ($::instance_conf->get_dunning_creator eq 'invoice_employee') ?
                       $form->{employee_id}                                        :
                       SL::DB::Manager::Employee->current->id;
@@ -1038,6 +1049,13 @@ sub print_dunning {
   # this generates the file in the spool directory
   $form->parse_template($myconfig);
 
+  push @{ $form->{DUNNING_PDFS} }        , $filename;
+  push @{ $form->{DUNNING_PDFS_EMAIL} }  , { 'path'       => "${spool}/$filename",
+                                             'name'       => $form->get_formname_translation('dunning') . "_${dunning_id}.pdf" };
+  push @{ $form->{DUNNING_PDFS_STORAGE} }, { 'dunning_id' => $dunning_id,
+                                             'path'       => "${spool}/$filename",
+                                             'name'       => $form->get_formname_translation('dunning') . "_${dunning_id}.pdf" };
+
   $main::lxdebug->leave_sub();
 }
 
index 1ac780f..93e57d0 100644 (file)
@@ -34,6 +34,7 @@
 
 use POSIX qw(strftime);
 
+use List::Util qw(notall);
 use List::MoreUtils qw(none);
 
 use SL::IS;
@@ -210,6 +211,7 @@ sub save_dunning {
 
   my $active=1;
   my @rows = ();
+  my @status;
   undef($form->{DUNNING_PDFS});
 
   my $saved_language_id = $form->{language_id};
@@ -242,7 +244,10 @@ sub save_dunning {
         if (!$form->{force_lang}) {
           $form->{language_id} = @{$level}[0]->{language_id};
         }
-        DN->save_dunning(\%myconfig, $form, $level);
+        my $rc =  DN->save_dunning(\%myconfig, $form, $level);
+        $rc->{error} =~ s{\n}{<br />}g if $rc->{error};
+        push @status, { invnumbers => [map { $form->{'invnumber_' . $_->{row}} } @$level],
+                        map { ( $_ => $rc->{$_} ) } qw(error dunning_id print_original_invoice send_email), };
       }
     }
 
@@ -260,15 +265,27 @@ sub save_dunning {
       if (!$form->{force_lang}) {
         $form->{language_id} = @{$level}[0]->{language_id};
       }
-      DN->save_dunning(\%myconfig, $form, $level);
+      my $rc = DN->save_dunning(\%myconfig, $form, $level);
+      $rc->{error} =~ s{\n}{<br />}g if $rc->{error};
+      push @status, { invnumbers => [map { $form->{'invnumber_' . $_->{row}} } @$level],
+                      map { ( $_ => $rc->{$_} ) } qw(error dunning_id print_original_invoice send_email), };
     }
   }
 
   $form->{language_id} = $saved_language_id;
 
-  if (scalar @{ $form->{DUNNING_PDFS} }) {
+  my $pdf_filename;
+  my $pdf_content;
+  if ($form->{DUNNING_PDFS} && scalar @{ $form->{DUNNING_PDFS} }) {
     $form->{dunning_id} = strftime("%Y%m%d", localtime time) if scalar @{ $form->{DUNNING_PDFS}} > 1;
-    DN->melt_pdfs(\%myconfig, $form, $form->{copies});
+    ($pdf_filename, $pdf_content) = DN->melt_pdfs(\%myconfig, $form, $form->{copies}, return_content => $form->{media} ne 'printer');
+
+    flash('info', t8('Dunning Process started for selected invoices!'));
+    if ($form->{media} eq 'printer') {
+      flash('info', t8('The PDF has been printed'));
+    } else {
+      flash('info', t8('The PDF has been created'));
+    }
   }
 
   # saving the history
@@ -279,10 +296,13 @@ sub save_dunning {
   }
   # /saving the history
 
-  if ($form->{media} eq 'printer') {
-    delete $form->{callback};
-    $form->redirect($locale->text('Dunning Process started for selected invoices!'));
-  }
+  setup_dn_status_action_bar();
+  $form->{"title"} = $locale->text("Dunning status");
+  $form->header();
+  print $form->parse_html_template('dunning/status', {
+    pdf_filename => $pdf_filename,
+    pdf_content  => $pdf_content,
+    status       => \@status, });
 
   $main::lxdebug->leave_sub();
 }
@@ -692,4 +712,17 @@ sub setup_dn_edit_config_action_bar {
   }
 }
 
+sub setup_dn_status_action_bar {
+  for my $bar ($::request->layout->get('actionbar')) {
+    $bar->add(
+      action => [
+        t8('Back'),
+        link      => $::form->{callback},
+        accesskey => 'enter',
+      ],
+    );
+  }
+
+}
+
 # end of main
diff --git a/templates/webpages/dunning/status.html b/templates/webpages/dunning/status.html
new file mode 100644 (file)
index 0000000..bcdad04
--- /dev/null
@@ -0,0 +1,40 @@
+[% USE HTML %]
+[% USE LxERP -%]
+[% USE P -%]
+[% USE T8 -%]
+[% USE Base64 -%]
+
+<h1>[% title | html %]</h1>
+
+[%- INCLUDE 'common/flash.html' -%]
+
+<table>
+  <thead class="listheading">
+    <tr>
+      <th>[% 'Dunning number' | $T8 %]</th>
+      <th width="250px">[% 'Invoice Number' | $T8 %]</th>
+      <th>[% 'Include original Invoices?' | $T8 %]</th>
+      <th>[% 'eMail?' | $T8 %]</th>
+      <th>[% 'Status' | $T8 %]</th>
+    </tr>
+  </thead>
+  <tbody>
+    [% FOREACH s = status -%]
+    <tr class=[%- IF s.error %]"listrow_error"[% ELSE %]"listrow"[% END %]>
+      <td>[% IF !s.error %][% P.link_tag('dn.pl?action=show_dunning&showold=1&dunning_id=' _ s.dunning_id, s.dunning_id) %][% END %]</td>
+      <td>[% s.invnumbers.join(", ") %]</td>
+      <td>[% s.print_original_invoice ? LxERP.t8('Yes') : LxERP.t8('No') %]</td>
+      <td>[% s.send_email ? LxERP.t8('Yes') : LxERP.t8('No') %]</td>
+      <td>[% s.error ? s.error : LxERP.t8('Ok') %]</td>
+    </tr>
+    [%- END %]
+  </tbody>
+</table>
+
+[%- IF pdf_filename && pdf_content -%]
+  <script type="text/javascript">
+    <!--
+      $(function() {kivi.save_file('[% pdf_content.encode_base64 %]', 'application/pdf', 0, '[% pdf_filename %]');});
+    -->
+  </script>
+[%- END %]