at.austriapro.ebinterface.ubl.from.AbstractToEbInterfaceConverter Maven / Gradle / Ivy
/*
* Copyright (c) 2010-2015 Bundesrechenzentrum GmbH - www.brz.gv.at
* Copyright (c) 2015-2024 AUSTRIAPRO - www.austriapro.at
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.austriapro.ebinterface.ubl.from;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Translatable;
import com.helger.commons.datetime.XMLOffsetDate;
import com.helger.commons.error.SingleError;
import com.helger.commons.error.list.ErrorList;
import com.helger.commons.regex.RegExHelper;
import com.helger.commons.string.StringHelper;
import com.helger.commons.text.IMultilingualText;
import com.helger.commons.text.display.IHasDisplayTextWithArgs;
import com.helger.commons.text.resolve.DefaultTextResolver;
import com.helger.commons.text.util.TextHelper;
import com.helger.peppolid.IProcessIdentifier;
import at.austriapro.ebinterface.ubl.AbstractConverter;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.AllowanceChargeType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.BranchType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.FinancialAccountType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.FinancialInstitutionType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.PartyIdentificationType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.PartyNameType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.PartyType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.PaymentMandateType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.PaymentMeansType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.TaxCategoryType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.TaxSubtotalType;
import oasis.names.specification.ubl.schema.xsd.commonaggregatecomponents_21.TaxTotalType;
import oasis.names.specification.ubl.schema.xsd.commonbasiccomponents_21.AllowanceChargeReasonType;
import oasis.names.specification.ubl.schema.xsd.commonbasiccomponents_21.IDType;
import oasis.names.specification.ubl.schema.xsd.commonbasiccomponents_21.InvoiceTypeCodeType;
import oasis.names.specification.ubl.schema.xsd.commonbasiccomponents_21.ProfileIDType;
import oasis.names.specification.ubl.schema.xsd.commonbasiccomponents_21.UBLVersionIDType;
import oasis.names.specification.ubl.schema.xsd.creditnote_21.CreditNoteType;
import oasis.names.specification.ubl.schema.xsd.invoice_21.InvoiceType;
/**
* Base class for Peppol UBL to ebInterface converter
*
* @author philip
*/
@Immutable
public abstract class AbstractToEbInterfaceConverter extends AbstractConverter
{
@Translatable
public enum EText implements IHasDisplayTextWithArgs
{
OR ("oder", "or"),
NO_UBL_VERSION_ID ("Die UBLVersionID fehlt. Einer der folgenden Werte wird erwartet: {0}",
"No UBLVersionID present. One of the following values is expected: {0}"),
INVALID_UBL_VERSION_ID ("Die UBLVersionID ''{0}'' ist ungültig. Einer der folgenden Werte wird erwartet: {1}",
"Invalid UBLVersionID value ''{0}'' present. One of the following values is expected: {1}"),
NO_PROFILE_ID ("Die ProfileID fehlt", "No ProfileID present."),
INVALID_PROFILE_ID ("Die ProfileID ''{0}'' ist ungültig.", "Invalid ProfileID value ''{0}'' present."),
NO_CUSTOMIZATION_ID ("Die CustomizationID fehlt", "No CustomizationID present."),
INVALID_CUSTOMIZATION_SCHEME_ID ("Die CustomizationID schemeID ''{0}'' ist ungültig. Diese muss den Wert ''{1}'' haben.",
"Invalid CustomizationID schemeID value ''{0}'' present. It must be ''{1}''."),
INVALID_CUSTOMIZATION_ID ("Die angegebene CustomizationID ''{0}'' ist ungültig. Sie wird vom angegebenen Profil nicht unterstützt.",
"Invalid CustomizationID value ''{0}'' present. It is not supported by the passed profile."),
NO_INVOICE_TYPECODE ("Der InvoiceTypeCode fehlt. Es wird einer der folgenden Werte erwartet: {0}",
"No InvoiceTypeCode present. It must be one of the following values: {0}"),
INVALID_INVOICE_TYPECODE ("Der InvoiceTypeCode ''{0}'' ist ungültig.Es wird einer der folgenden Werte erwartet: {1}",
"Invalid InvoiceTypeCode value ''{0}'' present. It must be one of the following values: {1}"),
ADDRESS_NO_STREET ("In der Adresse fehlt die Straße.", "Address is missing a street name."),
ADDRESS_NO_CITY ("In der Adresse fehlt der Name der Stadt.", "Address is missing a city name."),
ADDRESS_NO_ZIPCODE ("In der Adresse fehlt die PLZ.", "Address is missing a ZIP code."),
ADDRESS_INVALID_COUNTRY ("Der angegebene Ländercode ''{0}'' ist ungültig.",
"The provided country code ''{0}'' is invalid."),
ADDRESS_NO_COUNTRY ("In der Adresse fehlt der Name des Landes.", "Address is missing a country."),
CONTACT_NO_NAME ("Im Kontakt fehlr der Name.", "Contact is missing a name."),
MULTIPLE_PARTIES ("Es sind mehrere Partynamen vorhanden - nur der erste wird verwendet.",
"Multiple party names present - only the first one is used."),
PARTY_NO_NAME ("Der Name der Party fehlt.", "Party name is missing."),
PARTY_UNSUPPORTED_ENDPOINT ("Ignoriere den Enpunkt ''{0}'' des Typs ''{1}''.",
"Ignoring endpoint ID ''{0}'' of type ''{1}''."),
PARTY_UNSUPPORTED_ADDRESS_IDENTIFIER ("Ignoriere die ID ''{0}'' des Typs ''{1}''.",
"Ignoring identification ''{0}'' of type ''{1}''."),
ORDERLINE_REF_ID_EMPTY ("Es muss ein Wert für die Bestellpositionsnummer angegeben werden.",
"A value must be provided for the order line reference ID."),
ALPHANUM_ID_TYPE_CHANGE ("''{0}'' ist ein ungültiger Typ und wurde auf ''{1}'' geändert.",
"''{0}'' is an invalid value and was changed to ''{1}''."),
INVALID_CURRENCY_CODE ("Der angegebene Währungscode ''{0}'' ist ungültig.",
"Invalid currency code ''{0}'' provided."),
MISSING_INVOICE_NUMBER ("Es wurde keine Rechnungsnummer angegeben.", "No invoice number was provided."),
MISSING_INVOICE_DATE ("Es wurde keine Rechnungsdatum angegeben.", "No invoice date was provided."),
BILLER_VAT_MISSING ("Die UID-Nummer des Rechnungsstellers fehlt. Verwenden Sie 'ATU00000000' für österreichische Rechnungssteller an wenn keine UID-Nummer notwendig ist.",
"Failed to get biller VAT identification number. Use 'ATU00000000' for Austrian invoice recipients if no VAT identification number is required."),
ERB_CUSTOMER_ASSIGNED_ACCOUNTID_MISSING ("Die ID des Rechnungsstellers beim Rechnungsempfänger fehlt.",
"Failed to get customer assigned account ID for supplier."),
INVOICE_RECIPIENT_VAT_MISSING ("Die UID-Nummer des Rechnungsempfängers fehlt. Verwenden Sie 'ATU00000000' für österreichische Empfänger an wenn keine UID-Nummer notwendig ist.",
"Failed to get invoice recipient VAT identification number. Use 'ATU00000000' for Austrian invoice recipients if no VAT identification number is required."),
INVOICE_RECIPIENT_PARTY_MISSING ("Die Adressdaten des Rechnungsempfängers fehlen.",
"The party information of the invoice recipient are missing."),
INVOICE_RECIPIENT_PARTY_SUPPLIER_ASSIGNED_ACCOUNT_ID_MISSING ("Die ID des Auftraggebers im System des Rechnungsstellers fehlt.",
"Failed to get supplier assigned account ID."),
ORDERING_PARTY_VAT_MISSING ("Die UID-Nummer des Auftraggebers fehlt. Verwenden Sie 'ATU00000000' für österreichische Empfänger an wenn keine UID-Nummer notwendig ist.",
"Failed to get ordering party VAT identification number. Use 'ATU00000000' for Austrian invoice recipients if no VAT identification number is required."),
ORDERING_PARTY_PARTY_MISSING ("Die Adressdaten des Auftraggebers fehlen.",
"The party information of the ordering party are missing."),
ORDERING_PARTY_SUPPLIER_ASSIGNED_ACCOUNT_ID_MISSING ("Die ID des Auftraggebers im System des Rechnungsstellers fehlt.",
"Failed to get supplier assigned account ID."),
ORDER_REFERENCE_MISSING ("Die Auftragsreferenz fehlt.", "The order reference is missing."),
ORDER_REFERENCE_MISSING_IGNORE_ORDER_POS ("Die Auftragsreferenz fehlt, daher kann auch die Bestellpositionsnummer nicht übernommen werden.",
"The order reference is missing and therefore the order position number cannot be used."),
ORDER_REFERENCE_TOO_LONG ("Die Auftragsreferenz ''{0}'' ist zu lang und wurde nach {1} Zeichen abgeschnitten.",
"Order reference value ''{0}'' is too long and was cut to {1} characters."),
UNSUPPORTED_TAX_SCHEME_ID ("Die Steuerschema ID ''{0}'' ist ungültig.", "The tax scheme ID ''{0}'' is invalid."),
TAX_PERCENT_MISSING ("Es konnte kein Steuersatz für diese Steuerkategorie ermittelt werden.",
"No tax percentage could be determined for this tax category."),
TAXABLE_AMOUNT_MISSING ("Es konnte kein Steuerbasisbetrag (der Betrag auf den die Steuer anzuwenden ist) für diese Steuerkategorie ermittelt werden.",
"No taxable amount could be determined for this tax category."),
UNSUPPORTED_TAX_SCHEME ("Nicht unterstütztes Steuerschema gefunden: ''{0}'' und ''{1}''.",
"Other tax scheme found and ignored: ''{0}'' and ''{1}''."),
DETAILS_TAX_PERCENTAGE_NOT_FOUND ("Der Steuersatz der Rechnungszeile konnte nicht ermittelt werden. Verwende den Standardwert {0}%.",
"Failed to resolve tax percentage for invoice line. Defaulting to {0}%."),
DETAILS_INVALID_POSITION ("Die Rechnungspositionsnummer ''{0}'' ist ungültig, sie muss größer als 0 sein.",
"The UBL invoice line ID ''{0}'' is invalid. The ID must be bigger than 0."),
DETAILS_INVALID_POSITION_SET_TO_INDEX ("Die Rechnungspositionsnummer ''{0}'' ist nicht numerisch. Es wird der Index {1} verwendet.",
"The UBL invoice line ID ''{0}'' is not numeric. Defaulting to index {1}."),
DETAILS_INVALID_UNIT ("Die Rechnungszeile hat keine Mengeneinheit. Verwende den Standardwert ''{0}''.",
"The UBL invoice line has no unit of measure. Defaulting to ''{0}''."),
DETAILS_INVALID_QUANTITY ("Die Rechnungszeile hat keine Menge. Verwende den Standardwert ''{0}''.",
"The UBL invoice line has no quantity. Defaulting to ''{0}''."),
VAT_ITEM_MISSING ("Keine einzige Steuersumme gefunden", "No single VAT item found."),
ALLOWANCE_CHARGE_NO_TAXRATE ("Die Steuerprozentrate für den globalen Zuschlag/Abschlag konnte nicht ermittelt werden.",
"Failed to resolve tax rate percentage for global AllowanceCharge."),
PAYMENTMEANS_CODE_INVALID ("Der PaymentMeansCode ''{0}'' ist ungültig. Für Überweisungen muss {1} verwenden werden und für Lastschriftverfahren {2}.",
"The PaymentMeansCode ''{0}'' is invalid. For credit/debit transfer use {1} and for direct debit use {2}."),
PAYMENT_ID_TOO_LONG_CUT ("Die Zahlungsreferenz ''{0}'' ist zu lang und wird abgeschnitten.",
"The payment reference ''{0}'' is too long and therefore cut."),
BIC_INVALID ("Der BIC ''{0}'' ist ungültig.", "The BIC ''{0}'' is invalid."),
IBAN_TOO_LONG_STRIPPING ("Der IBAN ''{0}'' ist zu lang. Er wurde nach {1} Zeichen abgeschnitten.",
"The IBAN ''{0}'' is too long and was cut to {1} characters."),
PAYMENTMEANS_UNSUPPORTED_CHANNELCODE ("Die Zahlungsart mit dem ChannelCode ''{0}'' wird ignoriert.",
"The payment means with ChannelCode ''{0}'' are ignored."),
ERB_NO_PAYMENT_METHOD ("Es muss eine Zahlungsart angegeben werden.", "A payment method must be provided."),
PAYMENT_DUE_DATE_ALREADY_CONTAINED ("Es wurde mehr als ein Zahlungsziel gefunden.",
"More than one payment due date was found."),
SETTLEMENT_PERIOD_MISSING ("Für Skontoeinträge muss mindestens ein Endedatum angegeben werden.",
"Discount items require a settlement end date."),
PENALTY_NOT_ALLOWED ("Strafzuschläge werden in ebInterface nicht unterstützt.",
"Penalty surcharges are not supported in ebInterface."),
DISCOUNT_WITHOUT_DUEDATE ("Skontoeinträge können nur angegeben werden, wenn auch ein Zahlungsziel angegeben wurde.",
"Discount items can only be provided if a payment due date is present."),
DELIVERY_WITHOUT_NAME ("Wenn eine Delivery/DeliveryLocation/Address angegeben ist muss auch ein Delivery/DeliveryParty/PartyName/Name angegeben werden.",
"If a Delivery/DeliveryLocation/Address is present, a Delivery/DeliveryParty/PartyName/Name must also be present."),
ERB_NO_DELIVERY_DATE ("Ein Lieferdatum oder ein Leistungszeitraum muss vorhanden sein.",
"A Delivery/DeliveryDate or an InvoicePeriod must be present."),
PREPAID_NOT_SUPPORTED ("Das Element wird nicht unterstützt.",
"The element is not supported!"),
MISSING_TAXCATEGORY_ID ("Das Element fehlt.", "Element is missing."),
MISSING_TAXCATEGORY_ID_VALUE ("Das Element hat keinen Wert.", "Element has no value."),
MISSING_TAXCATEGORY_TAXSCHEME_ID ("Das Element fehlt.", "Element is missing."),
MISSING_TAXCATEGORY_TAXSCHEME_ID_VALUE ("Das Element hat keinen Wert.", "Element has no value."),
EBI40_CANNOT_MIX_VAT_EXEMPTION ("In ebInterface 4.0 können nicht USt-Informationen und Steuerbefreiungen gemischt werden",
"ebInterface 4.0 cannot mix VAT information and tax exemptions");
private final IMultilingualText m_aTP;
EText (@Nonnull final String sDE, @Nonnull final String sEN)
{
m_aTP = TextHelper.create_DE_EN (sDE, sEN);
}
@Nullable
public String getDisplayText (@Nonnull final Locale aContentLocale)
{
return DefaultTextResolver.getTextStatic (this, m_aTP, aContentLocale);
}
}
protected static final class SEPADirectDebit
{
String m_sBIC;
boolean m_bUseBICFromFinancialInstitution = false;
String m_sIBAN;
String m_sBankAccountOwnerName;
String m_sCreditorID;
String m_sMandateReference;
XMLOffsetDate m_aDebitCollectionDate;
}
public static final String EBI_GENERATING_SYSTEM_40 = "UBL 2.1 to ebInterface 4.0 converter";
public static final String EBI_GENERATING_SYSTEM_41 = "UBL 2.1 to ebInterface 4.1 converter";
public static final String EBI_GENERATING_SYSTEM_42 = "UBL 2.1 to ebInterface 4.2 converter";
public static final String EBI_GENERATING_SYSTEM_43 = "UBL 2.1 to ebInterface 4.3 converter";
public static final String EBI_GENERATING_SYSTEM_50 = "UBL 2.1 to ebInterface 5.0 converter";
public static final String EBI_GENERATING_SYSTEM_60 = "UBL 2.1 to ebInterface 6.0 converter";
public static final String EBI_GENERATING_SYSTEM_61 = "UBL 2.1 to ebInterface 6.1 converter";
protected final IToEbinterfaceSettings m_aSettings;
/**
* Constructor
*
* @param aDisplayLocale
* The locale for error messages. May not be null
.
* @param aContentLocale
* The locale for the created ebInterface files. May not be
* null
.
* @param aSettings
* Conversion settings to be used. May not be null
.
*/
protected AbstractToEbInterfaceConverter (@Nonnull final Locale aDisplayLocale,
@Nonnull final Locale aContentLocale,
@Nonnull final IToEbinterfaceSettings aSettings)
{
super (aDisplayLocale, aContentLocale);
m_aSettings = ValueEnforcer.notNull (aSettings, "Settings");
}
@Nonnull
protected static String getAllowanceChargeComment (@Nonnull final AllowanceChargeType aUBLAllowanceCharge)
{
// AllowanceChargeReason to Comment
final StringBuilder aSB = new StringBuilder ();
for (final AllowanceChargeReasonType aUBLReason : aUBLAllowanceCharge.getAllowanceChargeReason ())
{
final String sReason = StringHelper.trim (aUBLReason.getValue ());
if (StringHelper.hasText (sReason))
{
if (aSB.length () > 0)
aSB.append ('\n');
aSB.append (sReason);
}
}
return aSB.toString ();
}
/**
* Check if the passed UBL invoice is transformable
*
* @param aUBLInvoice
* The UBL invoice to check. May not be null
.
* @param aTransformationErrorList
* The error list to be filled. May not be null
.
*/
protected final void checkInvoiceConsistency (@Nonnull final InvoiceType aUBLInvoice,
@Nonnull final ErrorList aTransformationErrorList)
{
// Check UBLVersionID
final UBLVersionIDType aUBLVersionID = aUBLInvoice.getUBLVersionID ();
if (aUBLVersionID == null)
{
// E.g. optional for EN invoices
if (m_aSettings.isUBLVersionIDMandatory ())
aTransformationErrorList.add (SingleError.builderError ()
.errorFieldName ("UBLVersionID")
.errorText (EText.NO_UBL_VERSION_ID.getDisplayTextWithArgs (m_aDisplayLocale,
StringHelper.imploder ()
.separator (", ")
.source (UBL_VERSION_20,
UBL_VERSION_21,
UBL_VERSION_22,
UBL_VERSION_23,
UBL_VERSION_24)
.build ()))
.build ());
}
else
{
final String sUBLVersionID = StringHelper.trim (aUBLVersionID.getValue ());
if (!UBL_VERSION_20.equals (sUBLVersionID) &&
!UBL_VERSION_21.equals (sUBLVersionID) &&
!UBL_VERSION_22.equals (sUBLVersionID) &&
!UBL_VERSION_23.equals (sUBLVersionID) &&
!UBL_VERSION_24.equals (sUBLVersionID))
{
aTransformationErrorList.add (SingleError.builderError ()
.errorFieldName ("UBLVersionID")
.errorText (EText.INVALID_UBL_VERSION_ID.getDisplayTextWithArgs (m_aDisplayLocale,
sUBLVersionID,
StringHelper.imploder ()
.separator (", ")
.source (UBL_VERSION_20,
UBL_VERSION_21,
UBL_VERSION_22,
UBL_VERSION_23,
UBL_VERSION_24)
.build ()))
.build ());
}
}
// Check ProfileID
final ProfileIDType aProfileID = aUBLInvoice.getProfileID ();
if (aProfileID == null)
{
if (m_aSettings.isUBLProfileIDMandatory ())
aTransformationErrorList.add (SingleError.builderWarn ()
.errorFieldName ("ProfileID")
.errorText (EText.NO_PROFILE_ID.getDisplayText (m_aDisplayLocale))
.build ());
}
else
{
final String sProfileID = StringHelper.trim (aProfileID.getValue ());
final IProcessIdentifier aProcID = m_aSettings.getProfileIDResolver ().apply (sProfileID);
if (aProcID == null)
{
aTransformationErrorList.add (SingleError.builderWarn ()
.errorFieldName ("ProfileID")
.errorText (EText.INVALID_PROFILE_ID.getDisplayTextWithArgs (m_aDisplayLocale,
sProfileID))
.build ());
}
}
// The CustomizationID can be basically anything - we don't care here
// Invoice type code
final InvoiceTypeCodeType aInvoiceTypeCode = aUBLInvoice.getInvoiceTypeCode ();
if (aInvoiceTypeCode == null)
{
// None present
aTransformationErrorList.add (SingleError.builderWarn ()
.errorFieldName ("InvoiceTypeCode")
.errorText (EText.NO_INVOICE_TYPECODE.getDisplayTextWithArgs (m_aDisplayLocale,
StringHelper.getImploded (", ",
INVOICE_TYPE_CODES)))
.build ());
}
else
{
// If one is present, it must match
final String sInvoiceTypeCode = StringHelper.trim (aInvoiceTypeCode.getValue ());
if (!INVOICE_TYPE_CODES.contains (sInvoiceTypeCode))
{
aTransformationErrorList.add (SingleError.builderError ()
.errorFieldName ("InvoiceTypeCode")
.errorText (EText.INVALID_INVOICE_TYPECODE.getDisplayTextWithArgs (m_aDisplayLocale,
sInvoiceTypeCode,
StringHelper.getImploded (", ",
INVOICE_TYPE_CODES)))
.build ());
}
}
}
/**
* Check if the passed UBL invoice is transformable
*
* @param aUBLCreditNote
* The UBL invoice to check. May not be null
.
* @param aTransformationErrorList
* The error list to be filled. May not be null
.
*/
protected final void checkCreditNoteConsistency (@Nonnull final CreditNoteType aUBLCreditNote,
@Nonnull final ErrorList aTransformationErrorList)
{
// Check UBLVersionID
final UBLVersionIDType aUBLVersionID = aUBLCreditNote.getUBLVersionID ();
if (aUBLVersionID == null)
{
// For EN invoices
if (m_aSettings.isUBLVersionIDMandatory ())
aTransformationErrorList.add (SingleError.builderError ()
.errorFieldName ("UBLVersionID")
.errorText (EText.NO_UBL_VERSION_ID.getDisplayTextWithArgs (m_aDisplayLocale,
StringHelper.imploder ()
.separator (", ")
.source (UBL_VERSION_20,
UBL_VERSION_21,
UBL_VERSION_22,
UBL_VERSION_23,
UBL_VERSION_24)
.build ()))
.build ());
}
else
{
final String sUBLVersionID = StringHelper.trim (aUBLVersionID.getValue ());
if (!UBL_VERSION_20.equals (sUBLVersionID) &&
!UBL_VERSION_21.equals (sUBLVersionID) &&
!UBL_VERSION_22.equals (sUBLVersionID) &&
!UBL_VERSION_23.equals (sUBLVersionID) &&
!UBL_VERSION_24.equals (sUBLVersionID))
{
aTransformationErrorList.add (SingleError.builderError ()
.errorFieldName ("UBLVersionID")
.errorText (EText.INVALID_UBL_VERSION_ID.getDisplayTextWithArgs (m_aDisplayLocale,
sUBLVersionID,
StringHelper.imploder ()
.separator (", ")
.source (UBL_VERSION_20,
UBL_VERSION_21,
UBL_VERSION_22,
UBL_VERSION_23,
UBL_VERSION_24)
.build ()))
.build ());
}
}
// Check ProfileID
final ProfileIDType aProfileID = aUBLCreditNote.getProfileID ();
if (aProfileID == null)
{
if (m_aSettings.isUBLProfileIDMandatory ())
aTransformationErrorList.add (SingleError.builderWarn ()
.errorFieldName ("ProfileID")
.errorText (EText.NO_PROFILE_ID.getDisplayText (m_aDisplayLocale))
.build ());
}
else
{
final String sProfileID = StringHelper.trim (aProfileID.getValue ());
final IProcessIdentifier aProcID = m_aSettings.getProfileIDResolver ().apply (sProfileID);
if (aProcID == null)
{
aTransformationErrorList.add (SingleError.builderWarn ()
.errorFieldName ("ProfileID")
.errorText (EText.INVALID_PROFILE_ID.getDisplayTextWithArgs (m_aDisplayLocale,
sProfileID))
.build ());
}
}
// The CustomizationID can be basically anything - we don't care here
}
protected static final boolean isTaxExemptionCategoryID (@Nullable final String sUBLTaxCategoryID)
{
// https://www.unece.org/fileadmin/DAM/trade/untdid/d16b/tred/tred5305.htm
// AE = VAT Reverse Charge
// E = Exempt from tax
// O = Services outside scope of tax
return "AE".equals (sUBLTaxCategoryID) || "E".equals (sUBLTaxCategoryID) || "O".equals (sUBLTaxCategoryID);
}
protected static boolean isVATSchemeID (final String sScheme)
{
// Peppol
if (SUPPORTED_TAX_SCHEME_ID.equals (sScheme))
return true;
// EN invoices
if ("VA".equals (sScheme))
return true;
return false;
}
@Nullable
protected static TaxCategoryType findTaxCategory (@Nonnull final List aUBLTaxTotals)
{
// No direct tax category -> check if it is somewhere in the tax total
for (final TaxTotalType aUBLTaxTotal : aUBLTaxTotals)
{
for (final TaxSubtotalType aUBLTaxSubTotal : aUBLTaxTotal.getTaxSubtotal ())
{
// Only handle VAT items
if (isVATSchemeID (aUBLTaxSubTotal.getTaxCategory ().getTaxScheme ().getIDValue ()))
{
// We found one -> just use it
return aUBLTaxSubTotal.getTaxCategory ();
}
}
}
return null;
}
@Nonnull
protected static SEPADirectDebit extractSEPADirectDebit (@Nonnull final XMLOffsetDate aUBLDueDate,
@Nonnull final PaymentMeansType aUBLPaymentMeans,
@Nullable final PartyType aUBLSupplierParty,
@Nullable final PartyType aUBLPayeeParty)
{
final SEPADirectDebit ret = new SEPADirectDebit ();
final FinancialAccountType aPayeeFA = aUBLPaymentMeans.getPayeeFinancialAccount ();
if (aPayeeFA != null)
{
ret.m_sIBAN = aPayeeFA.getIDValue ();
final BranchType aUBLBranch = aPayeeFA.getFinancialInstitutionBranch ();
if (aUBLBranch != null)
{
ret.m_sBIC = StringHelper.trim (aUBLBranch.getIDValue ());
if (StringHelper.hasNoText (ret.m_sBIC) || !RegExHelper.stringMatchesPattern (REGEX_BIC, ret.m_sBIC))
{
final FinancialInstitutionType aUBLFI = aUBLBranch.getFinancialInstitution ();
if (aUBLFI != null)
{
ret.m_sBIC = StringHelper.trim (aUBLFI.getIDValue ());
ret.m_bUseBICFromFinancialInstitution = true;
}
}
}
}
if (aUBLPayeeParty != null)
{
for (final PartyNameType aPartyName : aUBLPayeeParty.getPartyName ())
{
ret.m_sBankAccountOwnerName = StringHelper.trim (aPartyName.getNameValue ());
if (StringHelper.hasText (ret.m_sBankAccountOwnerName))
break;
}
for (final PartyIdentificationType aPartyID : aUBLPayeeParty.getPartyIdentification ())
{
final IDType aID = aPartyID.getID ();
if (SCHEME_SEPA.equals (aID.getSchemeID ()))
{
ret.m_sCreditorID = StringHelper.trim (aID.getValue ());
break;
}
}
}
if (StringHelper.hasNoText (ret.m_sBankAccountOwnerName))
{
// Try fallback to supplier party
if (aUBLSupplierParty != null)
for (final PartyNameType aPartyName : aUBLSupplierParty.getPartyName ())
{
ret.m_sBankAccountOwnerName = StringHelper.trim (aPartyName.getNameValue ());
if (StringHelper.hasText (ret.m_sBankAccountOwnerName))
break;
}
}
if (StringHelper.hasNoText (ret.m_sCreditorID))
{
// Try fallback to supplier party
if (aUBLSupplierParty != null)
for (final PartyIdentificationType aPartyID : aUBLSupplierParty.getPartyIdentification ())
{
final IDType aID = aPartyID.getID ();
if (SCHEME_SEPA.equals (aID.getSchemeID ()))
{
ret.m_sCreditorID = StringHelper.trim (aID.getValue ());
break;
}
}
}
final PaymentMandateType aMandate = aUBLPaymentMeans.getPaymentMandate ();
if (aMandate != null)
{
ret.m_sMandateReference = StringHelper.trim (aMandate.getIDValue ());
}
ret.m_aDebitCollectionDate = aUBLDueDate;
return ret;
}
/**
* Get a string in the form
* [string][sep][string][sep][string][or][last-string]. So the last and the
* second last entries are separated by " or " whereas the other entries are
* separated by the provided separator.
*
* @param sSep
* Separator to use. May not be null
.
* @param aValues
* Values to be combined.
* @return The combined string. Never null
.
*/
@Nonnull
protected final String getOrString (@Nonnull final String sSep, @Nullable final String... aValues)
{
final StringBuilder aSB = new StringBuilder ();
if (aValues != null)
{
final int nSecondLast = aSB.length () - 2;
for (int i = 0; i < aValues.length; ++i)
{
if (i > 0)
{
if (i == nSecondLast)
aSB.append (EText.OR.getDisplayText (m_aDisplayLocale));
else
aSB.append (sSep);
}
aSB.append (aValues[i]);
}
}
return aSB.toString ();
}
protected static boolean isUniversalBankTransaction (@Nullable final String sPaymentMeansCode)
{
// 30 = Credit transfer
// 31 = Debit transfer
// 42 = Payment to bank account
// 58 = SEPA credit transfer
return PAYMENT_MEANS_CREDIT_TRANSFER.equals (sPaymentMeansCode) ||
PAYMENT_MEANS_DEBIT_TRANSFER.equals (sPaymentMeansCode) ||
PAYMENT_MEANS_PAYMENT_TO_BANK_ACCOUNT.equals (sPaymentMeansCode) ||
PAYMENT_MEANS_SEPA_CREDIT_TRANSFER.equals (sPaymentMeansCode);
}
protected static boolean isDirectDebit (@Nullable final String sPaymentMeansCode)
{
// 49 = Direct debit
return PAYMENT_MEANS_DIRECT_DEBIT.equals (sPaymentMeansCode);
}
protected static boolean isSEPADirectDebit (@Nullable final String sPaymentMeansCode)
{
// 59 = SEPA direct debit
return PAYMENT_MEANS_SEPA_DIRECT_DEBIT.equals (sPaymentMeansCode);
}
protected static boolean isIBAN (@Nullable final String sPaymentChannelCode)
{
// null/empty for standard Peppol BIS
return StringHelper.hasNoText (sPaymentChannelCode) || PAYMENT_CHANNEL_CODE_IBAN.equals (sPaymentChannelCode);
}
protected static boolean isBIC (@Nullable final String sScheme)
{
return StringHelper.hasNoText (sScheme) || SCHEME_BIC.equalsIgnoreCase (sScheme);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy