diff --git a/History.md b/History.md
index 95f2618e3..49efca878 100644
--- a/History.md
+++ b/History.md
@@ -7,6 +7,8 @@
- UBL importer to also parse contacts
- https://github.com/ZUGFeRD/mustangproject/pull/369
- upgrade ph-schematron from 6.3.3 to 8
+- support inputstreams https://github.com/ZUGFeRD/mustangproject/pull/379
+- #314 ZUGFeRDInvoiceImporter additional constructur
2.10.0
=======
diff --git a/doc/development_documentation.md b/doc/development_documentation.md
index 447763201..e84890a40 100644
--- a/doc/development_documentation.md
+++ b/doc/development_documentation.md
@@ -1,5 +1,5 @@
-## General approach
+## Typical process
1. build
@@ -29,6 +29,18 @@ If you do a pull request, please do a feature branch, e.g. if you are working on
Most of mustang is a library, adding (autmated junit) test cases is often not only the most sustainable but also the fastest way to see if new/changed functionality works. If something is changed so that old test cases break on purpose please do not just remove them but take the time to fix the test cases
+## Typical workflow
+
+If e.g. new elements or attributes are added, they are often added
+* in the object so that a developer can use them
+* in the interface so that a old fashioned developer could use them as well
+* in the pullprovider so that it actually finds it's way into the XML
+* in at least one test, after the test has been run this should at least once be
+* validated. If that works one can start implementing the
+* reading part (along with tests), then it needs to be
+* documented e.g. on the homepage and
+* communicated, at the very least by mentioning it in the history.md
+
## Architecture
Mustang contains a library to read/write e-invoices,
diff --git a/library/src/main/java/org/mustangproject/CashDiscount.java b/library/src/main/java/org/mustangproject/CashDiscount.java
new file mode 100644
index 000000000..b88c5517e
--- /dev/null
+++ b/library/src/main/java/org/mustangproject/CashDiscount.java
@@ -0,0 +1,50 @@
+package org.mustangproject;
+
+import org.mustangproject.ZUGFeRD.IZUGFeRDCashDiscount;
+
+import java.math.BigDecimal;
+
+public class CashDiscount implements IZUGFeRDCashDiscount {
+
+ protected BigDecimal percent;
+ protected Integer days=null;
+
+ /***
+ * Create a cash discount (skonto) with the specified height in the specified period.
+ * Should someone add more period types than just "days" there
+ * is be space for a (optional) third parameter
+ *
+ * @param percent max 3 decimals "behind the dot", more precision is currently ignored
+ * @param days
+ */
+ public CashDiscount(BigDecimal percent, int days) {
+ this.percent = percent;
+ this.days = days;
+ }
+
+ /***
+ * @return this particular cash discount as cross industry invoice XML
+ */
+ public String getAsCII() {
+ return ""+
+ "Cash Discount"+
+ " "+
+ " "+days+""+
+ " "+XMLTools.nDigitFormat(percent,3)+""+
+ " "+
+ "";
+ }
+
+ /***
+ * since EN16931 voted not to have (or even allow) cash discounts in their core invoice the german
+ * XRechnung CIUS defined it's own proprietary format for a freetext field
+ * @return this particular cash discount in proprietary xrechnung format
+ */
+ public String getAsXRechnung() {
+ return "#SKONTO#TAGE="+days+"#PROZENT="+XMLTools.nDigitFormat(percent,3)+"#\n";
+ }
+
+
+
+
+}
diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java
index 2a1e8cd1d..aa26b64f1 100644
--- a/library/src/main/java/org/mustangproject/Invoice.java
+++ b/library/src/main/java/org/mustangproject/Invoice.java
@@ -26,12 +26,7 @@
import java.util.Date;
import java.util.List;
-import org.mustangproject.ZUGFeRD.IExportableTransaction;
-import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
-import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
-import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
-import org.mustangproject.ZUGFeRD.IZUGFeRDPaymentTerms;
-import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement;
+import org.mustangproject.ZUGFeRD.*;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -47,20 +42,21 @@ public class Invoice implements IExportableTransaction {
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
protected Date issueDate = null, dueDate = null, deliveryDate = null;
protected TradeParty sender = null, recipient = null, deliveryAddress = null;
- @JsonDeserialize(contentAs=Item.class)
+ protected ArrayList cashDiscounts = null;
+ @JsonDeserialize(contentAs = Item.class)
protected ArrayList ZFItems = null;
protected ArrayList notes = null;
- private List includedNotes = null;
- protected String sellerOrderReferencedDocumentID;
+ private List includedNotes = null;
+ protected String sellerOrderReferencedDocumentID;
protected String contractReferencedDocument = null;
- protected ArrayList xmlEmbeddedFiles=null;
+ protected ArrayList xmlEmbeddedFiles = null;
protected BigDecimal totalPrepaidAmount = null;
protected Date detailedDeliveryDateStart = null;
protected Date detailedDeliveryPeriodEnd = null;
protected ArrayList Allowances = new ArrayList<>(),
- Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
+ Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
protected IZUGFeRDPaymentTerms paymentTerms = null;
protected Date invoiceReferencedIssueDate;
protected String specifiedProcuringProjectID = null;
@@ -70,6 +66,7 @@ public class Invoice implements IExportableTransaction {
public Invoice() {
ZFItems = new ArrayList<>();
+ cashDiscounts = new ArrayList<>();
setCurrency("EUR");
}
@@ -79,7 +76,7 @@ public String getDocumentName() {
}
@Override
- public String getContractReferencedDocument() {
+ public String getContractReferencedDocument() {
return contractReferencedDocument;
}
@@ -100,14 +97,14 @@ public Invoice setDocumentCode(String documentCode) {
public Invoice embedFileInXML(FileAttachment fa) {
if (xmlEmbeddedFiles == null) {
- xmlEmbeddedFiles= new ArrayList<>();
+ xmlEmbeddedFiles = new ArrayList<>();
}
xmlEmbeddedFiles.add(fa);
return this;
}
@Override
- public FileAttachment[] getAdditionalReferencedDocuments() {
+ public FileAttachment[] getAdditionalReferencedDocuments() {
if (xmlEmbeddedFiles == null) {
return null;
}
@@ -115,6 +112,10 @@ public FileAttachment[] getAdditionalReferencedDocuments() {
}
+ @Override
+ public IZUGFeRDCashDiscount[] getCashDiscounts() {
+ return cashDiscounts.toArray(new IZUGFeRDCashDiscount[0]);
+ }
@Override
public String getNumber() {
@@ -139,6 +140,7 @@ public Invoice setCorrection(String number) {
documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE;
return this;
}
+
public Invoice setCreditNote() {
documentCode = DocumentCodeTypeConstants.CREDITNOTE;
return this;
@@ -229,16 +231,18 @@ public Invoice setShipToCountry(String shipToCountry) {
public String getBuyerOrderReferencedDocumentID() {
return buyerOrderReferencedDocumentID;
}
+
@Override
public String getSellerOrderReferencedDocumentID() {
return sellerOrderReferencedDocumentID;
}
- public Invoice setSellerOrderReferencedDocumentID(String sellerOrderReferencedDocumentID) {
- this.sellerOrderReferencedDocumentID = sellerOrderReferencedDocumentID;
- return this;
- }
+ public Invoice setSellerOrderReferencedDocumentID(String sellerOrderReferencedDocumentID) {
+ this.sellerOrderReferencedDocumentID = sellerOrderReferencedDocumentID;
+ return this;
+ }
+
/***
* usually the order number
* @param buyerOrderReferencedDocumentID string with number
@@ -258,22 +262,23 @@ public Invoice setInvoiceReferencedDocumentID(String invoiceReferencedDocumentID
this.invoiceReferencedDocumentID = invoiceReferencedDocumentID;
return this;
}
+
@Override
public String getInvoiceReferencedDocumentID() {
return invoiceReferencedDocumentID;
}
- @Override
- public Date getInvoiceReferencedIssueDate() {
- return invoiceReferencedIssueDate;
- }
+ @Override
+ public Date getInvoiceReferencedIssueDate() {
+ return invoiceReferencedIssueDate;
+ }
- public Invoice setInvoiceReferencedIssueDate(Date issueDate) {
- this.invoiceReferencedIssueDate = issueDate;
- return this;
- }
-
- @Override
+ public Invoice setInvoiceReferencedIssueDate(Date issueDate) {
+ this.invoiceReferencedIssueDate = issueDate;
+ return this;
+ }
+
+ @Override
public String getBuyerOrderReferencedDocumentIssueDateTime() {
return buyerOrderReferencedDocumentIssueDateTime;
}
@@ -285,7 +290,7 @@ public String getBuyerOrderReferencedDocumentIssueDateTime() {
* @return fluent setter
*/
public Invoice setTotalPrepaidAmount(BigDecimal prepaid) {
- totalPrepaidAmount=prepaid;
+ totalPrepaidAmount = prepaid;
return this;
}
@@ -380,13 +385,13 @@ public String getOwnZIP() {
@Override
- public String getOwnLocation() {
+ public String getOwnLocation() {
return sender.getLocation();
}
@Override
- public String getOwnCountry() {
+ public String getOwnCountry() {
return sender.getCountry();
}
@@ -399,12 +404,12 @@ public String[] getNotes() {
return notes.toArray(new String[0]);
}
- @Override
- public List getNotesWithSubjectCode() {
- return includedNotes;
- }
+ @Override
+ public List getNotesWithSubjectCode() {
+ return includedNotes;
+ }
- @Override
+ @Override
public String getCurrency() {
return currency;
}
@@ -473,13 +478,14 @@ public Invoice setOwnContact(Contact ownContact) {
}
@Override
- public TradeParty getRecipient() {
+ public TradeParty getRecipient() {
return recipient;
}
/**
* required.
* sets the invoice receiving institution = invoicee
+ *
* @param recipient the invoicee organisation
* @return fluent setter
*/
@@ -491,6 +497,7 @@ public Invoice setRecipient(TradeParty recipient) {
/**
* required.
* sets the invoicing institution = invoicer
+ *
* @param sender the invoicer
* @return fluent setter
*/
@@ -508,8 +515,8 @@ public IZUGFeRDAllowanceCharge[] getZFAllowances() {
if (Allowances.isEmpty()) {
return null;
} else {
- return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
- }
+ return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
+ }
}
@@ -518,8 +525,8 @@ public IZUGFeRDAllowanceCharge[] getZFCharges() {
if (Charges.isEmpty()) {
return null;
} else {
- return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
- }
+ return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
+ }
}
@@ -528,8 +535,8 @@ public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
if (LogisticsServiceCharges.isEmpty()) {
return null;
} else {
- return LogisticsServiceCharges.toArray(new IZUGFeRDAllowanceCharge[0]);
- }
+ return LogisticsServiceCharges.toArray(new IZUGFeRDAllowanceCharge[0]);
+ }
}
@@ -569,22 +576,33 @@ public Invoice setDeliveryAddress(TradeParty deliveryAddress) {
this.deliveryAddress = deliveryAddress;
return this;
}
+ /***
+ * Adds a cash discount (skonto)
+ * @param CashDiscount the percent/period combination
+ * @return fluent setter
+ */
+ public Invoice addCashDiscount(CashDiscount c) {
+ this.cashDiscounts.add(c);
+ return this;
+ }
+
@Override
public IZUGFeRDExportableItem[] getZFItems() {
return ZFItems.toArray(new IZUGFeRDExportableItem[0]);
}
- public void setZFItems(ArrayList ims) {
- ZFItems=ims;
+ public void setZFItems(ArrayList ims) {
+ ZFItems = ims;
}
/**
* required
* adds invoice "lines" :-)
- * @see Item
+ *
* @param item the invoice line
* @return fluent setter
+ * @see Item
*/
public Invoice addItem(IZUGFeRDExportableItem item) {
ZFItems.add(item);
@@ -669,6 +687,7 @@ public Date getDetailedDeliveryPeriodTo() {
/**
* adds a free text paragraph, which will become an includedNote element
+ *
* @param text freeform UTF8 plain text
* @return fluent setter
*/
@@ -679,129 +698,138 @@ public Invoice addNote(String text) {
notes.add(text);
return this;
}
-
- public Invoice addNotes(Collection notes) {
- if (notes == null) {
- return this;
- }
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.addAll(notes);
- return this;
- }
-
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#AAI}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addGeneralNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.generalNote(content));
- return this;
- }
-
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#REG}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addRegulatoryNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.regulatoryNote(content));
- return this;
- }
-
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#ABL}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addLegalNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.legalNote(content));
- return this;
- }
-
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#CUS}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addCustomsNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.customsNote(content));
- return this;
- }
-
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#SUR}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addSellerNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.sellerNote(content));
- return this;
- }
-
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#TXD}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addTaxNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.taxNote(content));
- return this;
- }
-
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#ACY}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addIntroductionNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.introductionNote(content));
- return this;
- }
- /**
- * adds a free text paragraph, which will become an includedNote element with explicit
- * subjectCode {@link SubjectCode#AAK}
- * @param content freeform UTF8 plain text
- * @return fluent setter
- */
- public Invoice addDiscountBonusNote(String content) {
- if (includedNotes == null) {
- includedNotes = new ArrayList<>();
- }
- includedNotes.add(IncludedNote.discountBonusNote(content));
- return this;
- }
-
+
+ public Invoice addNotes(Collection notes) {
+ if (notes == null) {
+ return this;
+ }
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.addAll(notes);
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#AAI}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addGeneralNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.generalNote(content));
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#REG}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addRegulatoryNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.regulatoryNote(content));
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#ABL}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addLegalNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.legalNote(content));
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#CUS}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addCustomsNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.customsNote(content));
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#SUR}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addSellerNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.sellerNote(content));
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#TXD}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addTaxNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.taxNote(content));
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#ACY}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addIntroductionNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.introductionNote(content));
+ return this;
+ }
+
+ /**
+ * adds a free text paragraph, which will become an includedNote element with explicit
+ * subjectCode {@link SubjectCode#AAK}
+ *
+ * @param content freeform UTF8 plain text
+ * @return fluent setter
+ */
+ public Invoice addDiscountBonusNote(String content) {
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.add(IncludedNote.discountBonusNote(content));
+ return this;
+ }
+
@Override
public String getSpecifiedProcuringProjectID() {
return specifiedProcuringProjectID;
@@ -841,6 +869,7 @@ public String getVATDueDateTypeCode() {
/**
* Decide when the VAT should be collected.
+ *
* @param vatDueDateTypeCode use EventTimeCodeTypeConstants
* @return fluent setter
*/
diff --git a/library/src/main/java/org/mustangproject/XMLTools.java b/library/src/main/java/org/mustangproject/XMLTools.java
index e85fe5429..2eda39bbc 100644
--- a/library/src/main/java/org/mustangproject/XMLTools.java
+++ b/library/src/main/java/org/mustangproject/XMLTools.java
@@ -120,36 +120,6 @@ public static String encodeXML(CharSequence s) {
return sb.toString();
}
-
- /**
- * Returns the Byte Order Mark size and thus allows to skips over a BOM
- * at the beginning of the given ByteArrayInputStream, if one exists.
- *
- * @param is the ByteArrayInputStream used
- * @throws IOException if can not be read from is
- * @see Autodetection of Character Encodings
- *
- public static int guessBOMSize(ByteArrayInputStream is) throws IOException {
- byte[] pad = new byte[4];
- is.read(pad);
- is.reset();
- int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
- int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
- int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
- //
- if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
- // UCS-4: BOM takes 4 bytes
- return 4;
- } else if (test3 == 0xEFBBFF) {
- // UTF-8: BOM takes 3 bytes
- return 3;
- } else if (test2 == 0xFEFF || test2 == 0xFFFE) {
- // UTF-16: BOM takes 2 bytes
- return 2;
- }
- return 0;
- }*/
-
/***
* removes utf8 byte order marks from byte arrays, in case one is there
* @param zugferdRaw the CII XML
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
index 6d7d7f896..219b7022d 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
@@ -140,6 +140,11 @@ default IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
return null;
}
+ default IZUGFeRDCashDiscount[] getCashDiscounts() { return null; }
+
+ /***
+ * @return the invoice line items with the positions
+ */
IZUGFeRDExportableItem[] getZFItems();
/**
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDCashDiscount.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDCashDiscount.java
new file mode 100644
index 000000000..90040a500
--- /dev/null
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDCashDiscount.java
@@ -0,0 +1,20 @@
+package org.mustangproject.ZUGFeRD;
+
+import org.mustangproject.XMLTools;
+
+public interface IZUGFeRDCashDiscount {
+
+
+ /***
+ * @return this particular cash discount as cross industry invoice XML
+ */
+ public String getAsCII();
+
+ /***
+ * since EN16931 voted not to have (or even allow) cash discounts in their core invoice the german
+ * XRechnung CIUS defined it's own proprietary format for a freetext field
+ * @return this particular cash discount in proprietary xrechnung format
+ */
+ public String getAsXRechnung();
+
+}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
index 4e3077df8..1a935abc9 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
@@ -689,6 +689,12 @@ public void generateXML(IExportableTransaction trans) {
} else {
xml += buildPaymentTermsXml();
}
+ if ((profile == Profiles.getByName("Extended"))&&(trans.getCashDiscounts()!=null)&&(trans.getCashDiscounts().length>0)) {
+ for (IZUGFeRDCashDiscount discount:trans.getCashDiscounts()
+ ) {
+ xml += discount.getAsCII();
+ }
+ }
final String allowanceTotalLine = "" + currencyFormat(calc.getAllowancesForPercent(null)) + "";
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java
index 01115e095..40978a4e3 100644
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java
@@ -93,7 +93,7 @@ public void testPushExport() {
ze.export(TARGET_PDF);
} catch (IOException | ParseException e) {
- fail("Exception should not be raised in testPushExport");
+ fail("Exception should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -142,7 +142,7 @@ public void testAttachmentsExport() {
assertTrue(theXML.contains("