Skip to content

Duplicate Notes and Missing BIC Parsing in ZUGFeRDInvoiceImporter #1006

@burak-inan

Description

@burak-inan

Two issues found in ZUGFeRDInvoiceImporter when parsing UBL invoices:

  1. Duplicate notes: Notes are added twice due to reused list
  2. Missing BIC: BIC not extracted from FinancialInstitutionBranch/ID

Issue 1: Duplicate Notes

Problem

When parsing UBL invoices, notes are duplicated because zpp.addNotes(includedNotes) is called twice with the same list.

Current Code

List<IncludedNote> includedNotes = new ArrayList<>();

// UBL notes
XPathExpression UBLNotesEx = xpath.compile("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"Note\"]");
NodeList UBLNotesNd = (NodeList) UBLNotesEx.evaluate(getDocument(), XPathConstants.NODESET);
if (UBLNotesNd.getLength() > 0) {
    for (int nodeIndex = 0; nodeIndex < UBLNotesNd.getLength(); nodeIndex++) {
        includedNotes.add(IncludedNote.generalNote(UBLNotesNd.item(nodeIndex).getTextContent()));
    }
    zpp.addNotes(includedNotes);  // <-- First addition
}

// ... later in ExchangedDocument loop ...
// CII IncludedNote parsing adds to same list

zpp.addNotes(includedNotes);  // <-- Second addition (UBL notes added again)

Suggested Fix

Remove the first zpp.addNotes(includedNotes) call, collect all notes, then add once:

List<IncludedNote> includedNotes = new ArrayList<>();

// UBL notes
XPathExpression UBLNotesEx = xpath.compile("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"Note\"]");
NodeList UBLNotesNd = (NodeList) UBLNotesEx.evaluate(getDocument(), XPathConstants.NODESET);
if (UBLNotesNd.getLength() > 0) {
    for (int nodeIndex = 0; nodeIndex < UBLNotesNd.getLength(); nodeIndex++) {
        includedNotes.add(IncludedNote.generalNote(UBLNotesNd.item(nodeIndex).getTextContent()));
    }
    // Removed: zpp.addNotes(includedNotes);
}

// ... CII IncludedNote parsing ...

zpp.addNotes(includedNotes);  // Single addition at the end

Issue 2: Missing BIC Parsing

Problem

BIC from PayeeFinancialAccount/FinancialInstitutionBranch/ID is not extracted for UBL invoices.

UBL Structure

<cac:PaymentMeans>
  <cac:PayeeFinancialAccount>
    <cbc:ID>DE89370400440532013000</cbc:ID>
    <cbc:Name>Account Name</cbc:Name>
    <cac:FinancialInstitutionBranch>
      <cbc:ID>COBADEFFXXX</cbc:ID>
    </cac:FinancialInstitutionBranch>
  </cac:PayeeFinancialAccount>
</cac:PaymentMeans>

Current Code

Only IBAN and account name are extracted:

if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) 
    && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("Name"))) {
    accountName = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex));
}
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) 
    && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("ID"))) {
    IBAN = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex));
}
// BIC extraction missing

Suggested Fix

Add BIC extraction in the same loop:

if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) 
    && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("Name"))) {
    accountName = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex));
}
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) 
    && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("ID"))) {
    IBAN = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex));
}
// Add BIC extraction
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null)
    && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("FinancialInstitutionBranch"))) {
    NodeList branchChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes();
    for (int branchChildIndex = 0; branchChildIndex < branchChilds.getLength(); branchChildIndex++) {
        if ((branchChilds.item(branchChildIndex).getLocalName() != null)
            && (branchChilds.item(branchChildIndex).getLocalName().equals("ID"))) {
            BIC = XMLTools.trimOrNull(branchChilds.item(branchChildIndex));
        }
    }
}

Set BIC when creating BankDetails:

if (IBAN != null) {
    BankDetails bd = new BankDetails(IBAN);
    // Set BIC
    if (BIC != null) {
        bd.setBIC(BIC);
    }
    if (accountName != null) {
        bd.setAccountName(accountName);
    }
    bankDetails.add(bd);
}

Impact

  • Duplicate notes: Causes duplicate <ram:IncludedNote> elements when re-exporting
  • Missing BIC: Incomplete payment information, may cause payment processing issues

Environment

  • Affects: UBL invoices
  • CII invoices: Not affected (notes only added once, BIC parsed via BICID)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions