commit d8d909892ba302d142df9430786242502fa437fe
Author: Moritz Bunkus <m.bunkus@linet.de>
Date:   Mon Nov 29 16:09:28 2021 +0100

    Verkaufsrechnungen direkt als Factur-X/ZUGFeRD-XML exportieren können

diff --git a/bin/mozilla/io.pl b/bin/mozilla/io.pl
index d0e1f5717..eedde3f88 100644
--- a/bin/mozilla/io.pl
+++ b/bin/mozilla/io.pl
@@ -2201,3 +2201,35 @@ sub _maybe_attach_zugferd_data {
     $::form->error($e->message);
   }
 }
+
+sub download_factur_x_xml {
+  my ($form) = @_;
+
+  my $record = _make_record();
+
+  die if !$record
+      || !$record->can('customer')
+      || !$record->customer
+      || !$record->can('create_pdf_a_print_options')
+      || !$record->can('create_zugferd_data')
+      || !$record->customer->create_zugferd_invoices_for_this_customer;
+
+  my $xml_content = eval { $record->create_zugferd_data };
+
+  if (my $e = SL::X::ZUGFeRDValidation->caught) {
+    $::form->error($e->message);
+  }
+
+  my $attachment_filename = $::form->generate_attachment_filename;
+  $attachment_filename    =~ s{\.[^.]+$}{.xml};
+  my %headers             = (
+    '-type'           => 'application/xml',
+    '-connection'     => 'close',
+    '-attachment'     => $attachment_filename,
+    '-content-length' => length($xml_content),
+  );
+
+  print $::request->cgi->header(%headers);
+
+  $::locale->with_raw_io(\*STDOUT, sub { print $xml_content });
+}
diff --git a/bin/mozilla/is.pl b/bin/mozilla/is.pl
index 76d4b3edb..12deb267b 100644
--- a/bin/mozilla/is.pl
+++ b/bin/mozilla/is.pl
@@ -276,12 +276,14 @@ sub prepare_invoice {
 }
 
 sub setup_is_action_bar {
+  my ($tmpl_var)              = @_;
   my $form                    = $::form;
   my $change_never            = $::instance_conf->get_is_changeable == 0;
   my $change_on_same_day_only = $::instance_conf->get_is_changeable == 2 && ($form->current_date(\%::myconfig) ne $form->{gldate});
   my $payments_balanced       = ($::form->{oldtotalpaid} == 0);
   my $has_storno              = ($::form->{storno} && !$::form->{storno_id});
   my $may_edit_create         = $::auth->assert('invoice_edit', 1);
+  my $factur_x_enabled        = $tmpl_var->{invoice_obj} && $tmpl_var->{invoice_obj}->customer->create_zugferd_invoices_for_this_customer;
   my ($is_linked_bank_transaction, $warn_unlinked_delivery_order);
     if ($::form->{id}
         && SL::DB::Default->get->payments_changeable != 0
@@ -423,6 +425,14 @@ sub setup_is_action_bar {
                     : $form->{postal_invoice} ? t8('This customer wants a postal invoices.')
                     :                     undef,
         ],
+        action => [ t8('Factur-X/ZUGFeRD'),
+          submit   => [ '#form', { action => "download_factur_x_xml" } ],
+          checks   => [ 'kivi.validate_form' ],
+          disabled => !$may_edit_create  ? t8('You must not print this invoice.')
+                    : !$form->{id}       ? t8('This invoice has not been posted yet.')
+                    : !$factur_x_enabled ? t8('Creating Factur-X/ZUGFeRD invoices is not enabled for this customer.')
+                    :                      undef,
+        ],
       ], # end of combobox "Export"
 
       combobox => [
@@ -562,7 +572,7 @@ sub form_header {
   $TMPL_VAR{payment_terms_obj} = get_payment_terms_for_invoice();
   $form->{duedate}             = $TMPL_VAR{payment_terms_obj}->calc_date(reference_date => $form->{invdate}, due_date => $form->{duedate})->to_kivitendo if $TMPL_VAR{payment_terms_obj};
 
-  setup_is_action_bar();
+  setup_is_action_bar(\%TMPL_VAR);
 
   $form->header();
 
diff --git a/js/locale/de.js b/js/locale/de.js
index 3e79c9780..c91c11226 100644
--- a/js/locale/de.js
+++ b/js/locale/de.js
@@ -89,6 +89,7 @@ namespace("kivi").setupLocale({
 "July":"Juli",
 "Jun":"Jun",
 "June":"Juni",
+"Leading and trailing whitespaces have been removed.":"",
 "Loading...":"Wird geladen...",
 "Map":"Karte",
 "Mar":"März",
diff --git a/locale/de/all b/locale/de/all
index 3125d9961..11d51a17c 100755
--- a/locale/de/all
+++ b/locale/de/all
@@ -822,6 +822,7 @@ $self->{texts} = {
   'Created for'                 => 'Erstellt für',
   'Created on'                  => 'Erstellt am',
   'Creating Documents'          => 'Erzeuge Dokumente',
+  'Creating Factur-X/ZUGFeRD invoices is not enabled for this customer.' => 'Das Erzeugen von Factur-X/ZUGFeRD-Rechnungen ist für diesen Kunden nicht aktiviert.',
   'Creating invoices'           => 'Erzeuge Rechnungen',
   'Creating the PDF failed:'    => 'PDF-Erzeugung fehlgeschlagen:',
   'Creation Date'               => 'Erstelldatum',
@@ -1501,6 +1502,7 @@ $self->{texts} = {
   'Extended status'             => 'Erweiterter Status',
   'Extension Of Time'           => 'Dauerfristverlängerung',
   'Factor'                      => 'Faktor',
+  'Factur-X/ZUGFeRD'            => 'Factur-X/ZUGFeRD',
   'Factur-X/ZUGFeRD import'     => 'Factur-X-/ZUGFeRD-Import',
   'Factur-X/ZUGFeRD invoice'    => 'Factur-X-/ZUGFeRD-Rechnung',
   'Factur-X/ZUGFeRD notes for each invoice' => 'Factur-X-/ZUGFeRD-Notizen für jede Rechnung',
@@ -1933,6 +1935,7 @@ $self->{texts} = {
   'Lastcost'                    => 'Einkaufspreis',
   'Lastcost (with X being a number)' => 'Einkaufspreis (X ist eine fortlaufende Zahl)',
   'Lastname'                    => 'Nachname',
+  'Leading and trailing whitespaces have been removed.' => 'Leerzeichen wurden vorne und hinten entfernt',
   'Left'                        => 'Links',
   'Letter'                      => 'Brief',
   'Letter Draft'                => 'Briefentwurf',
diff --git a/locale/en/all b/locale/en/all
index d91103979..5a5e49b4f 100644
--- a/locale/en/all
+++ b/locale/en/all
@@ -822,6 +822,7 @@ $self->{texts} = {
   'Created for'                 => '',
   'Created on'                  => '',
   'Creating Documents'          => '',
+  'Creating Factur-X/ZUGFeRD invoices is not enabled for this customer.' => '',
   'Creating invoices'           => '',
   'Creating the PDF failed:'    => '',
   'Creation Date'               => '',
@@ -1501,6 +1502,7 @@ $self->{texts} = {
   'Extended status'             => '',
   'Extension Of Time'           => '',
   'Factor'                      => '',
+  'Factur-X/ZUGFeRD'            => '',
   'Factur-X/ZUGFeRD import'     => '',
   'Factur-X/ZUGFeRD invoice'    => '',
   'Factur-X/ZUGFeRD notes for each invoice' => '',
