]> wagnertech.de Git - mfinanz.git/blobdiff - SL/DB/Helper/ZUGFeRD.pm
ZUGFeRD: UStID des Kunden angeben, sofern bekannt
[mfinanz.git] / SL / DB / Helper / ZUGFeRD.pm
index 5cee13a3e36ea9b07366bede9e877b00ffa22e76..826cef1a94dc3422395d6835f0684f6e6310b9b0 100644 (file)
@@ -15,7 +15,7 @@ use SL::Helper::UNECERecommendation20;
 
 use Carp;
 use Encode qw(encode);
-use List::MoreUtils qw(pairwise);
+use List::MoreUtils qw(any pairwise);
 use List::Util qw(first sum);
 use Template;
 use XML::Writer;
@@ -50,7 +50,10 @@ sub _type_code {
   # 381 (Credit note)
   # 389 (Credit note, self billed invoice)
 
-  return $type eq 'credit_note' ? 381 : 380;
+  return $type eq 'credit_note'        ? 381
+       : $type eq 'invoice_storno'     ? 457
+       : $type eq 'credit_note_storno' ? 458
+       :                                 380;
 }
 
 sub _unit_code {
@@ -298,9 +301,12 @@ sub _exchanged_document_context {
 
   #   <rsm:ExchangedDocumentContext>
   $params{xml}->startTag("rsm:ExchangedDocumentContext");
-  $params{xml}->startTag("ram:TestIndicator");
-  $params{xml}->dataElement("udt:Indicator", "true"); # TODO: change to 'false'
-  $params{xml}->endTag;
+
+  if ($::instance_conf->get_create_zugferd_invoices == 2) {
+    $params{xml}->startTag("ram:TestIndicator");
+    $params{xml}->dataElement("udt:Indicator", "true");
+    $params{xml}->endTag;
+  }
 
   $params{xml}->startTag("ram:GuidelineSpecifiedDocumentContextParameter");
   $params{xml}->dataElement("ram:ID", "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended");
@@ -362,6 +368,20 @@ sub _exchanged_document {
   #   </rsm:ExchangedDocument>
 }
 
+sub _specified_tax_registration {
+  my ($ustid_nr, %params) = @_;
+
+  return unless $ustid_nr;
+
+  $ustid_nr = "DE$ustid_nr" unless $ustid_nr =~ m{^[A-Z]{2}};
+
+  #         <ram:SpecifiedTaxRegistration>
+  $params{xml}->startTag("ram:SpecifiedTaxRegistration");
+  $params{xml}->dataElement("ram:ID", _u8($ustid_nr), "schemeID" => "VA");
+  $params{xml}->endTag;
+  #         </ram:SpecifiedTaxRegistration>
+}
+
 sub _seller_trade_party {
   my ($self, %params) = @_;
 
@@ -408,15 +428,7 @@ sub _seller_trade_party {
     #         </ram:PostalTradeAddress>
   }
 
-  my $ustid_nr = $::instance_conf->get_co_ustid;
-  if ($ustid_nr) {
-    $ustid_nr = "DE$ustid_nr" unless $ustid_nr =~ m{^[A-Z]{2}};
-    #         <ram:SpecifiedTaxRegistration>
-    $params{xml}->startTag("ram:SpecifiedTaxRegistration");
-    $params{xml}->dataElement("ram:ID", _u8($ustid_nr), "schemeID" => "VA");
-    $params{xml}->endTag;
-    #         </ram:SpecifiedTaxRegistration>
-  }
+  _specified_tax_registration($::instance_conf->get_co_ustid, %params);
 
   $params{xml}->endTag;
   #     </ram:SellerTradeParty>
@@ -431,6 +443,7 @@ sub _buyer_trade_party {
   $params{xml}->dataElement("ram:Name", _u8($self->customer->name));
 
   _customer_postal_trade_address(%params, customer => $self->customer);
+  _specified_tax_registration($self->customer->ustid, %params);
 
   $params{xml}->endTag;
   #       </ram:BuyerTradeParty>
@@ -515,9 +528,42 @@ sub _supply_chain_trade_transaction {
   #   </rsm:SupplyChainTradeTransaction>
 }
 
+sub _validate_data {
+  my ($self) = @_;
+
+  my $prefix = $::locale->text('The ZUGFeRD invoice data cannot be generated because the data validation failed.') . ' ';
+
+  if (!$::instance_conf->get_co_ustid) {
+    SL::X::ZUGFeRDValidation->throw(message => $prefix . $::locale->text('The VAT registration number is missing in the client configuration.'));
+  }
+
+  if (!$::instance_conf->get_company || any { my $get = "get_address_$_"; !$::instance_conf->$get } qw(street1 zipcode city)) {
+    SL::X::ZUGFeRDValidation->throw(message => $prefix . $::locale->text('The company\'s address information is incomplete in the client configuration.'));
+  }
+
+  if ($::instance_conf->get_address_country && !SL::Helper::ISO3166::map_name_to_alpha_2_code($::instance_conf->get_address_country)) {
+    SL::X::ZUGFeRDValidation->throw(message => $prefix . $::locale->text('The country from the company\'s address in the client configuration cannot be mapped to an ISO 3166-1 alpha 2 code.'));
+  }
+
+  if ($self->customer->country && !SL::Helper::ISO3166::map_name_to_alpha_2_code($self->customer->country)) {
+    SL::X::ZUGFeRDValidation->throw(message => $prefix . $::locale->text('The country from the customer\'s address cannot be mapped to an ISO 3166-1 alpha 2 code.'));
+  }
+
+  if (!SL::Helper::ISO4217::map_currency_name_to_code($self->currency->name)) {
+    SL::X::ZUGFeRDValidation->throw(message => $prefix . $::locale->text('The currency "#1" cannot be mapped to an ISO 4217 currency code.', $self->currency->name));
+  }
+
+  my $failed_unit = first { !SL::Helper::UNECERecommendation20::map_name_to_code($_) } map { $_->unit } @{ $self->items };
+  if ($failed_unit) {
+    SL::X::ZUGFeRDValidation->throw(message => $prefix . $::locale->text('One of the units used (#1) cannot be mapped to a known unit code from the UN/ECE Recommendation 20 list.', $failed_unit));
+  }
+}
+
 sub create_zugferd_data {
   my ($self) = @_;
 
+  _validate_data($self);
+
   my %ptc_data = $self->calculate_prices_and_taxes;
   my $output   = '';
   my $xml      = XML::Writer->new(