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;
# 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 {
# <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");
# </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) = @_;
# </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>
$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>
# </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(