-
-
Notifications
You must be signed in to change notification settings - Fork 201
Description
Summary
The ZUGFeRDInvoiceImporter class fails to correctly parse UBL CreditNote documents because it uses Invoice-specific element names when querying CreditNote XML structures.
Problem
UBL uses different element names for Invoice and CreditNote documents:
| Invoice Element | CreditNote Element |
|---|---|
InvoiceTypeCode |
CreditNoteTypeCode |
InvoiceLine |
CreditNoteLine |
InvoicedQuantity |
CreditedQuantity |
DueDate |
PaymentMeans/PaymentDueDate |
Note: According to the Peppol BIS Billing 3.0 CreditNote specification, there is no direct DueDate element for CreditNote. The due date is located at CreditNote/PaymentMeans/PaymentDueDate.
Currently, the extractInto() method only uses Invoice element names, causing CreditNote parsing to fail.
Affected Code Locations
1. ZUGFeRDInvoiceImporter.extractInto() - Type code
Type code extraction only looks for InvoiceTypeCode:
typeCode = this.extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"InvoiceTypeCode\"]").trim();2. ZUGFeRDInvoiceImporter.extractInto() - Due date
Due date extraction doesn't account for CreditNote's different structure:
dueDate = this.extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"]").trim();3. ZUGFeRDInvoiceImporter.extractInto() - Line items
Line item extraction only looks for InvoiceLine:
xpr = xpath.compile("//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]|//*[local-name()=\"InvoiceLine\"]");4. Item constructor - Quantity
The Item class constructor uses InvoicedQuantity:
itemMap.getNode(new String[]{"InvoicedQuantity"}).ifPresent((icn) -> {
this.setQuantity(new BigDecimal(icn.getTextContent().trim()));
this.product.setUnit(icn.getAttributes().getNamedItem("unitCode").getNodeValue());
});Suggested Fix
1. Type code extraction
typeCode = this.extractString("/*[local-name()=\"Invoice\"]/*[local-name()=\"InvoiceTypeCode\"] | /*[local-name()=\"CreditNote\"]/*[local-name()=\"CreditNoteTypeCode\"]").trim();2. Due date extraction
dueDate = this.extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"] | /*[local-name()=\"CreditNote\"]/*[local-name()=\"PaymentMeans\"]/*[local-name()=\"PaymentDueDate\"]").trim();3. Line item extraction
xpr = xpath.compile("//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]|//*[local-name()=\"InvoiceLine\"]|//*[local-name()=\"CreditNoteLine\"]");4. Item constructor quantity extraction
itemMap.getNode(new String[]{"InvoicedQuantity", "CreditedQuantity"}).ifPresent((icn) -> {
this.setQuantity(new BigDecimal(icn.getTextContent().trim()));
this.product.setUnit(icn.getAttributes().getNamedItem("unitCode").getNodeValue());
});5. Removed due date restriction in Zugferd2PullProvider.generateXML() method
Before:
if (trans.getDocumentCode() != null
&& Arrays.asList(DocumentCodeTypeConstants.CORRECTEDINVOICE, DocumentCodeTypeConstants.CREDITNOTE).contains(trans.getDocumentCode())) {
hasDueDate = false;
}After: This restriction has been removed entirely, allowing due dates for corrected invoices and credit notes.
6. Added description null check in Zugferd2PullProvider.buildPaymentTermsXml() method
if(pt.getDescription() != null) {
paymentTermsXml += "" + pt.getDescription() + "";
}Environment
- Mustang Version: 2.21.0