Merge pull request #1060 from meparis/fix-bt18-referenceTypeCode

Add ReferenceTypeCode for BT-18 AdditionalReferencedDocument
This commit is contained in:
Jochen Staerk
2026-04-07 15:55:25 +02:00
committed by GitHub
3 changed files with 81 additions and 1 deletions

View File

@@ -208,7 +208,18 @@ public class Invoice implements IExportableTransaction {
setObjectIdentifierReferencedDocument(dr);
return this;
}
public Invoice setObjectIdentifierReferencedDocument(String id, String referenceTypeCode) {
ReferencedDocument dr = new ReferencedDocument(id);
dr.setReferenceTypeCode(referenceTypeCode);
return setObjectIdentifierReferencedDocument(dr);
}
public Invoice setObjectIdentifierReferencedDocument(String id, String referenceTypeCode, Date issueDate) {
ReferencedDocument dr = new ReferencedDocument(id);
dr.setReferenceTypeCode(referenceTypeCode);
dr.setFormattedIssueDateTime(issueDate);
return setObjectIdentifierReferencedDocument(dr);
}
public Invoice setNumber(String number) {
this.number = number;

View File

@@ -659,6 +659,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
xml += "<ram:AdditionalReferencedDocument>"
+ "<ram:IssuerAssignedID>" + XMLTools.encodeXML(trans.getObjectIdentifierReferencedDocument().getIssuerAssignedID()) + "</ram:IssuerAssignedID>"
+ "<ram:TypeCode>130</ram:TypeCode>";
// NEW: BT-18-1 scheme identifier
String rtc = trans.getObjectIdentifierReferencedDocument().getReferenceTypeCode();
if (rtc != null && !rtc.isEmpty()) {
xml += "<ram:ReferenceTypeCode>" + XMLTools.encodeXML(rtc) + "</ram:ReferenceTypeCode>";
}
if (trans.getObjectIdentifierReferencedDocument().getFormattedIssueDateTime()!=null) {
xml += "<ram:FormattedIssueDateTime>" + DATE.qdtFormat(trans.getObjectIdentifierReferencedDocument().getFormattedIssueDateTime()) + "</ram:FormattedIssueDateTime>";
}

View File

@@ -0,0 +1,64 @@
package org.mustangproject.ZUGFeRD;
import junit.framework.TestCase;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.TradeParty;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import static org.xmlunit.assertj.XmlAssert.assertThat;
public class BT18ReferenceTypeCodeTest extends TestCase {
/**
* Ensures BT-18-1 (scheme identifier) is serialized as ram:ReferenceTypeCode
* inside ram:AdditionalReferencedDocument (TypeCode=130).
*/
public void testBT18ReferenceTypeCodeIsWrittenWhenSet() {
// Minimal invoice (XRechnung profile => CII output)
Invoice i = new Invoice()
.setIssueDate(new Date())
.setDueDate(new Date())
.setDeliveryDate(new Date())
.setSender(new TradeParty("Test company", "teststr", "55232", "teststadt", "DE"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"))
.setNumber("INV-123")
.addItem(new Item(
new Product("Testprodukt", "", "C62", BigDecimal.ZERO),
new BigDecimal("1.00"),
BigDecimal.ONE
));
// BT-18: Invoiced Object Identifier (AdditionalReferencedDocument / TypeCode 130)
ReferencedDocument rd = new ReferencedDocument("ID unique");
rd.setReferenceTypeCode("AJW"); // BT-18-1
i.setObjectIdentifierReferencedDocument(rd);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(i);
String xml = new String(zf2p.getXML(), StandardCharsets.UTF_8);
// Assert: we still have a CII invoice
assertTrue(xml.contains("<rsm:CrossIndustryInvoice"));
// Assert: BT-18 block contains ID, TypeCode=130 and ReferenceTypeCode=AJW
assertThat(xml)
.valueByXPath("string(//*[local-name()='AdditionalReferencedDocument']/*[local-name()='TypeCode'])")
.isEqualTo("130");
assertThat(xml)
.valueByXPath("string(//*[local-name()='AdditionalReferencedDocument']/*[local-name()='IssuerAssignedID'])")
.isEqualTo("ID unique");
assertThat(xml)
.valueByXPath("string(//*[local-name()='AdditionalReferencedDocument']/*[local-name()='ReferenceTypeCode'])")
.isEqualTo("AJW");
}
}