Merge branch 'master' into buyerorderid
This commit is contained in:
@@ -1,10 +1,18 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/***
|
||||
* (absolute) allowances on item and document level
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class Allowance extends Charge {
|
||||
|
||||
/***
|
||||
@@ -23,11 +31,28 @@ public class Allowance extends Charge {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
|
||||
if(totalAmount != null) {
|
||||
return totalAmount;
|
||||
} else if (percent!=null) {
|
||||
BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP);
|
||||
// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
|
||||
BigDecimal singlePriceDiff=currentItem.getValue().subtract(singlePrice);
|
||||
return singlePriceDiff;
|
||||
} else {
|
||||
throw new RuntimeException("percent must be set");
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Always to return false for IZUGFeRDAllowanceCharge
|
||||
* @return false since its not supposed to be calculated negatively
|
||||
*/
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public boolean isCharge() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementPayment;
|
||||
|
||||
/**
|
||||
* provides e.g. the IBAN to transfer money to :-)
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
||||
/**
|
||||
* the bank account number
|
||||
@@ -15,15 +18,17 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
||||
/**
|
||||
* BIC, I believe it's optional
|
||||
*/
|
||||
protected String BIC=null;
|
||||
protected String BIC = null;
|
||||
/**
|
||||
* the "name" of the bank account (holder)
|
||||
*/
|
||||
protected String accountName=null;
|
||||
protected String accountName = null;
|
||||
|
||||
/***
|
||||
* bean constructor
|
||||
*/
|
||||
public BankDetails() { }
|
||||
public BankDetails() {
|
||||
}
|
||||
|
||||
/***
|
||||
* constructor for IBAN only :-)
|
||||
@@ -32,6 +37,7 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
||||
public BankDetails(String IBAN) {
|
||||
this.IBAN = IBAN;
|
||||
}
|
||||
|
||||
/***
|
||||
* constructor for normal use :-)
|
||||
* @param IBAN the IBAN as string
|
||||
@@ -55,6 +61,7 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
||||
* identify the IBAN. Of course you will specify your own IBAN in full length but
|
||||
* if you deduct from a customer's account you may e.g. leave out the first or last
|
||||
* digits so that nobody spying on the invoice gets to know the complete number
|
||||
*
|
||||
* @param IBAN the "IBAN ID", i.e. the IBAN or parts of it
|
||||
* @return fluent setter
|
||||
*/
|
||||
@@ -81,9 +88,10 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* getOwn... methods will be removed in the future in favor of Tradeparty (e.g. Sender) class
|
||||
* */
|
||||
|
||||
/*
|
||||
I'd really like to get rid of all those getOwn... methods some time but in this case they are in the interface :-(
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
@JsonIgnore
|
||||
@@ -101,11 +109,12 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
||||
|
||||
/**
|
||||
* set Holder
|
||||
*
|
||||
* @param name account name (usually account holder if != sender)
|
||||
* @return fluent setter
|
||||
*/
|
||||
public BankDetails setAccountName(String name) {
|
||||
accountName=name;
|
||||
accountName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -115,5 +124,4 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
109
library/src/main/java/org/mustangproject/CalculatedInvoice.java
Normal file
109
library/src/main/java/org/mustangproject/CalculatedInvoice.java
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2023 Jochen Stärk, see LICENSE file
|
||||
package org.mustangproject;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.TransactionCalculator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class CalculatedInvoice extends Invoice implements Serializable {
|
||||
|
||||
protected BigDecimal lineTotalAmount=null;
|
||||
protected BigDecimal duePayable=null;
|
||||
protected BigDecimal grandTotal=null;
|
||||
protected BigDecimal taxBasis=null;
|
||||
protected TransactionCalculator tc=null;
|
||||
|
||||
public void calculate() {
|
||||
tc=new TransactionCalculator(this);
|
||||
grandTotal=tc.getGrandTotal();
|
||||
lineTotalAmount=tc.getValue();
|
||||
duePayable=tc.getDuePayable();
|
||||
taxBasis= tc.getTaxBasis();
|
||||
}
|
||||
public BigDecimal getGrandTotal() {
|
||||
if (grandTotal==null) {
|
||||
calculate();
|
||||
}
|
||||
return grandTotal;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* usually one would use calculate, use only if the invoice is parsed
|
||||
* @param grand the gross total
|
||||
* @return fluent setter
|
||||
*/
|
||||
public CalculatedInvoice setGrandTotal(BigDecimal grand) {
|
||||
grandTotal=grand;
|
||||
return this;
|
||||
}
|
||||
public BigDecimal getTaxBasis() {
|
||||
if (taxBasis==null) {
|
||||
calculate();
|
||||
}
|
||||
return taxBasis;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* usually one would use calculate, use only if the invoice is parsed
|
||||
* @param basis taxable net total
|
||||
* @return fluent setter
|
||||
*/
|
||||
public CalculatedInvoice setTaxBasis(BigDecimal basis) {
|
||||
taxBasis=basis;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BigDecimal getDuePayable() {
|
||||
if (duePayable==null) {
|
||||
calculate();
|
||||
}
|
||||
return duePayable;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* usually one would use calculate, use only if the invoice is parsed
|
||||
* @param due the gross total minus prepaid
|
||||
* @return fluent setter
|
||||
*/
|
||||
public CalculatedInvoice setDuePayable(BigDecimal due) {
|
||||
duePayable=due;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BigDecimal getLineTotalAmount() {
|
||||
if (lineTotalAmount==null) {
|
||||
calculate();
|
||||
}
|
||||
return lineTotalAmount;
|
||||
}
|
||||
|
||||
/***
|
||||
* usually one would use calculate, use only if the invoice is parsed
|
||||
* @param total the net total
|
||||
* @return fluent setter
|
||||
*/
|
||||
public CalculatedInvoice setLineTotalAmount(BigDecimal total) {
|
||||
lineTotalAmount=total;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* this can be used to additionally e.g. access the VAT amounts
|
||||
* @return a updated transactioncalulator
|
||||
*/
|
||||
public TransactionCalculator getCalculation() {
|
||||
return tc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDCashDiscount;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -7,6 +10,8 @@ import java.math.BigDecimal;
|
||||
/***
|
||||
* A class to represent discounts for early payments ("Skonto")
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class CashDiscount implements IZUGFeRDCashDiscount {
|
||||
|
||||
/***
|
||||
@@ -31,9 +36,35 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
|
||||
this.days = days;
|
||||
}
|
||||
|
||||
/***
|
||||
* bean contructor
|
||||
*/
|
||||
public CashDiscount() {
|
||||
|
||||
}
|
||||
|
||||
public BigDecimal getPercent() {
|
||||
return percent;
|
||||
}
|
||||
|
||||
public CashDiscount setPercent(BigDecimal percent) {
|
||||
this.percent = percent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getDays() {
|
||||
return days;
|
||||
}
|
||||
|
||||
public CashDiscount setDays(Integer days) {
|
||||
this.days = days;
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* @return this particular cash discount as cross industry invoice XML
|
||||
*/
|
||||
@JsonIgnore
|
||||
public String getAsCII() {
|
||||
return "<ram:SpecifiedTradePaymentTerms>"+
|
||||
"<ram:Description>Cash Discount</ram:Description>"+
|
||||
@@ -49,6 +80,7 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
|
||||
* XRechnung CIUS defined it's own proprietary format for a freetext field
|
||||
* @return this particular cash discount in proprietary xrechnung format
|
||||
*/
|
||||
@JsonIgnore
|
||||
public String getAsXRechnung() {
|
||||
return "#SKONTO#TAGE="+days+"#PROZENT="+XMLTools.nDigitFormat(percent,2)+"#\n";
|
||||
}
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/***
|
||||
* Absolute and relative charges for document and item level
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class Charge implements IZUGFeRDAllowanceCharge {
|
||||
|
||||
/**
|
||||
@@ -18,6 +24,10 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
||||
* the absolute value if not percentage
|
||||
*/
|
||||
protected BigDecimal totalAmount;
|
||||
/**
|
||||
* the value the percentage is applied upon
|
||||
*/
|
||||
protected BigDecimal basisAmount;
|
||||
/**
|
||||
* the tax rate the charge belongs to
|
||||
*/
|
||||
@@ -98,6 +108,22 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BigDecimal getBasisAmount() {
|
||||
return basisAmount;
|
||||
}
|
||||
|
||||
/***
|
||||
* sets a potential basis for the potential percentage
|
||||
* @param basis the basis amount
|
||||
* @return fluid setter
|
||||
*/
|
||||
public Charge setBasisAmount(BigDecimal basis) {
|
||||
this.basisAmount = basis;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getReasonCode() {
|
||||
return reasonCode;
|
||||
@@ -116,10 +142,13 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
||||
|
||||
@Override
|
||||
public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
|
||||
if (percent!=null) {
|
||||
return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100)));
|
||||
} else if(totalAmount != null) {
|
||||
if(totalAmount != null) {
|
||||
return totalAmount;
|
||||
} else if (percent!=null) {
|
||||
BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP);
|
||||
// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
|
||||
BigDecimal singlePriceDiff=currentItem.getValue().add(singlePrice);
|
||||
return singlePriceDiff;
|
||||
} else {
|
||||
throw new RuntimeException("percent must be set");
|
||||
}
|
||||
@@ -129,7 +158,10 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
||||
if (totalAmount!=null) {
|
||||
return totalAmount;
|
||||
} else {
|
||||
throw new RuntimeException("totalAmount must be set");
|
||||
if (percent==null) {
|
||||
throw new RuntimeException("totalAmount must be set");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +183,7 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
||||
* @return true since it is supposed to be calculated negatively
|
||||
*/
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public boolean isCharge() {
|
||||
return true;
|
||||
}
|
||||
|
||||
115
library/src/main/java/org/mustangproject/ClassCode.java
Normal file
115
library/src/main/java/org/mustangproject/ClassCode.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
* Copyright (c) 2024 Jan N. Klug
|
||||
* <p>
|
||||
* Use is subject to license terms.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* <p>
|
||||
* **********************************************************************
|
||||
*/
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* A schemed classification for products. The scheme can be anything defined in UNTDID 7143.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class ClassCode {
|
||||
private String listID;
|
||||
private String code;
|
||||
private String listVersionID;
|
||||
|
||||
/**
|
||||
* A UNTDID 7143 schemed classification code
|
||||
*
|
||||
* @param listID the scheme from UNTDID 7143
|
||||
* @param code the classification code
|
||||
* @param listVersionID an (optional) version of the scheme
|
||||
*/
|
||||
public ClassCode(String listID, String code, String listVersionID) {
|
||||
this.listID = listID;
|
||||
this.code = code;
|
||||
this.listVersionID = listVersionID;
|
||||
}
|
||||
|
||||
/**
|
||||
* A UNTDID 7143 schemed classification code
|
||||
*
|
||||
* @param listID the scheme from UNTDID 7143
|
||||
* @param code the classification code
|
||||
*/
|
||||
public ClassCode(String listID, String code) {
|
||||
this(listID, code, null);
|
||||
}
|
||||
|
||||
/***
|
||||
* bean constructor
|
||||
*/
|
||||
public ClassCode() {
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Set the version for the scheme returned by {@link #getListID()}
|
||||
* @param listVersionID the scheme version
|
||||
*/
|
||||
public void setListVersionID(String listVersionID) {
|
||||
this.listVersionID = listVersionID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scheme (according to UNTDID 7143) that describes the value returned by {@link #getCode()},
|
||||
* potentially versioned by {@link #getListVersionID()}
|
||||
*
|
||||
* @return the scheme
|
||||
*/
|
||||
public String getListID() {
|
||||
return listID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code that (following the scheme returned by {@link #getListID()}) describes the product
|
||||
*
|
||||
* @return the classification code itself
|
||||
*/
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (optional) version for the scheme returned by {@link #getListID()}
|
||||
*
|
||||
* @return the version or {@code null} if not set
|
||||
*/
|
||||
public String getListVersionID() {
|
||||
return listVersionID;
|
||||
}
|
||||
|
||||
public static ClassCode fromNode(Node node) {
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
if (attrs != null && attrs.getNamedItem("listID") != null) {
|
||||
ClassCode classCode = new ClassCode(attrs.getNamedItem("listID").getNodeValue(), node.getTextContent());
|
||||
if (attrs.getNamedItem("listVersionID") != null) {
|
||||
classCode.setListVersionID(attrs.getNamedItem("listVersionID").getNodeValue());
|
||||
}
|
||||
return classCode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
@@ -11,6 +12,7 @@ import org.w3c.dom.NodeList;
|
||||
* @see TradeParty
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class Contact implements IZUGFeRDExportableContact {
|
||||
|
||||
/**
|
||||
@@ -112,7 +114,9 @@ public class Contact implements IZUGFeRDExportableContact {
|
||||
if (currentItemNode.getLocalName() != null) {
|
||||
|
||||
if (currentItemNode.getLocalName().equals("PersonName")/*CII*/||currentItemNode.getLocalName().equals("Name")/*UBL*/) {
|
||||
setName(currentItemNode.getFirstChild().getNodeValue());
|
||||
if (currentItemNode.getFirstChild()!=null) {
|
||||
setName(currentItemNode.getFirstChild().getNodeValue());
|
||||
}
|
||||
}
|
||||
if (currentItemNode.getLocalName().equals("TelephoneUniversalCommunication")) { /*CII*/
|
||||
NodeList tel = currentItemNode.getChildNodes();
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
* Copyright (c) 2024 Jan N. Klug
|
||||
* <p>
|
||||
* Use is subject to license terms.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* <p>
|
||||
* **********************************************************************
|
||||
*/
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IDesignatedProductClassification;
|
||||
|
||||
/**
|
||||
* An implementation of {@link IDesignatedProductClassification} for describing a {@link org.mustangproject.Product}
|
||||
*
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class DesignatedProductClassification implements IDesignatedProductClassification {
|
||||
private ClassCode classCode;
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* A schemed product descriptor
|
||||
*
|
||||
* @param classCode an UNTDID 7143 schemed class code
|
||||
* @param className a verbal description of the class code
|
||||
*/
|
||||
public DesignatedProductClassification(ClassCode classCode, String className) {
|
||||
this.classCode = classCode;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
/**
|
||||
* A schemed product descriptor
|
||||
*
|
||||
* @param classCode an UNTDID 7143 schemed class code
|
||||
*/
|
||||
public DesignatedProductClassification(ClassCode classCode) {
|
||||
this(classCode, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean constructor for schemed product descriptor
|
||||
*/
|
||||
public DesignatedProductClassification() {
|
||||
classCode = null;// we need this constructor for jackson, i.e. to be able to JSON
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassCode getClassCode() {
|
||||
return classCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the human-readable name of the class code
|
||||
*
|
||||
* @param className the name of the class code (can be {@code null})
|
||||
*/
|
||||
public void setClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,42 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementDebit;
|
||||
|
||||
/**
|
||||
* provides e.g. the IBAN to transfer money to :-)
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
|
||||
/**
|
||||
* Debited account identifier (BT-91)
|
||||
*/
|
||||
protected final String IBAN;
|
||||
protected String IBAN;
|
||||
|
||||
/**
|
||||
* Mandate reference identifier (BT-89)
|
||||
*/
|
||||
protected final String mandate;
|
||||
protected String mandate;
|
||||
|
||||
/**
|
||||
* payment means code (BT-81 / UNTDID 4461)
|
||||
*/
|
||||
protected String paymentMeansCode = "59";
|
||||
|
||||
/**
|
||||
* Payment means description (BT-82)
|
||||
*/
|
||||
protected String paymentMeansInformation = "SEPA direct debit";
|
||||
|
||||
/**
|
||||
* bean constructor
|
||||
*/
|
||||
public DirectDebit() {
|
||||
this.IBAN = "";
|
||||
this.mandate = "";
|
||||
}
|
||||
|
||||
/***
|
||||
* constructor for normal use :-)
|
||||
@@ -26,6 +48,16 @@ public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
|
||||
this.mandate = mandate;
|
||||
}
|
||||
|
||||
public DirectDebit setPaymentMeansCode(String paymentMeansCode) {
|
||||
this.paymentMeansCode = paymentMeansCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DirectDebit setPaymentMeansInformation(String paymentMeansInformation) {
|
||||
this.paymentMeansInformation = paymentMeansInformation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* getter for the IBAN
|
||||
* @return IBAN
|
||||
@@ -35,8 +67,28 @@ public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
|
||||
return this.IBAN;
|
||||
}
|
||||
|
||||
public DirectDebit setIBAN(String iBAN) {
|
||||
this.IBAN = iBAN;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMandate() {
|
||||
return this.mandate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansCode() {
|
||||
return this.paymentMeansCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansInformation() {
|
||||
return this.paymentMeansInformation;
|
||||
}
|
||||
|
||||
public DirectDebit setMandate(String mandate) {
|
||||
this.mandate = mandate;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.mustangproject;
|
||||
|
||||
public enum EStandard {
|
||||
facturx, orderx, despatchadvice, ubldespatchadvice, zugferd, cii, ubl
|
||||
facturx, orderx, despatchadvice, ubldespatchadvice, zugferd, cii, ubl, ubl_creditnote
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.mustangproject.Exceptions;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
/***
|
||||
* will be thrown if an invoice cant be reproduced numerically
|
||||
*/
|
||||
public class ArithmetricException extends ParseException {
|
||||
public ArithmetricException() {
|
||||
this("");
|
||||
}
|
||||
|
||||
public ArithmetricException(String details) {
|
||||
super("Could not reproduce the invoice. " + details, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.mustangproject.Exceptions;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
/***
|
||||
* will be thrown if a invoice cant be read
|
||||
*/
|
||||
public class StructureException extends ParseException {
|
||||
public StructureException(String message, int line) {
|
||||
super(message, line);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,39 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class FileAttachment {
|
||||
|
||||
protected String filename;
|
||||
protected String mimetype;
|
||||
protected String relation;
|
||||
protected String relation = "Unspecified";
|
||||
protected String description;
|
||||
protected byte[] data;
|
||||
|
||||
|
||||
/***
|
||||
* bean contructor
|
||||
*/
|
||||
public FileAttachment() {
|
||||
|
||||
}
|
||||
|
||||
public FileAttachment(String filename, String mimetype, String relation, byte[] data) {
|
||||
this.filename = filename;
|
||||
this.mimetype = mimetype;
|
||||
this.relation = relation;
|
||||
this.data = data;
|
||||
description = "Additional file attachment";
|
||||
this.description = "Additional file attachment";
|
||||
}
|
||||
|
||||
public FileAttachment(String filename, String mimetype, byte[] data) {
|
||||
this.filename = filename;
|
||||
this.mimetype = mimetype;
|
||||
this.data = data;
|
||||
this.description = "Additional file attachment";
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
@@ -47,6 +67,28 @@ public class FileAttachment {
|
||||
return relation;
|
||||
}
|
||||
|
||||
/***
|
||||
* only needed when embedded in PDF described
|
||||
*
|
||||
* values
|
||||
* - Source shall be used if this file specification is the original
|
||||
* source material for the associated content.
|
||||
* - Data shall be used if this file specification represents information
|
||||
* used to derive a visual presentation, such as for a table or a
|
||||
* graph.
|
||||
* - Alternative shall be used if this file specification is an alternative
|
||||
* representation of content, for example audio.
|
||||
* - Supplement shall be used if this file specification represents a
|
||||
* supplemental representation of the original source or data that
|
||||
* may be more easily consumable (e.g. A MathML version of an
|
||||
* equation).
|
||||
* - Unspecified shall be used when the relationship is not known
|
||||
* or cannot be described using one of the other values.
|
||||
* @param relation String: either : Source, Data or Alternative. Usually Data, except source if the file attachment
|
||||
* is the basis for the pdf (xrechnung2fx) or Alternative if it contains the same content (e.g. the
|
||||
* factur-x.xml file in a factur-x PDF)
|
||||
* @return fluent setter
|
||||
*/
|
||||
public FileAttachment setRelation(String relation) {
|
||||
this.relation = relation;
|
||||
return this;
|
||||
@@ -60,8 +102,4 @@ public class FileAttachment {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,68 +1,100 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
/**
|
||||
* A grouping of business terms to indicate accounting-relevant free texts including a qualification of these.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class IncludedNote {
|
||||
private final String content;
|
||||
private final SubjectCode subjectCode;
|
||||
private String content;
|
||||
|
||||
private static final String INCLUDE_START = "<ram:IncludedNote>";
|
||||
private static final String INCLUDE_END = "</ram:IncludedNote>";
|
||||
private static final String CONTENT_START = "<ram:Content>";
|
||||
private static final String CONTENT_END = "</ram:Content>";
|
||||
private static final String SUBJECT_CODE_START = "<ram:SubjectCode>";
|
||||
private static final String SUBJECT_CODE_END = "</ram:SubjectCode>";
|
||||
private SubjectCode subjectCode;
|
||||
|
||||
private IncludedNote(String content, SubjectCode subjectCode) {
|
||||
this.content = content;
|
||||
this.subjectCode = subjectCode;
|
||||
}
|
||||
private static final String INCLUDE_START = "<ram:IncludedNote>";
|
||||
private static final String INCLUDE_END = "</ram:IncludedNote>";
|
||||
private static final String CONTENT_START = "<ram:Content>";
|
||||
private static final String CONTENT_END = "</ram:Content>";
|
||||
private static final String SUBJECT_CODE_START = "<ram:SubjectCode>";
|
||||
private static final String SUBJECT_CODE_END = "</ram:SubjectCode>";
|
||||
|
||||
public static IncludedNote generalNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.AAI);
|
||||
}
|
||||
public static IncludedNote regulatoryNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.REG);
|
||||
}
|
||||
public static IncludedNote legalNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.ABL);
|
||||
}
|
||||
public static IncludedNote customsNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.CUS);
|
||||
}
|
||||
public static IncludedNote sellerNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.SUR);
|
||||
}
|
||||
public static IncludedNote taxNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.TXD);
|
||||
}
|
||||
public static IncludedNote introductionNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.ACY);
|
||||
}
|
||||
public static IncludedNote discountBonusNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.AAK);
|
||||
}
|
||||
public IncludedNote(String content, SubjectCode subjectCode) {
|
||||
this.content = content;
|
||||
this.subjectCode = subjectCode;
|
||||
}
|
||||
|
||||
public static IncludedNote unspecifiedNote(String content) {
|
||||
return new IncludedNote(content, null);
|
||||
}
|
||||
/**
|
||||
* bean constructor
|
||||
*/
|
||||
public IncludedNote() {
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
public static IncludedNote generalNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.AAI);
|
||||
}
|
||||
|
||||
public static IncludedNote regulatoryNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.REG);
|
||||
}
|
||||
|
||||
public static IncludedNote legalNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.ABL);
|
||||
}
|
||||
|
||||
public static IncludedNote customsNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.CUS);
|
||||
}
|
||||
|
||||
public static IncludedNote sellerNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.SUR);
|
||||
}
|
||||
|
||||
public static IncludedNote taxNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.TXD);
|
||||
}
|
||||
|
||||
public static IncludedNote introductionNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.ACY);
|
||||
}
|
||||
|
||||
public static IncludedNote discountBonusNote(String content) {
|
||||
return new IncludedNote(content, SubjectCode.AAK);
|
||||
}
|
||||
|
||||
public static IncludedNote unspecifiedNote(String content) {
|
||||
return new IncludedNote(content, null);
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public SubjectCode getSubjectCode() {
|
||||
return subjectCode;
|
||||
}
|
||||
|
||||
|
||||
public IncludedNote setSubjectCode(SubjectCode subjectCode) {
|
||||
this.subjectCode = subjectCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IncludedNote setContent(String content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public String toCiiXml() {
|
||||
String result = INCLUDE_START + CONTENT_START +
|
||||
XMLTools.encodeXML(getContent()) + CONTENT_END;
|
||||
if (getSubjectCode() != null) {
|
||||
result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END;
|
||||
}
|
||||
return result + INCLUDE_END;
|
||||
}
|
||||
|
||||
public SubjectCode getSubjectCode() {
|
||||
return subjectCode;
|
||||
}
|
||||
|
||||
public String toCiiXml(){
|
||||
String result = INCLUDE_START + CONTENT_START +
|
||||
XMLTools.encodeXML(getContent() )+ CONTENT_END;
|
||||
if (getSubjectCode() != null) {
|
||||
result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END;
|
||||
}
|
||||
return result + INCLUDE_END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,11 +21,9 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.*;
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
||||
|
||||
@@ -37,11 +35,12 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
* @see IExportableTransaction if you want to implement an interface instead
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
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 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, 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;
|
||||
protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null;
|
||||
protected ArrayList<CashDiscount> cashDiscounts = null;
|
||||
@JsonDeserialize(contentAs = Item.class)
|
||||
protected ArrayList<IZUGFeRDExportableItem> ZFItems = null;
|
||||
@@ -57,13 +56,20 @@ public class Invoice implements IExportableTransaction {
|
||||
|
||||
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
|
||||
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
|
||||
protected IZUGFeRDPaymentTerms paymentTerms = null;
|
||||
protected ArrayList<IZUGFeRDPaymentTerms> paymentTerms = new ArrayList<>();
|
||||
|
||||
protected String invoiceReferencedDocumentID = null;
|
||||
protected Date invoiceReferencedIssueDate;
|
||||
// New field for storing Invoiced Object Identifier (BG-3)
|
||||
protected ArrayList<ReferencedDocument> invoiceReferencedDocuments = null;
|
||||
|
||||
protected String specifiedProcuringProjectID = null;
|
||||
protected String specifiedProcuringProjectName = null;
|
||||
protected String despatchAdviceReferencedDocumentID = null;
|
||||
protected String vatDueDateTypeCode = null;
|
||||
protected String creditorReferenceID; // required when direct debit is used.
|
||||
private BigDecimal roundingAmount=null;
|
||||
private String paymentReference; // Remittance information / Verwendungszweck, BT-83
|
||||
|
||||
public Invoice() {
|
||||
ZFItems = new ArrayList<>();
|
||||
@@ -113,6 +119,20 @@ public class Invoice implements IExportableTransaction {
|
||||
|
||||
}
|
||||
|
||||
/***
|
||||
* setter in case e.g. jackson tries to map attachments (normal use embedFileInXML)
|
||||
* @param fileArr Array of FileAttachments
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Invoice setAdditionalReferencedDocuments(FileAttachment[] fileArr) {
|
||||
if (fileArr!=null) {
|
||||
xmlEmbeddedFiles = new ArrayList<>(Arrays.asList(fileArr));
|
||||
} else {
|
||||
xmlEmbeddedFiles = new ArrayList<>();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDCashDiscount[] getCashDiscounts() {
|
||||
return cashDiscounts.toArray(new IZUGFeRDCashDiscount[0]);
|
||||
@@ -410,6 +430,11 @@ public class Invoice implements IExportableTransaction {
|
||||
return includedNotes;
|
||||
}
|
||||
|
||||
public Invoice setNotesWithSubjectCode(List<IncludedNote> theList) {
|
||||
includedNotes=theList;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrency() {
|
||||
return currency;
|
||||
@@ -465,6 +490,26 @@ public class Invoice implements IExportableTransaction {
|
||||
return sender;
|
||||
}
|
||||
|
||||
/***
|
||||
* for currency rounding differences to 5ct e.g. in Netherlands ("Rappenrundung")
|
||||
* @return null if not set, otherwise BigDecimal of Euros
|
||||
*/
|
||||
@Override
|
||||
public BigDecimal getRoundingAmount() {
|
||||
return roundingAmount;
|
||||
}
|
||||
|
||||
/***
|
||||
* set the cent e.g. to reach the next 5ct mark for currencies in certain countries
|
||||
* e.g. in the Netherlands ("Rappenrundung")
|
||||
* @param amount
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Invoice setRoundingAmount(BigDecimal amount) {
|
||||
roundingAmount=amount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* sets a named sender contact
|
||||
* @deprecated use setSender
|
||||
@@ -511,6 +556,26 @@ public class Invoice implements IExportableTransaction {
|
||||
return this;
|
||||
}
|
||||
|
||||
// Getter for BG-3
|
||||
@Override
|
||||
public ArrayList<ReferencedDocument> getInvoiceReferencedDocuments() {
|
||||
return invoiceReferencedDocuments;
|
||||
}
|
||||
|
||||
// Setter for BG-3
|
||||
public void setInvoiceReferencedDocuments(ArrayList<ReferencedDocument> invoiceReferencedDocuments) {
|
||||
this.invoiceReferencedDocuments = invoiceReferencedDocuments;
|
||||
}
|
||||
|
||||
// Method to add a single ReferencedDocument for BG-3
|
||||
public Invoice addInvoiceReferencedDocument(ReferencedDocument doc) {
|
||||
if (invoiceReferencedDocuments == null) {
|
||||
invoiceReferencedDocuments = new ArrayList<>();
|
||||
}
|
||||
invoiceReferencedDocuments.add(doc);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
|
||||
if (Allowances.isEmpty()) {
|
||||
@@ -520,6 +585,20 @@ public class Invoice implements IExportableTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* this is wrong and only used from jackson
|
||||
* @param iza the Array of allowances/charges
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Invoice setZFAllowances(Allowance[] iza) {
|
||||
Allowances=new ArrayList<>();
|
||||
|
||||
for (IZUGFeRDAllowanceCharge cz:iza) {
|
||||
Allowances.add(cz);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IZUGFeRDAllowanceCharge[] getZFCharges() {
|
||||
@@ -530,6 +609,18 @@ public class Invoice implements IExportableTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* this is wrong and only used from jackson
|
||||
* @param iza the array of charges
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Invoice setZFCharges(Charge[] iza) {
|
||||
Charges=new ArrayList<>();
|
||||
for (IZUGFeRDAllowanceCharge cz:iza) {
|
||||
Charges.add(cz);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
|
||||
@@ -555,11 +646,49 @@ public class Invoice implements IExportableTransaction {
|
||||
|
||||
@Override
|
||||
public IZUGFeRDPaymentTerms getPaymentTerms() {
|
||||
return paymentTerms;
|
||||
if (!paymentTerms.isEmpty()) {
|
||||
return paymentTerms.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Invoice setPaymentTerms(IZUGFeRDPaymentTerms paymentTerms) {
|
||||
this.paymentTerms = paymentTerms;
|
||||
public Invoice setPaymentTerms(IZUGFeRDPaymentTerms paymentTerm) {
|
||||
if (paymentTerms.isEmpty()) {
|
||||
paymentTerms.add(paymentTerm);
|
||||
}
|
||||
else {
|
||||
paymentTerms.set(0, paymentTerm);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDPaymentTerms[] getExtendedPaymentTerms() {
|
||||
return paymentTerms.toArray(new IZUGFeRDPaymentTerms[0]);
|
||||
}
|
||||
|
||||
public Invoice setExtendedPaymentTerms(IZUGFeRDPaymentTerms[] paymentTerms) {
|
||||
this.paymentTerms.clear();
|
||||
this.paymentTerms.addAll(Arrays.asList(paymentTerms));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple payment terms when using the EXTENDED profile.
|
||||
* @return
|
||||
*/
|
||||
public Invoice addPaymentTerms(IZUGFeRDPaymentTerms paymentTerm) {
|
||||
paymentTerms.add(paymentTerm);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public String getPaymentReference() {
|
||||
return paymentReference;
|
||||
}
|
||||
|
||||
public Invoice setPaymentReference(String paymentReference) {
|
||||
this.paymentReference = paymentReference;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -577,6 +706,22 @@ public class Invoice implements IExportableTransaction {
|
||||
this.deliveryAddress = deliveryAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TradeParty getPayee() {
|
||||
return this.payee;
|
||||
}
|
||||
|
||||
/***
|
||||
* if the payee is not the seller, it can be specified here
|
||||
* @param payee the payment receiving organisation
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Invoice setPayee(TradeParty payee) {
|
||||
this.payee = payee;
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* Adds a cash discount (skonto)
|
||||
* @param c the CashDiscount percent/period combination
|
||||
@@ -680,11 +825,20 @@ public class Invoice implements IExportableTransaction {
|
||||
return detailedDeliveryDateStart;
|
||||
}
|
||||
|
||||
public Invoice setDetailedDeliveryPeriodFrom(Date dt) {
|
||||
detailedDeliveryDateStart=dt;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDetailedDeliveryPeriodTo() {
|
||||
return detailedDeliveryPeriodEnd;
|
||||
}
|
||||
|
||||
public Invoice setDetailedDeliveryPeriodTo(Date dt) {
|
||||
detailedDeliveryPeriodEnd=dt;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a free text paragraph, which will become an includedNote element
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IReferencedDocument;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
|
||||
import org.mustangproject.util.NodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/***
|
||||
* describes any invoice line
|
||||
*/
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class Item implements IZUGFeRDExportableItem {
|
||||
protected BigDecimal price, quantity, tax, grossPrice, lineTotalAmount;
|
||||
protected BigDecimal price = BigDecimal.ZERO;
|
||||
protected BigDecimal quantity;
|
||||
protected BigDecimal tax;
|
||||
protected BigDecimal grossPrice;
|
||||
protected BigDecimal lineTotalAmount;
|
||||
protected BigDecimal basisQuantity = BigDecimal.ONE;
|
||||
protected Date detailedDeliveryPeriodFrom = null, detailedDeliveryPeriodTo = null;
|
||||
protected Date detailedDeliveryPeriodFrom = null;
|
||||
protected Date detailedDeliveryPeriodTo = null;
|
||||
protected String id;
|
||||
protected String buyerOrderReferencedDocumentLineID = null;
|
||||
protected String buyerOrderReferencedDocumentID = null;
|
||||
@@ -28,8 +40,11 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
protected ArrayList<String> notes = null;
|
||||
protected ArrayList<ReferencedDocument> referencedDocuments = null;
|
||||
protected ArrayList<ReferencedDocument> additionalReference = null;
|
||||
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
|
||||
Charges = new ArrayList<>();
|
||||
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>();
|
||||
protected ArrayList<IZUGFeRDAllowanceCharge> Charges = new ArrayList<>();
|
||||
protected List<IncludedNote> includedNotes = null;
|
||||
protected String accountingReference;
|
||||
//protected HashMap<String, String> attributes = new HashMap<>();
|
||||
|
||||
/***
|
||||
* default constructor
|
||||
@@ -43,7 +58,6 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* empty constructor
|
||||
* do not use, but might be used e.g. by jackson
|
||||
@@ -52,100 +66,67 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
}
|
||||
|
||||
public Item(NodeList itemChilds, boolean recalcPrice) {
|
||||
String price = "0";
|
||||
String basisQuantity = "1";
|
||||
String name = "";
|
||||
String sellerAssignedID = null;
|
||||
String description = "";
|
||||
SchemedID gid = null;
|
||||
String quantity = "0";
|
||||
String vatPercent = null;
|
||||
String lineTotal = "0";
|
||||
String unitCode = "0";
|
||||
String buyerOrderReferencedDocumentLineID = null;
|
||||
String buyerOrderReferencedDocumentID = null;
|
||||
NodeMap itemMap = new NodeMap(itemChilds);
|
||||
|
||||
ArrayList<ReferencedDocument> rdocs = null;
|
||||
ArrayList<ReferencedDocument> addRefs = null;
|
||||
itemMap.getAsNodeMap("Item").ifPresent(icnm -> {
|
||||
// ubl
|
||||
//we need: name description unitcode
|
||||
//and we additionally have vat%
|
||||
|
||||
// nodes.item(i).getTextContent())) {
|
||||
setProduct(new Product(itemMap.getNode("Item").get()));
|
||||
icnm.getAsString("Name").ifPresent(product::setName);
|
||||
icnm.getAsString("Description").ifPresent(product::setDescription);
|
||||
|
||||
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
|
||||
String lineTrade = itemChilds.item(itemChildIndex).getLocalName();
|
||||
if ((lineTrade != null) && (lineTrade.equals("Item"))) {
|
||||
// ubl
|
||||
//we need: name description unitcode
|
||||
//and we additionally have vat%
|
||||
NodeList UBLitemChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
||||
for (Node currentUBLItemChildNode : XMLTools.asList(UBLitemChilds)) {
|
||||
icnm.getAsNodeMap("SellersItemIdentification").ifPresent(SellersItemIdentification -> {
|
||||
SellersItemIdentification.getAsString("ID").ifPresent(product::setSellerAssignedID);
|
||||
});
|
||||
|
||||
if ((currentUBLItemChildNode.getLocalName() != null) && (currentUBLItemChildNode.getLocalName().equals("Name"))) {
|
||||
name = currentUBLItemChildNode.getTextContent();
|
||||
}
|
||||
if ((currentUBLItemChildNode.getLocalName() != null) && (currentUBLItemChildNode.getLocalName().equals("ClassifiedTaxCategory"))) {
|
||||
for (Node currentUBLTaxChildNode : XMLTools.asList(currentUBLItemChildNode.getChildNodes())) {
|
||||
if ((currentUBLTaxChildNode.getLocalName() != null) && (currentUBLTaxChildNode.getLocalName().equals("Percent"))) {
|
||||
vatPercent = currentUBLTaxChildNode.getTextContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((lineTrade != null) && (lineTrade.equals("Price"))) {
|
||||
// ubl
|
||||
// PriceAmount with currencyID and BaseQuantity with unitCode
|
||||
NodeList UBLpriceChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
||||
for (Node currentUBLPriceChildNode : XMLTools.asList(UBLpriceChilds)) {
|
||||
icnm.getAsNodeMap("BuyersItemIdentification").ifPresent(BuyersItemIdentification -> {
|
||||
BuyersItemIdentification.getAsString("ID").ifPresent(product::setBuyerAssignedID);
|
||||
});
|
||||
|
||||
if ((currentUBLPriceChildNode.getLocalName() != null) && (currentUBLPriceChildNode.getLocalName().equals("PriceAmount"))) {
|
||||
price = currentUBLPriceChildNode.getTextContent();
|
||||
}
|
||||
if ((currentUBLPriceChildNode.getLocalName() != null) && (currentUBLPriceChildNode.getLocalName().equals("BaseQuantity"))) {
|
||||
basisQuantity = currentUBLPriceChildNode.getTextContent();
|
||||
}
|
||||
}
|
||||
icnm.getAsNodeMap("ClassifiedTaxCategory").flatMap(m -> m.getAsBigDecimal("Percent"))
|
||||
.ifPresent(product::setVATPercent);
|
||||
});
|
||||
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(icnm -> {
|
||||
icnm.getAsString("LineID").ifPresent(this::setId);
|
||||
});
|
||||
|
||||
}
|
||||
if ((lineTrade != null) && (lineTrade.equals("InvoicedQuantity"))) {
|
||||
// ubl
|
||||
quantity = itemChilds.item(itemChildIndex).getTextContent();
|
||||
unitCode = itemChilds.item(itemChildIndex).getAttributes()
|
||||
.getNamedItem("unitCode").getNodeValue();
|
||||
}
|
||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedLineTradeAgreement")
|
||||
|| lineTrade.equals("SpecifiedSupplyChainTradeAgreement"))) {
|
||||
NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
||||
for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds
|
||||
.getLength(); tradeLineChildIndex++) {
|
||||
itemMap.getAsNodeMap("Price").ifPresent(icnm -> {
|
||||
// ubl
|
||||
// PriceAmount with currencyID and BaseQuantity with unitCode
|
||||
icnm.getAsBigDecimal("PriceAmount").ifPresent(this::setPrice);
|
||||
icnm.getAsBigDecimal("BaseQuantity").ifPresent(this::setBasisQuantity);
|
||||
});
|
||||
|
||||
if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && tradeLineChilds
|
||||
.item(tradeLineChildIndex).getLocalName().equals("AdditionalReferencedDocument")) {
|
||||
String IssuerAssignedID = "";
|
||||
String TypeCode = "";
|
||||
String ReferenceTypeCode = "";
|
||||
itemMap.getNode("InvoicedQuantity").ifPresent(icn -> {
|
||||
// ubl
|
||||
setQuantity(new BigDecimal(icn.getTextContent().trim()));
|
||||
product.setUnit(icn.getAttributes().getNamedItem("unitCode").getNodeValue());
|
||||
});
|
||||
|
||||
NodeList refDocChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
|
||||
for (int refDocIndex = 0; refDocIndex < refDocChilds.getLength(); refDocIndex++) {
|
||||
String localName = refDocChilds.item(refDocIndex).getLocalName();
|
||||
if ((localName != null) && (localName.equals("IssuerAssignedID"))) {
|
||||
IssuerAssignedID = refDocChilds.item(refDocIndex).getTextContent();
|
||||
}
|
||||
if ((localName != null) && (localName.equals("TypeCode"))) {
|
||||
TypeCode = refDocChilds.item(refDocIndex).getTextContent();
|
||||
}
|
||||
if ((localName != null) && (localName.equals("ReferenceTypeCode"))) {
|
||||
ReferenceTypeCode = refDocChilds.item(refDocIndex).getTextContent();
|
||||
}
|
||||
}
|
||||
itemMap.getAllNodes("DocumentReference").map(ReferencedDocument::fromNode)
|
||||
.forEach(this::addAdditionalReference);
|
||||
|
||||
ReferencedDocument rd = new ReferencedDocument(IssuerAssignedID, TypeCode,
|
||||
ReferenceTypeCode);
|
||||
if (rdocs == null) {
|
||||
rdocs = new ArrayList<>();
|
||||
}
|
||||
rdocs.add(rd);
|
||||
// ubl
|
||||
|
||||
}
|
||||
itemMap.getAsNodeMap("OrderLineReference")
|
||||
// ubl
|
||||
.flatMap(bordNodes -> bordNodes.getAsString("LineID"))
|
||||
.ifPresent(this::addReferencedLineID);
|
||||
|
||||
itemMap.getAsString("ID")
|
||||
.ifPresent(this::setId);
|
||||
|
||||
|
||||
itemMap.getAsString("Note")
|
||||
.ifPresent(this::addNote);
|
||||
|
||||
|
||||
itemMap.getAsNodeMap("SpecifiedLineTradeAgreement", "SpecifiedSupplyChainTradeAgreement").ifPresent(icnm -> {
|
||||
icnm.getAsNodeMap("BuyerOrderReferencedDocument")
|
||||
.flatMap(bordNodes -> bordNodes.getAsString("LineID"))
|
||||
.ifPresent(this::addReferencedLineID);
|
||||
|
||||
if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && tradeLineChilds.item(tradeLineChildIndex).getLocalName().equals("BuyerOrderReferencedDocument")) {
|
||||
NodeList docChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
|
||||
@@ -159,166 +140,155 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
}
|
||||
}
|
||||
|
||||
if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && tradeLineChilds
|
||||
.item(tradeLineChildIndex).getLocalName().equals("NetPriceProductTradePrice")) {
|
||||
NodeList netChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
|
||||
for (int netIndex = 0; netIndex < netChilds.getLength(); netIndex++) {
|
||||
if ((netChilds.item(netIndex).getLocalName() != null)
|
||||
&& (netChilds.item(netIndex).getLocalName().equals("ChargeAmount"))) {
|
||||
price = netChilds.item(netIndex).getTextContent();// ChargeAmount
|
||||
icnm.getAsNodeMap("NetPriceProductTradePrice").ifPresent(npptpNodes -> {
|
||||
npptpNodes.getAsBigDecimal("ChargeAmount").ifPresent(this::setPrice);
|
||||
npptpNodes.getAsBigDecimal("BasisQuantity").ifPresent(this::setBasisQuantity);
|
||||
});
|
||||
|
||||
}
|
||||
if ((netChilds.item(netIndex).getLocalName() != null)
|
||||
&& ((netChilds.item(netIndex).getLocalName().equals("BasisQuantity")) || (netChilds.item(netIndex).getLocalName().equals("InvoicedQuantity")))) {
|
||||
basisQuantity = netChilds.item(netIndex).getTextContent();// ChargeAmount
|
||||
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).
|
||||
forEach(this::addReferencedDocument);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
itemMap.getNode("SpecifiedTradeProduct").map(Product::new).ifPresent(this::setProduct);//CII
|
||||
itemMap.getNode("SpecifiedTradeProduct").map(Product::new).ifPresent(this::setProduct);//UBL
|
||||
|
||||
// RequestedQuantity is for Order-X, BilledQuantity for FX and ZF
|
||||
itemMap.getAsNodeMap("SpecifiedLineTradeDelivery", "SpecifiedSupplyChainTradeDelivery")
|
||||
.flatMap(icnm -> icnm.getNode("BilledQuantity", "RequestedQuantity", "DespatchedQuantity"))
|
||||
.ifPresent(bq -> {
|
||||
setQuantity(new BigDecimal(bq.getTextContent().trim()));
|
||||
if (bq.hasAttributes()) {
|
||||
Node unitAttr = bq.getAttributes().getNamedItem("unitCode");
|
||||
if (unitAttr != null) {
|
||||
product.setUnit(unitAttr.getNodeValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
itemMap.getAsNodeMap("SpecifiedLineTradeSettlement", "SpecifiedSupplyChainTradeSettlement").ifPresent(icnm -> {
|
||||
icnm.getAsNodeMap("ApplicableTradeTax")
|
||||
.flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent"))
|
||||
.ifPresent(product::setVATPercent);
|
||||
icnm.getAsNodeMap("ApplicableTradeTax")
|
||||
.flatMap(cnm -> cnm.getAsString("ExemptionReason"))
|
||||
.ifPresent(product::setTaxExemptionReason);
|
||||
|
||||
icnm.getAllNodes("SpecifiedTradeAllowanceCharge").map(NodeMap::new).forEach(stac -> {
|
||||
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> {
|
||||
String isChargeString = ci.getAsString("Indicator").get();
|
||||
String percentString = stac.getAsStringOrNull("CalculationPercent");
|
||||
String amountString = stac.getAsStringOrNull("ActualAmount");
|
||||
String basisAmountString = stac.getAsStringOrNull("BasisAmount");
|
||||
String reason = stac.getAsStringOrNull("Reason");
|
||||
Charge izac = new Charge();
|
||||
if (isChargeString.equalsIgnoreCase("false")) {
|
||||
izac = new Allowance();
|
||||
} else {
|
||||
izac = new Charge();
|
||||
}
|
||||
if (amountString != null) {
|
||||
izac.setTotalAmount(new BigDecimal(amountString));
|
||||
if (percentString!=null&&(percentString!="0")) {
|
||||
izac.setTotalAmount(new BigDecimal(amountString).divide(getQuantity()));
|
||||
}
|
||||
}
|
||||
if (basisAmountString != null) {
|
||||
izac.setBasisAmount(new BigDecimal(basisAmountString));
|
||||
}
|
||||
if (percentString != null) {
|
||||
izac.setPercent(new BigDecimal(percentString));
|
||||
}
|
||||
if (reason != null) {
|
||||
izac.setReason(reason);
|
||||
}
|
||||
|
||||
if (isChargeString.equalsIgnoreCase("false")) {
|
||||
addAllowance(izac);
|
||||
} else {
|
||||
addCharge(izac);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
if (recalcPrice && !BigDecimal.ZERO.equals(quantity)) {
|
||||
icnm.getAsNodeMap("SpecifiedTradeSettlementLineMonetarySummation")
|
||||
.flatMap(cnm -> cnm.getAsBigDecimal("LineTotalAmount"))
|
||||
.ifPresent(lineTotal -> setPrice(lineTotal.divide(quantity, 4, RoundingMode.HALF_UP)));
|
||||
}
|
||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedLineTradeDelivery")
|
||||
|| lineTrade.equals("SpecifiedSupplyChainTradeDelivery"))) {
|
||||
NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
||||
for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds
|
||||
.getLength(); tradeLineChildIndex++) {
|
||||
String tradeName = tradeLineChilds.item(tradeLineChildIndex).getLocalName();
|
||||
if ((tradeName != null)
|
||||
&& (tradeName.equals("BilledQuantity") || tradeName.equals("RequestedQuantity")
|
||||
|| tradeName.equals("DespatchedQuantity"))) {
|
||||
// RequestedQuantity is for Order-X, BilledQuantity for FX and ZF
|
||||
quantity = tradeLineChilds.item(tradeLineChildIndex).getTextContent();
|
||||
unitCode = tradeLineChilds.item(tradeLineChildIndex).getAttributes()
|
||||
.getNamedItem("unitCode").getNodeValue();
|
||||
|
||||
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
|
||||
|
||||
icnm.getAsString("ReceivableSpecifiedTradeAccountingAccount").ifPresent(s -> this.accountingReference = s == null ? null : s.trim());
|
||||
|
||||
icnm.getAsNodeMap("BillingSpecifiedPeriod").ifPresent(periodNode -> {
|
||||
Date start = periodNode.getAsNodeMap("StartDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(dts -> XMLTools.tryDate(dts)).orElse(null);
|
||||
Date end = periodNode.getAsNodeMap("EndDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(dts -> XMLTools.tryDate(dts)).orElse(null);
|
||||
setDetailedDeliveryPeriod(start, end);
|
||||
});
|
||||
});
|
||||
|
||||
itemMap.getAllNodes("AllowanceCharge").map(NodeMap::new).forEach(stac -> { //UBL
|
||||
|
||||
String isChargeString = stac.getAsString("ChargeIndicator").get();
|
||||
String percentString = stac.getAsStringOrNull("MultiplierFactorNumeric");
|
||||
String amountString = stac.getAsStringOrNull("Amount");
|
||||
String reason = stac.getAsStringOrNull("AllowanceChargeReason");
|
||||
Charge izac = new Charge();
|
||||
if (isChargeString.equalsIgnoreCase("false")) {
|
||||
izac = new Allowance();
|
||||
} else {
|
||||
izac = new Charge();
|
||||
}
|
||||
if (amountString != null) {
|
||||
izac.setTotalAmount(new BigDecimal(amountString));
|
||||
}
|
||||
if (percentString != null) {
|
||||
izac.setPercent(new BigDecimal(percentString));
|
||||
}
|
||||
if (reason != null) {
|
||||
izac.setReason(reason);
|
||||
}
|
||||
|
||||
if (isChargeString.equalsIgnoreCase("false")) {
|
||||
addAllowance(izac);
|
||||
} else {
|
||||
addCharge(izac);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(adld -> {
|
||||
List<IncludedNote> includedNotes = new ArrayList<>();
|
||||
adld.getAllNodes("IncludedNote").forEach(item -> {
|
||||
String subjectCode = "";
|
||||
String content = null;
|
||||
NodeList includedNodeChilds = item.getChildNodes();
|
||||
for (int issueDateChildIndex = 0; issueDateChildIndex < includedNodeChilds.getLength(); issueDateChildIndex++) {
|
||||
if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null)
|
||||
&& (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("Content"))) {
|
||||
content = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex));
|
||||
}
|
||||
if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null)
|
||||
&& (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("SubjectCode"))) {
|
||||
subjectCode = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedTradeProduct"))) {
|
||||
NodeList tradeProductChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
||||
for (int tradeProductChildIndex = 0; tradeProductChildIndex < tradeProductChilds
|
||||
.getLength(); tradeProductChildIndex++) {
|
||||
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
|
||||
&& (tradeProductChilds.item(tradeProductChildIndex).getLocalName()
|
||||
.equals("Name"))) {
|
||||
name = tradeProductChilds.item(tradeProductChildIndex).getTextContent();
|
||||
}
|
||||
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
|
||||
&& (tradeProductChilds.item(tradeProductChildIndex).getLocalName()
|
||||
.equals("SellerAssignedID"))) {
|
||||
sellerAssignedID = tradeProductChilds.item(tradeProductChildIndex).getTextContent();
|
||||
}
|
||||
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
|
||||
&& (tradeProductChilds.item(tradeProductChildIndex).getLocalName()
|
||||
.equals("GlobalID"))) {
|
||||
if (tradeProductChilds.item(tradeProductChildIndex).getAttributes()
|
||||
.getNamedItem("schemeID") != null) {
|
||||
gid = new SchemedID()
|
||||
.setScheme(tradeProductChilds.item(tradeProductChildIndex).getAttributes()
|
||||
.getNamedItem("schemeID").getNodeValue())
|
||||
.setId(tradeProductChilds.item(tradeProductChildIndex).getTextContent());
|
||||
}
|
||||
|
||||
boolean foundCode = false;
|
||||
for (SubjectCode code : SubjectCode.values()) {
|
||||
if (code.toString().equals(subjectCode)) {
|
||||
includedNotes.add(new IncludedNote(content, code));
|
||||
foundCode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedLineTradeSettlement")
|
||||
|| lineTrade.equals("SpecifiedSupplyChainTradeSettlement"))) {
|
||||
NodeList tradeSettlementChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
||||
for (int tradeSettlementChildIndex = 0; tradeSettlementChildIndex < tradeSettlementChilds
|
||||
.getLength(); tradeSettlementChildIndex++) {
|
||||
|
||||
String tradeSettlementName = tradeSettlementChilds.item(tradeSettlementChildIndex)
|
||||
.getLocalName();
|
||||
if (tradeSettlementName != null) {
|
||||
if (tradeSettlementName.equals("ApplicableTradeTax")) {
|
||||
NodeList taxChilds = tradeSettlementChilds.item(tradeSettlementChildIndex)
|
||||
.getChildNodes();
|
||||
for (int taxChildIndex = 0; taxChildIndex < taxChilds
|
||||
.getLength(); taxChildIndex++) {
|
||||
String taxChildName = taxChilds.item(taxChildIndex).getLocalName();
|
||||
if ((taxChildName != null) && (taxChildName.equals("RateApplicablePercent")
|
||||
|| taxChildName.equals("ApplicablePercent"))) {
|
||||
vatPercent = taxChilds.item(taxChildIndex).getTextContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tradeSettlementName.equals("SpecifiedTradeSettlementLineMonetarySummation")) {
|
||||
NodeList totalChilds = tradeSettlementChilds.item(tradeSettlementChildIndex)
|
||||
.getChildNodes();
|
||||
for (int totalChildIndex = 0; totalChildIndex < totalChilds
|
||||
.getLength(); totalChildIndex++) {
|
||||
if ((totalChilds.item(totalChildIndex).getLocalName() != null) && (totalChilds
|
||||
.item(totalChildIndex).getLocalName().equals("LineTotalAmount"))) {
|
||||
lineTotal = totalChilds.item(totalChildIndex).getTextContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tradeSettlementName.equals("AdditionalReferencedDocument")) {
|
||||
String IssuerAssignedID = "";
|
||||
String TypeCode = "";
|
||||
String ReferenceTypeCode = "";
|
||||
|
||||
NodeList refDocChilds = tradeSettlementChilds.item(tradeSettlementChildIndex).getChildNodes();
|
||||
for (int refDocIndex = 0; refDocIndex < refDocChilds.getLength(); refDocIndex++) {
|
||||
String localName = refDocChilds.item(refDocIndex).getLocalName();
|
||||
if ((localName != null) && (localName.equals("IssuerAssignedID"))) {
|
||||
IssuerAssignedID = refDocChilds.item(refDocIndex).getTextContent();
|
||||
}
|
||||
if ((localName != null) && (localName.equals("TypeCode"))) {
|
||||
TypeCode = refDocChilds.item(refDocIndex).getTextContent();
|
||||
}
|
||||
if ((localName != null) && (localName.equals("ReferenceTypeCode"))) {
|
||||
ReferenceTypeCode = refDocChilds.item(refDocIndex).getTextContent();
|
||||
}
|
||||
}
|
||||
|
||||
ReferencedDocument rd = new ReferencedDocument(IssuerAssignedID, TypeCode,
|
||||
ReferenceTypeCode);
|
||||
if (addRefs == null) {
|
||||
addRefs = new ArrayList<>();
|
||||
}
|
||||
addRefs.add(rd);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (!foundCode) {
|
||||
includedNotes.add(new IncludedNote(content, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
BigDecimal prc = new BigDecimal(price.trim());
|
||||
BigDecimal qty = new BigDecimal(quantity.trim());
|
||||
if ((recalcPrice) && (!qty.equals(BigDecimal.ZERO))) {
|
||||
prc = new BigDecimal(lineTotal.trim()).divide(qty, 4, RoundingMode.HALF_UP);
|
||||
}
|
||||
Product p = new Product(name, description, unitCode,
|
||||
vatPercent == null ? null : new BigDecimal(vatPercent.trim()));
|
||||
if (gid != null) {
|
||||
p.addGlobalID(gid);
|
||||
}
|
||||
if (sellerAssignedID != null) {
|
||||
p.setSellerAssignedID(sellerAssignedID);
|
||||
}
|
||||
setProduct(p);
|
||||
setPrice(prc);
|
||||
setQuantity(qty);
|
||||
setBasisQuantity(new BigDecimal(basisQuantity));
|
||||
if (rdocs != null) {
|
||||
for (ReferencedDocument rdoc : rdocs) {
|
||||
addReferencedDocument(rdoc);
|
||||
}
|
||||
}
|
||||
if (addRefs != null) {
|
||||
for (ReferencedDocument rdoc : addRefs) {
|
||||
addAdditionalReference(rdoc);
|
||||
}
|
||||
}
|
||||
addBuyerOrderReferencedDocumentLineID( buyerOrderReferencedDocumentLineID );
|
||||
addBuyerOrderReferencedDocumentID( buyerOrderReferencedDocumentID );
|
||||
});
|
||||
addNotes(includedNotes);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Item addBuyerOrderReferencedDocumentLineID(String s) {
|
||||
buyerOrderReferencedDocumentLineID = s;
|
||||
return this;
|
||||
@@ -339,6 +309,20 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public IZUGFeRDAllowanceCharge[] getAllowances() {
|
||||
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Allowances.size()];
|
||||
return Allowances.toArray(izac);
|
||||
}
|
||||
|
||||
@Override public IZUGFeRDAllowanceCharge[] getCharges() {
|
||||
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Charges.size()];
|
||||
return Charges.toArray(izac);
|
||||
}
|
||||
|
||||
/***
|
||||
* BT 132 (issue https://github.com/ZUGFeRD/mustangproject/issues/247)
|
||||
* @return the line ID of the order (BT132)
|
||||
*/
|
||||
@Override
|
||||
public String getBuyerOrderReferencedDocumentLineID() {
|
||||
return buyerOrderReferencedDocumentLineID;
|
||||
@@ -348,6 +332,11 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
return lineTotalAmount;
|
||||
}
|
||||
|
||||
public Item setNotesWithSubjectCode(List<IncludedNote> theList) {
|
||||
includedNotes = theList;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* should only be set by calculator classes or maybe when reading from XML
|
||||
*
|
||||
@@ -438,6 +427,30 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
|
||||
}
|
||||
|
||||
/***
|
||||
* jackson convenience method
|
||||
*/
|
||||
public void setItemAllowances(ArrayList<Allowance> theAllowances) {
|
||||
if (theAllowances != null) {
|
||||
Allowances.clear();
|
||||
for (Allowance theAllowance : theAllowances) {
|
||||
Allowances.add(theAllowance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* jackson convenience method
|
||||
*/
|
||||
public void setItemCharges(ArrayList<Charge> theCharges) {
|
||||
if (theCharges != null) {
|
||||
Charges.clear();
|
||||
for (Charge theCharge : theCharges) {
|
||||
Charges.add(theCharge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDAllowanceCharge[] getItemCharges() {
|
||||
if (Charges.isEmpty()) {
|
||||
@@ -463,7 +476,7 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
|
||||
/***
|
||||
* Adds a item level addition to the price (will be multiplied by quantity)
|
||||
* @see org.mustangproject.Charge
|
||||
* @see Charge
|
||||
* @param izac a relative or absolute charge
|
||||
* @return fluent setter
|
||||
*/
|
||||
@@ -474,11 +487,12 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
|
||||
/***
|
||||
* Adds a item level reduction the price (will be multiplied by quantity)
|
||||
* @see org.mustangproject.Allowance
|
||||
* @see Allowance
|
||||
* @param izac a relative or absolute allowance
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Item addAllowance(IZUGFeRDAllowanceCharge izac) {
|
||||
|
||||
Allowances.add(izac);
|
||||
return this;
|
||||
}
|
||||
@@ -493,6 +507,26 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
notes = new ArrayList<>();
|
||||
}
|
||||
notes.add(text);
|
||||
|
||||
addNote(IncludedNote.unspecifiedNote(text));
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* adds categorized item level freetext fields (includednote)
|
||||
* @param theNote IncludedNote to add
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Item addNote(IncludedNote theNote) {
|
||||
|
||||
if (includedNotes == null) {
|
||||
includedNotes = new ArrayList<>();
|
||||
}
|
||||
includedNotes.add(theNote);
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -519,7 +553,7 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
|
||||
|
||||
/***
|
||||
* adds item level references along with their typecodes and issuerassignedIDs (contract ID, cost centre, ...)
|
||||
* adds item level references along with their typecodes and issuerassignedIDs (contract ID, cost centre, ...)
|
||||
* @param doc the ReferencedDocument to add
|
||||
* @return fluent setter
|
||||
*/
|
||||
@@ -538,8 +572,8 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
}
|
||||
return additionalReference.toArray(new IReferencedDocument[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***
|
||||
* specify a item level delivery period
|
||||
* (apart from the document level delivery period, and the document level
|
||||
@@ -560,6 +594,7 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
* this will be included in a BillingSpecifiedPeriod element
|
||||
* @return the beginning of the delivery period
|
||||
*/
|
||||
@Override
|
||||
public Date getDetailedDeliveryPeriodFrom() {
|
||||
return detailedDeliveryPeriodFrom;
|
||||
}
|
||||
@@ -569,8 +604,29 @@ public class Item implements IZUGFeRDExportableItem {
|
||||
* this will be included in a BillingSpecifiedPeriod element
|
||||
* @return the end of the delivery period
|
||||
*/
|
||||
@Override
|
||||
public Date getDetailedDeliveryPeriodTo() {
|
||||
return detailedDeliveryPeriodTo;
|
||||
}
|
||||
|
||||
public IZUGFeRDExportableItem addNotes(Collection<IncludedNote> notes) {
|
||||
if (notes == null) {
|
||||
return this;
|
||||
}
|
||||
if (includedNotes == null) {
|
||||
includedNotes = new ArrayList<>();
|
||||
}
|
||||
includedNotes.addAll(notes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IncludedNote> getNotesWithSubjectCode() {
|
||||
return includedNotes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccountingReference() {
|
||||
return accountingReference;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.*;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
@@ -9,6 +10,7 @@ import org.w3c.dom.NodeList;
|
||||
* A organisation, i.e. usually a company
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
|
||||
|
||||
protected SchemedID schemedID = null;
|
||||
@@ -18,12 +20,16 @@ public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
|
||||
}
|
||||
|
||||
public LegalOrganisation(String ID, String scheme) {
|
||||
this.schemedID = new SchemedID(ID, scheme);
|
||||
this.schemedID = new SchemedID(scheme, ID);
|
||||
}
|
||||
|
||||
public LegalOrganisation(String ID) {
|
||||
this.schemedID = new SchemedID(null, ID);
|
||||
}
|
||||
|
||||
public LegalOrganisation(SchemedID schemedID, String tradingBusinessName) {
|
||||
this.schemedID = schemedID;
|
||||
this.tradingBusinessName=tradingBusinessName;
|
||||
this.tradingBusinessName = tradingBusinessName;
|
||||
}
|
||||
|
||||
/***
|
||||
@@ -48,8 +54,8 @@ public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
|
||||
this.setSchemedID(gid);
|
||||
}
|
||||
}
|
||||
if (currentItemNode.getLocalName().equals("TradingBusinessName")) {
|
||||
setTradingBusinessName(currentItemNode.getFirstChild().getNodeValue());
|
||||
if ((currentItemNode.getLocalName().equals("TradingBusinessName")) && (currentItemNode.getFirstChild() != null)) {
|
||||
setTradingBusinessName(currentItemNode.getFirstChild().getNodeValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,42 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
import org.mustangproject.ZUGFeRD.IDesignatedProductClassification;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
|
||||
import org.mustangproject.util.NodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/***
|
||||
* describes a product, good or service used in an invoice item line
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
|
||||
public class Product implements IZUGFeRDExportableProduct {
|
||||
protected String unit, name, sellerAssignedID, buyerAssignedID;
|
||||
protected String description="";
|
||||
protected String description = "";
|
||||
protected String taxExemptionReason = null;
|
||||
protected String taxCategoryCode = null;
|
||||
protected BigDecimal VATPercent;
|
||||
protected boolean isReverseCharge = false;
|
||||
protected boolean isIntraCommunitySupply = false;
|
||||
protected SchemedID globalId = null;
|
||||
protected String countryOfOrigin = null;
|
||||
protected HashMap<String, String> attributes = null;
|
||||
protected ArrayList<Charge> charges=new ArrayList<>();
|
||||
protected ArrayList<Allowance> allowances=new ArrayList<>();
|
||||
protected HashMap<String, String> attributes = new HashMap<>();
|
||||
|
||||
protected List<IDesignatedProductClassification> classifications = new ArrayList<>();
|
||||
|
||||
/***
|
||||
* default constructor
|
||||
@@ -34,6 +52,63 @@ public class Product implements IZUGFeRDExportableProduct {
|
||||
this.VATPercent = VATPercent;
|
||||
}
|
||||
|
||||
public Product(Node node) {
|
||||
NodeMap nodeMap = new NodeMap(node);
|
||||
|
||||
nodeMap.getNode("GlobalID").ifPresent(idNode -> {
|
||||
if (idNode.hasAttributes()
|
||||
&& idNode.getAttributes().getNamedItem("schemeID") != null) {
|
||||
globalId = new SchemedID()
|
||||
.setScheme(idNode.getAttributes().getNamedItem("schemeID").getNodeValue())
|
||||
.setId(idNode.getTextContent());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
nodeMap.getAsString("SellerAssignedID").ifPresent(this::setSellerAssignedID);
|
||||
nodeMap.getAsString("BuyerAssignedID").ifPresent(this::setBuyerAssignedID);
|
||||
nodeMap.getAsString("Name").ifPresent(this::setName);
|
||||
nodeMap.getAsString("Description").ifPresent(this::setDescription);
|
||||
|
||||
|
||||
nodeMap.getAllNodes("ApplicableProductCharacteristic").map(NodeMap::new).forEach(apcNodes -> { // ApplicableProductCharacteristic is 0 .. unbounded
|
||||
String key = apcNodes.getAsStringOrNull("Description");
|
||||
String value = apcNodes.getAsStringOrNull("Value");
|
||||
if (key != null && value != null) {
|
||||
if (attributes == null) {
|
||||
attributes = new HashMap<>();
|
||||
}
|
||||
attributes.put(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
//UBL
|
||||
nodeMap.getAsNodeMap("AdditionalItemProperty").ifPresent(aipNodes -> {
|
||||
String name = aipNodes.getAsStringOrNull("Name");
|
||||
String val = aipNodes.getAsStringOrNull("Value");
|
||||
if (name != null && val != null) {
|
||||
if (attributes == null) {
|
||||
attributes = new HashMap<>();
|
||||
}
|
||||
attributes.put(name, val);
|
||||
}
|
||||
});
|
||||
|
||||
nodeMap.getAsNodeMap("CommodityClassification").ifPresent(dpcNodes -> {
|
||||
String className = dpcNodes.getAsStringOrNull("ClassName");
|
||||
dpcNodes.getNode("ItemClassificationCode").map(ClassCode::fromNode).ifPresent(classCode ->
|
||||
classifications.add(new DesignatedProductClassification(classCode, className)));
|
||||
});
|
||||
|
||||
//UBL
|
||||
nodeMap.getAsNodeMap("DesignatedProductClassification").ifPresent(dpcNodes -> {
|
||||
String className = dpcNodes.getAsStringOrNull("ClassName");
|
||||
dpcNodes.getNode("ClassCode").map(ClassCode::fromNode).ifPresent(classCode ->
|
||||
classifications.add(new DesignatedProductClassification(classCode, className)));
|
||||
});
|
||||
|
||||
nodeMap.getAsString("OriginTradeCounty").ifPresent(this::setCountryOfOrigin);
|
||||
}
|
||||
|
||||
/***
|
||||
* empty constructor
|
||||
@@ -67,6 +142,48 @@ public class Product implements IZUGFeRDExportableProduct {
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
*
|
||||
* @return e.g. intra-commnunity supply or small business
|
||||
*/
|
||||
@Override
|
||||
public String getTaxExemptionReason() {
|
||||
return taxExemptionReason;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* @param taxExemptionReasonText String e.g. Kleinunternehmer gemäß §19 UStG https://github.com/ZUGFeRD/mustangproject/issues/463
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Product setTaxExemptionReason(String taxExemptionReasonText) {
|
||||
taxExemptionReason = taxExemptionReasonText;
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* @return e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply)
|
||||
*/
|
||||
@Override
|
||||
public String getTaxCategoryCode() {
|
||||
if (taxCategoryCode == null) {
|
||||
return IZUGFeRDExportableProduct.super.getTaxCategoryCode();
|
||||
}
|
||||
return taxCategoryCode;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* @param code e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply) see also https://github.com/ZUGFeRD/mustangproject/issues/463
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Product setTaxCategoryCode(String code) {
|
||||
taxCategoryCode = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getSellerAssignedID() {
|
||||
return sellerAssignedID;
|
||||
@@ -125,6 +242,8 @@ public class Product implements IZUGFeRDExportableProduct {
|
||||
public Product setIntraCommunitySupply() {
|
||||
isIntraCommunitySupply = true;
|
||||
setVATPercent(BigDecimal.ZERO);
|
||||
setTaxExemptionReason("Intra-community supply");
|
||||
setTaxCategoryCode("K");
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -186,35 +305,132 @@ public class Product implements IZUGFeRDExportableProduct {
|
||||
* @return fluent setter
|
||||
*/
|
||||
public Product setVATPercent(BigDecimal VATPercent) {
|
||||
this.VATPercent = VATPercent;
|
||||
if (VATPercent == null) {
|
||||
this.VATPercent = BigDecimal.ZERO;
|
||||
} else {
|
||||
this.VATPercent = VATPercent;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCountryOfOrigin() {
|
||||
return this.countryOfOrigin;
|
||||
return this.countryOfOrigin;
|
||||
}
|
||||
|
||||
public Product setCountryOfOrigin(String countryOfOrigin) {
|
||||
this.countryOfOrigin = countryOfOrigin;
|
||||
return this;
|
||||
this.countryOfOrigin = countryOfOrigin;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> getAttributes() {
|
||||
return this.attributes;
|
||||
if (attributes.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return this.attributes;
|
||||
}
|
||||
}
|
||||
|
||||
public Product setAttributes(HashMap<String, String> attributes) {
|
||||
this.attributes = attributes;
|
||||
return this;
|
||||
public Product setAttributes(Map<String, String> attributes) {
|
||||
this.attributes.clear();
|
||||
if (attributes != null) {
|
||||
this.attributes.putAll(attributes);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Product addAttribute(String name, String value ) {
|
||||
if ( this.attributes == null ) {
|
||||
this.attributes = new HashMap<>();
|
||||
}
|
||||
this.attributes.put(name, value);
|
||||
return this;
|
||||
public Product addAttribute(String name, String value) {
|
||||
this.attributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDesignatedProductClassification[] getClassifications() {
|
||||
if (classifications.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return classifications.toArray(new IDesignatedProductClassification[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the current set of {@link IDesignatedProductClassification}s with a new set
|
||||
*
|
||||
* @param classifications the new set of classifications
|
||||
* @return the modified object
|
||||
*/
|
||||
public Product setClassifications(IDesignatedProductClassification[] classifications) {
|
||||
this.classifications.clear();
|
||||
if (classifications != null) {
|
||||
this.classifications.addAll(Arrays.asList(classifications));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provide Jackson a hint as to use DesignatedProductClassification for the
|
||||
* IDesignatedProductClassification product classifications
|
||||
*
|
||||
* @param classifications the new set of classifications
|
||||
* @return fluent setter
|
||||
*/
|
||||
@JsonSetter("classifications")
|
||||
public Product setClassificationsClass(DesignatedProductClassification[] classifications) {
|
||||
this.classifications.clear();
|
||||
if (classifications != null) {
|
||||
this.classifications.addAll(Arrays.asList(classifications));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link IDesignatedProductClassification} classification
|
||||
*
|
||||
* @param classification the classification
|
||||
* @return the modified object
|
||||
*/
|
||||
public Product addClassification(IDesignatedProductClassification classification) {
|
||||
this.classifications.add(classification);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Product addCharge(Charge e) {
|
||||
charges.add(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Product addAllowance(Allowance a) {
|
||||
allowances.add(a);
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* returns the AppliedTradeAllowanceCharges of this product which are actually Charges
|
||||
* @return array of or null, if none
|
||||
*/
|
||||
@Override
|
||||
public Charge[] getCharges() {
|
||||
if (charges.size()==0) {
|
||||
return null;
|
||||
}
|
||||
Charge[] chargeArr = new Charge[charges.size()];
|
||||
return charges.toArray(chargeArr);
|
||||
}
|
||||
|
||||
@Override
|
||||
/***
|
||||
* returns the AppliedTradeAllowanceCharges of this product which are actually Allowances
|
||||
* @return array of or null, if none
|
||||
*/
|
||||
public Allowance[] getAllowances() {
|
||||
if (allowances.size()==0) {
|
||||
return null;
|
||||
}
|
||||
Allowance[] allowanceArr = new Allowance[allowances.size()];
|
||||
return allowances.toArray(allowanceArr);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +1,44 @@
|
||||
package org.mustangproject;
|
||||
|
||||
import org.mustangproject.ZUGFeRD.IReferencedDocument;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mustangproject.ZUGFeRD.IReferencedDocument;
|
||||
import org.mustangproject.util.NodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class ReferencedDocument implements IReferencedDocument {
|
||||
|
||||
String issuerAssignedID;
|
||||
String typeCode;
|
||||
String referenceTypeCode;
|
||||
Date formattedIssueDateTime;
|
||||
|
||||
public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode) {
|
||||
this.issuerAssignedID = issuerAssignedID;
|
||||
this(issuerAssignedID);
|
||||
this.typeCode = typeCode;
|
||||
this.referenceTypeCode = referenceTypeCode;
|
||||
}
|
||||
|
||||
public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode, Date formattedIssueDateTime) {
|
||||
this(issuerAssignedID, typeCode, referenceTypeCode);
|
||||
this.formattedIssueDateTime = formattedIssueDateTime;
|
||||
}
|
||||
|
||||
public ReferencedDocument(String issuerAssignedID, String referenceTypeCode) {
|
||||
this(issuerAssignedID, "916", referenceTypeCode); // additional invoice related document
|
||||
}
|
||||
|
||||
public ReferencedDocument(String issuerAssingedID, Date formattedIssueDateTime) {
|
||||
this(issuerAssingedID);
|
||||
this.formattedIssueDateTime = formattedIssueDateTime;
|
||||
}
|
||||
|
||||
public ReferencedDocument(String issuerAssignedID) {
|
||||
this.issuerAssignedID = issuerAssignedID;
|
||||
this.typeCode = "916"; // additional invoice related document
|
||||
this.referenceTypeCode = referenceTypeCode;
|
||||
}
|
||||
|
||||
/***
|
||||
@@ -44,6 +65,15 @@ public class ReferencedDocument implements IReferencedDocument {
|
||||
this.referenceTypeCode = referenceTypeCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* issue date of this line
|
||||
*
|
||||
* @param formattedIssueDateTime as Date
|
||||
*/
|
||||
public void setFormattedIssueDateTime(Date formattedIssueDateTime) {
|
||||
this.formattedIssueDateTime = formattedIssueDateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIssuerAssignedID() {
|
||||
return issuerAssignedID;
|
||||
@@ -58,4 +88,21 @@ public class ReferencedDocument implements IReferencedDocument {
|
||||
public String getReferenceTypeCode() {
|
||||
return referenceTypeCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getFormattedIssueDateTime()
|
||||
{
|
||||
return formattedIssueDateTime;
|
||||
}
|
||||
|
||||
public static ReferencedDocument fromNode(Node node) {
|
||||
if (!node.hasChildNodes()) {
|
||||
return null;
|
||||
}
|
||||
NodeMap nodes = new NodeMap(node);
|
||||
return new ReferencedDocument(nodes.getAsStringOrNull("IssuerAssignedID", "ID"),
|
||||
nodes.getAsStringOrNull("TypeCode", "DocumentTypeCode"),
|
||||
nodes.getAsStringOrNull("ReferenceTypeCode"),
|
||||
XMLTools.tryDate(nodes.getAsStringOrNull("FormattedIssueDateTime")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package org.mustangproject;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class SchemedID {
|
||||
protected String scheme;
|
||||
protected String id;
|
||||
@@ -31,4 +37,9 @@ public class SchemedID {
|
||||
setId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SchemedID{scheme='" + scheme + "', id='" + id + "'}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,5 +36,9 @@ public enum SubjectCode {
|
||||
/**
|
||||
* Discount and bonus agreements
|
||||
*/
|
||||
AAK
|
||||
AAK,
|
||||
/**
|
||||
* Vehicle licence number
|
||||
*/
|
||||
ABZ
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package org.mustangproject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
|
||||
import org.mustangproject.ZUGFeRD.IZUGFeRDLegalOrganisation;
|
||||
@@ -12,15 +14,18 @@ import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
|
||||
/***
|
||||
* A organisation, i.e. usually a company
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
|
||||
protected String name, zip, street, location, country;
|
||||
protected String name, zip, street, location, country, taxScheme;
|
||||
protected String taxID = null, vatID = null;
|
||||
protected String ID = null;
|
||||
protected String description = null;
|
||||
@@ -59,6 +64,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected void parseFromUBL(NodeList nodes) {
|
||||
if (nodes.getLength() > 0) {
|
||||
|
||||
@@ -68,8 +74,34 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
|
||||
if (currentItemNode.getLocalName() != null) {
|
||||
String currentUBLChild = currentItemNode.getLocalName();
|
||||
if (currentUBLChild.equals("Party")) {
|
||||
// if (currentUBLChild.equals("Delivery")) {
|
||||
// NodeList delivery = currentItemNode.getChildNodes();
|
||||
// for (int deliveryIndex = 0; deliveryIndex < delivery.getLength(); deliveryIndex++) {
|
||||
// if (delivery.item(deliveryIndex).getLocalName() != null) {
|
||||
// Node currentNode = delivery.item(deliveryIndex);
|
||||
// if (currentNode.getLocalName().equals("DeliveryLocation")) {
|
||||
// NodeList deliveryLocation = currentNode.getChildNodes();
|
||||
// for (int deliveryLocationIndex = 0; deliveryLocationIndex < deliveryLocation.getLength(); deliveryLocationIndex++) {
|
||||
// if (deliveryLocation.item(deliveryLocationIndex).getLocalName() != null) {
|
||||
// if (deliveryLocation.item(deliveryLocationIndex).getLocalName().equals("ID")) {
|
||||
// //Node currentNode = partyID.item(partyIDIndex);
|
||||
// setID(deliveryLocation.item(deliveryLocationIndex).getTextContent());
|
||||
// if ((deliveryLocation.item(deliveryLocationIndex).getAttributes() != null &&
|
||||
// (deliveryLocation.item(deliveryLocationIndex).getAttributes().getNamedItem("schemeID") != null))
|
||||
// ) {
|
||||
// SchemedID sID = new SchemedID().setScheme(deliveryLocation.item(deliveryLocationIndex).getAttributes().getNamedItem("schemeID").getTextContent());
|
||||
// addGlobalID(sID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (currentUBLChild.equals("Party")) {
|
||||
NodeList party = currentItemNode.getChildNodes();
|
||||
for (int partyIndex = 0; partyIndex < party.getLength(); partyIndex++) {
|
||||
if (party.item(partyIndex).getLocalName() != null) {
|
||||
@@ -87,19 +119,102 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (party.item(partyIndex).getLocalName().equals("EndpointID")) {
|
||||
Node currentNode = party.item(partyIndex);
|
||||
if ((currentNode.getAttributes() != null &&
|
||||
(currentNode.getAttributes().getNamedItem("schemeID") != null))
|
||||
&& (party.item(partyIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("EM"))
|
||||
) {
|
||||
setEmail(currentNode.getTextContent());
|
||||
}
|
||||
|
||||
}
|
||||
if (currentTopElementName.equals("PartyIdentification")) {
|
||||
NodeList partyID = party.item(partyIndex).getChildNodes();
|
||||
for (int partyIDIndex = 0; partyIDIndex < partyID.getLength(); partyIDIndex++) {
|
||||
if (partyID.item(partyIDIndex).getLocalName() != null) {
|
||||
if (partyID.item(partyIDIndex).getLocalName().equals("ID")) {
|
||||
Node currentNode = partyID.item(partyIDIndex);
|
||||
if ((currentNode.getAttributes() != null &&
|
||||
(currentNode.getAttributes().getNamedItem("schemeID") != null))
|
||||
) {
|
||||
SchemedID sID = new SchemedID().setScheme(currentNode.getAttributes().getNamedItem("schemeID").getTextContent()).setId(currentNode.getTextContent());
|
||||
addGlobalID(sID);
|
||||
|
||||
}
|
||||
else {
|
||||
setID(currentNode.getTextContent());
|
||||
}
|
||||
|
||||
// UBL only: formally it can have a name as well but BT27 party name *should* be stored in
|
||||
// so overwrite if one exists
|
||||
if (currentTopElementName.equals("PartyLegalEntity")) {
|
||||
NodeList legal = party.item(partyIndex).getChildNodes();
|
||||
for (int legalChildIndex = 0; legalChildIndex < legal.getLength(); legalChildIndex++) {
|
||||
if (legal.item(legalChildIndex).getLocalName() != null) {
|
||||
if (legal.item(legalChildIndex).getLocalName().equals("RegistrationName")) {
|
||||
setName(legal.item(legalChildIndex).getTextContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTopElementName.equals("PartyTaxScheme")) {
|
||||
NodeList partyTaxScheme = party.item(partyIndex).getChildNodes();
|
||||
String CompanyId = null;
|
||||
for (int partyTaxSchemeIndex = 0; partyTaxSchemeIndex < partyTaxScheme.getLength(); partyTaxSchemeIndex++) {
|
||||
if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName() != null) {
|
||||
if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("CompanyID")) {
|
||||
CompanyId = (partyTaxScheme.item(partyTaxSchemeIndex).getTextContent());
|
||||
}
|
||||
if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("TaxScheme")) {
|
||||
NodeList taxSchemechilds = partyTaxScheme.item(partyTaxSchemeIndex).getChildNodes();
|
||||
for (int taxSchemechildsIndex = 0; taxSchemechildsIndex < taxSchemechilds.getLength(); taxSchemechildsIndex++) {
|
||||
if (taxSchemechilds.item(taxSchemechildsIndex).getLocalName() != null) {
|
||||
if (taxSchemechilds.item(taxSchemechildsIndex).getTextContent().equals("FC") || (taxSchemechilds.item(taxSchemechildsIndex).getTextContent().equals("NOVAT"))) {
|
||||
setTaxID(CompanyId);
|
||||
} else {
|
||||
setVATID(CompanyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
UBL only: formally it can have a name as well but BT27 party name *should* be stored in
|
||||
so overwrite if one exists
|
||||
*/
|
||||
|
||||
if (currentTopElementName.equals("PartyLegalEntity")) {
|
||||
NodeList legal = party.item(partyIndex).getChildNodes();
|
||||
LegalOrganisation lo = null;
|
||||
for (int legalChildIndex = 0; legalChildIndex < legal.getLength(); legalChildIndex++) {
|
||||
if (legal.item(legalChildIndex).getLocalName() != null) {
|
||||
|
||||
if (legal.item(legalChildIndex).getLocalName().equals("RegistrationName")) {
|
||||
if (lo == null) {
|
||||
lo = new LegalOrganisation();
|
||||
}
|
||||
lo.setTradingBusinessName(legal.item(legalChildIndex).getTextContent());
|
||||
}
|
||||
if (legal.item(legalChildIndex).getLocalName().equals("CompanyLegalForm")) {
|
||||
setDescription(legal.item(legalChildIndex).getTextContent());
|
||||
}
|
||||
if (legal.item(legalChildIndex).getLocalName().equals("CompanyID")) {
|
||||
if (lo == null) {
|
||||
lo = new LegalOrganisation();
|
||||
}
|
||||
if (legal.item(legalChildIndex).getAttributes().getNamedItem("schemeID")!=null) {
|
||||
SchemedID sid = new SchemedID(legal.item(legalChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue(), legal.item(legalChildIndex).getTextContent());
|
||||
lo.setSchemedID(sid);
|
||||
}
|
||||
}
|
||||
// we dont have that attribute yet in the legalorganisation: CompanyLegalForm
|
||||
if (lo != null) {
|
||||
setLegalOrganisation(lo);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTopElementName.equals("PostalAddress")) {
|
||||
|
||||
NodeList postal = party.item(partyIndex).getChildNodes();
|
||||
@@ -147,8 +262,6 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (postal.item(postalChildIndex).getLocalName().equals("Name")) {
|
||||
setName(postal.item(postalChildIndex).getTextContent());
|
||||
@@ -166,7 +279,6 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (currentUBLChild.equals("GlobalID")) {
|
||||
@@ -180,56 +292,6 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
NodeList contact = nodes.item(nodeIndex).getChildNodes();
|
||||
setContact(new Contact(contact));
|
||||
}
|
||||
|
||||
if (currentUBLChild.equals("PostalTradeAddress")) {
|
||||
NodeList postal = nodes.item(nodeIndex).getChildNodes();
|
||||
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
|
||||
if (postal.item(postalChildIndex).getLocalName() != null) {
|
||||
if (postal.item(postalChildIndex).getLocalName().equals("LineOne")) {
|
||||
setStreet(postal.item(postalChildIndex).getTextContent());
|
||||
}
|
||||
if (postal.item(postalChildIndex).getLocalName().equals("LineTwo")) {
|
||||
setAdditionalAddress(postal.item(postalChildIndex).getTextContent());
|
||||
}
|
||||
if (postal.item(postalChildIndex).getLocalName().equals("LineThree")) {
|
||||
setAdditionalAddressExtension(postal.item(postalChildIndex).getTextContent());
|
||||
}
|
||||
if (postal.item(postalChildIndex).getLocalName().equals("CityName")) {
|
||||
setLocation(postal.item(postalChildIndex).getTextContent());
|
||||
}
|
||||
if (postal.item(postalChildIndex).getLocalName().equals("PostcodeCode")) {
|
||||
setZIP(postal.item(postalChildIndex).getTextContent());
|
||||
}
|
||||
if (postal.item(postalChildIndex).getLocalName().equals("CountryID")) {
|
||||
setCountry(postal.item(postalChildIndex).getTextContent());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (currentUBLChild.equals("SpecifiedTaxRegistration")) {
|
||||
NodeList taxChilds = nodes.item(nodeIndex).getChildNodes();
|
||||
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
|
||||
if (taxChilds.item(taxChildIndex).getLocalName() != null) {
|
||||
if ((taxChilds.item(taxChildIndex).getLocalName().equals("ID"))) {
|
||||
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
|
||||
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
|
||||
if (firstChild != null) {
|
||||
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("VA")) {
|
||||
setVATID(firstChild.getNodeValue());
|
||||
}
|
||||
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("FC")) {
|
||||
setTaxID(firstChild.getNodeValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,6 +486,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getUriUniversalCommunicationID() {
|
||||
if (uriUniversalCommunicationId != null) {
|
||||
return uriUniversalCommunicationId.getID();
|
||||
@@ -433,6 +496,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String getUriUniversalCommunicationIDScheme() {
|
||||
if (uriUniversalCommunicationId != null) {
|
||||
return uriUniversalCommunicationId.getScheme();
|
||||
@@ -497,6 +561,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (optional)
|
||||
*
|
||||
@@ -508,6 +573,15 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* primarily for invoiceimporter and JSON
|
||||
*
|
||||
* @return the list of sepa mandates
|
||||
*/
|
||||
public List<DirectDebit> getDebitDetails() {
|
||||
return debitDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDLegalOrganisation getLegalOrganisation() {
|
||||
return legalOrg;
|
||||
@@ -667,6 +741,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||
return contact;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public IZUGFeRDTradeSettlement[] getAsTradeSettlement() {
|
||||
if (bankDetails.isEmpty() && debitDetails.isEmpty()) {
|
||||
return null;
|
||||
|
||||
@@ -4,15 +4,13 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.AbstractList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
public class XMLTools extends XMLWriter {
|
||||
@Override
|
||||
@@ -23,36 +21,11 @@ public class XMLTools extends XMLWriter {
|
||||
@Override
|
||||
public String escapeElementEntities(String s) {
|
||||
return super.escapeElementEntities(s);
|
||||
|
||||
}
|
||||
|
||||
public static List<Node> asList(NodeList n) {
|
||||
return n.getLength() == 0 ?
|
||||
Collections.<Node>emptyList() : new NodeListWrapper(n);
|
||||
}
|
||||
|
||||
static final class NodeListWrapper extends AbstractList<Node>
|
||||
implements RandomAccess {
|
||||
private final NodeList list;
|
||||
|
||||
NodeListWrapper(NodeList l) {
|
||||
list = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node get(int index) {
|
||||
return list.item(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.getLength();
|
||||
}
|
||||
}
|
||||
|
||||
public static String nDigitFormat(BigDecimal value, int scale) {
|
||||
/*
|
||||
* I needed 123,45, locale independent.I tried
|
||||
* I needed 123.45, locale independent.I tried
|
||||
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale
|
||||
* specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" );
|
||||
* df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false);
|
||||
@@ -70,7 +43,114 @@ public class XMLTools extends XMLWriter {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the value of an node
|
||||
*
|
||||
* @param node the Node to get the value from
|
||||
* @return A String or empty String, if no value was found
|
||||
*/
|
||||
public static String getNodeValue(Node node) {
|
||||
if (node != null && node.getFirstChild() != null) {
|
||||
return node.getFirstChild().getNodeValue();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tries to convert a String to BigDecimal.
|
||||
*
|
||||
* @param nodeValue The value as String
|
||||
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
|
||||
*/
|
||||
public static BigDecimal tryBigDecimal(String nodeValue) {
|
||||
try {
|
||||
return new BigDecimal(nodeValue);
|
||||
} catch (final Exception e) {
|
||||
try {
|
||||
return BigDecimal.valueOf(Float.valueOf(nodeValue));
|
||||
} catch (final Exception ex) {
|
||||
return new BigDecimal("0.00");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tries to convert a Node to a BigDecimal.
|
||||
*
|
||||
* @param node The value as String
|
||||
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
|
||||
*/
|
||||
public static BigDecimal tryBigDecimal(Node node) {
|
||||
final String nodeValue = XMLTools.getNodeValue(node);
|
||||
if (nodeValue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return XMLTools.tryBigDecimal(nodeValue);
|
||||
}
|
||||
/***
|
||||
* formats a number so that at least minDecimals are displayed but at the maximum maxDecimals are there, i.e.
|
||||
* cuts potential 0s off the end until minDecimals
|
||||
* @param value the value to be formatted
|
||||
* @param maxDecimals number of maximal scale
|
||||
* @param minDecimals number of minimal scale
|
||||
* @return value as String with decimals in the specified range
|
||||
*/
|
||||
public static String nDigitFormatDecimalRange(BigDecimal value, int maxDecimals, int minDecimals) {
|
||||
if ((maxDecimals<minDecimals)||(maxDecimals<0)||(minDecimals<0)) {
|
||||
throw new IllegalArgumentException("Invalid scale range provided");
|
||||
}
|
||||
int curDecimals=maxDecimals;
|
||||
while ( (curDecimals>minDecimals) && (value.setScale(curDecimals, RoundingMode.HALF_UP).compareTo(value.setScale(curDecimals-1, RoundingMode.HALF_UP))==0)) {
|
||||
curDecimals--;
|
||||
}
|
||||
return value.setScale(curDecimals, RoundingMode.HALF_UP).toPlainString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* returns a util.Date from a 102 String yyyymmdd in a node
|
||||
* @param node the node
|
||||
* @return a util.Date, or null, if not parseable
|
||||
*/
|
||||
public static Date tryDate(Node node) {
|
||||
final String nodeValue = XMLTools.getNodeValue(node);
|
||||
if (nodeValue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return tryDate(nodeValue);
|
||||
}
|
||||
|
||||
/***
|
||||
* returns a util.Date from a 102 String yyyymmdd
|
||||
* @param toParse the string
|
||||
* @return a util.Date, or null, if not parseable
|
||||
*/
|
||||
public static Date tryDate(String toParse) {
|
||||
SimpleDateFormat formatter = null;
|
||||
if (toParse==null) {
|
||||
return null;
|
||||
}
|
||||
if (toParse.contains("-")) {
|
||||
// from ubl
|
||||
formatter = new SimpleDateFormat("yyyy-MM-dd");
|
||||
} else {
|
||||
formatter = ZUGFeRDDateFormat.DATE.getFormatter();
|
||||
}
|
||||
try {
|
||||
return formatter.parse(toParse);
|
||||
} catch (final Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* relplaces some entities like < , > and & with their escaped pendant like &lt;
|
||||
* @param s the string
|
||||
* @return the "safe" string
|
||||
*/
|
||||
public static String encodeXML(CharSequence s) {
|
||||
if (s == null) {
|
||||
return "";
|
||||
@@ -140,7 +220,20 @@ public class XMLTools extends XMLWriter {
|
||||
}
|
||||
|
||||
public static byte[] getBytesFromStream(InputStream fileinput) throws IOException {
|
||||
return IOUtils.toByteArray (fileinput);
|
||||
// Stream closing responsibility is with the caller
|
||||
return IOUtils.toByteArray(fileinput);
|
||||
}
|
||||
|
||||
|
||||
public static String trimOrNull(Node node) {
|
||||
if (node != null) {
|
||||
String textContent = node.getTextContent();
|
||||
if (textContent != null) {
|
||||
return textContent.trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
* Copyright (c) 2024 Jan N. Klug
|
||||
* <p>
|
||||
* Use is subject to license terms.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* <p>
|
||||
* **********************************************************************
|
||||
*/
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import org.mustangproject.ClassCode;
|
||||
|
||||
/**
|
||||
* A product classification that allows to describe a product. Classification codes are schemed by the available systems in UNTDID 7143.
|
||||
*/
|
||||
public interface IDesignatedProductClassification {
|
||||
/**
|
||||
* Classification code
|
||||
*
|
||||
* @return the classification code
|
||||
*/
|
||||
ClassCode getClassCode();
|
||||
|
||||
/**
|
||||
* an optional, human-readable description of the classifcation code
|
||||
*
|
||||
* @return the name or {@code null} if not set
|
||||
*/
|
||||
default String getClassName() { return null; }
|
||||
}
|
||||
@@ -30,11 +30,13 @@ package org.mustangproject.ZUGFeRD;
|
||||
* */
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.mustangproject.FileAttachment;
|
||||
import org.mustangproject.IncludedNote;
|
||||
import org.mustangproject.ReferencedDocument;
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
||||
|
||||
/***
|
||||
@@ -303,8 +305,7 @@ public interface IExportableTransaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* get payment terms. if set, getPaymentTermDescription() and getDueDate() are
|
||||
* ignored
|
||||
* get payment terms. if set, getPaymentTermDescription() and getDueDate() are ignored
|
||||
*
|
||||
* @return the IZUGFeRDPaymentTerms of the invoice
|
||||
*/
|
||||
@@ -312,6 +313,18 @@ public interface IExportableTransaction {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getPaymentReference() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get payment terms for the EXTENDED profile (multiple terms are allowed)
|
||||
* @return
|
||||
*/
|
||||
default IZUGFeRDPaymentTerms[] getExtendedPaymentTerms() {
|
||||
return new IZUGFeRDPaymentTerms[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if a rebate agreements exists
|
||||
*
|
||||
@@ -322,10 +335,20 @@ public interface IExportableTransaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* get reference document number typically used for Invoice Corrections Will be
|
||||
* added as IncludedNote in comfort profile
|
||||
* get the rounding amount
|
||||
* (only to be usef for NL whose currency requires a rounding to 5ct)
|
||||
*
|
||||
* @return the ID of the document this document refers to
|
||||
* @return the Bigdecimal
|
||||
*/
|
||||
default BigDecimal getRoundingAmount() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get BuyerReference (BT-10) an identifier assigned by the buyer and used
|
||||
* for internal routing. Used for the Leitweg-ID.
|
||||
*
|
||||
* @return the BuyerReference of this document
|
||||
*/
|
||||
default String getReferenceNumber() {
|
||||
return null;
|
||||
@@ -415,13 +438,23 @@ public interface IExportableTransaction {
|
||||
*
|
||||
* @return the ID of the document
|
||||
*/
|
||||
@Deprecated
|
||||
default String getInvoiceReferencedDocumentID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default Date getInvoiceReferencedIssueDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for BG-3
|
||||
* @return list of documents
|
||||
*/
|
||||
default ArrayList<ReferencedDocument> getInvoiceReferencedDocuments() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the issue timestamp of the BuyerOrderReferencedDocument, which sits in
|
||||
@@ -450,11 +483,19 @@ public interface IExportableTransaction {
|
||||
*
|
||||
* @return the IZUGFeRDExportableTradeParty delivery address
|
||||
*/
|
||||
|
||||
default IZUGFeRDExportableTradeParty getDeliveryAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* payee / payment receiver, if different from seller, ram:Payee (only supported for zf2)
|
||||
*
|
||||
* @return the IZUGFeRDExportableTradeParty payment receiver, if different from sellver
|
||||
*/
|
||||
default IZUGFeRDExportableTradeParty getPayee() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* specifies the document level delivery period, will be included in a
|
||||
* BillingSpecifiedPeriod element
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface IReferencedDocument {
|
||||
|
||||
/***
|
||||
@@ -20,4 +22,12 @@ public interface IReferencedDocument {
|
||||
*/
|
||||
String getReferenceTypeCode();
|
||||
|
||||
/***
|
||||
*
|
||||
* issue date of this line
|
||||
*
|
||||
* @return date of the issue
|
||||
*/
|
||||
Date getFormattedIssueDateTime();
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,12 @@ public interface IZUGFeRDAllowanceCharge {
|
||||
*/
|
||||
default BigDecimal getPercent() {return null;}
|
||||
|
||||
/***
|
||||
* returns a basis the precentage is calculated from
|
||||
* @return null or the basis
|
||||
*/
|
||||
default BigDecimal getBasisAmount() {return null;}
|
||||
|
||||
/***
|
||||
* get a description for the allowance/charge
|
||||
* @return the description
|
||||
|
||||
@@ -28,7 +28,9 @@ package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.mustangproject.IncludedNote;
|
||||
import org.mustangproject.Item;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
@@ -41,7 +43,11 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
||||
* item level discounts
|
||||
* @return array of the discounts on a single item
|
||||
*/
|
||||
@Deprecated
|
||||
default IZUGFeRDAllowanceCharge[] getItemAllowances() {
|
||||
if (getProduct()!=null) {
|
||||
return getProduct().getAllowances();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -49,7 +55,25 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
||||
* item level price additions
|
||||
* @return array of the additional charges on the item
|
||||
*/
|
||||
@Deprecated
|
||||
default IZUGFeRDAllowanceCharge[] getItemCharges() {
|
||||
if (getProduct()!=null) {
|
||||
return getProduct().getCharges();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default IZUGFeRDAllowanceCharge[] getAllowances() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* item level price additions
|
||||
* @return array of the additional charges on the item
|
||||
*/
|
||||
@Deprecated
|
||||
default IZUGFeRDAllowanceCharge[] getCharges() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -90,7 +114,7 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
||||
|
||||
/**
|
||||
* how many items units per price
|
||||
*
|
||||
*
|
||||
* @return item units per price
|
||||
*/
|
||||
default BigDecimal getBasisQuantity() {
|
||||
@@ -150,14 +174,35 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
||||
default Date getDetailedDeliveryPeriodTo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* specify allowances amount for the line item total
|
||||
* get all (allowances and charges) SpecifiedTradeAllowanceCharges
|
||||
*
|
||||
* @return the sum of allowances for this item
|
||||
* @return the real item lecel SpecifiedTradeAllowanceCharges
|
||||
*/
|
||||
default IZUGFeRDAllowanceCharge[] getItemTotalAllowances() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
*
|
||||
* @return the line ID
|
||||
*/
|
||||
default String getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A grouping of business terms to indicate accounting-relevant free texts including a qualification of these.
|
||||
*
|
||||
* The information are written to the same xml nodes like {@link #getNotes()} but with explicit subjectCode.
|
||||
* @return list of the notes
|
||||
*/
|
||||
default List<IncludedNote> getNotesWithSubjectCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getAccountingReference() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,4 +165,30 @@ public interface IZUGFeRDExportableProduct {
|
||||
default HashMap<String, String> getAttributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* product level discounts (AppliedTradeAllowanceCharge, will change net price)
|
||||
* @return array of the discounts on a single product
|
||||
*/
|
||||
default IZUGFeRDAllowanceCharge[] getAllowances() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* product level charges (AppliedTradeAllowanceCharge, will change net price)
|
||||
* @return array of the additional charges on the product
|
||||
*/
|
||||
default IZUGFeRDAllowanceCharge[] getCharges() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Detailed information about the product
|
||||
*
|
||||
* @return an array containing the product classifications or {@code null} if not set
|
||||
*/
|
||||
default IDesignatedProductClassification[] getClassifications() { return null; }
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ public interface IZUGFeRDTradeSettlementDebit extends IZUGFeRDTradeSettlement {
|
||||
@Override
|
||||
default String getSettlementXML() {
|
||||
String xml = "<ram:SpecifiedTradeSettlementPaymentMeans>"
|
||||
+ "<ram:TypeCode>59</ram:TypeCode>"
|
||||
+ "<ram:Information>SEPA direct debit</ram:Information>"
|
||||
+ "<ram:TypeCode>" + XMLTools.encodeXML(getPaymentMeansCode()) + "</ram:TypeCode>"
|
||||
+ "<ram:Information>" + XMLTools.encodeXML(getPaymentMeansInformation()) + "</ram:Information>"
|
||||
+ "<ram:PayerPartyDebtorFinancialAccount>"
|
||||
+ "<ram:IBANID>" + XMLTools.encodeXML(getIBAN()) + "</ram:IBANID>"
|
||||
+ "</ram:PayerPartyDebtorFinancialAccount>";
|
||||
@@ -51,4 +51,14 @@ public interface IZUGFeRDTradeSettlementDebit extends IZUGFeRDTradeSettlement {
|
||||
*/
|
||||
String getMandate();
|
||||
|
||||
/***
|
||||
* @return payment means code (BT-81 / UNTDID 4461)
|
||||
*/
|
||||
String getPaymentMeansCode();
|
||||
|
||||
/***
|
||||
* @return payment means description (BT-82) (optional)
|
||||
*/
|
||||
String getPaymentMeansInformation();
|
||||
|
||||
}
|
||||
|
||||
@@ -2,30 +2,49 @@ package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/***
|
||||
* the linecalculator does the math within an item line, and e.g. calculates quantity*price.
|
||||
* @see TransactionCalculator
|
||||
*/
|
||||
public class LineCalculator {
|
||||
private final BigDecimal price;
|
||||
private final BigDecimal priceGross;
|
||||
private final BigDecimal itemTotalNetAmount;
|
||||
private final BigDecimal itemTotalVATAmount;
|
||||
private BigDecimal allowance = BigDecimal.ZERO;
|
||||
private BigDecimal charge = BigDecimal.ZERO;
|
||||
private BigDecimal allowanceItemTotal = BigDecimal.ZERO;
|
||||
protected BigDecimal price;
|
||||
protected BigDecimal priceGross;
|
||||
protected BigDecimal itemTotalNetAmount;
|
||||
protected BigDecimal itemTotalVATAmount;
|
||||
protected BigDecimal lineAllowance = BigDecimal.ZERO;
|
||||
protected BigDecimal lineCharge = BigDecimal.ZERO;
|
||||
protected BigDecimal itemAllowance = BigDecimal.ZERO;
|
||||
protected BigDecimal itemCharge = BigDecimal.ZERO;
|
||||
protected BigDecimal allowanceItemTotal = BigDecimal.ZERO;
|
||||
|
||||
public LineCalculator(IZUGFeRDExportableItem currentItem) {
|
||||
|
||||
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
|
||||
for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
|
||||
addAllowance(allowance.getTotalAmount(currentItem));
|
||||
BigDecimal factor=BigDecimal.ONE;
|
||||
BigDecimal singleAllowance=allowance.getTotalAmount(currentItem);
|
||||
addItemAllowance(singleAllowance);
|
||||
|
||||
if ((allowance.getPercent()!=null)&&(allowance.getPercent().compareTo(BigDecimal.ZERO)!=0)) {
|
||||
factor=currentItem.getQuantity();
|
||||
}
|
||||
addAllowanceItemTotal(singleAllowance.multiply(factor));
|
||||
|
||||
}
|
||||
}
|
||||
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
|
||||
for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
|
||||
addCharge(charge.getTotalAmount(currentItem));
|
||||
BigDecimal factor=BigDecimal.ONE;
|
||||
BigDecimal singleCharge=charge.getTotalAmount(currentItem);
|
||||
addItemCharge(singleCharge);
|
||||
if ((charge.getPercent()!=null)&&(charge.getPercent().compareTo(BigDecimal.ZERO)!=0)) {
|
||||
factor=currentItem.getQuantity();
|
||||
}
|
||||
subtractAllowanceItemTotal(singleCharge.multiply(factor));
|
||||
|
||||
}
|
||||
}
|
||||
if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) {
|
||||
@@ -34,16 +53,47 @@ public class LineCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal vatPercent = currentItem.getProduct().getVATPercent();
|
||||
if (vatPercent == null)
|
||||
BigDecimal vatPercent = null;
|
||||
if (currentItem.getProduct()!=null) {
|
||||
vatPercent = currentItem.getProduct().getVATPercent();
|
||||
}
|
||||
if (vatPercent == null) {
|
||||
vatPercent = BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100));
|
||||
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
|
||||
price = priceGross.subtract(allowance).add(charge);
|
||||
itemTotalNetAmount = currentItem.getQuantity().multiply(getPrice()).divide(currentItem.getBasisQuantity())
|
||||
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
|
||||
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
|
||||
|
||||
BigDecimal quantity=BigDecimal.ZERO;
|
||||
if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) {
|
||||
quantity=currentItem.getQuantity();
|
||||
}
|
||||
|
||||
price=currentItem.getPrice();
|
||||
priceGross=price;
|
||||
// price=price.subtract(itemAllowance).add(itemCharge);
|
||||
// BigDecimal delta=charge.subtract(allowanceItemTotal).subtract(allowance);
|
||||
// delta=delta.divide(currentItem.getQuantity(), 18, RoundingMode.HALF_UP);
|
||||
|
||||
BigDecimal delta=BigDecimal.ZERO;
|
||||
if (currentItem.getProduct().getAllowances()!=null) {
|
||||
for (IZUGFeRDAllowanceCharge ccaf:currentItem.getProduct().getAllowances()) {
|
||||
delta=delta.subtract(ccaf.getTotalAmount(currentItem));
|
||||
}
|
||||
}
|
||||
if (currentItem.getProduct().getCharges()!=null) {
|
||||
for (IZUGFeRDAllowanceCharge ccaf : currentItem.getProduct().getCharges()) {
|
||||
delta = delta.subtract(ccaf.getTotalAmount(currentItem));
|
||||
}
|
||||
}
|
||||
|
||||
price=price.add(delta);
|
||||
// Division/Zero occurred here.
|
||||
// Used the setScale only because that's also done in getBasisQuantity
|
||||
BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0
|
||||
? BigDecimal.ONE.setScale(4)
|
||||
: currentItem.getBasisQuantity();
|
||||
itemTotalNetAmount = quantity.multiply(price).divide(basisQuantity, 18, RoundingMode.HALF_UP)
|
||||
.add(lineCharge).subtract(lineAllowance).subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
|
||||
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);//.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
@@ -66,16 +116,27 @@ public class LineCalculator {
|
||||
return priceGross;
|
||||
}
|
||||
|
||||
public void addAllowance(BigDecimal b) {
|
||||
allowance = allowance.add(b);
|
||||
public void addLineAllowance(BigDecimal b) {
|
||||
lineAllowance = lineAllowance.add(b);
|
||||
}
|
||||
|
||||
public void addCharge(BigDecimal b) {
|
||||
charge = charge.add(b);
|
||||
public void addLineCharge(BigDecimal b) {
|
||||
lineCharge = lineCharge.add(b);
|
||||
}
|
||||
|
||||
public void addItemAllowance(BigDecimal b) {
|
||||
itemAllowance = itemAllowance.add(b);
|
||||
}
|
||||
|
||||
public void addItemCharge(BigDecimal b) {
|
||||
itemCharge = itemCharge.add(b);
|
||||
}
|
||||
|
||||
public void addAllowanceItemTotal(BigDecimal b) {
|
||||
allowanceItemTotal = allowanceItemTotal.add(b);
|
||||
}
|
||||
public void subtractAllowanceItemTotal(BigDecimal b) {
|
||||
allowanceItemTotal = allowanceItemTotal.subtract(b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.Map;
|
||||
|
||||
import org.mustangproject.EStandard;
|
||||
import org.mustangproject.FileAttachment;
|
||||
import org.mustangproject.ReferencedDocument;
|
||||
import org.mustangproject.XMLTools;
|
||||
|
||||
public class OXPullProvider extends ZUGFeRD2PullProvider {
|
||||
@@ -459,6 +460,19 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
|
||||
}
|
||||
xml += "</ram:InvoiceReferencedDocument>";
|
||||
}
|
||||
if (trans.getInvoiceReferencedDocuments() != null) {
|
||||
for (ReferencedDocument doc : trans.getInvoiceReferencedDocuments()) {
|
||||
xml += "<ram:InvoiceReferencedDocument>"
|
||||
+ "<ram:IssuerAssignedID>"
|
||||
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
|
||||
if (doc.getFormattedIssueDateTime() != null) {
|
||||
xml += "<ram:FormattedIssueDateTime>"
|
||||
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
|
||||
+ "</ram:FormattedIssueDateTime>";
|
||||
}
|
||||
xml += "</ram:InvoiceReferencedDocument>";
|
||||
}
|
||||
}
|
||||
|
||||
xml += "</ram:ApplicableHeaderTradeSettlement>";
|
||||
// + " <IncludedSupplyChainTradeLineItem>"
|
||||
@@ -492,36 +506,44 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
|
||||
|
||||
private String buildPaymentTermsXml() {
|
||||
|
||||
final IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
|
||||
if (paymentTerms == null) {
|
||||
final IZUGFeRDPaymentTerms[] paymentTerms = trans.getExtendedPaymentTerms();
|
||||
|
||||
String paymentTermsXml = "";
|
||||
if (paymentTerms == null || paymentTerms.length == 0) {
|
||||
return "";
|
||||
}
|
||||
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
|
||||
|
||||
final IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
|
||||
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
|
||||
if (discountTerms != null) {
|
||||
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
|
||||
final String currency = trans.getCurrency();
|
||||
final String basisAmount = currencyFormat(calc.getGrandTotal());
|
||||
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
|
||||
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
|
||||
for (IZUGFeRDPaymentTerms pt : paymentTerms)
|
||||
{
|
||||
paymentTermsXml += "<ram:SpecifiedTradePaymentTerms>";
|
||||
|
||||
final IZUGFeRDPaymentDiscountTerms discountTerms = pt.getDiscountTerms();
|
||||
paymentTermsXml += "<ram:Description>" + pt.getDescription() + "</ram:Description>";
|
||||
if (discountTerms != null)
|
||||
{
|
||||
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
|
||||
final String currency = trans.getCurrency();
|
||||
final String basisAmount = currencyFormat(calc.getGrandTotal());
|
||||
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
|
||||
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
|
||||
+ "</ram:CalculationPercent>";
|
||||
|
||||
if (discountTerms.getBaseDate() != null) {
|
||||
final Date baseDate = discountTerms.getBaseDate();
|
||||
paymentTermsXml += "<ram:BasisDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(baseDate);
|
||||
paymentTermsXml += "</ram:BasisDateTime>";
|
||||
if (discountTerms.getBaseDate() != null)
|
||||
{
|
||||
final Date baseDate = discountTerms.getBaseDate();
|
||||
paymentTermsXml += "<ram:BasisDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(baseDate);
|
||||
paymentTermsXml += "</ram:BasisDateTime>";
|
||||
|
||||
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
|
||||
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
|
||||
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
|
||||
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
return paymentTermsXml;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ import org.apache.pdfbox.preflight.parser.PreflightParser;
|
||||
|
||||
import jakarta.activation.DataSource;
|
||||
|
||||
// Copied from PDFBox preflight 2.0.x
|
||||
// Copied from PDFBox preflight 2.0.x
|
||||
final class ByteArrayDataSource implements DataSource
|
||||
{
|
||||
private ByteArrayOutputStream data;
|
||||
private String type = null;
|
||||
private String name = null;
|
||||
|
||||
public ByteArrayDataSource (InputStream is) throws IOException
|
||||
public ByteArrayDataSource (final InputStream is) throws IOException
|
||||
{
|
||||
data = new ByteArrayOutputStream ();
|
||||
IOUtils.copy (is, data);
|
||||
@@ -36,7 +36,7 @@ final class ByteArrayDataSource implements DataSource
|
||||
* @param type
|
||||
* the type to set
|
||||
*/
|
||||
public void setType (String type)
|
||||
public void setType (final String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ final class ByteArrayDataSource implements DataSource
|
||||
* @param name
|
||||
* the name to set
|
||||
*/
|
||||
public void setName (String name)
|
||||
public void setName (final String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
@@ -70,12 +70,13 @@ final class ByteArrayDataSource implements DataSource
|
||||
// Try to create an API similar to the 2.x one
|
||||
final class PreflightParserHelper
|
||||
{
|
||||
private static File createTmpFile (InputStream input) throws IOException
|
||||
private static File createTmpFile (final InputStream input) throws IOException
|
||||
{
|
||||
FileOutputStream fos = null;
|
||||
try
|
||||
{
|
||||
File tmpFile = File.createTempFile ("mustang-pdf", ".pdf");
|
||||
final File tmpFile = File.createTempFile ("mustang-pdf", ".pdf");
|
||||
tmpFile.deleteOnExit ();
|
||||
fos = new FileOutputStream (tmpFile);
|
||||
IOUtils.copy (input, fos);
|
||||
return tmpFile;
|
||||
@@ -87,7 +88,7 @@ final class PreflightParserHelper
|
||||
}
|
||||
}
|
||||
|
||||
public static PreflightParser createPreflightParser (DataSource dataSource) throws IOException
|
||||
public static PreflightParser createPreflightParser (final DataSource dataSource) throws IOException
|
||||
{
|
||||
return new PreflightParser (createTmpFile (dataSource.getInputStream ()));
|
||||
}
|
||||
|
||||
@@ -4,13 +4,17 @@ import static java.math.BigDecimal.ZERO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/***
|
||||
* The Transactioncalculator e.g. adds the line totals and applies VAT on whole
|
||||
* invoices
|
||||
*
|
||||
*
|
||||
* @see LineCalculator
|
||||
*/
|
||||
public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
@@ -27,7 +31,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
/***
|
||||
* if something had already been paid in advance, this will get it from the
|
||||
* transaction
|
||||
*
|
||||
*
|
||||
* @return prepaid amount
|
||||
*/
|
||||
protected BigDecimal getTotalPrepaid() {
|
||||
@@ -39,21 +43,21 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
}
|
||||
|
||||
/***
|
||||
* the invoice total with VAT, corrected by prepaid amount, allowances and
|
||||
* charges
|
||||
*
|
||||
* the invoice total with VAT, allowances and
|
||||
* charges, WITHOUT considering prepaid amount
|
||||
*
|
||||
* @return the invoice total including taxes
|
||||
*/
|
||||
public BigDecimal getGrandTotal() {
|
||||
|
||||
final BigDecimal res = getTaxBasis();
|
||||
BigDecimal basis = getTaxBasis();
|
||||
return getVATPercentAmountMap().values().stream().map(VATAmount::getCalculated)
|
||||
.map(p -> p.setScale(2, RoundingMode.HALF_UP)).reduce(BigDecimal.ZERO, BigDecimal::add).add(res);
|
||||
.map(p -> p.setScale(2, RoundingMode.HALF_UP)).reduce(BigDecimal.ZERO, BigDecimal::add).add(basis);
|
||||
}
|
||||
|
||||
/***
|
||||
* returns total of charges for this tax rate
|
||||
*
|
||||
*
|
||||
* @param percent a specific rate, or null for any rate
|
||||
* @return the total amount
|
||||
*/
|
||||
@@ -62,6 +66,24 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
return sumAllowanceCharge(percent, charges);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns information about every tax that is involved in the current transaction.
|
||||
*
|
||||
* @return transaction taxes.
|
||||
*/
|
||||
public Set<VATAmount> getTaxDetails() {
|
||||
return getVATPercentAmountMap().entrySet().stream()
|
||||
.map(entry ->
|
||||
new VATAmount(
|
||||
entry.getValue().getBasis(),
|
||||
entry.getValue().getCalculated(),
|
||||
entry.getValue().getCategoryCode()
|
||||
).setApplicablePercent(entry.getKey())
|
||||
)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private BigDecimal sumAllowanceCharge(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
|
||||
BigDecimal res = BigDecimal.ZERO;
|
||||
if ((charges != null) && (charges.length > 0)) {
|
||||
@@ -77,7 +99,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
/***
|
||||
* returns a (potentially concatenated) string of charge reasons, or "Charges"
|
||||
* if none are defined
|
||||
*
|
||||
*
|
||||
* @param percent a specific rate, or null for any rate
|
||||
* @return the space separated String
|
||||
*/
|
||||
@@ -91,23 +113,20 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
}
|
||||
|
||||
private String getAllowanceChargeReasonForPercent(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
|
||||
String res = " ";
|
||||
if ((charges != null) && (charges.length > 0)) {
|
||||
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
|
||||
if ((percent == null) || (currentCharge.getTaxPercent().compareTo(percent) == 0)
|
||||
&& currentCharge.getReason() != null) {
|
||||
res += currentCharge.getReason() + " ";
|
||||
}
|
||||
}
|
||||
if (charges == null) {
|
||||
return "";
|
||||
}
|
||||
res = res.substring(0, res.length() - 1);
|
||||
return res;
|
||||
return Arrays.stream(charges)
|
||||
.filter(currentCharge -> (percent == null || currentCharge.getTaxPercent().compareTo(percent) == 0))
|
||||
.map(IZUGFeRDAllowanceCharge::getReason)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
/***
|
||||
* returns a (potentially concatenated) string of allowance reasons, or
|
||||
* "Allowances", if none are defined
|
||||
*
|
||||
*
|
||||
* @param percent a specific rate, or null for any rate
|
||||
* @return the space separated String
|
||||
*/
|
||||
@@ -122,7 +141,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
|
||||
/***
|
||||
* returns total of allowances for this tax rate
|
||||
*
|
||||
*
|
||||
* @param percent a specific rate, or null for any rate
|
||||
* @return the total amount
|
||||
*/
|
||||
@@ -134,25 +153,25 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
/***
|
||||
* returns the total net value of all items, without document level
|
||||
* charges/allowances
|
||||
*
|
||||
*
|
||||
* @return item sum
|
||||
*/
|
||||
protected BigDecimal getTotal() {
|
||||
BigDecimal dec = Stream.of(trans.getZFItems()).map(LineCalculator::new)
|
||||
.map(LineCalculator::getItemTotalNetAmount).reduce(ZERO, BigDecimal::add);
|
||||
.map(LineCalculator::getItemTotalNetAmount).reduce(ZERO, BigDecimal::add);
|
||||
return dec;
|
||||
}
|
||||
|
||||
/***
|
||||
* returns the total net value of the invoice, including charges/allowances on
|
||||
* document level
|
||||
*
|
||||
*
|
||||
* @return item sum +- charges/allowances
|
||||
*/
|
||||
protected BigDecimal getTaxBasis() {
|
||||
public BigDecimal getTaxBasis() {
|
||||
return getTotal().add(getChargesForPercent(null).setScale(2, RoundingMode.HALF_UP))
|
||||
.subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP))
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
.subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP))
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,11 +186,18 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
final String vatDueDateTypeCode = trans.getVATDueDateTypeCode();
|
||||
|
||||
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
|
||||
BigDecimal percent = currentItem.getProduct().getVATPercent();
|
||||
BigDecimal percent = null;
|
||||
if (currentItem.getProduct() != null) {
|
||||
percent = currentItem.getProduct().getVATPercent();
|
||||
}
|
||||
if (percent != null) {
|
||||
LineCalculator lc = new LineCalculator(currentItem);
|
||||
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
|
||||
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
|
||||
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
|
||||
String reasonText = currentItem.getProduct().getTaxExemptionReason();
|
||||
if (reasonText != null) {
|
||||
itemVATAmount.setVatExemptionReasonText(reasonText);
|
||||
}
|
||||
VATAmount current = hm.get(percent.stripTrailingZeros());
|
||||
if (current == null) {
|
||||
hm.put(percent.stripTrailingZeros(), itemVATAmount);
|
||||
@@ -189,8 +215,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
VATAmount theAmount = hm.get(taxPercent.stripTrailingZeros());
|
||||
if (theAmount == null) {
|
||||
theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
|
||||
currentCharge.getCategoryCode() != null ? currentCharge.getCategoryCode() : "S",
|
||||
vatDueDateTypeCode);
|
||||
currentCharge.getCategoryCode() != null ? currentCharge.getCategoryCode() : "S",
|
||||
vatDueDateTypeCode);
|
||||
}
|
||||
theAmount.setBasis(theAmount.getBasis().add(currentCharge.getTotalAmount(this)));
|
||||
BigDecimal factor = taxPercent.divide(new BigDecimal(100));
|
||||
@@ -207,8 +233,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
VATAmount theAmount = hm.get(taxPercent.stripTrailingZeros());
|
||||
if (theAmount == null) {
|
||||
theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
|
||||
currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S",
|
||||
vatDueDateTypeCode);
|
||||
currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S",
|
||||
vatDueDateTypeCode);
|
||||
}
|
||||
theAmount.setBasis(theAmount.getBasis().subtract(currentAllowance.getTotalAmount(this)));
|
||||
BigDecimal factor = taxPercent.divide(new BigDecimal(100));
|
||||
@@ -235,4 +261,11 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
return getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
public BigDecimal getDuePayable() {
|
||||
BigDecimal res = getGrandTotal().subtract(getTotalPrepaid());
|
||||
if (trans.getRoundingAmount() != null) {
|
||||
res = res.add(trans.getRoundingAmount());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,16 @@ import java.math.RoundingMode;
|
||||
*/
|
||||
public class VATAmount {
|
||||
|
||||
|
||||
protected BigDecimal basis, calculated, applicablePercent;
|
||||
|
||||
protected String categoryCode;
|
||||
|
||||
protected String vatExemptionReasonText;
|
||||
|
||||
protected String dueDateTypeCode;
|
||||
|
||||
|
||||
public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) {
|
||||
super();
|
||||
this.basis = basis;
|
||||
@@ -48,35 +58,41 @@ public class VATAmount {
|
||||
this.dueDateTypeCode = dueDateTypeCode;
|
||||
}
|
||||
|
||||
BigDecimal basis, calculated, applicablePercent;
|
||||
|
||||
String categoryCode;
|
||||
|
||||
String dueDateTypeCode;
|
||||
|
||||
public BigDecimal getApplicablePercent() {
|
||||
return applicablePercent;
|
||||
}
|
||||
|
||||
public void setApplicablePercent(BigDecimal applicablePercent) {
|
||||
public VATAmount setApplicablePercent(BigDecimal applicablePercent) {
|
||||
|
||||
this.applicablePercent = applicablePercent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BigDecimal getBasis() {
|
||||
return basis;
|
||||
}
|
||||
|
||||
public void setBasis(BigDecimal basis) {
|
||||
public VATAmount setBasis(BigDecimal basis) {
|
||||
this.basis = basis.setScale(2, RoundingMode.HALF_UP);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public BigDecimal getCalculated() {
|
||||
return calculated;
|
||||
}
|
||||
|
||||
public void setCalculated(BigDecimal calculated) {
|
||||
public VATAmount setCalculated(BigDecimal calculated) {
|
||||
this.calculated = calculated;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getVatExemptionReasonText() {
|
||||
return vatExemptionReasonText;
|
||||
}
|
||||
|
||||
public VATAmount setVatExemptionReasonText(String theText) {
|
||||
this.vatExemptionReasonText = theText;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,34 +108,38 @@ public class VATAmount {
|
||||
/**
|
||||
* @param documentCode as String
|
||||
* @deprecated Use {@link #setCategoryCode(String)} instead
|
||||
* @return fluent setter
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDocumentCode(String documentCode) {
|
||||
public VATAmount setDocumentCode(String documentCode) {
|
||||
this.categoryCode = documentCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCategoryCode() {
|
||||
return categoryCode;
|
||||
}
|
||||
|
||||
public void setCategoryCode(String categoryCode) {
|
||||
public VATAmount setCategoryCode(String categoryCode) {
|
||||
this.categoryCode = categoryCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDueDateTypeCode() {
|
||||
return dueDateTypeCode;
|
||||
}
|
||||
|
||||
public void setDueDateTypeCode(String dueDateTypeCode) {
|
||||
public VATAmount setDueDateTypeCode(String dueDateTypeCode) {
|
||||
this.dueDateTypeCode = dueDateTypeCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VATAmount add(VATAmount v) {
|
||||
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode);
|
||||
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText() != null ? v.getVatExemptionReasonText(): this.vatExemptionReasonText);
|
||||
}
|
||||
|
||||
public VATAmount subtract(VATAmount v) {
|
||||
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode, this.dueDateTypeCode);
|
||||
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringReader;
|
||||
import org.apache.fop.apps.*;
|
||||
import org.apache.fop.apps.io.ResourceResolverFactory;
|
||||
import org.apache.fop.configuration.Configuration;
|
||||
import org.apache.fop.configuration.ConfigurationException;
|
||||
import org.apache.fop.configuration.DefaultConfigurationBuilder;
|
||||
import org.apache.xmlgraphics.util.MimeConstants;
|
||||
import org.mustangproject.ClasspathResolverURIAdapter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.sax.SAXResult;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ValidationLogVisualizer {
|
||||
public enum Language {
|
||||
EN,
|
||||
FR,
|
||||
DE
|
||||
}
|
||||
|
||||
static final ClassLoader CLASS_LOADER = ValidationLogVisualizer.class.getClassLoader();
|
||||
private static final String RESOURCE_PATH = "";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ValidationLogVisualizer.class);
|
||||
|
||||
private TransformerFactory mFactory = null;
|
||||
private Templates mXsltPDFTemplate = null;
|
||||
|
||||
|
||||
public ValidationLogVisualizer() {
|
||||
mFactory = new net.sf.saxon.TransformerFactoryImpl();
|
||||
// fact = TransformerFactory.newInstance();
|
||||
mFactory.setURIResolver(new ValidationLogVisualizer.ClasspathResourceURIResolver());
|
||||
}
|
||||
|
||||
protected void applyXSLTToPDF(final String xmlContent, final OutputStream PDFOutstream)
|
||||
throws TransformerException {
|
||||
Transformer transformer = mXsltPDFTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(new StringReader(xmlContent)), new StreamResult(PDFOutstream));
|
||||
}
|
||||
|
||||
protected String toFOP(final String xmlContent)
|
||||
throws TransformerException {
|
||||
|
||||
try {
|
||||
if (mXsltPDFTemplate == null) {
|
||||
mXsltPDFTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/result-pdf.xsl")));
|
||||
}
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
LOGGER.error("Failed to init XSLT templates", ex);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
|
||||
applyXSLTToPDF(xmlContent, baos);
|
||||
|
||||
} catch (Exception e1) {
|
||||
LOGGER.error("Failed to create PDF", e1);
|
||||
}
|
||||
|
||||
return baos.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public byte[] createPDFBytes(String xmlLogfileContent) {
|
||||
|
||||
// the writing part
|
||||
|
||||
String result = null;
|
||||
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*/
|
||||
try {
|
||||
result = this.toFOP(xmlLogfileContent);
|
||||
} catch ( TransformerException e) {
|
||||
LOGGER.error("Failed to apply FOP", e);
|
||||
}
|
||||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
|
||||
|
||||
Configuration cfg = null;
|
||||
try {
|
||||
cfg = cfgBuilder.build(CLASS_LOADER.getResourceAsStream("fop-config.xconf"));
|
||||
} catch (ConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI(), new ClasspathResolverURIAdapter()).setConfiguration(cfg);
|
||||
// Step 1: Construct a FopFactory by specifying a reference to the configuration file
|
||||
// (reuse if you plan to render multiple documents!)
|
||||
|
||||
FopFactory fopFactory = builder.build();
|
||||
|
||||
fopFactory.getFontManager().setResourceResolver(
|
||||
ResourceResolverFactory.createInternalResourceResolver(
|
||||
new File(".").toURI(),
|
||||
new ClasspathResolverURIAdapter()));
|
||||
|
||||
FOUserAgent userAgent = fopFactory.newFOUserAgent();
|
||||
|
||||
userAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-3b");
|
||||
|
||||
// Step 2: Set up output stream.
|
||||
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (OutputStream out = new BufferedOutputStream(baos)) {
|
||||
|
||||
// Step 3: Construct fop with desired output format
|
||||
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);
|
||||
|
||||
// Step 4: Setup JAXP using identity transformer
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
Transformer transformer = factory.newTransformer(); // identity transformer
|
||||
|
||||
// Step 5: Setup input and output for XSLT transformation
|
||||
// Setup input stream
|
||||
Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
// Resulting SAX events (the generated FO) must be piped through to FOP
|
||||
Result res = new SAXResult(fop.getDefaultHandler());
|
||||
|
||||
// Step 6: Start XSLT transformation and FOP processing
|
||||
transformer.transform(src, res);
|
||||
|
||||
} catch (FOPException | IOException | TransformerException e) {
|
||||
LOGGER.error("Failed to create PDF", e);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public byte[] toPDF(String xmlLogfileContent) {
|
||||
return createPDFBytes(xmlLogfileContent);
|
||||
}
|
||||
|
||||
public void toPDF(String xmlLogfileContent, String pdfFilename) {
|
||||
byte[] pdfData = createPDFBytes(xmlLogfileContent);
|
||||
try (FileOutputStream fos = new FileOutputStream(pdfFilename)) {
|
||||
fos.write(pdfData);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to write PDF to file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClasspathResourceURIResolver implements URIResolver {
|
||||
ClasspathResourceURIResolver() {
|
||||
// Do nothing, just prevents synthetic access warning.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Source resolve(String href, String base) throws TransformerException {
|
||||
return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/" + href));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,44 +433,57 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider {
|
||||
}
|
||||
|
||||
private String buildPaymentTermsXml() {
|
||||
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
|
||||
final IZUGFeRDPaymentTerms[] paymentTerms = trans.getExtendedPaymentTerms();
|
||||
|
||||
final IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
|
||||
final IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
|
||||
final Date dueDate = paymentTerms.getDueDate();
|
||||
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
|
||||
throw new IllegalStateException(
|
||||
String paymentTermsXml = "";
|
||||
if (paymentTerms == null || paymentTerms.length == 0) {
|
||||
return paymentTermsXml;
|
||||
}
|
||||
|
||||
for (IZUGFeRDPaymentTerms pt : paymentTerms)
|
||||
{
|
||||
paymentTermsXml += "<ram:SpecifiedTradePaymentTerms>";
|
||||
|
||||
final IZUGFeRDPaymentDiscountTerms discountTerms = pt.getDiscountTerms();
|
||||
final Date dueDate = pt.getDueDate();
|
||||
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null)
|
||||
{
|
||||
throw new IllegalStateException(
|
||||
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
|
||||
}
|
||||
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
|
||||
if (dueDate != null) {
|
||||
paymentTermsXml += "<ram:DueDateDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(dueDate);
|
||||
paymentTermsXml += "</ram:DueDateDateTime>";
|
||||
}
|
||||
|
||||
if (discountTerms != null) {
|
||||
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
|
||||
final String currency = trans.getCurrency();
|
||||
final String basisAmount = currencyFormat(calc.getGrandTotal());
|
||||
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
|
||||
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
|
||||
+ "</ram:CalculationPercent>";
|
||||
|
||||
if (discountTerms.getBaseDate() != null) {
|
||||
final Date baseDate = discountTerms.getBaseDate();
|
||||
paymentTermsXml += "<ram:BasisDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(baseDate);
|
||||
paymentTermsXml += "</ram:BasisDateTime>";
|
||||
|
||||
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
|
||||
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
|
||||
}
|
||||
paymentTermsXml += "<ram:Description>" + pt.getDescription() + "</ram:Description>";
|
||||
if (dueDate != null)
|
||||
{
|
||||
paymentTermsXml += "<ram:DueDateDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(dueDate);
|
||||
paymentTermsXml += "</ram:DueDateDateTime>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
|
||||
}
|
||||
if (discountTerms != null)
|
||||
{
|
||||
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
|
||||
final String currency = trans.getCurrency();
|
||||
final String basisAmount = currencyFormat(calc.getGrandTotal());
|
||||
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
|
||||
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
|
||||
+ "</ram:CalculationPercent>";
|
||||
|
||||
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
if (discountTerms.getBaseDate() != null)
|
||||
{
|
||||
final Date baseDate = discountTerms.getBaseDate();
|
||||
paymentTermsXml += "<ram:BasisDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(baseDate);
|
||||
paymentTermsXml += "</ram:BasisDateTime>";
|
||||
|
||||
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
|
||||
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
}
|
||||
return paymentTermsXml;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +45,15 @@ import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.mustangproject.FileAttachment;
|
||||
import org.mustangproject.IncludedNote;
|
||||
import org.mustangproject.ReferencedDocument;
|
||||
import org.mustangproject.XMLTools;
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
||||
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger (ZUGFeRD2PullProvider.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRD2PullProvider.class);
|
||||
|
||||
protected byte[] zugferdData;
|
||||
protected IExportableTransaction trans;
|
||||
@@ -76,11 +78,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
|
||||
protected String priceFormat(BigDecimal value) {
|
||||
return XMLTools.nDigitFormat(value, 4);
|
||||
// 18 decimals are max for price and qty due to xml restrictions,
|
||||
// see Chapter 3.2.3 of https://www.w3.org/TR/xmlschema-2/
|
||||
return XMLTools.nDigitFormatDecimalRange(value, 18, 4);
|
||||
}
|
||||
|
||||
protected String quantityFormat(BigDecimal value) {
|
||||
return XMLTools.nDigitFormat(value, 4);
|
||||
return XMLTools.nDigitFormatDecimalRange(value, 18, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,7 +97,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
try {
|
||||
document = DocumentHelper.parseText(new String(zugferdData));
|
||||
} catch (final DocumentException e1) {
|
||||
LOGGER.error ("Failed to parse ZUGFeRD data", e1);
|
||||
LOGGER.error("Failed to parse ZUGFeRD data", e1);
|
||||
}
|
||||
try {
|
||||
final OutputFormat format = OutputFormat.createPrettyPrint();
|
||||
@@ -103,7 +107,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
res = sw.toString().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
} catch (final IOException e) {
|
||||
LOGGER.error ("Failed to write ZUGFeRD data", e);
|
||||
LOGGER.error("Failed to write ZUGFeRD data", e);
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -137,14 +141,25 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
xml += "<ram:GlobalID schemeID=\"" + XMLTools.encodeXML(party.getGlobalIDScheme()) + "\">"
|
||||
+ XMLTools.encodeXML(party.getGlobalID()) + "</ram:GlobalID>";
|
||||
}
|
||||
xml += "<ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>";
|
||||
if (party.getName() != null && !party.getName().isEmpty()) {
|
||||
xml += "<ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>";
|
||||
}
|
||||
if (party.getDescription() != null) {
|
||||
xml += "<ram:Description>" + XMLTools.encodeXML(party.getDescription()) + "</ram:Description>";
|
||||
}
|
||||
if (party.getLegalOrganisation() != null) {
|
||||
xml += "<ram:SpecifiedLegalOrganization> ";
|
||||
if (party.getLegalOrganisation().getSchemedID() != null) {
|
||||
xml += "<ram:ID schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
|
||||
if (profile == Profiles.getByName("Minimum")) {
|
||||
xml += "<ram:ID>" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
|
||||
} else {
|
||||
String schemeAttribute = "";
|
||||
if ((party.getLegalOrganisation().getSchemedID().getScheme() != null) && (party.getLegalOrganisation().getSchemedID().getScheme().length() > 0)) {
|
||||
schemeAttribute = "schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\"";
|
||||
|
||||
}
|
||||
xml += "<ram:ID " + schemeAttribute + ">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
|
||||
}
|
||||
}
|
||||
if (party.getLegalOrganisation().getTradingBusinessName() != null) {
|
||||
xml += "<ram:TradingBusinessName>" + XMLTools.encodeXML(party.getLegalOrganisation().getTradingBusinessName()) + "</ram:TradingBusinessName>";
|
||||
@@ -155,11 +170,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
if ((party.getContact() != null) && (isSender || profile == Profiles.getByName("EN16931") || profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
|
||||
xml += "<ram:DefinedTradeContact>";
|
||||
if (party.getContact().getName() != null) {
|
||||
xml += "<ram:PersonName>" + XMLTools.encodeXML(party.getContact().getName())
|
||||
xml += "<ram:PersonName>"
|
||||
+ XMLTools.encodeXML(party.getContact().getName())
|
||||
+ "</ram:PersonName>";
|
||||
}
|
||||
if (party.getContact().getPhone() != null) {
|
||||
|
||||
xml += "<ram:TelephoneUniversalCommunication><ram:CompleteNumber>"
|
||||
+ XMLTools.encodeXML(party.getContact().getPhone()) + "</ram:CompleteNumber>"
|
||||
+ "</ram:TelephoneUniversalCommunication>";
|
||||
@@ -200,7 +215,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
+ "</ram:CityName>";
|
||||
}
|
||||
|
||||
//country IS mandatory
|
||||
//country IS mandatory
|
||||
xml += "<ram:CountryID>" + XMLTools.encodeXML(party.getCountry())
|
||||
+ "</ram:CountryID>"
|
||||
+ "</ram:PostalTradeAddress>";
|
||||
@@ -228,6 +243,30 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
|
||||
}
|
||||
|
||||
protected String getTradePartyPayeeAsXML(IZUGFeRDExportableTradeParty party) {
|
||||
String xml = "";
|
||||
// According EN16931 either GlobalID or seller assigned ID might be present for a Payee
|
||||
if (party.getID() != null) {
|
||||
xml += "<ram:ID>" + XMLTools.encodeXML(party.getID()) + "</ram:ID>";
|
||||
}
|
||||
if ((party.getGlobalIDScheme() != null) && (party.getGlobalID() != null)) {
|
||||
xml += "<ram:GlobalID schemeID=\"" + XMLTools.encodeXML(party.getGlobalIDScheme()) + "\">"
|
||||
+ XMLTools.encodeXML(party.getGlobalID())
|
||||
+ "</ram:GlobalID>";
|
||||
}
|
||||
xml += "<ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>";
|
||||
|
||||
if (party.getLegalOrganisation() != null) {
|
||||
xml += "<ram:SpecifiedLegalOrganization> ";
|
||||
if (party.getLegalOrganisation().getSchemedID() != null) {
|
||||
xml += "<ram:ID schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
|
||||
}
|
||||
xml += "</ram:SpecifiedLegalOrganization>";
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* returns the XML for a charge or allowance on item level
|
||||
@@ -247,20 +286,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
|
||||
String reason = "";
|
||||
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended"))) {
|
||||
// only in extended profile
|
||||
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung") || profile == Profiles.getByName("EN16931"))) {
|
||||
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
|
||||
}
|
||||
String reasonCode = "";
|
||||
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("XRechnung"))) {
|
||||
if (allowance.getReasonCode() != null) {
|
||||
// only in XRechnung profile
|
||||
reasonCode = "<ram:ReasonCode>" + allowance.getReasonCode() + "</ram:ReasonCode>";
|
||||
}
|
||||
final String allowanceChargeStr = "<ram:AppliedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
|
||||
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
|
||||
"<ram:ActualAmount>" + priceFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
|
||||
reason +
|
||||
reasonCode +
|
||||
reason +
|
||||
"</ram:AppliedTradeAllowanceCharge>";
|
||||
return allowanceChargeStr;
|
||||
}
|
||||
@@ -283,20 +321,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
|
||||
String reason = "";
|
||||
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended"))) {
|
||||
// only in extended profile
|
||||
boolean isEN16931=(profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931"));
|
||||
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || isEN16931)) {
|
||||
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
|
||||
}
|
||||
String reasonCode = "";
|
||||
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("XRechnung"))) {
|
||||
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("Extended") || isEN16931)) {
|
||||
// only in XRechnung profile
|
||||
reasonCode = "<ram:ReasonCode>" + allowance.getReasonCode() + "</ram:ReasonCode>";
|
||||
}
|
||||
final String itemTotalAllowanceChargeStr = "<ram:SpecifiedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
|
||||
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
|
||||
"<ram:ActualAmount>" + currencyFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
|
||||
reason +
|
||||
reasonCode +
|
||||
reason +
|
||||
"</ram:SpecifiedTradeAllowanceCharge>";
|
||||
return itemTotalAllowanceChargeStr;
|
||||
}
|
||||
@@ -306,11 +344,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
this.trans = trans;
|
||||
this.calc = new TransactionCalculator(trans);
|
||||
|
||||
boolean hasDueDate = false;
|
||||
boolean hasDueDate = trans.getDueDate() != null;
|
||||
final SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
|
||||
|
||||
String exemptionReason = "";
|
||||
|
||||
if (trans.getPaymentTermDescription() != null) {
|
||||
paymentTermsDescription = XMLTools.encodeXML(trans.getPaymentTermDescription());
|
||||
}
|
||||
@@ -325,7 +361,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
paymentTermsDescription += discount.getAsXRechnung();
|
||||
}
|
||||
} else if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
|
||||
if ( trans.getDueDate() != null ) {
|
||||
if (trans.getDueDate() != null) {
|
||||
paymentTermsDescription = "Please remit until " + germanDateFormat.format(trans.getDueDate());
|
||||
}
|
||||
}
|
||||
@@ -360,27 +396,27 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
+ "</ram:GuidelineSpecifiedDocumentContextParameter>"
|
||||
+ "</rsm:ExchangedDocumentContext>"
|
||||
+ "<rsm:ExchangedDocument>"
|
||||
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>"
|
||||
// + "<ram:Name>RECHNUNG</ram:Name>"
|
||||
// + "<ram:TypeCode>380</ram:TypeCode>"
|
||||
+ "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
|
||||
+ "<ram:IssueDateTime>"
|
||||
+ DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
|
||||
+ buildNotes(trans)
|
||||
|
||||
+ "</rsm:ExchangedDocument>"
|
||||
+ "<rsm:SupplyChainTradeTransaction>";
|
||||
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>";
|
||||
if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) {
|
||||
xml += "<ram:Name>" + XMLTools.encodeXML(trans.getDocumentName()) + "</ram:Name>";
|
||||
}
|
||||
xml += "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
|
||||
+ "<ram:IssueDateTime>" + DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
|
||||
+ buildNotes(trans)
|
||||
+ "</rsm:ExchangedDocument>"
|
||||
+ "<rsm:SupplyChainTradeTransaction>";
|
||||
int lineID = 0;
|
||||
for (final IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
|
||||
lineID++;
|
||||
if (currentItem.getProduct().getTaxExemptionReason() != null) {
|
||||
exemptionReason = "<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
|
||||
String lineIDStr = Integer.toString(lineID);
|
||||
if (currentItem.getId() != null) {
|
||||
lineIDStr = currentItem.getId();
|
||||
}
|
||||
final LineCalculator lc = new LineCalculator(currentItem);
|
||||
if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BasicWL"))) {
|
||||
xml += "<ram:IncludedSupplyChainTradeLineItem>" +
|
||||
"<ram:AssociatedDocumentLineDocument>"
|
||||
+ "<ram:LineID>" + lineID + "</ram:LineID>"
|
||||
+ "<ram:LineID>" + lineIDStr + "</ram:LineID>"
|
||||
+ buildItemNotes(currentItem)
|
||||
+ "</ram:AssociatedDocumentLineDocument>"
|
||||
|
||||
@@ -398,33 +434,52 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>";
|
||||
}
|
||||
String allowanceChargeStr = "";
|
||||
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
|
||||
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
|
||||
if (currentItem.getProduct().getAllowances() != null && currentItem.getProduct().getAllowances().length > 0) {
|
||||
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getProduct().getAllowances()) {
|
||||
allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
|
||||
}
|
||||
}
|
||||
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
|
||||
for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
|
||||
if (currentItem.getProduct().getCharges() != null && currentItem.getProduct().getCharges().length > 0) {
|
||||
for (final IZUGFeRDAllowanceCharge charge : currentItem.getProduct().getCharges()) {
|
||||
allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
String itemTotalAllowanceChargeStr = "";
|
||||
if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) {
|
||||
for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getItemTotalAllowances()) {
|
||||
if (currentItem.getAllowances() != null && currentItem.getAllowances().length > 0) {
|
||||
for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getAllowances()) {
|
||||
itemTotalAllowanceChargeStr += getItemTotalAllowanceChargeStr(itemTotalAllowance, currentItem);
|
||||
}
|
||||
}
|
||||
if (currentItem.getCharges() != null && currentItem.getCharges().length > 0) {
|
||||
for (final IZUGFeRDAllowanceCharge itemTotalCharges : currentItem.getCharges()) {
|
||||
itemTotalAllowanceChargeStr += getItemTotalAllowanceChargeStr(itemTotalCharges, currentItem);
|
||||
}
|
||||
}
|
||||
|
||||
xml += "<ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>";
|
||||
if (currentItem.getProduct().getDescription().length() > 0) {
|
||||
if (currentItem.getProduct().getDescription() != null && currentItem.getProduct().getDescription().length() > 0) {
|
||||
xml += "<ram:Description>" +
|
||||
XMLTools.encodeXML(currentItem.getProduct().getDescription()) +
|
||||
"</ram:Description>";
|
||||
}
|
||||
if (currentItem.getProduct().getClassifications() != null && currentItem.getProduct().getClassifications().length > 0) {
|
||||
for (IDesignatedProductClassification classification : currentItem.getProduct().getClassifications()) {
|
||||
xml += "<ram:DesignatedProductClassification>"
|
||||
+ "<ram:ClassCode listID=\"" + XMLTools.encodeXML(classification.getClassCode().getListID()) + "\"";
|
||||
if (classification.getClassCode().getListVersionID() != null) {
|
||||
xml += " listVersionID=\"" + XMLTools.encodeXML(classification.getClassCode().getListVersionID()) + "\"";
|
||||
}
|
||||
xml += ">" + classification.getClassCode().getCode() + "</ram:ClassCode>";
|
||||
if (classification.getClassName() != null) {
|
||||
xml += "<ram:ClassName>" + XMLTools.encodeXML(classification.getClassName()) + "</ram:ClassName>";
|
||||
}
|
||||
xml += "</ram:DesignatedProductClassification>";
|
||||
}
|
||||
}
|
||||
if (currentItem.getProduct().getAttributes() != null) {
|
||||
for ( Entry<String, String> entry : currentItem.getProduct().getAttributes().entrySet() ) {
|
||||
for (Entry<String, String> entry : currentItem.getProduct().getAttributes().entrySet()) {
|
||||
xml += "<ram:ApplicableProductCharacteristic>" +
|
||||
"<ram:Description>" + XMLTools.encodeXML(entry.getKey()) + "</ram:Description>" +
|
||||
"<ram:Value>" + XMLTools.encodeXML(entry.getValue()) + "</ram:Value>" +
|
||||
@@ -433,8 +488,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
if (currentItem.getProduct().getCountryOfOrigin() != null) {
|
||||
xml += "<ram:OriginTradeCountry><ram:ID>" +
|
||||
XMLTools.encodeXML(currentItem.getProduct().getCountryOfOrigin()) +
|
||||
"</ram:ID></ram:OriginTradeCountry>";
|
||||
XMLTools.encodeXML(currentItem.getProduct().getCountryOfOrigin()) +
|
||||
"</ram:ID></ram:OriginTradeCountry>";
|
||||
}
|
||||
xml += "</ram:SpecifiedTradeProduct>"
|
||||
|
||||
@@ -489,12 +544,17 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
+ "</ram:SpecifiedLineTradeDelivery>"
|
||||
+ "<ram:SpecifiedLineTradeSettlement>"
|
||||
+ "<ram:ApplicableTradeTax>"
|
||||
+ "<ram:TypeCode>VAT</ram:TypeCode>"
|
||||
+ exemptionReason
|
||||
+ "<ram:CategoryCode>" + currentItem.getProduct().getTaxCategoryCode() + "</ram:CategoryCode>"
|
||||
+ "<ram:RateApplicablePercent>"
|
||||
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>"
|
||||
+ "</ram:ApplicableTradeTax>";
|
||||
+ "<ram:TypeCode>VAT</ram:TypeCode>";
|
||||
if (currentItem.getProduct().getTaxExemptionReason() != null) {
|
||||
xml += "<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
|
||||
}
|
||||
xml += "<ram:CategoryCode>" + currentItem.getProduct().getTaxCategoryCode() + "</ram:CategoryCode>";
|
||||
if (!currentItem.getProduct().getTaxCategoryCode().equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) {
|
||||
xml += "<ram:RateApplicablePercent>"
|
||||
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>";
|
||||
}
|
||||
xml += "</ram:ApplicableTradeTax>";
|
||||
|
||||
if ((currentItem.getDetailedDeliveryPeriodFrom() != null) || (currentItem.getDetailedDeliveryPeriodTo() != null)) {
|
||||
xml += "<ram:BillingSpecifiedPeriod>";
|
||||
if (currentItem.getDetailedDeliveryPeriodFrom() != null) {
|
||||
@@ -506,7 +566,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
xml += "</ram:BillingSpecifiedPeriod>";
|
||||
}
|
||||
|
||||
xml += itemTotalAllowanceChargeStr;
|
||||
// item charges/allowances
|
||||
if (!itemTotalAllowanceChargeStr.isEmpty()) {
|
||||
xml += itemTotalAllowanceChargeStr ;
|
||||
}
|
||||
|
||||
xml += "<ram:SpecifiedTradeSettlementLineMonetarySummation>"
|
||||
+ "<ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount())
|
||||
@@ -619,13 +682,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
|
||||
xml += "</ram:ApplicableHeaderTradeDelivery>";
|
||||
xml += "<ram:ApplicableHeaderTradeSettlement>";
|
||||
|
||||
if ((trans.getCreditorReferenceID() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
|
||||
xml += "<ram:CreditorReferenceID>" + XMLTools.encodeXML(trans.getCreditorReferenceID()) + "</ram:CreditorReferenceID>";
|
||||
}
|
||||
if ((trans.getNumber() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
|
||||
xml += "<ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>";
|
||||
if ((trans.getPaymentReference() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
|
||||
xml += "<ram:PaymentReference>" + XMLTools.encodeXML(trans.getPaymentReference()) + "</ram:PaymentReference>";
|
||||
}
|
||||
xml += "<ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>";
|
||||
if (this.trans.getPayee() != null) {
|
||||
xml += "<ram:PayeeTradeParty>" +
|
||||
getTradePartyPayeeAsXML(this.trans.getPayee()) +
|
||||
"</ram:PayeeTradeParty>";
|
||||
}
|
||||
|
||||
if (trans.getTradeSettlementPayment() != null) {
|
||||
for (final IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
|
||||
@@ -661,17 +730,25 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
final String amountDueDateTypeCode = amount.getDueDateTypeCode();
|
||||
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
|
||||
if (getProfile() != Profiles.getByName("Minimum")) {
|
||||
String exemptionReasonTextXML = "";
|
||||
if ((displayExemptionReason) && (amount.getVatExemptionReasonText() != null)) {
|
||||
exemptionReasonTextXML = "<ram:ExemptionReason>" + XMLTools.encodeXML(amount.getVatExemptionReasonText()) + "</ram:ExemptionReason>";
|
||||
|
||||
}
|
||||
|
||||
xml += "<ram:ApplicableTradeTax>"
|
||||
+ "<ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
|
||||
+ "</ram:CalculatedAmount>" //currencyID=\"EUR\"
|
||||
+ "<ram:TypeCode>VAT</ram:TypeCode>"
|
||||
+ (displayExemptionReason ? exemptionReason : "")
|
||||
+ exemptionReasonTextXML
|
||||
+ "<ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>" // currencyID=\"EUR\"
|
||||
+ "<ram:CategoryCode>" + amountCategoryCode + "</ram:CategoryCode>"
|
||||
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "")
|
||||
+ "<ram:RateApplicablePercent>"
|
||||
+ vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent></ram:ApplicableTradeTax>";
|
||||
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "");
|
||||
if (!amountCategoryCode.equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) {
|
||||
xml += "<ram:RateApplicablePercent>"
|
||||
+ vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent>";
|
||||
}
|
||||
xml += "</ram:ApplicableTradeTax>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -687,23 +764,23 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
|
||||
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
|
||||
if (profile == Profiles.getByName("XRechnung")) {
|
||||
for(IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
|
||||
if ((profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")) || (profile == Profiles.getByName("EXTENDED"))) {
|
||||
for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
|
||||
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
||||
"<ram:ChargeIndicator>" +
|
||||
"<udt:Indicator>true</udt:Indicator>" +
|
||||
"</ram:ChargeIndicator>" +
|
||||
"<ram:ActualAmount>" + currencyFormat(charge.getTotalAmount(calc)) + "</ram:ActualAmount>";
|
||||
if (charge.getReason() != null) {
|
||||
xml += "<ram:Reason>" + XMLTools.encodeXML(charge.getReason()) + "</ram:Reason>";
|
||||
}
|
||||
if (charge.getReasonCode() != null) {
|
||||
xml += "<ram:ReasonCode>" + charge.getReasonCode() + "</ram:ReasonCode>";
|
||||
}
|
||||
if (charge.getReason() != null) {
|
||||
xml += "<ram:Reason>" + XMLTools.encodeXML(charge.getReason()) + "</ram:Reason>";
|
||||
}
|
||||
xml += "<ram:CategoryTradeTax>" +
|
||||
"<ram:TypeCode>VAT</ram:TypeCode>" +
|
||||
"<ram:CategoryCode>" + charge.getCategoryCode() + "</ram:CategoryCode>";
|
||||
if (charge.getTaxPercent() != null) {
|
||||
if (charge.getTaxPercent() != null && !charge.getCategoryCode().equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) {
|
||||
xml += "<ram:RateApplicablePercent>" + vatFormat(charge.getTaxPercent()) + "</ram:RateApplicablePercent>";
|
||||
}
|
||||
xml += "</ram:CategoryTradeTax>" +
|
||||
@@ -731,7 +808,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
|
||||
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
|
||||
if (profile == Profiles.getByName("XRechnung")) {
|
||||
for(IZUGFeRDAllowanceCharge allowance : trans.getZFAllowances()) {
|
||||
for (IZUGFeRDAllowanceCharge allowance : trans.getZFAllowances()) {
|
||||
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
||||
"<ram:ChargeIndicator>" +
|
||||
"<udt:Indicator>false</udt:Indicator>" +
|
||||
@@ -772,7 +849,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((trans.getPaymentTerms() == null) && (getProfile() != Profiles.getByName("Minimum")) && ((paymentTermsDescription != null) || (trans.getTradeSettlement() != null) || (hasDueDate))) {
|
||||
xml += "<ram:SpecifiedTradePaymentTerms>";
|
||||
|
||||
@@ -780,6 +856,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
xml += "<ram:Description>" + paymentTermsDescription + "</ram:Description>";
|
||||
}
|
||||
|
||||
if (trans.getDueDate() != null) {
|
||||
xml += "<ram:DueDateDateTime>" // $NON-NLS-2$
|
||||
+ DATE.udtFormat(trans.getDueDate())
|
||||
+ "</ram:DueDateDateTime>";// 20130704
|
||||
}
|
||||
|
||||
if (trans.getTradeSettlement() != null) {
|
||||
for (final IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
|
||||
if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit)) {
|
||||
@@ -788,12 +870,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDueDate && (trans.getDueDate() != null)) {
|
||||
xml += "<ram:DueDateDateTime>" // $NON-NLS-2$
|
||||
+ DATE.udtFormat(trans.getDueDate())
|
||||
+ "</ram:DueDateDateTime>";// 20130704
|
||||
|
||||
}
|
||||
xml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
} else {
|
||||
xml += buildPaymentTermsXml();
|
||||
@@ -811,7 +887,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
final String chargesTotalLine = "<ram:ChargeTotalAmount>" + currencyFormat(calc.getChargesForPercent(null)) + "</ram:ChargeTotalAmount>";
|
||||
|
||||
xml += "<ram:SpecifiedTradeSettlementHeaderMonetarySummation>";
|
||||
if (getProfile() != Profiles.getByName("Minimum")) {
|
||||
if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BASICWL"))) {
|
||||
xml += "<ram:LineTotalAmount>" + currencyFormat(calc.getTotal()) + "</ram:LineTotalAmount>";
|
||||
xml += chargesTotalLine
|
||||
+ allowanceTotalLine;
|
||||
@@ -820,14 +896,18 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
// //
|
||||
// currencyID=\"EUR\"
|
||||
+ "<ram:TaxTotalAmount currencyID=\"" + trans.getCurrency() + "\">"
|
||||
+ currencyFormat(calc.getGrandTotal().subtract(calc.getTaxBasis())) + "</ram:TaxTotalAmount>"
|
||||
+ "<ram:GrandTotalAmount>" + currencyFormat(calc.getGrandTotal()) + "</ram:GrandTotalAmount>";
|
||||
+ currencyFormat(calc.getGrandTotal().subtract(calc.getTaxBasis())) + "</ram:TaxTotalAmount>";
|
||||
if (trans.getRoundingAmount() != null) {
|
||||
xml += "<ram:RoundingAmount>" + currencyFormat(trans.getRoundingAmount()) + "</ram:RoundingAmount>";
|
||||
}
|
||||
|
||||
xml += "<ram:GrandTotalAmount>" + currencyFormat(calc.getGrandTotal()) + "</ram:GrandTotalAmount>";
|
||||
// //
|
||||
// currencyID=\"EUR\"
|
||||
if (getProfile() != Profiles.getByName("Minimum")) {
|
||||
xml += "<ram:TotalPrepaidAmount>" + currencyFormat(calc.getTotalPrepaid()) + "</ram:TotalPrepaidAmount>";
|
||||
}
|
||||
xml += "<ram:DuePayableAmount>" + currencyFormat(calc.getGrandTotal().subtract(calc.getTotalPrepaid())) + "</ram:DuePayableAmount>"
|
||||
xml += "<ram:DuePayableAmount>" + currencyFormat(calc.getDuePayable()) + "</ram:DuePayableAmount>"
|
||||
+ "</ram:SpecifiedTradeSettlementHeaderMonetarySummation>";
|
||||
if (trans.getInvoiceReferencedDocumentID() != null) {
|
||||
xml += "<ram:InvoiceReferencedDocument>"
|
||||
@@ -840,6 +920,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
xml += "</ram:InvoiceReferencedDocument>";
|
||||
}
|
||||
if (trans.getInvoiceReferencedDocuments() != null) {
|
||||
for (ReferencedDocument doc : trans.getInvoiceReferencedDocuments()) {
|
||||
xml += "<ram:InvoiceReferencedDocument>"
|
||||
+ "<ram:IssuerAssignedID>"
|
||||
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
|
||||
if (doc.getFormattedIssueDateTime() != null) {
|
||||
xml += "<ram:FormattedIssueDateTime>"
|
||||
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
|
||||
+ "</ram:FormattedIssueDateTime>";
|
||||
}
|
||||
xml += "</ram:InvoiceReferencedDocument>";
|
||||
}
|
||||
}
|
||||
|
||||
xml += "</ram:ApplicableHeaderTradeSettlement>";
|
||||
// + "<IncludedSupplyChainTradeLineItem>\n"
|
||||
@@ -871,8 +964,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
|
||||
protected String buildNotes(IExportableTransaction exportableTransaction) {
|
||||
final List<IncludedNote> includedNotes = Optional.ofNullable(exportableTransaction.getNotesWithSubjectCode())
|
||||
.orElse(new ArrayList<>());
|
||||
final List<IncludedNote> includedNotes = new ArrayList<>();
|
||||
Optional.ofNullable(exportableTransaction.getNotesWithSubjectCode()).ifPresent(includedNotes::addAll);
|
||||
|
||||
if (exportableTransaction.getNotes() != null) {
|
||||
for (final String currentNote : exportableTransaction.getNotes()) {
|
||||
includedNotes.add(IncludedNote.unspecifiedNote(currentNote));
|
||||
@@ -896,56 +990,76 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||
}
|
||||
|
||||
private String buildPaymentTermsXml() {
|
||||
final IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
|
||||
if (paymentTerms == null) {
|
||||
|
||||
ArrayList<IZUGFeRDPaymentTerms> paymentTerms = new ArrayList<IZUGFeRDPaymentTerms>(Arrays.asList(trans.getExtendedPaymentTerms()));
|
||||
|
||||
IZUGFeRDPaymentTerms izpt= trans.getPaymentTerms();
|
||||
if (izpt!=null) {
|
||||
paymentTerms.add(izpt);
|
||||
}
|
||||
|
||||
String paymentTermsXml = "";
|
||||
if (paymentTerms.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
|
||||
|
||||
final IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
|
||||
final Date dueDate = paymentTerms.getDueDate();
|
||||
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
|
||||
throw new IllegalStateException(
|
||||
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
|
||||
}
|
||||
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
|
||||
for (IZUGFeRDPaymentTerms pt : paymentTerms)
|
||||
{
|
||||
|
||||
if (dueDate != null) {
|
||||
paymentTermsXml += "<ram:DueDateDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(dueDate);
|
||||
paymentTermsXml += "</ram:DueDateDateTime>";
|
||||
}
|
||||
paymentTermsXml += "<ram:SpecifiedTradePaymentTerms>";
|
||||
|
||||
if (trans.getTradeSettlement() != null) {
|
||||
for (final IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
|
||||
if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit)) {
|
||||
paymentTermsXml += payment.getPaymentXML();
|
||||
final IZUGFeRDPaymentDiscountTerms discountTerms = pt.getDiscountTerms();
|
||||
final Date dueDate = pt.getDueDate();
|
||||
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null)
|
||||
{
|
||||
throw new IllegalStateException(
|
||||
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
|
||||
}
|
||||
paymentTermsXml += "<ram:Description>" + pt.getDescription() + "</ram:Description>";
|
||||
|
||||
if (dueDate != null)
|
||||
{
|
||||
paymentTermsXml += "<ram:DueDateDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(dueDate);
|
||||
paymentTermsXml += "</ram:DueDateDateTime>";
|
||||
}
|
||||
|
||||
if (trans.getTradeSettlement() != null)
|
||||
{
|
||||
for (final IZUGFeRDTradeSettlement payment : trans.getTradeSettlement())
|
||||
{
|
||||
if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit))
|
||||
{
|
||||
paymentTermsXml += payment.getPaymentXML();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (discountTerms != null) {
|
||||
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
|
||||
final String currency = trans.getCurrency();
|
||||
final String basisAmount = currencyFormat(calc.getGrandTotal());
|
||||
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
|
||||
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
|
||||
+ "</ram:CalculationPercent>";
|
||||
if (discountTerms != null)
|
||||
{
|
||||
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
|
||||
final String currency = trans.getCurrency();
|
||||
final String basisAmount = currencyFormat(calc.getGrandTotal());
|
||||
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
|
||||
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
|
||||
+ "</ram:CalculationPercent>";
|
||||
|
||||
if (discountTerms.getBaseDate() != null) {
|
||||
final Date baseDate = discountTerms.getBaseDate();
|
||||
paymentTermsXml += "<ram:BasisDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(baseDate);
|
||||
paymentTermsXml += "</ram:BasisDateTime>";
|
||||
if (discountTerms.getBaseDate() != null)
|
||||
{
|
||||
final Date baseDate = discountTerms.getBaseDate();
|
||||
paymentTermsXml += "<ram:BasisDateTime>";
|
||||
paymentTermsXml += DATE.udtFormat(baseDate);
|
||||
paymentTermsXml += "</ram:BasisDateTime>";
|
||||
|
||||
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
|
||||
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
|
||||
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
|
||||
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
|
||||
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
return paymentTermsXml;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ import org.apache.pdfbox.pdmodel.font.PDCIDFontType2;
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
|
||||
import org.apache.xmpbox.XMPMetadata;
|
||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
||||
@@ -559,6 +560,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
||||
// https://github.com/ZUGFeRD/mustangproject/issues/249
|
||||
|
||||
COSName cidSet = COSName.getPDFName("CIDSet");
|
||||
COSName resources = COSName.getPDFName("Resources");
|
||||
|
||||
// iterate over all pdf pages
|
||||
|
||||
@@ -567,29 +569,45 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
||||
|
||||
PDPage page = (PDPage) object;
|
||||
PDResources res = page.getResources();
|
||||
for (COSName fontName : res.getFontNames()) {
|
||||
try {
|
||||
PDFont pdFont = res.getFont(fontName);
|
||||
if (pdFont instanceof PDType0Font) {
|
||||
PDType0Font typedFont = (PDType0Font) pdFont;
|
||||
|
||||
if (typedFont.getDescendantFont() instanceof PDCIDFontType2) {
|
||||
@SuppressWarnings("unused")
|
||||
PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
|
||||
PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor();
|
||||
|
||||
fontDescriptor.getCOSObject().removeItem(cidSet);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
// Check for fonts in PDXObjects:
|
||||
for (COSName xObjectName : res.getXObjectNames()) {
|
||||
PDXObject xObject = res.getXObject(xObjectName);
|
||||
COSDictionary d = xObject.getCOSObject().getCOSDictionary(resources);
|
||||
if (d != null) {
|
||||
PDResources xr = new PDResources(d);
|
||||
removeCIDSetFromPDResources(cidSet, xr);
|
||||
}
|
||||
// do stuff with the font
|
||||
}
|
||||
|
||||
// Check for fonts in document-resources:
|
||||
removeCIDSetFromPDResources(cidSet, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeCIDSetFromPDResources(COSName cidSet, PDResources res) throws IOException {
|
||||
for (COSName fontName : res.getFontNames()) {
|
||||
try {
|
||||
PDFont pdFont = res.getFont(fontName);
|
||||
if (pdFont instanceof PDType0Font) {
|
||||
PDType0Font typedFont = (PDType0Font) pdFont;
|
||||
|
||||
if (typedFont.getDescendantFont() instanceof PDCIDFontType2) {
|
||||
@SuppressWarnings("unused")
|
||||
PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
|
||||
PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor();
|
||||
|
||||
fontDescriptor.getCOSObject().removeItem(cidSet);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
// do stuff with the font
|
||||
}
|
||||
}
|
||||
|
||||
protected void prepareDocument() throws IOException {
|
||||
|
||||
PDDocumentCatalog cat = doc.getDocumentCatalog();
|
||||
|
||||
@@ -83,15 +83,17 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
|
||||
}
|
||||
|
||||
protected byte[] filenameToByteArray(String pdfFilename) throws IOException {
|
||||
FileInputStream fileInputStream = new FileInputStream(pdfFilename);
|
||||
return inputstreamToByteArray(fileInputStream);
|
||||
try (FileInputStream fileInputStream = new FileInputStream(pdfFilename)) {
|
||||
return inputstreamToByteArray(fileInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] inputstreamToByteArray(InputStream fileInputStream) throws IOException {
|
||||
byte[] bytes = new byte[fileInputStream.available()];
|
||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||
dataInputStream.readFully(bytes);
|
||||
return bytes;
|
||||
try (DataInputStream dataInputStream = new DataInputStream(fileInputStream)) {
|
||||
dataInputStream.readFully(bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
|
||||
@@ -13,92 +13,34 @@ package org.mustangproject.ZUGFeRD;
|
||||
* @version 1.1.0
|
||||
* @author jstaerk
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpression;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
|
||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||
import org.mustangproject.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class ZUGFeRDImporter {
|
||||
public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDImporter.class);
|
||||
|
||||
/**
|
||||
* if metadata has been found
|
||||
*/
|
||||
protected boolean containsMeta = false;
|
||||
/**
|
||||
* map filenames of additional XML files to their contents
|
||||
*/
|
||||
private final HashMap<String, byte[]> additionalXMLs = new HashMap<>();
|
||||
/**
|
||||
* map filenames of all embedded files in the respective PDF
|
||||
*/
|
||||
private final ArrayList<FileAttachment> PDFAttachments = new ArrayList<>();
|
||||
/**
|
||||
* Raw XML form of the extracted data - may be directly obtained.
|
||||
*/
|
||||
private byte[] rawXML = null;
|
||||
/**
|
||||
* XMP metadata
|
||||
*/
|
||||
private String xmpString = null; // XMP metadata
|
||||
/**
|
||||
* parsed Document
|
||||
*/
|
||||
private Document document;
|
||||
private Integer version;
|
||||
|
||||
|
||||
protected ZUGFeRDImporter() {
|
||||
//constructor for extending classes
|
||||
public ZUGFeRDImporter() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ZUGFeRDImporter(String pdfFilename) {
|
||||
try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
|
||||
extractLowLevel(bis);
|
||||
} catch (final IOException e) {
|
||||
LOGGER.error("Failed to extract ZUGFeRD data", e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
public ZUGFeRDImporter(String filename) {
|
||||
super(filename);
|
||||
}
|
||||
|
||||
|
||||
public ZUGFeRDImporter(InputStream pdfStream) {
|
||||
try {
|
||||
extractLowLevel(pdfStream);
|
||||
} catch (final IOException e) {
|
||||
LOGGER.error("Failed to extract ZUGFeRD data", e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
public ZUGFeRDImporter(InputStream stream) {
|
||||
super(stream);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,169 +55,21 @@ public class ZUGFeRDImporter {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
|
||||
*
|
||||
* @param inStream a inputstream of a pdf file
|
||||
*/
|
||||
private void extractLowLevel(InputStream inStream) throws IOException {
|
||||
BufferedInputStream pdfStream = new BufferedInputStream(inStream);
|
||||
byte[] pad = new byte[4];
|
||||
pdfStream.mark(0);
|
||||
pdfStream.read(pad);
|
||||
pdfStream.reset();
|
||||
byte[] pdfSignature = {'%', 'P', 'D', 'F'};
|
||||
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
|
||||
|
||||
|
||||
try (PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream))) {
|
||||
// PDDocumentInformation info = doc.getDocumentInformation();
|
||||
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
|
||||
//start
|
||||
|
||||
if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
|
||||
LOGGER.info("no-xmlpart");
|
||||
return;
|
||||
}
|
||||
|
||||
final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
|
||||
xmpString = convertStreamToString(XMP);
|
||||
|
||||
final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
|
||||
if (etn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, PDComplexFileSpecification> efMap = etn.getNames();
|
||||
// String filePath = "/tmp/";
|
||||
|
||||
if (efMap != null) {
|
||||
extractFiles(efMap); // see
|
||||
// https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
|
||||
} else {
|
||||
|
||||
final List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids();
|
||||
if (kids == null) {
|
||||
return;
|
||||
}
|
||||
for (final PDNameTreeNode<PDComplexFileSpecification> node : kids) {
|
||||
final Map<String, PDComplexFileSpecification> namesL = node.getNames();
|
||||
extractFiles(namesL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no PDF probably XML
|
||||
containsMeta = true;
|
||||
setRawXML(XMLTools.getBytesFromStream(pdfStream));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
|
||||
for (final String alias : names.keySet()) {
|
||||
|
||||
final PDComplexFileSpecification fileSpec = names.get(alias);
|
||||
final String filename = fileSpec.getFilename();
|
||||
/**
|
||||
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
|
||||
*/
|
||||
|
||||
final PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
|
||||
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml")) || filename.equals("xrechnung.xml") || filename.equals("order-x.xml") || filename.equals("cida.xml")) {
|
||||
containsMeta = true;
|
||||
|
||||
// String embeddedFilename = filePath + filename;
|
||||
// File file = new File(filePath + filename);
|
||||
// System.out.println("Writing " + embeddedFilename);
|
||||
// ByteArrayOutputStream fileBytes=new
|
||||
// ByteArrayOutputStream();
|
||||
// FileOutputStream fos = new FileOutputStream(file);
|
||||
|
||||
setRawXML(embeddedFile.toByteArray());
|
||||
|
||||
// fos.write(embeddedFile.getByteArray());
|
||||
// fos.close();
|
||||
}
|
||||
if (filename.startsWith("additional_data")) {
|
||||
additionalXMLs.put(filename, embeddedFile.toByteArray());
|
||||
}
|
||||
PDFAttachments.add(new FileAttachment(filename, embeddedFile.getSubtype(), "Data", embeddedFile.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected Document getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
|
||||
private void setDocument() throws ParserConfigurationException, IOException, SAXException {
|
||||
final DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
|
||||
xmlFact.setNamespaceAware(true);
|
||||
final DocumentBuilder builder = xmlFact.newDocumentBuilder();
|
||||
final ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
|
||||
/// is.skip(guessBOMSize(is));
|
||||
document = builder.parse(is);
|
||||
}
|
||||
|
||||
|
||||
public void setRawXML(byte[] rawXML) throws IOException {
|
||||
this.containsMeta = true;
|
||||
this.rawXML = rawXML;
|
||||
this.version = null;
|
||||
try {
|
||||
setDocument();
|
||||
} catch (ParserConfigurationException | SAXException e) {
|
||||
LOGGER.error("Failed to parse XML", e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected String extractString(String xpathStr) {
|
||||
if (!containsMeta) {
|
||||
throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
|
||||
}
|
||||
final String result;
|
||||
try {
|
||||
final Document document = getDocument();
|
||||
final XPathFactory xpathFact = XPathFactory.newInstance();
|
||||
final XPath xpath = xpathFact.newXPath();
|
||||
result = xpath.evaluate(xpathStr, document);
|
||||
} catch (final XPathExpressionException e) {
|
||||
LOGGER.error("Failed to evaluate XPath", e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/***
|
||||
* Wrapper for protected method extractString
|
||||
* @param xpathStr the xpath expression to be evaluated
|
||||
* @return the extracted String for the specific path in the document
|
||||
*/
|
||||
public String wExtractString(String xpathStr) {
|
||||
return extractString(xpathStr);
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @return the reference (purpose) the sender specified for this invoice
|
||||
*/
|
||||
public String getForeignReference() {
|
||||
String result = extractString("//*[local-name() = 'ApplicableHeaderTradeSettlement']/*[local-name() = 'PaymentReference']");
|
||||
if (result == null || result.isEmpty()) {
|
||||
result = extractString("//*[local-name() = 'ApplicableSupplyChainTradeSettlement']/*[local-name() = 'PaymentReference']");
|
||||
}
|
||||
return result;
|
||||
|
||||
return importedInvoice.getNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ZUGFeRD Profile
|
||||
*/
|
||||
public String getZUGFeRDProfil() {
|
||||
|
||||
String guideline = extractString("//*[local-name() = 'GuidelineSpecifiedDocumentContextParameter']//*[local-name() = 'ID']");
|
||||
if (guideline.contains("xrechnung")) {
|
||||
return "XRECHNUNG";
|
||||
@@ -292,6 +86,7 @@ public class ZUGFeRDImporter {
|
||||
case "urn:factur-x.eu:1p0:minimum":
|
||||
return "MINIMUM";
|
||||
case "urn:ferd:CrossIndustryDocument:invoice:1p0:extended":
|
||||
case "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended":
|
||||
case "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended":
|
||||
return "EXTENDED";
|
||||
default:
|
||||
@@ -299,21 +94,6 @@ public class ZUGFeRDImporter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Invoice Currency Code
|
||||
*/
|
||||
public String getInvoiceCurrencyCode() {
|
||||
try {
|
||||
if (getVersion() == 1) {
|
||||
return extractString("//*[local-name() = 'ApplicableSupplyChainTradeSettlement']//*[local-name() = 'InvoiceCurrencyCode']");
|
||||
} else {
|
||||
return extractString("//*[local-name() = 'ApplicableHeaderTradeSettlement']//*[local-name() = 'InvoiceCurrencyCode']");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Exception was already logged
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the IssuerAssigned ID
|
||||
@@ -336,57 +116,6 @@ public class ZUGFeRDImporter {
|
||||
return extractIssuerAssignedID("ContractReferencedDocument");
|
||||
}
|
||||
|
||||
private String extractIssuerAssignedID(String propertyName) {
|
||||
try {
|
||||
if (getVersion() == 1) {
|
||||
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'ID']");
|
||||
} else {
|
||||
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'IssuerAssignedID']");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Exception was already logged
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the BuyerTradeParty ID
|
||||
*/
|
||||
public String getBuyerTradePartyID() {
|
||||
return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'ID']");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Issue Date()
|
||||
*/
|
||||
public String getIssueDate() {
|
||||
try {
|
||||
if (getVersion() == 1) {
|
||||
return extractString("//*[local-name() = 'HeaderExchangedDocument']//*[local-name() = 'IssueDateTime']//*[local-name() = 'DateTimeString']");
|
||||
} else {
|
||||
return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'IssueDateTime']//*[local-name() = 'DateTimeString']");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Exception was already logged
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public Date getDetailedDeliveryPeriodFrom() {
|
||||
final String toParse = extractString(
|
||||
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
|
||||
"//*[local-name() = 'BillingSpecifiedPeriod']" +
|
||||
"//*[local-name() = 'StartDateTime']//*[local-name() = 'DateTimeString']");
|
||||
return tryDate(toParse);
|
||||
}
|
||||
|
||||
public Date getDetailedDeliveryPeriodTo() {
|
||||
final String toParse = extractString(
|
||||
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
|
||||
"//*[local-name() = 'BillingSpecifiedPeriod']" +
|
||||
"//*[local-name() = 'EndDateTime']//*[local-name() = 'DateTimeString']");
|
||||
return tryDate(toParse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the TaxBasisTotalAmount
|
||||
@@ -470,7 +199,16 @@ public class ZUGFeRDImporter {
|
||||
* @return the BuyerTradeParty SpecifiedTaxRegistration ID
|
||||
*/
|
||||
public String getBuyertradePartySpecifiedTaxRegistrationID() {
|
||||
return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'SpecifiedTaxRegistration']//*[local-name() = 'ID']");
|
||||
String id = null;
|
||||
if ((importedInvoice.getRecipient()!=null) && (importedInvoice.getRecipient().getLegalOrganisation()!=null)) {
|
||||
// this *should* be the official result
|
||||
id = importedInvoice.getRecipient().getLegalOrganisation().getSchemedID().getID();
|
||||
}
|
||||
// but also provide some fallback
|
||||
if (id == null) {
|
||||
id = getBuyerTradePartyID();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@@ -494,14 +232,14 @@ public class ZUGFeRDImporter {
|
||||
* @return the BuyerTradeParty Name
|
||||
*/
|
||||
public String getBuyerTradePartyName() {
|
||||
return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'Name']");
|
||||
return importedInvoice.getRecipient().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the BuyerTradeParty Name
|
||||
*/
|
||||
public String getDeliveryTradePartyName() {
|
||||
return extractString("//*[local-name() = 'ShipToTradeParty']//*[local-name() = 'Name']");
|
||||
return importedInvoice.getDeliveryAddress().getName();
|
||||
}
|
||||
|
||||
|
||||
@@ -525,7 +263,7 @@ public class ZUGFeRDImporter {
|
||||
* @return the Payment Terms
|
||||
*/
|
||||
public String getPaymentTerms() {
|
||||
return extractString("//*[local-name() = 'SpecifiedTradePaymentTerms']//*[local-name() = 'Description']");
|
||||
return importedInvoice.getPaymentTermDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -548,16 +286,7 @@ public class ZUGFeRDImporter {
|
||||
* @return the Invoice ID
|
||||
*/
|
||||
public String getInvoiceID() {
|
||||
try {
|
||||
if (getVersion() == 1) {
|
||||
return extractString("//*[local-name() = 'HeaderExchangedDocument']//*[local-name() = 'ID']");
|
||||
} else {
|
||||
return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'ID']");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Exception was already logged
|
||||
return "";
|
||||
}
|
||||
return importedInvoice.getNumber();
|
||||
}
|
||||
|
||||
|
||||
@@ -582,16 +311,7 @@ public class ZUGFeRDImporter {
|
||||
* @return the referred document
|
||||
*/
|
||||
public String getReference() {
|
||||
try {
|
||||
if (getVersion() == 1) {
|
||||
return extractString("//*[local-name() = 'ApplicableSupplyChainTradeAgreement']/*[local-name() = 'BuyerReference']");
|
||||
} else {
|
||||
return extractString("//*[local-name() = 'ApplicableHeaderTradeAgreement']/*[local-name() = 'BuyerReference']");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Exception was already logged
|
||||
return "";
|
||||
}
|
||||
return importedInvoice.getReferenceNumber();
|
||||
}
|
||||
|
||||
|
||||
@@ -615,7 +335,18 @@ public class ZUGFeRDImporter {
|
||||
* @return the sender's account IBAN code
|
||||
*/
|
||||
public String getIBAN() {
|
||||
return extractString("//*[local-name() = 'PayeePartyCreditorFinancialAccount']/*[local-name() = 'IBANID']");
|
||||
if ((importedInvoice==null)||(importedInvoice.getTradeSettlement()==null)) {
|
||||
return null;
|
||||
}
|
||||
for (IZUGFeRDTradeSettlement settlement : importedInvoice.getTradeSettlement()) {
|
||||
if (settlement instanceof IZUGFeRDTradeSettlementDebit) {
|
||||
return ((IZUGFeRDTradeSettlementDebit) settlement).getIBAN();
|
||||
}
|
||||
if (settlement instanceof IZUGFeRDTradeSettlementPayment) {
|
||||
return ((IZUGFeRDTradeSettlementPayment) settlement).getOwnIBAN();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -628,14 +359,7 @@ public class ZUGFeRDImporter {
|
||||
* @return the total payable amount
|
||||
*/
|
||||
public String getAmount() {
|
||||
String result = extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']/*[local-name() = 'DuePayableAmount']");
|
||||
if (result == null || result.isEmpty()) {
|
||||
|
||||
/* fx/zf would be SpecifiedTradeSettlementMonetarySummation
|
||||
* but ox is SpecifiedTradeSettlementHeaderMonetarySummation...*/
|
||||
result = extractString("//*[local-name() = 'GrandTotalAmount']");
|
||||
}
|
||||
return result;
|
||||
return importedInvoice.getGrandTotal().toPlainString();
|
||||
}
|
||||
|
||||
|
||||
@@ -643,7 +367,60 @@ public class ZUGFeRDImporter {
|
||||
* @return when the payment is due
|
||||
*/
|
||||
public String getDueDate() {
|
||||
return extractString("//*[local-name() = 'SpecifiedTradePaymentTerms']/*[local-name() = 'DueDateDateTime']/*[local-name() = 'DateTimeString']");
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
||||
return sdf.format(importedInvoice.getDueDate());
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
|
||||
/**
|
||||
* @return the Invoice Currency Code
|
||||
*/
|
||||
public String getInvoiceCurrencyCode() {
|
||||
return importedInvoice.getCurrency();
|
||||
}
|
||||
|
||||
|
||||
private String extractIssuerAssignedID(String propertyName) {
|
||||
try {
|
||||
if (getVersion() == 1) {
|
||||
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'ID']");
|
||||
} else {
|
||||
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'IssuerAssignedID']");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
// Exception was already logged
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the BuyerTradeParty ID
|
||||
*/
|
||||
public String getBuyerTradePartyID() {
|
||||
String id = importedInvoice.getRecipient().getID();
|
||||
if (id == null) {
|
||||
// provide some fallback
|
||||
id = importedInvoice.getRecipient().getVATID();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Issue Date()
|
||||
*/
|
||||
public String getIssueDate() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
||||
return sdf.format(importedInvoice.getIssueDate());
|
||||
}
|
||||
|
||||
public Date getDetailedDeliveryPeriodFrom() {
|
||||
return importedInvoice.getDetailedDeliveryPeriodFrom();
|
||||
}
|
||||
|
||||
public Date getDetailedDeliveryPeriodTo() {
|
||||
return importedInvoice.getDetailedDeliveryPeriodTo();
|
||||
}
|
||||
|
||||
|
||||
@@ -691,28 +468,6 @@ public class ZUGFeRDImporter {
|
||||
}
|
||||
|
||||
|
||||
public EStandard getStandard() throws Exception {
|
||||
if (!containsMeta) {
|
||||
throw new Exception("Not yet parsed");
|
||||
}
|
||||
final String head = getUTF8();
|
||||
String rootNode = extractString("local-name(/*)");
|
||||
if (rootNode.equals("CrossIndustryDocument")) {
|
||||
return EStandard.zugferd;
|
||||
} else if (rootNode.equals("Invoice")) {
|
||||
return EStandard.ubl;
|
||||
} else if (rootNode.equals("CrossIndustryInvoice")) {
|
||||
return EStandard.facturx;
|
||||
} else if (rootNode.equals("SCRDMCCBDACIDAMessageStructure")) {
|
||||
return EStandard.despatchadvice;
|
||||
} else if (head.contains("<rsm:SCRDMCCBDACIOMessageStructure")) {
|
||||
return EStandard.orderx;
|
||||
}
|
||||
|
||||
throw new Exception("ZUGFeRD version could not be determined");
|
||||
|
||||
}
|
||||
|
||||
public int getVersion() throws Exception {
|
||||
if (!containsMeta) {
|
||||
throw new Exception("Not yet parsed");
|
||||
@@ -736,35 +491,6 @@ public class ZUGFeRDImporter {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return return UTF8 XML (without BOM) of the invoice
|
||||
*/
|
||||
public String getUTF8() {
|
||||
if (rawXML == null) {
|
||||
return null;
|
||||
}
|
||||
if (rawXML.length < 3) {
|
||||
return new String(rawXML);
|
||||
}
|
||||
|
||||
|
||||
final byte[] bomlessData;
|
||||
|
||||
if ((rawXML[0] == (byte) 0xEF)
|
||||
&& (rawXML[1] == (byte) 0xBB)
|
||||
&& (rawXML[2] == (byte) 0xBF)) {
|
||||
// I don't like BOMs, lets remove it
|
||||
bomlessData = new byte[rawXML.length - 3];
|
||||
System.arraycopy(rawXML, 3, bomlessData, 0,
|
||||
rawXML.length - 3);
|
||||
} else {
|
||||
bomlessData = rawXML;
|
||||
}
|
||||
|
||||
return new String(bomlessData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the raw XML data as extracted from the ZUGFeRD PDF file.
|
||||
*
|
||||
@@ -790,14 +516,6 @@ public class ZUGFeRDImporter {
|
||||
}
|
||||
|
||||
|
||||
static String convertStreamToString(java.io.InputStream is) {
|
||||
try {
|
||||
return IOUtils.toString(is, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an instance of PostalTradeAddress for SellerTradeParty section
|
||||
*
|
||||
@@ -929,9 +647,11 @@ public class ZUGFeRDImporter {
|
||||
|
||||
/**
|
||||
* returns a list of LineItems
|
||||
* @deprecated use invoiceimporter getZFItems
|
||||
*
|
||||
* @return a List of LineItem instances
|
||||
*/
|
||||
@Deprecated
|
||||
public List<Item> getLineItemList() {
|
||||
final List<Node> nodeList = getLineItemNodes();
|
||||
final List<Item> lineItemList = new ArrayList<>();
|
||||
@@ -953,7 +673,7 @@ public class ZUGFeRDImporter {
|
||||
if (node != null) {
|
||||
final NodeList tradeAgreementChildren = node.getChildNodes();
|
||||
node = getNodeByName(tradeAgreementChildren, "ChargeAmount");
|
||||
lineItem.setPrice(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.setPrice(XMLTools.tryBigDecimal(node));
|
||||
node = getNodeByName(tradeAgreementChildren, "BasisQuantity");
|
||||
if (node != null && node.getAttributes() != null) {
|
||||
final Node unitCodeAttribute = node.getAttributes().getNamedItem("unitCode");
|
||||
@@ -966,49 +686,65 @@ public class ZUGFeRDImporter {
|
||||
node = getNodeByName(nn.getChildNodes(), "GrossPriceProductTradePrice");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "ChargeAmount");
|
||||
lineItem.setGrossPrice(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.setGrossPrice(XMLTools.tryBigDecimal(node));
|
||||
}
|
||||
break;
|
||||
|
||||
case "AssociatedDocumentLineDocument":
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "LineID");
|
||||
lineItem.setId(getNodeValue(node));
|
||||
lineItem.setId(XMLTools.getNodeValue(node));
|
||||
break;
|
||||
|
||||
case "SpecifiedTradeProduct":
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "GlobalID");
|
||||
if (node != null) {
|
||||
SchemedID globalId = new SchemedID()
|
||||
.setScheme(node.getAttributes()
|
||||
.getNamedItem("schemeID").getNodeValue())
|
||||
.setId(XMLTools.getNodeValue(node));
|
||||
lineItem.getProduct().addGlobalID(globalId);
|
||||
}
|
||||
node = getNodeByName(nn.getChildNodes(), "SellerAssignedID");
|
||||
lineItem.getProduct().setSellerAssignedID(getNodeValue(node));
|
||||
lineItem.getProduct().setSellerAssignedID(XMLTools.getNodeValue(node));
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "BuyerAssignedID");
|
||||
lineItem.getProduct().setBuyerAssignedID(getNodeValue(node));
|
||||
lineItem.getProduct().setBuyerAssignedID(XMLTools.getNodeValue(node));
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "Name");
|
||||
lineItem.getProduct().setName(getNodeValue(node));
|
||||
lineItem.getProduct().setName(XMLTools.getNodeValue(node));
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "Description");
|
||||
lineItem.getProduct().setDescription(getNodeValue(node));
|
||||
lineItem.getProduct().setDescription(XMLTools.getNodeValue(node));
|
||||
break;
|
||||
|
||||
case "SpecifiedLineTradeDelivery":
|
||||
case "SpecifiedSupplyChainTradeDelivery":
|
||||
node = getNodeByName(nn.getChildNodes(), "BilledQuantity");
|
||||
lineItem.setQuantity(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.setQuantity(XMLTools.tryBigDecimal(node));
|
||||
break;
|
||||
|
||||
case "SpecifiedLineTradeSettlement":
|
||||
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "RateApplicablePercent");
|
||||
lineItem.getProduct().setVATPercent(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.getProduct().setVATPercent(XMLTools.tryBigDecimal(node));
|
||||
}
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "CalculatedAmount");
|
||||
lineItem.setTax(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.setTax(XMLTools.tryBigDecimal(node));
|
||||
}
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "CategoryCode");
|
||||
if(node != null){
|
||||
lineItem.getProduct().setTaxCategoryCode(XMLTools.getNodeValue(node));
|
||||
}
|
||||
}
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "BillingSpecifiedPeriod");
|
||||
if (node != null) {
|
||||
final Node start = getNodeByName(node.getChildNodes(), "StartDateTime");
|
||||
@@ -1021,13 +757,13 @@ public class ZUGFeRDImporter {
|
||||
if (end != null) {
|
||||
dateTimeEnd = getNodeByName(end.getChildNodes(), "DateTimeString");
|
||||
}
|
||||
lineItem.setDetailedDeliveryPeriod(tryDate(dateTimeStart), tryDate(dateTimeEnd));
|
||||
lineItem.setDetailedDeliveryPeriod(XMLTools.tryDate(dateTimeStart), XMLTools.tryDate(dateTimeEnd));
|
||||
}
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "SpecifiedTradeSettlementLineMonetarySummation");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "LineTotalAmount");
|
||||
lineItem.setLineTotalAmount(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.setLineTotalAmount(XMLTools.tryBigDecimal(node));
|
||||
}
|
||||
break;
|
||||
case "SpecifiedSupplyChainTradeSettlement":
|
||||
@@ -1036,19 +772,19 @@ public class ZUGFeRDImporter {
|
||||
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "ApplicablePercent");
|
||||
lineItem.getProduct().setVATPercent(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.getProduct().setVATPercent(XMLTools.tryBigDecimal(node));
|
||||
}
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "CalculatedAmount");
|
||||
lineItem.setTax(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.setTax(XMLTools.tryBigDecimal(node));
|
||||
}
|
||||
|
||||
node = getNodeByName(nn.getChildNodes(), "SpecifiedTradeSettlementMonetarySummation");
|
||||
if (node != null) {
|
||||
node = getNodeByName(node.getChildNodes(), "LineTotalAmount");
|
||||
lineItem.setLineTotalAmount(tryBigDecimal(getNodeValue(node)));
|
||||
lineItem.setLineTotalAmount(XMLTools.tryBigDecimal(node));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1123,51 +859,4 @@ public class ZUGFeRDImporter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the value of an node
|
||||
*
|
||||
* @param node the Node to get the value from
|
||||
* @return A String or empty String, if no value was found
|
||||
*/
|
||||
private String getNodeValue(Node node) {
|
||||
if (node != null && node.getFirstChild() != null) {
|
||||
return node.getFirstChild().getNodeValue();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* tries to convert an String to BigDecimal.
|
||||
*
|
||||
* @param nodeValue The value as String
|
||||
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
|
||||
*/
|
||||
private BigDecimal tryBigDecimal(String nodeValue) {
|
||||
try {
|
||||
return new BigDecimal(nodeValue);
|
||||
} catch (final Exception e) {
|
||||
try {
|
||||
return BigDecimal.valueOf(Float.valueOf(nodeValue));
|
||||
} catch (final Exception ex) {
|
||||
return new BigDecimal("0.00");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Date tryDate(Node node) {
|
||||
final String nodeValue = getNodeValue(node);
|
||||
if (nodeValue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return tryDate(nodeValue);
|
||||
}
|
||||
|
||||
private static Date tryDate(String toParse) {
|
||||
final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter();
|
||||
try {
|
||||
return formatter.parse(toParse);
|
||||
} catch (final Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,56 +20,38 @@
|
||||
*/
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import com.helger.commons.io.stream.StreamHelper;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Templates;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.URIResolver;
|
||||
import javax.xml.transform.sax.SAXResult;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.apache.fop.apps.FOPException;
|
||||
import org.apache.fop.apps.FOUserAgent;
|
||||
import org.apache.fop.apps.Fop;
|
||||
import org.apache.fop.apps.FopFactory;
|
||||
import org.apache.fop.apps.FopFactoryBuilder;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.fop.apps.*;
|
||||
import org.apache.fop.apps.io.ResourceResolverFactory;
|
||||
import org.apache.fop.configuration.Configuration;
|
||||
import org.apache.fop.configuration.ConfigurationException;
|
||||
import org.apache.fop.configuration.DefaultConfigurationBuilder;
|
||||
import org.apache.xmlgraphics.util.MimeConstants;
|
||||
import org.mustangproject.ClasspathResolverURIAdapter;
|
||||
import org.mustangproject.EStandard;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.helger.commons.io.stream.StreamHelper;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.sax.SAXResult;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ZUGFeRDVisualizer {
|
||||
|
||||
@@ -97,7 +79,7 @@ public class ZUGFeRDVisualizer {
|
||||
private Templates mXsltXRTemplate = null;
|
||||
private Templates mXsltUBLTemplate = null;
|
||||
private Templates mXsltCIOTemplate = null;
|
||||
private Templates mXsltHTMLTemplate = null;
|
||||
private Map<Language, Templates> mXsltHTMLTemplates = null;
|
||||
private Templates mXsltPDFTemplate = null;
|
||||
private Templates mXsltZF1HTMLTemplate = null;
|
||||
|
||||
@@ -107,123 +89,170 @@ public class ZUGFeRDVisualizer {
|
||||
mFactory.setURIResolver(new ClasspathResourceURIResolver());
|
||||
}
|
||||
|
||||
public String visualize(String xmlFilename, Language lang)
|
||||
throws FileNotFoundException, TransformerException, IOException, SAXException, ParserConfigurationException {
|
||||
|
||||
try {
|
||||
if (mXsltXRTemplate == null) {
|
||||
mXsltXRTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
||||
}
|
||||
if (mXsltPDFTemplate == null) {
|
||||
mXsltPDFTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
|
||||
}
|
||||
if (mXsltHTMLTemplate == null) {
|
||||
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
|
||||
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
|
||||
}
|
||||
if (mXsltZF1HTMLTemplate == null) {
|
||||
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
|
||||
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
|
||||
}
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
LOGGER.error("Failed to init XSLT templates", ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* *
|
||||
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
|
||||
* http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf
|
||||
* http://countwordsfree.com/xmlviewer
|
||||
*/
|
||||
FileInputStream fis = new FileInputStream(xmlFilename);
|
||||
String fileContent = "";
|
||||
try {
|
||||
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
|
||||
} catch (IOException e2) {
|
||||
LOGGER.error("Failed to read file content", e2);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
/***
|
||||
* returns which standard is used, CII or UBL
|
||||
* @param fis inputstream (will be consumed)
|
||||
* @return (facturx = cii)
|
||||
*/
|
||||
private EStandard findOutStandardFromRootNode(InputStream fis)
|
||||
throws ParserConfigurationException {
|
||||
|
||||
String zf1Signature = "CrossIndustryDocument";
|
||||
String zf2Signature = "CrossIndustryInvoice";
|
||||
String ublSignature = "Invoice";
|
||||
String ublCreditNoteSignature = "CreditNote";
|
||||
String cioSignature = "SCRDMCCBDACIOMessageStructure" +
|
||||
"";
|
||||
boolean doPostProcessing = false;
|
||||
String cioSignature = "SCRDMCCBDACIOMessageStructure";
|
||||
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
//REDHAT
|
||||
//https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf
|
||||
dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
||||
|
||||
//OWASP
|
||||
//https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
|
||||
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
// Disable external DTDs as well
|
||||
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
|
||||
dbf.setXIncludeAware(false);
|
||||
dbf.setExpandEntityReferences(false);
|
||||
dbf.setNamespaceAware(true);
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document doc = db.parse(new InputSource(fis));
|
||||
Element root = doc.getDocumentElement();
|
||||
fis = new FileInputStream(xmlFilename); // fis wont reset() so re-read from beginning
|
||||
if (root.getLocalName().equals(zf1Signature)) {
|
||||
applyZF1XSLT(fis, baos);
|
||||
} else if (root.getLocalName().equals(zf2Signature)) {
|
||||
try {
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document doc = db.parse(new InputSource(fis));
|
||||
Element root = doc.getDocumentElement();
|
||||
if (root.getLocalName().equals(zf1Signature)) {
|
||||
return EStandard.zugferd;
|
||||
} else if (root.getLocalName().equals(zf2Signature)) {
|
||||
return EStandard.facturx;
|
||||
} else if (root.getLocalName().equals(ublSignature)) {
|
||||
return EStandard.ubl;
|
||||
} else if (root.getLocalName().equals(ublCreditNoteSignature)) {
|
||||
return EStandard.ubl_creditnote;
|
||||
} else if (root.getLocalName().equals(cioSignature)) {
|
||||
return EStandard.orderx;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to recognize standard", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String visualize(String xmlFilename, Language lang)
|
||||
throws IOException, TransformerException, ParserConfigurationException {
|
||||
try (FileInputStream fis = new FileInputStream(xmlFilename)) {
|
||||
return visualize(fis, lang);
|
||||
}
|
||||
}
|
||||
|
||||
public String visualize(InputStream inputXml, Language lang)
|
||||
throws IOException, TransformerException, ParserConfigurationException {
|
||||
initTemplates(lang);
|
||||
|
||||
String fileContent = new String(IOUtils.toByteArray(inputXml), StandardCharsets.UTF_8);
|
||||
EStandard thestandard = findOutStandardFromRootNode(new ByteArrayInputStream(fileContent.getBytes(StandardCharsets.UTF_8)));
|
||||
ByteArrayOutputStream htmlOutput = new ByteArrayOutputStream();
|
||||
|
||||
|
||||
ByteArrayInputStream xmlContentStream = new ByteArrayInputStream(fileContent.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
if (thestandard == EStandard.zugferd) {
|
||||
applyZF1XSLT(xmlContentStream, htmlOutput);
|
||||
return htmlOutput.toString(StandardCharsets.UTF_8);
|
||||
} else if (thestandard == EStandard.facturx) {
|
||||
//zf2 or fx
|
||||
applyZF2XSLT(fis, iaos);
|
||||
doPostProcessing = true;
|
||||
} else if (root.getLocalName().equals(ublSignature)) {
|
||||
applyZF2XSLT(xmlContentStream, htmlOutput);
|
||||
} else if (thestandard == EStandard.ubl) {
|
||||
//zf2 or fx
|
||||
applyUBL2XSLT(fis, iaos);
|
||||
doPostProcessing = true;
|
||||
} else if (root.getLocalName().equals(ublCreditNoteSignature)) {
|
||||
applyUBL2XSLT(xmlContentStream, htmlOutput);
|
||||
} else if (thestandard == EStandard.ubl_creditnote) {
|
||||
//zf2 or fx
|
||||
applyUBLCreditNote2XSLT(fis, iaos);
|
||||
doPostProcessing = true;
|
||||
} else if (root.getLocalName().equals(cioSignature)) {
|
||||
applyUBLCreditNote2XSLT(xmlContentStream, htmlOutput);
|
||||
} else if (thestandard == EStandard.orderx) {
|
||||
//zf2 or fx
|
||||
applyCIO2XSLT(fis, iaos);
|
||||
doPostProcessing = true;
|
||||
applyCIO2XSLT(xmlContentStream, htmlOutput);
|
||||
} else {
|
||||
throw new IllegalArgumentException("File does not look like CII or UBL");
|
||||
}
|
||||
if (doPostProcessing) {
|
||||
// take the copy of the stream and re-write it to an InputStream
|
||||
PipedInputStream in = new PipedInputStream();
|
||||
PipedOutputStream out;
|
||||
try {
|
||||
out = new PipedOutputStream(in);
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// write the original OutputStream to the PipedOutputStream
|
||||
// note that in order for the below method to work, you need
|
||||
// to ensure that the data has finished writing to the
|
||||
// ByteArrayOutputStream
|
||||
iaos.writeTo(out);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to write to stream", e);
|
||||
} finally {
|
||||
// close the PipedOutputStream here because we're done writing data
|
||||
// once this thread has completed its run
|
||||
StreamHelper.close(out);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
applyXSLTToHTML(in, baos);
|
||||
} catch (IOException e1) {
|
||||
LOGGER.error("Failed to create HTML", e1);
|
||||
}
|
||||
|
||||
Optional<InputStream> in = copyStream(htmlOutput);
|
||||
ByteArrayOutputStream htmlOutStream = new ByteArrayOutputStream();
|
||||
if (in.isPresent()) {
|
||||
applyXSLTToHTML(in.get(), htmlOutStream, lang);
|
||||
}
|
||||
|
||||
return baos.toString(StandardCharsets.UTF_8);
|
||||
return htmlOutStream.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: jstaerk: why not copy with that simple call: new ByteArrayInputStream(byteArrayOutputStream.toByteArray()) ?
|
||||
*/
|
||||
private Optional<InputStream> copyStream(ByteArrayOutputStream byteArrayOutputStream) {
|
||||
// take the copy of the stream and re-write it to an InputStream
|
||||
PipedInputStream in = new PipedInputStream();
|
||||
try {
|
||||
PipedOutputStream out = new PipedOutputStream(in);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// write the original OutputStream to the PipedOutputStream
|
||||
// note that in order for the below method to work, you need
|
||||
// to ensure that the data has finished writing to the
|
||||
// ByteArrayOutputStream
|
||||
byteArrayOutputStream.writeTo(out);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to write to stream", e);
|
||||
} finally {
|
||||
// close the PipedOutputStream here because we're done writing data
|
||||
// once this thread has completed its run
|
||||
StreamHelper.close(out);
|
||||
}
|
||||
}).start();
|
||||
} catch (IOException e1) {
|
||||
LOGGER.error("Failed to create HTML", e1);
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(in);
|
||||
}
|
||||
|
||||
|
||||
private void initTemplates(Language lang) throws TransformerConfigurationException {
|
||||
if (mXsltXRTemplate == null) {
|
||||
mXsltXRTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
||||
}
|
||||
|
||||
if (mXsltHTMLTemplates == null) {
|
||||
mXsltHTMLTemplates = new HashMap<>();
|
||||
if (mXsltHTMLTemplates.get(lang) == null) {
|
||||
Templates mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
|
||||
mXsltHTMLTemplates.put(lang, mXsltHTMLTemplate);
|
||||
}
|
||||
}
|
||||
if (mXsltZF1HTMLTemplate == null) {
|
||||
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
|
||||
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
|
||||
}
|
||||
}
|
||||
|
||||
protected String toFOP(String xmlFilename)
|
||||
throws FileNotFoundException, TransformerException {
|
||||
throws IOException, TransformerException, ParserConfigurationException {
|
||||
EStandard theStandard;
|
||||
try (FileInputStream fis = new FileInputStream(xmlFilename)) {
|
||||
theStandard = findOutStandardFromRootNode(fis);
|
||||
}
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(xmlFilename)) {
|
||||
return toFOP(fis, theStandard);
|
||||
}
|
||||
}
|
||||
|
||||
protected String toFOP(InputStream is, EStandard theStandard)
|
||||
throws TransformerException, IOException {
|
||||
|
||||
try {
|
||||
if (mXsltXRTemplate == null) {
|
||||
mXsltXRTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
||||
}
|
||||
if (mXsltPDFTemplate == null) {
|
||||
mXsltPDFTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
|
||||
@@ -232,58 +261,86 @@ public class ZUGFeRDVisualizer {
|
||||
LOGGER.error("Failed to init XSLT templates", ex);
|
||||
}
|
||||
|
||||
FileInputStream fis = new FileInputStream(xmlFilename);
|
||||
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
//zf2 or fx
|
||||
applyZF2XSLT(fis, iaos);
|
||||
|
||||
PipedInputStream in = new PipedInputStream();
|
||||
PipedOutputStream out;
|
||||
try {
|
||||
out = new PipedOutputStream(in);
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// write the original OutputStream to the PipedOutputStream
|
||||
// note that in order for the below method to work, you need
|
||||
// to ensure that the data has finished writing to the
|
||||
// ByteArrayOutputStream
|
||||
iaos.writeTo(out);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to write to stream", e);
|
||||
} finally {
|
||||
// close the PipedOutputStream here because we're done writing data
|
||||
// once this thread has completed its run
|
||||
StreamHelper.close(out);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
applyXSLTToPDF(in, baos);
|
||||
} catch (IOException e1) {
|
||||
LOGGER.error("Failed to create PDF", e1);
|
||||
if (theStandard == EStandard.facturx) {
|
||||
applyZF2XSLT(is, iaos);
|
||||
} else if (theStandard == EStandard.ubl) {
|
||||
applyUBL2XSLT(is, iaos);
|
||||
} else if (theStandard == EStandard.ubl_creditnote) {
|
||||
applyUBLCreditNote2XSLT(is, iaos);
|
||||
}
|
||||
|
||||
|
||||
Optional<InputStream> in = copyStream(iaos);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
if (in.isPresent()) {
|
||||
applyXSLTToPDF(in.get(), baos);
|
||||
}
|
||||
return baos.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public void toPDF(String xmlFilename, String pdfFilename) {
|
||||
|
||||
// the writing part
|
||||
File CIIinputFile = new File(xmlFilename);
|
||||
File XMLinputFile = new File(xmlFilename);
|
||||
|
||||
String result = null;
|
||||
String fopInput = null;
|
||||
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*/
|
||||
try {
|
||||
result = this.toFOP(CIIinputFile.getAbsolutePath());
|
||||
} catch (FileNotFoundException | TransformerException e) {
|
||||
fopInput = this.toFOP(XMLinputFile.getAbsolutePath());
|
||||
} catch (TransformerException | IOException | ParserConfigurationException e) {
|
||||
LOGGER.error("Failed to apply FOP", e);
|
||||
}
|
||||
|
||||
toPDFfromFOP(fopInput, () -> {
|
||||
try {
|
||||
return new FileOutputStream(pdfFilename);
|
||||
} catch (FileNotFoundException e) {
|
||||
LOGGER.error("Failed to create PDF", e);
|
||||
}
|
||||
return null;
|
||||
}, (OutputStream out) -> {});
|
||||
}
|
||||
|
||||
public byte[] toPDF(String xmlContent) {
|
||||
|
||||
String fopInput = null;
|
||||
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*/
|
||||
try {
|
||||
ByteArrayInputStream fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));
|
||||
EStandard theStandard = findOutStandardFromRootNode(fis);
|
||||
fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-(
|
||||
|
||||
fopInput = toFOP(fis, theStandard);
|
||||
} catch (TransformerException | IOException | ParserConfigurationException e) {
|
||||
LOGGER.error("Failed to apply FOP", e);
|
||||
}
|
||||
|
||||
AtomicReference<byte[]> byteHolder = new AtomicReference<>();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
toPDFfromFOP(fopInput, () -> new BufferedOutputStream(os), (OutputStream out) -> {
|
||||
|
||||
try {
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to create PDF", e);
|
||||
}
|
||||
byteHolder.set(os.toByteArray());
|
||||
});
|
||||
|
||||
return byteHolder.get();
|
||||
}
|
||||
|
||||
private void toPDFfromFOP(String fopInput, Supplier<OutputStream> outputStreamDelegate, Consumer<OutputStream> consumerDelegate) {
|
||||
|
||||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
|
||||
|
||||
Configuration cfg = null;
|
||||
@@ -311,40 +368,46 @@ public class ZUGFeRDVisualizer {
|
||||
// Step 2: Set up output stream.
|
||||
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
|
||||
|
||||
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFilename))) {
|
||||
try (OutputStream out = new BufferedOutputStream(outputStreamDelegate.get())) {
|
||||
|
||||
// Step 3: Construct fop with desired output format
|
||||
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);
|
||||
|
||||
// Step 4: Setup JAXP using identity transformer
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
Transformer transformer = factory.newTransformer(); // identity transformer
|
||||
|
||||
// Step 5: Setup input and output for XSLT transformation
|
||||
// Setup input stream
|
||||
Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)));
|
||||
Source src = new StreamSource(new ByteArrayInputStream(fopInput.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
// Resulting SAX events (the generated FO) must be piped through to FOP
|
||||
Result res = new SAXResult(fop.getDefaultHandler());
|
||||
|
||||
// Step 6: Start XSLT transformation and FOP processing
|
||||
transformer.transform(src, res);
|
||||
|
||||
//Files.write(Paths.get("C:\\Users\\jstaerk\\temp\\fop.pdf"), res.toString().getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
consumerDelegate.accept(out);
|
||||
|
||||
} catch (FOPException | IOException | TransformerException e) {
|
||||
LOGGER.error("Failed to create PDF", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
|
||||
throws TransformerException {
|
||||
if (mXsltXRTemplate == null) {
|
||||
mXsltXRTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
||||
|
||||
}
|
||||
Transformer transformer = mXsltXRTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
|
||||
}
|
||||
|
||||
protected void applyCIO2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
protected void applyCIO2XSLT(final InputStream xmlFile, final OutputStream htmlOutstream)
|
||||
throws TransformerException {
|
||||
if (mXsltCIOTemplate == null) {
|
||||
mXsltCIOTemplate = mFactory.newTemplates(
|
||||
@@ -352,10 +415,10 @@ public class ZUGFeRDVisualizer {
|
||||
}
|
||||
Transformer transformer = mXsltCIOTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutstream));
|
||||
}
|
||||
|
||||
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
|
||||
throws TransformerException {
|
||||
if (mXsltUBLTemplate == null) {
|
||||
mXsltUBLTemplate = mFactory.newTemplates(
|
||||
@@ -363,10 +426,10 @@ public class ZUGFeRDVisualizer {
|
||||
}
|
||||
Transformer transformer = mXsltUBLTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
|
||||
}
|
||||
|
||||
protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
|
||||
throws TransformerException {
|
||||
if (mXsltUBLTemplate == null) {
|
||||
mXsltUBLTemplate = mFactory.newTemplates(
|
||||
@@ -374,28 +437,30 @@ public class ZUGFeRDVisualizer {
|
||||
}
|
||||
Transformer transformer = mXsltUBLTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
|
||||
}
|
||||
|
||||
protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
|
||||
throws TransformerException {
|
||||
Transformer transformer = mXsltZF1HTMLTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
|
||||
}
|
||||
|
||||
protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
throws TransformerException {
|
||||
Transformer transformer = mXsltHTMLTemplate.newTransformer();
|
||||
protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream htmlOutStream, Language lang)
|
||||
throws TransformerException, IOException {
|
||||
Transformer transformer = mXsltHTMLTemplates.get(lang).newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
|
||||
xmlFile.close();
|
||||
}
|
||||
|
||||
protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream)
|
||||
throws TransformerException {
|
||||
throws TransformerException, IOException {
|
||||
Transformer transformer = mXsltPDFTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream));
|
||||
xmlFile.close();
|
||||
}
|
||||
|
||||
private static class ClasspathResourceURIResolver implements URIResolver {
|
||||
@@ -404,7 +469,7 @@ public class ZUGFeRDVisualizer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Source resolve(String href, String base) throws TransformerException {
|
||||
public Source resolve(String href, String base) {
|
||||
return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/" + href));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
* Copyright 2018 Jochen Staerk
|
||||
*
|
||||
* <p>
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*********************************************************************** */
|
||||
* <p>
|
||||
* **********************************************************************
|
||||
*/
|
||||
package org.mustangproject.ZUGFeRD.model;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -29,6 +31,7 @@ public class TaxCategoryCodeTypeConstants {
|
||||
public static final String ZEROTAXPRODUCTS = "Z";
|
||||
public static final String UNTAXEDSERVICE = "O";
|
||||
public static final String INTRACOMMUNITY = "K";
|
||||
|
||||
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE).collect(Collectors.toSet());
|
||||
public static final String FREEEXPORT = "G";
|
||||
|
||||
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT, UNTAXEDSERVICE).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.mustangproject.util;
|
||||
|
||||
public final class ByteArraySearcher {
|
||||
|
||||
private ByteArraySearcher() {
|
||||
}
|
||||
|
||||
public static int indexOf(byte[] haystack, byte[] needle) {
|
||||
if (needle.length > haystack.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Any needle to search?
|
||||
if (needle.length == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= haystack.length - needle.length; i++) {
|
||||
boolean found = true;
|
||||
for (int j = 0; j < needle.length; j++) {
|
||||
if (haystack[i + j] != needle[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static boolean contains(byte[] haystack, byte[] needle) {
|
||||
return indexOf(haystack, needle) >= 0;
|
||||
}
|
||||
|
||||
public static boolean startsWith(byte[] haystack, byte[] needle) {
|
||||
if (needle.length > haystack.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Any needle to search?
|
||||
if (needle.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int j = 0; j < needle.length; j++) {
|
||||
if (haystack[j] != needle[j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
151
library/src/main/java/org/mustangproject/util/NodeMap.java
Normal file
151
library/src/main/java/org/mustangproject/util/NodeMap.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
* Copyright (c) 2024 Jan N. Klug
|
||||
* <p>
|
||||
* Use is subject to license terms.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* <p>
|
||||
* **********************************************************************
|
||||
*/
|
||||
package org.mustangproject.util;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The {@link NodeMap} contains a {@link Map} representation of DOM object
|
||||
* It can be constructed either from the children of a single {@link Node} or a {@link NodeList}.
|
||||
*/
|
||||
public class NodeMap {
|
||||
private final Map<String, List<Node>> map = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create a new {@link NodeMap}
|
||||
* The {@link Node} that is passed to the constructor must not be null.
|
||||
* The {@link NodeMap} will be empty when no child nodes are present.
|
||||
*
|
||||
* @param node the node that shall be represented by this {@link NodeMap}
|
||||
* @throws IllegalArgumentException when argument is null
|
||||
*/
|
||||
public NodeMap(Node node) {
|
||||
if (node == null) {
|
||||
throw new IllegalArgumentException("node cannot be null");
|
||||
}
|
||||
if (node.hasChildNodes()) {
|
||||
mapNodeList(node.getChildNodes());
|
||||
}
|
||||
}
|
||||
|
||||
public NodeMap(NodeList nodeList) {
|
||||
if (nodeList == null) {
|
||||
throw new IllegalArgumentException("nodeList cannot be null");
|
||||
}
|
||||
mapNodeList(nodeList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matching node by {@code LocalName}
|
||||
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||
*
|
||||
* @param localNames one or more {@code LocalName}s
|
||||
* @return the matching node
|
||||
*/
|
||||
public Optional<Node> getNode(String... localNames) {
|
||||
return getAllNodes(localNames).findAny();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link NodeMap} of the child of a matching node by {@code LocalName}
|
||||
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||
*
|
||||
* @param localNames one or more {@code LocalName}s
|
||||
* @return the {@link NodeMap} representation of the matching node
|
||||
*/
|
||||
public Optional<NodeMap> getAsNodeMap(String... localNames) {
|
||||
return getNode(localNames).filter(Node::hasChildNodes).map(NodeMap::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text content of a matching node
|
||||
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||
*
|
||||
* @param localNames one or more {@code LocalName}s
|
||||
* @return the text content of the matching node
|
||||
*/
|
||||
public Optional<String> getAsString(String... localNames) {
|
||||
return getNode(localNames).map(Node::getTextContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text content of a matching node
|
||||
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||
*
|
||||
* @param localNames one or more {@code LocalName}s
|
||||
* @return the text content of the matching node, converted to BigDecimal
|
||||
*/
|
||||
public Optional<BigDecimal> getAsBigDecimal(String... localNames) {
|
||||
return getNode(localNames).map(Node::getTextContent).map(s->{
|
||||
try {
|
||||
return new BigDecimal(s.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text content of a matching node
|
||||
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||
*
|
||||
* @param localNames one or more {@code LocalName}s
|
||||
* @return the text content of the matching node or {@code null} when no matching node could be found
|
||||
*/
|
||||
public String getAsStringOrNull(String... localNames) {
|
||||
return getAsString(localNames).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all matching nodes
|
||||
*
|
||||
* @param localNames one or more {@code LocalName}s
|
||||
* @return a {@code Stream} that contains all matching nodes (can be empty if nothing matches)
|
||||
*/
|
||||
public Stream<Node> getAllNodes(String... localNames) {
|
||||
List<String> localNamesList = Arrays.asList(localNames);
|
||||
return map.entrySet().stream().filter(e -> localNamesList.contains(e.getKey())).flatMap(e -> e.getValue().stream());
|
||||
}
|
||||
|
||||
private void mapNodeList(NodeList nodeList) {
|
||||
IntStream.range(0, nodeList.getLength()).mapToObj(nodeList::item)
|
||||
.filter(node -> node != null && node.getLocalName() != null)
|
||||
.forEach(node -> map.computeIfAbsent(node.getLocalName(), k -> new ArrayList<>()).add(node));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
}
|
||||
BIN
library/src/main/resources/fonts/SourceSansPro-Bold.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSansPro-Bold.ttf
Normal file
Binary file not shown.
BIN
library/src/main/resources/fonts/SourceSansPro-BoldIt.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSansPro-BoldIt.ttf
Normal file
Binary file not shown.
BIN
library/src/main/resources/fonts/SourceSansPro-It.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSansPro-It.ttf
Normal file
Binary file not shown.
BIN
library/src/main/resources/fonts/SourceSansPro-Regular.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSansPro-Regular.ttf
Normal file
Binary file not shown.
BIN
library/src/main/resources/fonts/SourceSerifPro-Bold.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSerifPro-Bold.ttf
Normal file
Binary file not shown.
BIN
library/src/main/resources/fonts/SourceSerifPro-BoldIt.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSerifPro-BoldIt.ttf
Normal file
Binary file not shown.
BIN
library/src/main/resources/fonts/SourceSerifPro-It.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSerifPro-It.ttf
Normal file
Binary file not shown.
BIN
library/src/main/resources/fonts/SourceSerifPro-Regular.ttf
Normal file
BIN
library/src/main/resources/fonts/SourceSerifPro-Regular.ttf
Normal file
Binary file not shown.
@@ -1,37 +1,57 @@
|
||||
<fop version="1.0">
|
||||
|
||||
<!-- Strict user configuration -->
|
||||
<strict-configuration>true</strict-configuration>
|
||||
|
||||
<!-- Strict FO validation -->
|
||||
<strict-validation>true</strict-validation>
|
||||
|
||||
<!-- Base URL for resolving relative URLs -->
|
||||
|
||||
<!-- Font Base URL for resolving relative font URLs -->
|
||||
|
||||
<!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi -->
|
||||
<source-resolution>96</source-resolution>
|
||||
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi -->
|
||||
<target-resolution>96</target-resolution>
|
||||
|
||||
<!-- default page-height and page-width, in case
|
||||
value is specified as auto -->
|
||||
<default-page-settings height="297mm" width="210mm"/><!-- DIN A/4 -->
|
||||
|
||||
<!-- etc. etc..... -->
|
||||
|
||||
<renderers>
|
||||
<renderer mime="application/pdf">
|
||||
<fonts><!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
|
||||
<auto-detect/>
|
||||
<font kerning="no" embed-url="classpath:FreeSans.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSerifPro" style="normal" weight="normal" />
|
||||
<font-triplet name="Times-Bold" style="normal" weight="normal" />
|
||||
</font>
|
||||
</fonts>
|
||||
<output-profile>classpath:AdobeCompat-v2.icc</output-profile>
|
||||
</renderer>
|
||||
</renderers>
|
||||
|
||||
</fop>
|
||||
<fop version="1.0">
|
||||
|
||||
<!-- Strict user configuration -->
|
||||
<strict-configuration>true</strict-configuration>
|
||||
|
||||
<!-- Strict FO validation -->
|
||||
<strict-validation>true</strict-validation>
|
||||
|
||||
<!-- Base URL for resolving relative URLs -->
|
||||
|
||||
<!-- Font Base URL for resolving relative font URLs -->
|
||||
|
||||
<!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi -->
|
||||
<source-resolution>96</source-resolution>
|
||||
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi -->
|
||||
<target-resolution>96</target-resolution>
|
||||
|
||||
<!-- default page-height and page-width, in case
|
||||
value is specified as auto -->
|
||||
<default-page-settings height="297mm" width="210mm"/><!-- DIN A/4 -->
|
||||
|
||||
<!-- etc. etc..... -->
|
||||
|
||||
<renderers>
|
||||
<renderer mime="application/pdf">
|
||||
<fonts>
|
||||
<!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
|
||||
<auto-detect/>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-Regular.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSansPro" style="normal" weight="400"/>
|
||||
</font>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-It.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSansPro" style="italic" weight="400"/>
|
||||
</font>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-Bold.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSansPro" style="normal" weight="700"/>
|
||||
</font>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-BoldIt.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSansPro" style="italic" weight="700"/>
|
||||
</font>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-Regular.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSerifPro" style="normal" weight="400"/>
|
||||
</font>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-It.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSerifPro" style="italic" weight="400"/>
|
||||
</font>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-Bold.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSerifPro" style="normal" weight="700"/>
|
||||
</font>
|
||||
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-BoldIt.ttf" embedding-mode="subset">
|
||||
<font-triplet name="SourceSerifPro" style="italic" weight="700"/>
|
||||
</font>
|
||||
</fonts>
|
||||
<output-profile>classpath:AdobeCompat-v2.icc</output-profile>
|
||||
</renderer>
|
||||
</renderers>
|
||||
</fop>
|
||||
|
||||
@@ -1,33 +1,37 @@
|
||||
<configuration>
|
||||
|
||||
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<target>System.err</target>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
|
||||
<then>
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- Daily rollover -->
|
||||
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
|
||||
|
||||
<!-- Keep 5 years worth of history -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
</then>
|
||||
</if>
|
||||
|
||||
<!-- Configure so that it outputs to both console and log file -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="FILE"/>
|
||||
<appender-ref ref="STDERR"/>
|
||||
</root>
|
||||
</configuration>
|
||||
<configuration>
|
||||
<appender name="STDERR"
|
||||
class="ch.qos.logback.core.ConsoleAppender">
|
||||
<target>System.err</target>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
|
||||
<then>
|
||||
<appender name="FILE"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- Daily rollover -->
|
||||
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
|
||||
<!-- Keep 5 years worth of history -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
</then>
|
||||
</if>
|
||||
<!-- Configure so that it outputs to both console and log file -->
|
||||
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
|
||||
<then>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
</then>
|
||||
</if>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDERR"/>
|
||||
</root>
|
||||
</configuration>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -198,7 +198,7 @@
|
||||
<entry key="xr:Third_party_payment_type" id="BT-DEX-001">Art der Fremdforderung</entry>
|
||||
<entry key="xr:Third_party_payment_amount" id="BT-DEX-002">Betrag der Fremdforderung</entry>
|
||||
<entry key="xr:Third_party_payment_description" id="BT-DEX-003">Beschreibung der Fremdforderung</entry>
|
||||
<entry key="uebersicht">Übersicht</entry>
|
||||
<entry key="uebersicht">Daten der E-Rechnung</entry>
|
||||
<entry key="uebersichtKaeufer" id="BG-7">Informationen zum Käufer</entry>
|
||||
<entry key="uebersichtVerkaeufer" id="BG-4">Informationen zum Verkäufer</entry>
|
||||
<entry key="uebersichtRechnungsInfo" id="invoice-data">Rechnungsdaten</entry>
|
||||
@@ -214,7 +214,7 @@
|
||||
<entry key="uebersichtZahlungLastschrift" id="BG-19">Lastschrift</entry>
|
||||
<entry key="uebersichtZahlungUeberweisung" id="BG-17">Überweisung</entry>
|
||||
<entry key="uebersichtBemerkungen" id="BG-1">Bemerkungen zur Rechnung</entry>
|
||||
<entry key="details">Details</entry>
|
||||
<entry key="details">Rechnungspositionen</entry>
|
||||
<entry key="detailsPositionAbrechnungszeitraum" id="BG-26">Abrechnungszeitraum</entry>
|
||||
<entry key="detailsPositionPreiseinzelheiten" id="BG-29">Preiseinzelheiten</entry>
|
||||
<entry key="detailsPositionNachlaesse" id="BG-27">Nachlässe auf Ebene der Rechnungsposition</entry>
|
||||
|
||||
377
library/src/main/resources/stylesheets/result-pdf.xsl
Normal file
377
library/src/main/resources/stylesheets/result-pdf.xsl
Normal file
@@ -0,0 +1,377 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="2.0">
|
||||
<!-- Imports -->
|
||||
<xsl:import href="common-xr.xsl"/>
|
||||
<xsl:import href="xr-pdf/lib/konstanten.xsl"/>
|
||||
<!--
|
||||
FO engine used can be specified.
|
||||
Specific extensions will be then enabled.
|
||||
Supported values are:
|
||||
axf - Antenna House XSL Formatter
|
||||
fop - Apache FOP
|
||||
-->
|
||||
<xsl:param name="foengine"/>
|
||||
<xsl:param name="axf.extensions"
|
||||
select="if ($foengine eq 'axf') then true() else false()"/>
|
||||
<xsl:param name="fop.extensions"
|
||||
select="if ($foengine eq 'fop') then true() else false()"/>
|
||||
<xsl:variable name="xml_result_color">
|
||||
<xsl:if test="/validation/xml/summary/@status = 'valid'">
|
||||
<xsl:text>green</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
|
||||
<xsl:text>red</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="xml_result_text">
|
||||
<xsl:if test="/validation/xml/summary/@status = 'valid'">
|
||||
<xsl:text>Das XML ist valide.</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
|
||||
<xsl:text>Das XML ist nicht valide.</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="pdf_result_color">
|
||||
<xsl:if test="/validation/pdf/summary/@status = 'valid'">
|
||||
<xsl:text>green</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="/validation/pdf/summary/@status = 'invalid'">
|
||||
<xsl:text>red</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="pdf_result_text">
|
||||
<xsl:if test="/validation/pdf/summary/@status = 'valid'">
|
||||
<xsl:text>Das ZUGFeRD-PDF ist valide.</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="/validation/pdf/summary/@status = 'invalid'">
|
||||
<xsl:text>Das ZUGFeRD-PDF ist nicht valide.</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="result_color">
|
||||
<xsl:if test="/validation/summary/@status = 'valid'">
|
||||
<xsl:text>green</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="/validation/summary/@status = 'invalid'">
|
||||
<xsl:text>red</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="result_text">
|
||||
<xsl:if test="/validation/summary/@status = 'valid'">
|
||||
<xsl:text>Es wird empfohlen, das Dokument anzunehmen und es weiterzuverarbeiten.</xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="/validation/summary/@status = 'invalid'">
|
||||
<xsl:text>Es wird empfohlen, das Dokument zurückzuweisen.</xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:variable>
|
||||
<xsl:template match="validation">
|
||||
<fo:root language="{$lang}"
|
||||
font-family="{$fontSans}">
|
||||
<fo:layout-master-set>
|
||||
<fo:simple-page-master master-name="DIN-A4"
|
||||
page-height="297mm"
|
||||
page-width="210mm">
|
||||
<fo:region-body region-name="body"
|
||||
margin="20mm 10mm 20mm 20mm"/>
|
||||
</fo:simple-page-master>
|
||||
</fo:layout-master-set>
|
||||
<fo:page-sequence master-reference="DIN-A4">
|
||||
<fo:flow flow-name="body">
|
||||
<fo:block font-size="24px"
|
||||
font-weight="bold">
|
||||
<xsl:text>Prüfbericht</xsl:text>
|
||||
</fo:block>
|
||||
<xsl:call-template name="SubHeader">
|
||||
<xsl:with-param name="text"
|
||||
select="'Angaben zum geprüften Dokument'"/>
|
||||
<xsl:with-param name="color"
|
||||
select="'black'"/>
|
||||
</xsl:call-template>
|
||||
<fo:table>
|
||||
<fo:table-column border-style="none"/>
|
||||
<fo:table-column column-width="70%"
|
||||
border-style="none"/>
|
||||
<fo:table-body>
|
||||
<fo:table-row>
|
||||
<fo:table-cell>
|
||||
<fo:block text-align="left">Referenz:</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block text-align="right">
|
||||
<xsl:value-of select="./@filename"/>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
<fo:table-row>
|
||||
<fo:table-cell>
|
||||
<fo:block text-align="left">Zeitpunkt der Prüfung:</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block text-align="right">
|
||||
<xsl:value-of select="./@datetime"/>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
<fo:table-row>
|
||||
<fo:table-cell>
|
||||
<fo:block text-align="left">Erkannter Dokumenttyp:</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block text-align="right">
|
||||
<xsl:call-template name="EnableLineBreaks">
|
||||
<xsl:with-param name="text"
|
||||
select="./xml/info/profile"/>
|
||||
<xsl:with-param name="separator"
|
||||
select="'#'"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
</fo:table-body>
|
||||
</fo:table>
|
||||
<xsl:apply-templates select="./pdf"/>
|
||||
<xsl:apply-templates select="./xml"/>
|
||||
<!--
|
||||
<xsl:call-template name="SubHeader">
|
||||
<xsl:with-param name="text"
|
||||
select=="'Konformitätsprüfung:'"/>
|
||||
<xsl:with-param name="color"
|
||||
select=="'black'"/>
|
||||
</xsl:call-template>
|
||||
-->
|
||||
<xsl:call-template name="SubHeader">
|
||||
<xsl:with-param name="text"
|
||||
select="concat('Bewertung: ', $result_text)"/>
|
||||
<xsl:with-param name="color"
|
||||
select="$result_color"/>
|
||||
</xsl:call-template>
|
||||
<fo:block>Validierungsergebnisse im Detail:</fo:block>
|
||||
<fo:table>
|
||||
<fo:table-column border-style="solid"/>
|
||||
<fo:table-column border-style="solid"/>
|
||||
<fo:table-column border-style="solid"/>
|
||||
<fo:table-column border-style="solid"
|
||||
column-width="68%"/>
|
||||
<fo:table-header>
|
||||
<fo:table-row background-color="#E0E0E0"
|
||||
font-weight="bold"
|
||||
border-style="solid">
|
||||
<fo:table-cell>
|
||||
<fo:block margin="0mm"
|
||||
padding="1mm">Type</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block margin="0mm"
|
||||
padding="1mm">Code</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block margin="0mm"
|
||||
padding="1mm">Schwere</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block margin="0mm"
|
||||
padding="1mm">Text</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
</fo:table-header>
|
||||
<fo:table-body page-break-after="auto"
|
||||
page-break-before="auto"
|
||||
page-break-inside="avoid">
|
||||
<xsl:choose>
|
||||
<xsl:when test="./pdf/messages|./xml/messages|./messages">
|
||||
<xsl:apply-templates select="./pdf/messages|./xml/messages|./messages"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<fo:table-row border-style="solid"
|
||||
font-size="12px">
|
||||
<fo:table-cell number-columns-spanned="4">
|
||||
<fo:block margin="0mm"
|
||||
padding="1mm"
|
||||
text-align="center">Es gibt keine Hinweise, Warnungen oder Fehler.</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</fo:table-body>
|
||||
</fo:table>
|
||||
</fo:flow>
|
||||
</fo:page-sequence>
|
||||
</fo:root>
|
||||
</xsl:template>
|
||||
<xsl:template match="notice|warning|error|exception|fatal">
|
||||
<xsl:variable name="msg_color">
|
||||
<xsl:choose>
|
||||
<xsl:when test="name() = 'error' or name() = 'exception' or name() = 'fatal'">
|
||||
<xsl:text>red</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="name() = 'warning'">
|
||||
<xsl:text>orange</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>black</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="msg_label">
|
||||
<xsl:choose>
|
||||
<xsl:when test="name() = 'error' or name() = 'exception' or name() = 'fatal'">
|
||||
<xsl:text>Fehler</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="name() = 'warning'">
|
||||
<xsl:text>Warnung</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>Hinweis</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="msg_text">
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(., ' [ID ')">
|
||||
<xsl:value-of select="substring-before(., ' [ID')"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="rows-spanned">
|
||||
<xsl:choose>
|
||||
<xsl:when test="./@location">
|
||||
<xsl:value-of select="'2'"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="'1'"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<fo:table-row border-style="solid"
|
||||
font-size="12px"
|
||||
keep-with-previous="auto"
|
||||
keep-with-next="always">
|
||||
<fo:table-cell number-rows-spanned="{$rows-spanned}">
|
||||
<fo:block margin="0mm"
|
||||
padding="1mm">
|
||||
<xsl:value-of select="./@type"/>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block margin="0mm"
|
||||
padding="1mm">
|
||||
<xsl:value-of select="substring-before(substring-after(., ' [ID '), ']')"/>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block color="{$msg_color}"
|
||||
margin="0mm"
|
||||
padding="1mm">
|
||||
<xsl:value-of select="$msg_label"/>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
<fo:table-cell>
|
||||
<fo:block color="{$msg_color}"
|
||||
margin="0mm"
|
||||
padding="1mm">
|
||||
<xsl:call-template name="IntersperseWithZeroSpaces">
|
||||
<xsl:with-param name="str" select="$msg_text"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
<xsl:if test="./@location">
|
||||
<fo:table-row border-style="solid"
|
||||
font-size="8px"
|
||||
keep-with-previous="always"
|
||||
keep-with-next="auto">
|
||||
<fo:table-cell number-columns-spanned="3">
|
||||
<fo:block color="{$msg_color}"
|
||||
margin="0mm"
|
||||
padding="1mm">
|
||||
<fo:block font-size="12px">
|
||||
<xsl:value-of select="'Pfad: '"/>
|
||||
</fo:block>
|
||||
<xsl:call-template name="EnableLineBreaks">
|
||||
<xsl:with-param name="text"
|
||||
select="./@location"/>
|
||||
<xsl:with-param name="separator"
|
||||
select="'/'"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
<xsl:template match="pdf">
|
||||
<xsl:call-template name="SubHeader">
|
||||
<xsl:with-param name="text"
|
||||
select="concat('ZUGFeRD-PDF: ', $pdf_result_text)"/>
|
||||
<xsl:with-param name="color"
|
||||
select="$pdf_result_color"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
<xsl:template match="xml">
|
||||
<xsl:call-template name="SubHeader">
|
||||
<xsl:with-param name="text"
|
||||
select="concat('E-Rechnung XML: ', $xml_result_text)"/>
|
||||
<xsl:with-param name="color"
|
||||
select="$xml_result_color"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
<xsl:template name="SubHeader">
|
||||
<xsl:param name="text"/>
|
||||
<xsl:param name="color"/>
|
||||
<fo:block color="{$color}"
|
||||
background-color="#E0E0E0"
|
||||
margin-bottom="10px"
|
||||
padding="3px"
|
||||
font-weight="bold"
|
||||
margin-top="10px">
|
||||
<xsl:value-of select="$text"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
<xsl:template name="EnableLineBreaks">
|
||||
<xsl:param name="text"/>
|
||||
<xsl:param name="separator"/>
|
||||
<xsl:for-each select="tokenize($text, $separator)">
|
||||
<xsl:choose>
|
||||
<xsl:when test="position() eq 1">
|
||||
<fo:block>
|
||||
<xsl:value-of select="."/>
|
||||
</fo:block>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<fo:block>
|
||||
<xsl:value-of select="concat($separator, .)"/>
|
||||
</fo:block>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
<xsl:template name="IntersperseWithZeroSpaces">
|
||||
<xsl:param name="str"/>
|
||||
<xsl:variable name="spacechars">
|
||||
	

|
||||
      
|
||||
     ​
|
||||
</xsl:variable>
|
||||
<xsl:if test="string-length($str) > 0">
|
||||
<xsl:variable name="c1" select="substring($str, 1, 1)"/>
|
||||
<xsl:variable name="c2" select="substring($str, 2, 1)"/>
|
||||
|
||||
<xsl:value-of select="$c1"/>
|
||||
<xsl:if test="$c2 != '' and
|
||||
not(contains($spacechars, $c1) or
|
||||
contains($spacechars, $c2))">
|
||||
<xsl:text>​</xsl:text>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:call-template name="IntersperseWithZeroSpaces">
|
||||
<xsl:with-param name="str" select="substring($str, 2)"/>
|
||||
</xsl:call-template>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
@@ -789,7 +789,7 @@
|
||||
<xsl:apply-templates mode="list-entry" select="xr:DELIVERY_INFORMATION/xr:Deliver_to_location_identifier/@scheme_identifier">
|
||||
<xsl:with-param name="field-mapping-identifier" select="'xr:Deliver_to_location_identifier/@scheme_identifier'"/>
|
||||
</xsl:apply-templates>
|
||||
<xsl:apply-templates mode="list-entry" select="xr:DELIVERY_INFORMATION/xr:Actual_delivery_date">
|
||||
<xsl:apply-templates mode="list-entry" select="xr:DELIVERY_INFORMATION/xr:Actual_delivery_date">
|
||||
<xsl:with-param name="value" select="format-date(xr:DELIVERY_INFORMATION/xr:Actual_delivery_date, xrf:_('date-format'))"/>
|
||||
</xsl:apply-templates>
|
||||
<xsl:apply-templates mode="list-entry" select="xr:DELIVERY_INFORMATION/xr:Deliver_to_party_name"/>
|
||||
@@ -807,10 +807,11 @@
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="zusaetzeVertrag">
|
||||
<xsl:call-template name="box">
|
||||
<xsl:call-template name="spanned-box">
|
||||
<xsl:with-param name="identifier" select="'zusaetzeVertrag'"/>
|
||||
<xsl:with-param name="content">
|
||||
<xsl:call-template name="list">
|
||||
<xsl:with-param name="layout" select="'einspaltig'"/>
|
||||
<xsl:with-param name="content">
|
||||
<xsl:apply-templates mode="list-entry" select="xr:Tender_or_lot_reference"/>
|
||||
<xsl:apply-templates mode="list-entry" select="xr:Receiving_advice_reference"/>
|
||||
|
||||
@@ -398,7 +398,7 @@
|
||||
<nummer>BT-64</nummer>
|
||||
</xsl:when>
|
||||
<xsl:when test="$identifier = 'xr:Tax_representative_address_line_2'">
|
||||
<label>Postfach</label>
|
||||
<label>Adresszusatz</label>
|
||||
<nummer>BT-65</nummer>
|
||||
</xsl:when>
|
||||
<xsl:when test="$identifier = 'xr:Tax_representative_address_line_3'">
|
||||
@@ -486,7 +486,7 @@
|
||||
<nummer>BT-75</nummer>
|
||||
</xsl:when>
|
||||
<xsl:when test="$identifier = 'xr:Deliver_to_address_line_2'">
|
||||
<label>Postfach</label>
|
||||
<label>Adresszusatz</label>
|
||||
<nummer>BT-76</nummer>
|
||||
</xsl:when>
|
||||
<xsl:when test="$identifier = 'xr:Deliver_to_address_line_3'">
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<dc:title><xsl:value-of select="xr:Invoice_number"/></dc:title>
|
||||
<dc:title><rdf:Alt><rdf:li xml:lang="x-default"><xsl:value-of select="xr:Invoice_number"/></rdf:li></rdf:Alt></dc:title>
|
||||
<!--
|
||||
<dc:creator></dc:creator>
|
||||
<dc:description></dc:description>
|
||||
|
||||
@@ -1,235 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
|
||||
xmlns:xr="urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xrv="http://www.example.org/XRechnung-Viewer"
|
||||
xmlns:xrf="https://projekte.kosit.org/xrechnung/xrechnung-visualization/functions"
|
||||
version="2.0">
|
||||
|
||||
<!-- ==========================================================================
|
||||
== Schriften
|
||||
=========================================================================== -->
|
||||
|
||||
<xsl:variable name="fontSans">SourceSerifPro</xsl:variable>
|
||||
<xsl:variable name="fontSerif">SourceSerifPro</xsl:variable>
|
||||
|
||||
<xsl:variable name="amount-picture" select="xrf:_('amount-format')"/>
|
||||
<xsl:variable name="percentage-picture" select="xrf:_('percentage-format')"/>
|
||||
|
||||
|
||||
<!-- ==========================================================================
|
||||
== Attribute-Sets
|
||||
=========================================================================== -->
|
||||
|
||||
<!-- Fliesstext -->
|
||||
<xsl:attribute-set name="fliesstext">
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="line-height">12pt</xsl:attribute>
|
||||
<xsl:attribute name="hyphenation-ladder-count">3</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">true</xsl:attribute>
|
||||
<xsl:attribute name="language">de</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H1 Marker -->
|
||||
<xsl:attribute-set name="marker">
|
||||
<xsl:attribute name="font-size">18pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H1 -->
|
||||
<xsl:attribute-set name="h1">
|
||||
<xsl:attribute name="font-size">18pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H2-Container -->
|
||||
<xsl:attribute-set name="h2-container">
|
||||
<xsl:attribute name="border-top">0.5pt solid</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">2.5pt</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H2 -->
|
||||
<xsl:attribute-set name="h2">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="border">0.5pt solid</xsl:attribute>
|
||||
<xsl:attribute name="padding">4pt 6pt</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
<xsl:attribute name="margin">0</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H3 -->
|
||||
<xsl:attribute-set name="h3">
|
||||
<xsl:attribute name="font-size">10pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-top">2mm</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Separator -->
|
||||
<xsl:attribute-set name="separator">
|
||||
<xsl:attribute name="margin-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">3mm</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom">0.5pt dotted</xsl:attribute>
|
||||
<xsl:attribute name="color">#999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Wert-Felder -->
|
||||
<xsl:variable name="wertHG">#eeeeee</xsl:variable>
|
||||
<xsl:variable name="wert-legende-breite">28</xsl:variable>
|
||||
|
||||
<xsl:attribute-set name="wert-legende">
|
||||
<xsl:attribute name="font-size">7pt</xsl:attribute>
|
||||
<xsl:attribute name="line-height">10pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">1mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="wert-ausgabe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="line-height">10pt</xsl:attribute>
|
||||
<xsl:attribute name="background-color"><xsl:value-of select="$wertHG"/></xsl:attribute>
|
||||
<xsl:attribute name="padding-top">1mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">2mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Rechnung-Felder -->
|
||||
<xsl:attribute-set name="rechnung-legende">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-steuer">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-wert">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">right</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-legende-summe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-steuer-summe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-wert-summe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="text-align">right</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0mm</xsl:attribute>
|
||||
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Box-Container -->
|
||||
<xsl:attribute-set name="box-container-kapitel">
|
||||
<xsl:attribute name="margin-bottom">10mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="box-container-bereich">
|
||||
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-together.within-page">always</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="box-container-inner">
|
||||
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Tabular invoice lines -->
|
||||
<xsl:attribute-set name="invoicelines-table">
|
||||
<xsl:attribute name="padding-left">2pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">2pt</xsl:attribute>
|
||||
<xsl:attribute name="width">100%</xsl:attribute>
|
||||
<xsl:attribute name="table-layout">fixed</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-table-header">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-table-row">
|
||||
<!-- Nested sub-invoice lines will recursively decrease font-size -->
|
||||
<xsl:attribute name="font-size" select="if (self::xr:SUB_INVOICE_LINE) then '90%' else '100%'"/>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-nested-info">
|
||||
<xsl:attribute name="font-size">80%</xsl:attribute>
|
||||
<xsl:attribute name="font-style">italic</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-allowances-table">
|
||||
<xsl:attribute name="padding-left">2pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">2pt</xsl:attribute>
|
||||
<xsl:attribute name="width">100%</xsl:attribute>
|
||||
<xsl:attribute name="table-layout">fixed</xsl:attribute>
|
||||
<xsl:attribute name="font-size">80%</xsl:attribute>
|
||||
<xsl:attribute name="font-style">italic</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
</xsl:stylesheet>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
|
||||
xmlns:xr="urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xrv="http://www.example.org/XRechnung-Viewer"
|
||||
xmlns:xrf="https://projekte.kosit.org/xrechnung/xrechnung-visualization/functions"
|
||||
version="2.0">
|
||||
|
||||
<!-- ==========================================================================
|
||||
== Schriften
|
||||
=========================================================================== -->
|
||||
|
||||
<xsl:variable name="fontSans">SourceSansPro</xsl:variable>
|
||||
<xsl:variable name="fontSerif">SourceSerifPro</xsl:variable>
|
||||
|
||||
<xsl:variable name="amount-picture" select="xrf:_('amount-format')"/>
|
||||
<xsl:variable name="percentage-picture" select="xrf:_('percentage-format')"/>
|
||||
|
||||
|
||||
<!-- ==========================================================================
|
||||
== Attribute-Sets
|
||||
=========================================================================== -->
|
||||
|
||||
<!-- Fliesstext -->
|
||||
<xsl:attribute-set name="fliesstext">
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="line-height">12pt</xsl:attribute>
|
||||
<xsl:attribute name="hyphenation-ladder-count">3</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">true</xsl:attribute>
|
||||
<xsl:attribute name="language">de</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H1 Marker -->
|
||||
<xsl:attribute-set name="marker">
|
||||
<xsl:attribute name="font-size">18pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H1 -->
|
||||
<xsl:attribute-set name="h1">
|
||||
<xsl:attribute name="font-size">18pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H2-Container -->
|
||||
<xsl:attribute-set name="h2-container">
|
||||
<xsl:attribute name="border-top">0.5pt solid</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">2.5pt</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H2 -->
|
||||
<xsl:attribute-set name="h2">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="border">0.5pt solid</xsl:attribute>
|
||||
<xsl:attribute name="padding">4pt 6pt</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
<xsl:attribute name="margin">0</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- H3 -->
|
||||
<xsl:attribute-set name="h3">
|
||||
<xsl:attribute name="font-size">10pt</xsl:attribute>
|
||||
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-top">2mm</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Separator -->
|
||||
<xsl:attribute-set name="separator">
|
||||
<xsl:attribute name="margin-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">3mm</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom">0.5pt dotted</xsl:attribute>
|
||||
<xsl:attribute name="color">#999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Wert-Felder -->
|
||||
<xsl:variable name="wertHG">#eeeeee</xsl:variable>
|
||||
<xsl:variable name="wert-legende-breite">28</xsl:variable>
|
||||
|
||||
<xsl:attribute-set name="wert-legende">
|
||||
<xsl:attribute name="font-size">7pt</xsl:attribute>
|
||||
<xsl:attribute name="line-height">10pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">1mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="wert-ausgabe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="line-height">10pt</xsl:attribute>
|
||||
<xsl:attribute name="background-color"><xsl:value-of select="$wertHG"/></xsl:attribute>
|
||||
<xsl:attribute name="padding-top">1mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">2mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Rechnung-Felder -->
|
||||
<xsl:attribute-set name="rechnung-legende">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-steuer">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-wert">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">right</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0mm</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-legende-summe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-steuer-summe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">1mm</xsl:attribute>
|
||||
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="rechnung-wert-summe">
|
||||
<xsl:attribute name="font-size">9pt</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="text-align">right</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0mm</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0mm</xsl:attribute>
|
||||
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
|
||||
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Box-Container -->
|
||||
<xsl:attribute-set name="box-container-kapitel">
|
||||
<xsl:attribute name="margin-bottom">10mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="box-container-bereich">
|
||||
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
|
||||
<xsl:attribute name="keep-together.within-page">always</xsl:attribute>
|
||||
<xsl:attribute name="span">all</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="box-container-inner">
|
||||
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Tabular invoice lines -->
|
||||
<xsl:attribute-set name="invoicelines-table">
|
||||
<xsl:attribute name="padding-left">2pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">2pt</xsl:attribute>
|
||||
<xsl:attribute name="width">100%</xsl:attribute>
|
||||
<xsl:attribute name="table-layout">fixed</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-table-header">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-table-row">
|
||||
<!-- Nested sub-invoice lines will recursively decrease font-size -->
|
||||
<xsl:attribute name="font-size" select="if (self::xr:SUB_INVOICE_LINE) then '90%' else '100%'"/>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-nested-info">
|
||||
<xsl:attribute name="font-size">80%</xsl:attribute>
|
||||
<xsl:attribute name="font-style">italic</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<xsl:attribute-set name="invoicelines-allowances-table">
|
||||
<xsl:attribute name="padding-left">2pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">2pt</xsl:attribute>
|
||||
<xsl:attribute name="width">100%</xsl:attribute>
|
||||
<xsl:attribute name="table-layout">fixed</xsl:attribute>
|
||||
<xsl:attribute name="font-size">80%</xsl:attribute>
|
||||
<xsl:attribute name="font-style">italic</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
||||
@@ -1193,7 +1193,7 @@ function downloadData (element_id) {
|
||||
<div id="BT-50" title="BT-50" class="boxdaten wert"><xsl:value-of select="xr:BUYER_POSTAL_ADDRESS/xr:Buyer_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach (BT-51):</div>
|
||||
<div class="boxdaten legende">Adresszusatz (BT-51):</div>
|
||||
<div id="BT-51" title="BT-51" class="boxdaten wert"><xsl:value-of select="xr:BUYER_POSTAL_ADDRESS/xr:Buyer_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
@@ -1258,7 +1258,7 @@ function downloadData (element_id) {
|
||||
<div id="BT-35" title="BT-35" class="boxdaten wert"><xsl:value-of select="xr:SELLER_POSTAL_ADDRESS/xr:Seller_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach (BT-36):</div>
|
||||
<div class="boxdaten legende">Adresszusatz (BT-36):</div>
|
||||
<div id="BT-36" title="BT-36" class="boxdaten wert"><xsl:value-of select="xr:SELLER_POSTAL_ADDRESS/xr:Seller_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
@@ -1998,7 +1998,7 @@ function downloadData (element_id) {
|
||||
<div id="BT-64" title="BT-64" class="boxdaten wert"><xsl:value-of select="xr:SELLER_TAX_REPRESENTATIVE_POSTAL_ADDRESS/xr:Tax_representative_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach (BT-65):</div>
|
||||
<div class="boxdaten legende">Adresszusatz (BT-65):</div>
|
||||
<div id="BT-65" title="BT-65" class="boxdaten wert"><xsl:value-of select="xr:SELLER_TAX_REPRESENTATIVE_POSTAL_ADDRESS/xr:Tax_representative_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
@@ -2111,7 +2111,7 @@ function downloadData (element_id) {
|
||||
<div id="BT-75" title="BT-75" class="boxdaten wert"><xsl:value-of select="xr:DELIVER_TO_ADDRESS/xr:Deliver_to_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach (BT-76):</div>
|
||||
<div class="boxdaten legende">Adresszusatz (BT-76):</div>
|
||||
<div id="BT-76" title="BT-76" class="boxdaten wert"><xsl:value-of select="xr:DELIVER_TO_ADDRESS/xr:Deliver_to_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2355
library/src/main/resources/stylesheets/xrechnung-html.univ.xsl
Normal file
2355
library/src/main/resources/stylesheets/xrechnung-html.univ.xsl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -122,7 +122,7 @@
|
||||
<div title="BT-50" class="boxdaten wert"><xsl:value-of select="xr:BUYER_POSTAL_ADDRESS/xr:Buyer_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach:</div>
|
||||
<div class="boxdaten legende">Adresszusatz:</div>
|
||||
<div title="BT-51" class="boxdaten wert"><xsl:value-of select="xr:BUYER_POSTAL_ADDRESS/xr:Buyer_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
@@ -179,7 +179,7 @@
|
||||
<div title="BT-35" class="boxdaten wert"><xsl:value-of select="xr:SELLER_POSTAL_ADDRESS/xr:Seller_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach:</div>
|
||||
<div class="boxdaten legende">Adresszusatz:</div>
|
||||
<div title="BT-36" class="boxdaten wert"><xsl:value-of select="xr:SELLER_POSTAL_ADDRESS/xr:Seller_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
@@ -892,7 +892,7 @@
|
||||
<div title="BT-64" class="boxdaten wert"><xsl:value-of select="xr:SELLER_TAX_REPRESENTATIVE_POSTAL_ADDRESS/xr:Tax_representative_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach:</div>
|
||||
<div class="boxdaten legende">Adresszusatz:</div>
|
||||
<div title="BT-65" class="boxdaten wert"><xsl:value-of select="xr:SELLER_TAX_REPRESENTATIVE_POSTAL_ADDRESS/xr:Tax_representative_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
@@ -998,7 +998,7 @@
|
||||
<div title="BT-75" class="boxdaten wert"><xsl:value-of select="xr:DELIVER_TO_ADDRESS/xr:Deliver_to_address_line_1"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Postfach:</div>
|
||||
<div class="boxdaten legende">Adresszusatz:</div>
|
||||
<div title="BT-76" class="boxdaten wert"><xsl:value-of select="xr:DELIVER_TO_ADDRESS/xr:Deliver_to_address_line_2"/></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
|
||||
@@ -52,6 +52,15 @@ public class BaseTest extends TestCase {
|
||||
assertEquals("12.00", XMLTools.nDigitFormat(new BigDecimal("12"),2));
|
||||
assertEquals("12", XMLTools.nDigitFormat(new BigDecimal("12"),0));
|
||||
assertEquals("20000123.342", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),3));
|
||||
|
||||
assertEquals("0.00", XMLTools.nDigitFormatDecimalRange(BigDecimal.ZERO,2, 2));
|
||||
assertEquals("-1.10", XMLTools.nDigitFormatDecimalRange(new BigDecimal("-1.100000"), 4,2));
|
||||
assertEquals("-1.101", XMLTools.nDigitFormatDecimalRange(new BigDecimal("-1.101000"),10, 3));
|
||||
assertEquals("-1.10", XMLTools.nDigitFormatDecimalRange(new BigDecimal("-1.103"), 2,2));
|
||||
assertEquals("4", XMLTools.nDigitFormatDecimalRange(new BigDecimal("4"),2, 0));
|
||||
assertEquals("3.14", XMLTools.nDigitFormatDecimalRange(new BigDecimal("3.141526"),2, 0));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mustangproject.util.ByteArraySearcher;
|
||||
|
||||
public class ByteArraySearcherTest
|
||||
{
|
||||
@Test
|
||||
public void testIndexOf () {
|
||||
byte [] haystack = "Hello World".getBytes (StandardCharsets.ISO_8859_1);
|
||||
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H' }));
|
||||
assertEquals (1, ByteArraySearcher.indexOf (haystack, new byte [] { 'e' }));
|
||||
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H', 'e' }));
|
||||
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H', 'e' }));
|
||||
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H', 'e', 'l', 'l' }));
|
||||
assertEquals (0, ByteArraySearcher.indexOf (haystack, haystack));
|
||||
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [0]));
|
||||
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [] { 'a' }));
|
||||
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [] { 'h' }));
|
||||
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [] { 'r', 'o' }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWith () {
|
||||
byte [] haystack = "Hello World".getBytes (StandardCharsets.ISO_8859_1);
|
||||
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H' }));
|
||||
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'e' }));
|
||||
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H', 'e' }));
|
||||
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H', 'e' }));
|
||||
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H', 'e', 'l', 'l' }));
|
||||
assertTrue (ByteArraySearcher.startsWith (haystack, haystack));
|
||||
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [0]));
|
||||
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'a' }));
|
||||
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'h' }));
|
||||
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'r', 'o' }));
|
||||
}
|
||||
}
|
||||
@@ -3,28 +3,35 @@ package org.mustangproject.ZUGFeRD;
|
||||
import static java.math.BigDecimal.TEN;
|
||||
import static java.math.BigDecimal.valueOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mustangproject.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/***
|
||||
* tests the linecalculator and transactioncalculator classes
|
||||
*
|
||||
*/
|
||||
public class CalculationTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger (CalculationTest.class);
|
||||
public class CalculationTest extends ResourceCase {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CalculationTest.class);
|
||||
|
||||
@Test
|
||||
public void testLineCalculator_simpleAmounts_resultInValidVATAmount() {
|
||||
final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
|
||||
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(100))
|
||||
.setQuantity(TEN)
|
||||
.setProduct(product);
|
||||
.setQuantity(TEN)
|
||||
.setProduct(product);
|
||||
|
||||
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||
|
||||
@@ -41,15 +48,15 @@ public class CalculationTest {
|
||||
final IZUGFeRDAllowanceCharge allowance = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(14.8730));
|
||||
|
||||
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
|
||||
.setQuantity(valueOf(12))
|
||||
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
||||
.setProduct(product);
|
||||
.setQuantity(valueOf(12))
|
||||
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
||||
.setProduct(product);
|
||||
|
||||
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||
|
||||
assertEquals(valueOf(133.857).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
|
||||
assertEquals(valueOf(1606.28).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
|
||||
assertEquals(valueOf(257.0048).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
|
||||
assertEquals(valueOf(148.73).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
|
||||
assertEquals(valueOf(1769.89).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
|
||||
assertEquals(valueOf(283.1824).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -60,16 +67,49 @@ public class CalculationTest {
|
||||
// 20 % charge
|
||||
final IZUGFeRDAllowanceCharge charge = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(29.746));
|
||||
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
|
||||
.setQuantity(valueOf(12))
|
||||
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
||||
.setItemCharges(new IZUGFeRDAllowanceCharge[]{charge})
|
||||
.setProduct(product);
|
||||
.setQuantity(valueOf(12))
|
||||
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
||||
.setItemCharges(new IZUGFeRDAllowanceCharge[]{charge})
|
||||
.setProduct(product);
|
||||
|
||||
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||
|
||||
assertEquals(valueOf(163.603).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
|
||||
assertEquals(valueOf(1963.24).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
|
||||
assertEquals(valueOf(314.1184).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
|
||||
assertEquals(valueOf(148.73).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
|
||||
assertEquals(valueOf(1799.63).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
|
||||
assertEquals(valueOf(287.9408).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLineCalculatorForeignCurrencyExample() {
|
||||
/*** xml of official fx sample with allowances and charges
|
||||
* 10x100 with 10% and 50€ item discount =850€
|
||||
* +8,75 charges on document level=858,75, +19%VAT=1021,91
|
||||
* prepaid 500->due payable=521,91
|
||||
*/
|
||||
File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml");
|
||||
|
||||
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter();
|
||||
Invoice invoice=null;
|
||||
zii.doIgnoreCalculationErrors();
|
||||
boolean hasExceptions=false;
|
||||
try {
|
||||
zii.setInputStream(new FileInputStream(inputCII));
|
||||
|
||||
invoice=zii.extractInvoice();
|
||||
} catch (XPathExpressionException | ParseException e) {
|
||||
// handle Exceptions
|
||||
hasExceptions=true;
|
||||
} catch (FileNotFoundException e) {
|
||||
hasExceptions=true;
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
// Reading ZUGFeRD
|
||||
|
||||
final TransactionCalculator calculator = new TransactionCalculator(invoice);
|
||||
|
||||
assertEquals(valueOf(521.91).stripTrailingZeros(), calculator.getDuePayable().stripTrailingZeros());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -184,8 +224,106 @@ public class CalculationTest {
|
||||
invoice.addAllowance(new Allowance().setPercent(total_discount_percent).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatte"));
|
||||
}
|
||||
TransactionCalculator calculator = new TransactionCalculator(invoice);
|
||||
assertEquals(valueOf(101.86).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
|
||||
assertEquals(valueOf(307.18).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
|
||||
}
|
||||
|
||||
public void testSimpleItemPercentAllowance() {
|
||||
/***
|
||||
* a product with net 1.10 and qty 5 and relative item allowance of 10% should return 5 as line and grand total
|
||||
*/
|
||||
SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
Invoice invoice = new Invoice();
|
||||
invoice.setDocumentName("Rechnung");
|
||||
invoice.setNumber("777777");
|
||||
try {
|
||||
invoice.setIssueDate(sqlDate.parse("2020-12-31"));
|
||||
invoice.setDetailedDeliveryPeriod(sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[0]), sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[1]));
|
||||
invoice.setDeliveryDate(sqlDate.parse("2020-12-31"));
|
||||
invoice.setDueDate(sqlDate.parse("2021-01-15"));
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to set dates", e);
|
||||
|
||||
}
|
||||
TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE");
|
||||
sender.addVATID("DE2222222222");
|
||||
invoice.setSender(sender);
|
||||
|
||||
/* trade party (recipient) */
|
||||
TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE");
|
||||
recipient.setID("111111");
|
||||
recipient.addVATID("DE111111111");
|
||||
invoice.setRecipient(recipient);
|
||||
|
||||
/* item */
|
||||
Product product;
|
||||
Item item;
|
||||
|
||||
product = new Product("AAA", "", "H84", BigDecimal.ZERO);
|
||||
item = new Item(product, new BigDecimal("1.10"), new BigDecimal(5.00));
|
||||
|
||||
item.addAllowance(new Allowance().setPercent(new BigDecimal(10)).setTaxPercent(BigDecimal.ZERO));
|
||||
invoice.addItem(item);
|
||||
|
||||
TransactionCalculator calculator = new TransactionCalculator(invoice);
|
||||
assertEquals(new BigDecimal(5), calculator.getGrandTotal().stripTrailingZeros());
|
||||
}
|
||||
|
||||
public void testSimpleItemTotalAllowance() {
|
||||
/***
|
||||
* a product with net 1 and qty 5 and absolute _item_ allowance of 1 should return 4 as line total, and grand total
|
||||
*/
|
||||
SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
Invoice invoice = new Invoice();
|
||||
invoice.setDocumentName("Rechnung");
|
||||
invoice.setNumber("777777");
|
||||
try {
|
||||
invoice.setIssueDate(sqlDate.parse("2020-12-31"));
|
||||
invoice.setDetailedDeliveryPeriod(sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[0]), sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[1]));
|
||||
invoice.setDeliveryDate(sqlDate.parse("2020-12-31"));
|
||||
invoice.setDueDate(sqlDate.parse("2021-01-15"));
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to set dates", e);
|
||||
|
||||
}
|
||||
TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE");
|
||||
sender.addVATID("DE2222222222");
|
||||
invoice.setSender(sender);
|
||||
|
||||
/* trade party (recipient) */
|
||||
TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE");
|
||||
recipient.setID("111111");
|
||||
recipient.addVATID("DE111111111");
|
||||
invoice.setRecipient(recipient);
|
||||
|
||||
/* item */
|
||||
Product product;
|
||||
Item item;
|
||||
|
||||
product = new Product("AAA", "", "H84", BigDecimal.ZERO);
|
||||
item = new Item(product, new BigDecimal("1.00"), new BigDecimal(5.00));
|
||||
|
||||
item.addAllowance(new Allowance(new BigDecimal(1)).setTaxPercent(BigDecimal.ZERO));
|
||||
invoice.addItem(item);
|
||||
|
||||
TransactionCalculator calculator = new TransactionCalculator(invoice);
|
||||
assertEquals(new BigDecimal(4), calculator.getGrandTotal().stripTrailingZeros());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* LineCalculator should not throw an exception when calculating a non-terminating decimal expansion
|
||||
* */
|
||||
@Test
|
||||
public void testNonTerminatingDecimalExpansion() {
|
||||
final Product product = new Product();
|
||||
final IZUGFeRDExportableItem currentItem = new Item().setPrice(valueOf(386.52))
|
||||
.setQuantity(BigDecimal.valueOf(31))
|
||||
.setBasisQuantity(BigDecimal.valueOf(366))
|
||||
.setProduct(product);
|
||||
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||
assertEquals(BigDecimal.valueOf(32.74), calculator.getItemTotalNetAmount());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -109,6 +109,16 @@ public class DXTest extends MustangReaderTestCase {
|
||||
return "DE99XX12345";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansCode() {
|
||||
return "54";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansInformation() {
|
||||
return "Credit Card";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,22 +21,43 @@
|
||||
*/
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.experimental.theories.FromDataPoints;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mustangproject.Allowance;
|
||||
import org.mustangproject.BankDetails;
|
||||
import org.mustangproject.CalculatedInvoice;
|
||||
import org.mustangproject.CashDiscount;
|
||||
import org.mustangproject.Charge;
|
||||
import org.mustangproject.Contact;
|
||||
import org.mustangproject.Invoice;
|
||||
import org.mustangproject.Item;
|
||||
import org.mustangproject.Product;
|
||||
import org.mustangproject.SchemedID;
|
||||
import org.mustangproject.TradeParty;
|
||||
import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mustangproject.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class DeSerializationTest extends TestCase {
|
||||
public class DeSerializationTest extends ResourceCase {
|
||||
public void testJackson() throws JsonProcessingException {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("some org", "teststr", "55232", "teststadt", "DE").addTaxID("taxID").addBankDetails(new BankDetails("DE3600000123456", "ABCDEFG1001").setAccountName("Donald Duck"))).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0185").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal("1"), new BigDecimal(1.0)));
|
||||
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("some org", "teststr", "55232", "teststadt", "DE").addTaxID("taxID").addBankDetails(new BankDetails("DE3600000123456", "ABCDEFG1001").setAccountName("Donald Duck")).setEmail("info@company.com")).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0185").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal("1"), new BigDecimal(1.0)));
|
||||
String jsonArray = mapper.writeValueAsString(i);
|
||||
|
||||
// [{"stringValue":"a","intValue":1,"booleanValue":true},
|
||||
@@ -45,6 +66,827 @@ public class DeSerializationTest extends TestCase {
|
||||
Invoice fromJSON = mapper.readValue(jsonArray, Invoice.class);
|
||||
assertEquals(fromJSON.getNumber(), i.getNumber());
|
||||
assertEquals(fromJSON.getZFItems().length, i.getZFItems().length);
|
||||
assertEquals("info@company.com", fromJSON.getSender().getEmail());
|
||||
assertEquals("info@company.com", fromJSON.getSender().getUriUniversalCommunicationID());
|
||||
|
||||
}
|
||||
|
||||
public void testInvoiceLine() throws JsonProcessingException {
|
||||
File inputCII = getResourceAsFile("factur-x.xml");
|
||||
boolean hasExceptions = false;
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
try {
|
||||
zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8));
|
||||
|
||||
} catch (IOException e) {
|
||||
hasExceptions = true;
|
||||
}
|
||||
|
||||
CalculatedInvoice ci = new CalculatedInvoice();
|
||||
try {
|
||||
zii.extractInto(ci);
|
||||
} catch (XPathExpressionException e) {
|
||||
hasExceptions = true;
|
||||
} catch (ParseException e) {
|
||||
hasExceptions = true;
|
||||
}
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String jsonArray = mapper.writeValueAsString(ci);
|
||||
assertFalse(hasExceptions);
|
||||
assertTrue(jsonArray.contains("lineTotalAmount"));
|
||||
|
||||
}
|
||||
|
||||
public void testAllowanceRead() throws JsonProcessingException {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
// [{"stringValue":"a","intValue":1,"booleanValue":true},
|
||||
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
|
||||
|
||||
Invoice fromJSON = mapper.readValue("{\n" +
|
||||
" \"documentCode\": \"380\",\n" +
|
||||
" \"number\": \"471102\",\n" +
|
||||
" \"ownOrganisationName\": \"Lieferant GmbH\",\n" +
|
||||
" \"currency\": \"EUR\",\n" +
|
||||
" \"issueDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
|
||||
" \"deliveryDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
|
||||
" \"detailedDeliveryPeriodFrom\": \"2017-03-03T13:00:00.000+00:00\",\n" +
|
||||
" \"detailedDeliveryPeriodTo\": \"2017-03-04T13:00:00.000+00:00\",\n" +
|
||||
" \"sender\": {\n" +
|
||||
" \"name\": \"Lieferant GmbH\",\n" +
|
||||
" \"zip\": \"80333\",\n" +
|
||||
" \"street\": \"Lieferantenstraße 20\",\n" +
|
||||
" \"location\": \"München\",\n" +
|
||||
" \"country\": \"DE\",\n" +
|
||||
" \"taxID\": \"201/113/40209\",\n" +
|
||||
" \"vatID\": \"DE123456789\",\n" +
|
||||
" \"vatid\": \"DE123456789\"\n" +
|
||||
" },\n" +
|
||||
" \"recipient\": {\n" +
|
||||
" \"name\": \"Kunden AG Mitte\",\n" +
|
||||
" \"zip\": \"69876\",\n" +
|
||||
" \"street\": \"Kundenstraße 15\",\n" +
|
||||
" \"location\": \"Frankfurt\",\n" +
|
||||
" \"country\": \"DE\"\n" +
|
||||
" },\n" +
|
||||
" \"grandTotal\": 234.43,\n" +
|
||||
" \"zfitems\": [\n" +
|
||||
" {\n" +
|
||||
" \"price\": 9.9,\n" +
|
||||
" \"quantity\": 20,\n" +
|
||||
" \"tax\": null,\n" +
|
||||
" \"grossPrice\": null,\n" +
|
||||
" \"lineTotalAmount\": null,\n" +
|
||||
" \"basisQuantity\": 1,\n" +
|
||||
" \"detailedDeliveryPeriodFrom\": null,\n" +
|
||||
" \"detailedDeliveryPeriodTo\": null,\n" +
|
||||
" \"id\": null,\n" +
|
||||
" \"product\": {\n" +
|
||||
" \"unit\": \"H87\",\n" +
|
||||
" \"name\": \"Trennblätter A4\",\n" +
|
||||
" \"taxCategoryCode\": \"S\",\n" +
|
||||
" \"attributes\": null,\n" +
|
||||
" \"vatpercent\": 19\n" +
|
||||
" },\n" +
|
||||
" \"value\": 9.9\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"tradeSettlement\": null,\n" +
|
||||
" \"ownTaxID\": \"201/113/40209\",\n" +
|
||||
" \"ownVATID\": \"DE123456789\",\n" +
|
||||
" \"ownStreet\": \"Lieferantenstraße 20\",\n" +
|
||||
" \"ownZIP\": \"80333\",\n" +
|
||||
" \"ownLocation\": \"München\",\n" +
|
||||
" \"ownCountry\": \"DE\",\n" +
|
||||
" \"zfallowances\": [\n" +
|
||||
" {\n" +
|
||||
" \"totalAmount\": 1,\n" +
|
||||
" \"taxPercent\": 19,\n" +
|
||||
" \"reason\": \"Sondernachlass\",\n" +
|
||||
" \"reasonCode\": null,\n" +
|
||||
" \"categoryCode\": \"S\",\n" +
|
||||
" \"charge\": false\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}", Invoice.class);
|
||||
TransactionCalculator tc = new TransactionCalculator(fromJSON);
|
||||
assertEquals(tc.getGrandTotal(), new BigDecimal("234.43"));
|
||||
assertEquals(fromJSON.getNumber(), fromJSON.getNumber());
|
||||
|
||||
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
|
||||
zf2p.setProfile(Profiles.getByName("XRechnung"));
|
||||
zf2p.generateXML(fromJSON);
|
||||
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
|
||||
|
||||
assertEquals(fromJSON.getZFItems().length, fromJSON.getZFItems().length);
|
||||
assertTrue(theXML.contains("20170303"));
|
||||
assertTrue(theXML.contains("20170304"));
|
||||
|
||||
}
|
||||
|
||||
public void testDeserializedFiles() {
|
||||
File inputUBL = getResourceAsFile("XRECHNUNG_Elektron.ubl.xml");
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
zii.doIgnoreCalculationErrors();
|
||||
Invoice i = new Invoice();
|
||||
String exText = null;
|
||||
|
||||
try {
|
||||
zii.fromXML(new String(Files.readAllBytes(inputUBL.toPath()), StandardCharsets.UTF_8));
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
zii.extractInto(i);
|
||||
String json = mapper.writeValueAsString(i);
|
||||
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
|
||||
|
||||
assertEquals("181301674", i.getNumber());
|
||||
assertEquals(newInvoiceFromJSON.getNumber(), i.getNumber());
|
||||
assertEquals(newInvoiceFromJSON.getAdditionalReferencedDocuments()[0].getFilename(), i.getAdditionalReferencedDocuments()[0].getFilename());
|
||||
assertEquals(newInvoiceFromJSON.getAdditionalReferencedDocuments().length, 2);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
exText = e.getMessage();
|
||||
} catch (XPathExpressionException e) {
|
||||
exText = e.getMessage();
|
||||
} catch (ParseException e) {
|
||||
exText = e.getMessage();
|
||||
}
|
||||
assertNull(exText);
|
||||
|
||||
}
|
||||
|
||||
public void testFileSerialization() {
|
||||
|
||||
String base64 = "b25ldHdvdGhyZWU=";
|
||||
String json = "{\n" +
|
||||
" \"additionalReferencedDocuments\": [\n" +
|
||||
" {\n" +
|
||||
" \"data\": \"" + base64 + "\",\n" +
|
||||
" \"description\": \"Additional file attachment\",\n" +
|
||||
" \"filename\": \"text.txt\",\n" +
|
||||
" \"mimetype\": \"text/plain\",\n" +
|
||||
" \"relation\": \"Data\"\n" +
|
||||
" }\n" +
|
||||
"],\n" +
|
||||
"\n" +
|
||||
" \"number\": \"471102\",\n" +
|
||||
" \"currency\": \"EUR\",\n" +
|
||||
" \"issueDate\": \"2018-03-04T00:00:00.000\",\n" +
|
||||
" \"dueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
|
||||
" \"deliveryDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
|
||||
" \"sender\": {\n" +
|
||||
" \"name\": \"Lieferant GmbH\",\n" +
|
||||
" \"zip\": \"80333\",\n" +
|
||||
" \"street\": \"Lieferantenstraße 20\",\n" +
|
||||
" \"location\": \"München\",\n" +
|
||||
" \"country\": \"DE\",\n" +
|
||||
" \"taxID\": \"201/113/40209\",\n" +
|
||||
" \"vatID\": \"DE123456789\",\n" +
|
||||
" \"globalID\": \"4000001123452\",\n" +
|
||||
" \"globalIDScheme\": \"0088\"\n" +
|
||||
" },\n" +
|
||||
" \"recipient\": {\n" +
|
||||
" \"name\": \"Kunden AG Mitte\",\n" +
|
||||
" \"zip\": \"69876\",\n" +
|
||||
" \"street\": \"Kundenstraße 15\",\n" +
|
||||
" \"location\": \"Frankfurt\",\n" +
|
||||
" \"country\": \"DE\"\n" +
|
||||
" },\n" +
|
||||
" \"zfitems\": [\n" +
|
||||
" {\n" +
|
||||
" \"price\": 9.9,\n" +
|
||||
" \"quantity\": 20,\n" +
|
||||
" \"product\": {\n" +
|
||||
" \"unit\": \"H87\",\n" +
|
||||
" \"name\": \"Trennblätter A4\",\n" +
|
||||
" \"description\": \"\",\n" +
|
||||
" \"vatpercent\": 19,\n" +
|
||||
" \"taxCategoryCode\": \"S\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"price\": 5.5,\n" +
|
||||
" \"quantity\": 50,\n" +
|
||||
" \"product\": {\n" +
|
||||
" \"unit\": \"H87\",\n" +
|
||||
" \"name\": \"Joghurt Banane\",\n" +
|
||||
" \"description\": \"\",\n" +
|
||||
" \"vatpercent\": 7,\n" +
|
||||
" \"taxCategoryCode\": \"S\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}\n";
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
try {
|
||||
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
|
||||
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
|
||||
zf2p.setProfile(Profiles.getByName("XRechnung"));
|
||||
zf2p.generateXML(newInvoiceFromJSON);
|
||||
String theXML = new String(zf2p.getXML());
|
||||
assertTrue(theXML.contains("<udt:DateTimeString format=\"102\">20180304</udt:DateTimeString>"));
|
||||
assertTrue(theXML.contains(base64));
|
||||
|
||||
} catch (Exception e) {
|
||||
fail("No exception expected");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testFull300Roundtrip() {
|
||||
File inputCII = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.cii.xml");
|
||||
|
||||
Invoice i = new Invoice();
|
||||
String exText = null;
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
zii.doIgnoreCalculationErrors();
|
||||
try {
|
||||
zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8));
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
zii.extractInto(i);
|
||||
String json = mapper.writeValueAsString(i);
|
||||
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
|
||||
|
||||
assertEquals("Test_EeISI_100", i.getNumber());
|
||||
assertEquals(newInvoiceFromJSON.getNumber(), i.getNumber());
|
||||
|
||||
} catch (IOException e) {
|
||||
exText = e.getMessage();
|
||||
} catch (XPathExpressionException e) {
|
||||
exText = e.getMessage();
|
||||
} catch (ParseException e) {
|
||||
exText = e.getMessage();
|
||||
}
|
||||
assertNull(exText);
|
||||
|
||||
|
||||
}
|
||||
public void testNulledAttachments() {
|
||||
|
||||
String json="{\n" +
|
||||
" \"number\": \"471102\",\n" +
|
||||
" \"currency\": \"EUR\",\n" +
|
||||
" \"issueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
|
||||
" \"dueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
|
||||
" \"deliveryDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
|
||||
" \"sender\": {\n" +
|
||||
" \"name\": \"Lieferant GmbH\",\n" +
|
||||
" \"zip\": \"80333\",\n" +
|
||||
" \"street\": \"Lieferantenstraße 20\",\n" +
|
||||
" \"location\": \"München\",\n" +
|
||||
" \"country\": \"DE\",\n" +
|
||||
" \"taxID\": \"201/113/40209\",\n" +
|
||||
" \"vatID\": \"DE123456789\",\n" +
|
||||
" \"globalID\": \"4000001123452\",\n" +
|
||||
" \"globalIDScheme\": \"0088\"\n" +
|
||||
" },\n" +
|
||||
" \"recipient\": {\n" +
|
||||
" \"name\": \"Kunden AG Mitte\",\n" +
|
||||
" \"zip\": \"69876\",\n" +
|
||||
" \"street\": \"Kundenstraße 15\",\n" +
|
||||
" \"location\": \"Frankfurt\",\n" +
|
||||
" \"country\": \"DE\"\n" +
|
||||
" },\n" +
|
||||
"\"additionalReferencedDocuments\":null,"+
|
||||
" \"zfitems\": [\n" +
|
||||
" {\n" +
|
||||
" \"price\": 9.9,\n" +
|
||||
" \"quantity\": 20,\n" +
|
||||
" \"product\": {\n" +
|
||||
" \"unit\": \"H87\",\n" +
|
||||
" \"name\": \"Trennblätter A4\",\n" +
|
||||
" \"description\": \"\",\n" +
|
||||
" \"vatpercent\": 19,\n" +
|
||||
" \"taxCategoryCode\": \"S\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"price\": 5.5,\n" +
|
||||
" \"quantity\": 50,\n" +
|
||||
" \"product\": {\n" +
|
||||
" \"unit\": \"H87\",\n" +
|
||||
" \"name\": \"Joghurt Banane\",\n" +
|
||||
" \"description\": \"\",\n" +
|
||||
" \"vatpercent\": 7,\n" +
|
||||
" \"taxCategoryCode\": \"S\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}\n";
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
boolean exceptions=false;
|
||||
try {
|
||||
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
exceptions=true;
|
||||
}
|
||||
assertFalse(exceptions);
|
||||
}
|
||||
|
||||
public void testItemAllowances() {
|
||||
|
||||
String json="{\"number\":\"123\",\"currency\":\"EUR\",\"issueDate\":1738935176399,\"dueDate\":1738935176399,\"sender\":{\"name\":\"Test company\",\"zip\":\"55232\",\"street\":\"teststr\",\"location\":\"teststadt\",\"country\":\"DE\",\"taxID\":\"4711\",\"vatID\":\"DE0815\",\"vatid\":\"DE0815\"},\"recipient\":{\"name\":\"Franz Müller\",\"zip\":\"55232\",\"street\":\"teststr.12\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"contact\":{\"name\":\"contact testname\",\"phone\":\"123456\",\"email\":\"contact.testemail@example.org\",\"fax\":\"0911623562\"}},\"zfitems\":[{\"price\":3.00,\"quantity\":1,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemAllowances\":[{\"totalAmount\":0.1,\"categoryCode\":\"S\"}],\"value\":3.00},{\"price\":3.00,\"quantity\":1,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemAllowances\":[{\"percent\":50,\"taxPercent\":0,\"categoryCode\":\"S\"}],\"value\":3.00},{\"price\":3.00,\"quantity\":2,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemCharges\":[{\"totalAmount\":1,\"reason\":\"AnotherReason\",\"reasonCode\":\"ABK\",\"categoryCode\":\"S\"}],\"value\":3.00},{\"price\":3.00,\"quantity\":1,\"basisQuantity\":1,\"product\":{\"unit\":\"C62\",\"name\":\"Testprodukt\",\"taxCategoryCode\":\"S\",\"vatpercent\":19,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"itemAllowances\":[{\"totalAmount\":1,\"categoryCode\":\"S\"}],\"itemCharges\":[{\"totalAmount\":1,\"categoryCode\":\"S\"}],\"value\":3.00}],\"ownStreet\":\"teststr\",\"ownCountry\":\"DE\",\"zfcharges\":[{\"totalAmount\":1,\"taxPercent\":19,\"reason\":\"AReason\",\"reasonCode\":\"ABK\",\"categoryCode\":\"S\"}],\"ownLocation\":\"teststadt\",\"ownTaxID\":\"4711\",\"ownZIP\":\"55232\",\"ownVATID\":\"DE0815\",\"valid\":true}";
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
|
||||
TransactionCalculator tc=new TransactionCalculator(newInvoiceFromJSON);
|
||||
assertEquals(new BigDecimal("18.92"),tc.getGrandTotal());
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testIssuerAssignedIDRoundtrip() {
|
||||
String occurrenceFrom = "20201001";
|
||||
String occurrenceTo = "20201005";
|
||||
String contractID = "376zreurzu0983";
|
||||
|
||||
String orgID = "0009845";
|
||||
String orgname = "Test company";
|
||||
String number = "123";
|
||||
String priceStr = "1.00";
|
||||
String taxID = "9990815";
|
||||
BigDecimal price = new BigDecimal(priceStr);
|
||||
Invoice newInvoiceFromJSON = null;
|
||||
boolean hasExceptions = false;
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
try {
|
||||
SchemedID gtin = new SchemedID("0160", "2001015001325");
|
||||
SchemedID gln = new SchemedID("0088", "4304171000002");
|
||||
Invoice i = new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
|
||||
.setSellerOrderReferencedDocumentID("9384").setBuyerOrderReferencedDocumentID("28934")
|
||||
.setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurrenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurrenceTo))
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).setEmail("sender@test.org").setID(orgID).addVATID("DE0815"))
|
||||
.setDeliveryAddress(new TradeParty("just the other side of the street", "teststr.12a", "55232", "Entenhausen", "DE").addVATID("DE47110"))
|
||||
.setContractReferencedDocument(contractID)
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addGlobalID(gln).setEmail("recipient@test.org").addVATID("DE4711")
|
||||
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3"))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123").addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")))
|
||||
.addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16)))
|
||||
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
|
||||
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
|
||||
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String json = mapper.writeValueAsString(i);
|
||||
newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
|
||||
} catch (ParseException e) {
|
||||
hasExceptions = true;
|
||||
} catch (JsonProcessingException e) {
|
||||
hasExceptions = true;
|
||||
}
|
||||
assertEquals(newInvoiceFromJSON.getBuyerOrderReferencedDocumentID(), "28934");
|
||||
assertFalse(hasExceptions);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testDueDateRoundtrip() throws JsonProcessingException {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
// [{"stringValue":"a","intValue":1,"booleanValue":true},
|
||||
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
|
||||
|
||||
Invoice fromJSON = mapper.readValue("{\n" +
|
||||
" \"number\": \"RE - 228\",\n" +
|
||||
" \"currency\": \"EUR\",\n" +
|
||||
" \"issueDate\": \"2024-10-24\",\n" +
|
||||
" \"dueDate\": \"2024-10-26\",\n" +
|
||||
" \"deliveryDate\": \"2024-10-25\",\n" +
|
||||
" \"sender\": {\n" +
|
||||
" \"name\": \"Amazing Company\",\n" +
|
||||
" \"zip\": \"10000\",\n" +
|
||||
" \"street\": \"Straße der Kosmonauten 20\",\n" +
|
||||
" \"location\": \"Berlin\",\n" +
|
||||
" \"country\": \"DE\",\n" +
|
||||
" \"taxID\": \"201/113/40209\",\n" +
|
||||
" \"vatID\": \"DE123456789\",\n" +
|
||||
" \"globalID\": \"4000001123452\",\n" +
|
||||
" \"globalIDScheme\": \"0088\"\n" +
|
||||
" },\n" +
|
||||
" \"recipient\": {\n" +
|
||||
" \"name\": \"Amazing Company\",\n" +
|
||||
" \"zip\": \"1000\",\n" +
|
||||
" \"street\": \"Straße der Kosmonauten 10\",\n" +
|
||||
" \"location\": \"Berlin\",\n" +
|
||||
" \"taxID\": \"201/113/40209\",\n" +
|
||||
" \"vatID\": \"DE123456789\",\n" +
|
||||
" \"country\": \"DE\"\n" +
|
||||
" },\n" +
|
||||
" \"zfitems\": [\n" +
|
||||
" {\n" +
|
||||
" \"price\": 99.9,\n" +
|
||||
" \"quantity\": 10,\n" +
|
||||
" \"product\": {\n" +
|
||||
" \"unit\": \"H87\",\n" +
|
||||
" \"name\": \"Amazing Archives\",\n" +
|
||||
" \"description\": \"123\",\n" +
|
||||
" \"vatpercent\": \"19\",\n" +
|
||||
" \"taxCategoryCode\": \"3\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}\n", Invoice.class);
|
||||
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
|
||||
zf2p.setProfile(Profiles.getByName("XRechnung"));
|
||||
zf2p.generateXML(fromJSON);
|
||||
String theXML = new String(zf2p.getXML());
|
||||
assertTrue(theXML.contains("<udt:DateTimeString format=\"102\">20241026</udt:DateTimeString>"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testDirectDebit() throws JsonProcessingException {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
// [{"stringValue":"a","intValue":1,"booleanValue":true},
|
||||
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
|
||||
|
||||
boolean exceptions = false;
|
||||
String theXML = "";
|
||||
try {
|
||||
Invoice fromJSON = mapper.readValue("\n" +
|
||||
"\t{\n" +
|
||||
"\t\t\"documentCode\": \"380\",\n" +
|
||||
"\t\t\"number\": \"F20220031\",\n" +
|
||||
"\t\t\"referenceNumber\": \"SERVEXEC\",\n" +
|
||||
"\t\t\"buyerOrderReferencedDocumentID\": \"PO201925478\",\n" +
|
||||
"\t\t\"ownOrganisationName\": \"LE FOURNISSEUR\",\n" +
|
||||
"\t\t\"currency\": \"EUR\",\n" +
|
||||
"\t\t\"issueDate\": \"2022-01-30T23:00:00.000+00:00\",\n" +
|
||||
"\t\t\"dueDate\": \"2022-03-01T23:00:00.000+00:00\",\n" +
|
||||
"\t\t\"deliveryDate\": \"2022-01-27T23:00:00.000+00:00\",\n" +
|
||||
"\t\t\"sender\": {\n" +
|
||||
"\t\t\"name\": \"LE FOURNISSEUR\",\n" +
|
||||
"\t\t\t\"zip\": \"75018\",\n" +
|
||||
"\t\t\t\"street\": \"35 rue d'ici\",\n" +
|
||||
"\t\t\t\"location\": \"PARIS\",\n" +
|
||||
"\t\t\t\"country\": \"FR\",\n" +
|
||||
"\t\t\t\"vatID\": \"FR11123456782\",\n" +
|
||||
"\t\t\t\"additionalAddress\": \"Seller line 2\",\n" +
|
||||
"\t\t\t\"additionalAddressExtension\": \"Seller line 3\",\n" +
|
||||
"\t\t\t\"bankDetails\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"accountName\": null,\n" +
|
||||
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\",\n" +
|
||||
"\t\t\t\"bic\": \"BIC_MONCOMPTE\"\n" +
|
||||
"\t\t}\n" +
|
||||
" ],\n" +
|
||||
"\t\t\"debitDetails\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"mandate\": \"MANDATE PT\",\n" +
|
||||
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\"\n" +
|
||||
"\t\t}\n" +
|
||||
" ],\n" +
|
||||
"\t\t\"contact\": {\n" +
|
||||
"\t\t\t\"name\": \"M. CONTACT\",\n" +
|
||||
"\t\t\t\t\"phone\": \"01 02 03 54 87\",\n" +
|
||||
"\t\t\t\t\"email\": \"seller@seller.com\",\n" +
|
||||
"\t\t\t\t\"zip\": null,\n" +
|
||||
"\t\t\t\t\"street\": null,\n" +
|
||||
"\t\t\t\t\"location\": null,\n" +
|
||||
"\t\t\t\t\"country\": null,\n" +
|
||||
"\t\t\t\t\"fax\": null,\n" +
|
||||
"\t\t\t\t\"vatid\": null,\n" +
|
||||
"\t\t\t\t\"id\": null,\n" +
|
||||
"\t\t\t\t\"additionalAddress\": null\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\"email\": \"moi@seller.com\",\n" +
|
||||
"\t\t\t\"vatid\": \"FR11123456782\",\n" +
|
||||
"\t\t\t\"id\": \"123\",\n" +
|
||||
"\t\t\t\"legalOrganisation\": {\n" +
|
||||
"\t\t\t\"schemedID\": null,\n" +
|
||||
"\t\t\t\t\"tradingBusinessName\": \"SELLER TRADE NAME\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\"globalID\": \"587451236587\",\n" +
|
||||
"\t\t\t\"globalIDScheme\": \"0088\"\n" +
|
||||
"\t},\n" +
|
||||
"\t\t\"recipient\": {\n" +
|
||||
"\t\t\"name\": \"LE CLIENT\",\n" +
|
||||
"\t\t\t\"zip\": \"06000\",\n" +
|
||||
"\t\t\t\"street\": \"MON ADRESSE LIGNE 1\",\n" +
|
||||
"\t\t\t\"location\": \"MA VILLE\",\n" +
|
||||
"\t\t\t\"country\": \"FR\",\n" +
|
||||
"\t\t\t\"vatID\": \"FR 05 987 654 321\",\n" +
|
||||
"\t\t\t\"additionalAddress\": \"Buyer line 2\",\n" +
|
||||
"\t\t\t\"additionalAddressExtension\": \"Buyer line 3\",\n" +
|
||||
"\t\t\t\"contact\": {\n" +
|
||||
"\t\t\t\"name\": \"Buyer contact name\",\n" +
|
||||
"\t\t\t\t\"phone\": \"01 01 25 45 87\",\n" +
|
||||
"\t\t\t\t\"email\": \"buyer@buyer.com\",\n" +
|
||||
"\t\t\t\t\"zip\": null,\n" +
|
||||
"\t\t\t\t\"street\": null,\n" +
|
||||
"\t\t\t\t\"location\": null,\n" +
|
||||
"\t\t\t\t\"country\": null,\n" +
|
||||
"\t\t\t\t\"fax\": null,\n" +
|
||||
"\t\t\t\t\"vatid\": null,\n" +
|
||||
"\t\t\t\t\"id\": null,\n" +
|
||||
"\t\t\t\t\"additionalAddress\": null\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\"email\": \"me@buyer.com\",\n" +
|
||||
"\t\t\t\"vatid\": \"FR 05 987 654 321\",\n" +
|
||||
"\t\t\t\"legalOrganisation\": {\n" +
|
||||
"\t\t\t\"schemedID\": null,\n" +
|
||||
"\t\t\t\t\"tradingBusinessName\": null\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\"globalID\": \"3654789851\",\n" +
|
||||
"\t\t\t\"globalIDScheme\": \"0088\"\n" +
|
||||
"\t},\n" +
|
||||
"\t\t\"deliveryAddress\": {\n" +
|
||||
"\t\t\"name\": \"DEL Name\",\n" +
|
||||
"\t\t\t\"zip\": \"06000\",\n" +
|
||||
"\t\t\t\"street\": \"DEL ADRESSE LIGNE 1\",\n" +
|
||||
"\t\t\t\"location\": \"NICE\",\n" +
|
||||
"\t\t\t\"country\": \"FR\",\n" +
|
||||
"\t\t\t\"additionalAddress\": \"DEL line 2\",\n" +
|
||||
"\t\t\t\"id\": \"PRIVATE_ID_DEL\"\n" +
|
||||
"\t},\n" +
|
||||
"\t\t\"payee\": {\n" +
|
||||
"\t\t\"name\": \"PAYEE NAME\",\n" +
|
||||
"\t\t\t\"legalOrganisation\": {\n" +
|
||||
"\t\t\t\"schemedID\": null,\n" +
|
||||
"\t\t\t\t\"tradingBusinessName\": null\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\"globalID\": \"587451236586\",\n" +
|
||||
"\t\t\t\"globalIDScheme\": \"0088\"\n" +
|
||||
"\t},\n" +
|
||||
"\t\t\"sellerOrderReferencedDocumentID\": \"SALES REF 2547\",\n" +
|
||||
"\t\t\"despatchAdviceReferencedDocumentID\": \"DESPADV002\",\n" +
|
||||
"\t\t\"grandTotal\": 107.82,\n" +
|
||||
"\t\t\"detailedDeliveryPeriodFrom\": \"2021-12-31T23:00:00.000+00:00\",\n" +
|
||||
"\t\t\"detailedDeliveryPeriodTo\": \"2022-12-30T23:00:00.000+00:00\",\n" +
|
||||
"\t\t\"notesWithSubjectCode\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"content\": \"FOURNISSEUR F SARL au capital de 50 000 EUR\",\n" +
|
||||
"\t\t\t\"subjectCode\": \"REG\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"content\": \"RCS MAVILLE 123 456 782\",\n" +
|
||||
"\t\t\t\"subjectCode\": \"ABL\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"content\": \"35 ma rue a moi, code postal Ville Pays – contact@masociete.fr - www.masociete.fr – N° TVA : FR32 123 456 789\",\n" +
|
||||
"\t\t\t\"subjectCode\": \"AAI\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"content\": \"Tout retard de paiement engendre une pénalité exigible à compter de la date d'échéance, calculée sur la base de trois fois le taux d'intérêt légal.\",\n" +
|
||||
"\t\t\t\"subjectCode\": null\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"content\": \"Indemnité forfaitaire pour frais de recouvrement en cas de retard de paiement : 40 €.\",\n" +
|
||||
"\t\t\t\"subjectCode\": null\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"content\": \"Les réglements reçus avant la date d'échéance ne donneront pas lieu à escompte.\",\n" +
|
||||
"\t\t\t\"subjectCode\": null\n" +
|
||||
"\t\t}\n" +
|
||||
" ],\n" +
|
||||
"\t\t\"zfallowances\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"71\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"71\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"71\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": null,\n" +
|
||||
"\t\t\t\"reasonCode\": \"100\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 2,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"71\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"71\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"71\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": null,\n" +
|
||||
"\t\t\t\"reasonCode\": \"100\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1.4,\n" +
|
||||
"\t\t\t\"taxPercent\": 20,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE COMMERCIALE\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"100\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1.2,\n" +
|
||||
"\t\t\t\"taxPercent\": 10,\n" +
|
||||
"\t\t\t\"reason\": \"REMISE COMMERCIALE\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"100\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t}\n" +
|
||||
" ],\n" +
|
||||
"\t\t\"zfcharges\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
|
||||
"\t\t\t\"reasonCode\": null,\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
|
||||
"\t\t\t\"reasonCode\": null,\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
|
||||
"\t\t\t\"reasonCode\": null,\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
|
||||
"\t\t\t\"reasonCode\": null,\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": null,\n" +
|
||||
"\t\t\t\"reasonCode\": \"ADL\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
|
||||
"\t\t\t\"reasonCode\": null,\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 1,\n" +
|
||||
"\t\t\t\"taxPercent\": null,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
|
||||
"\t\t\t\"reasonCode\": null,\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 2.8,\n" +
|
||||
"\t\t\t\"taxPercent\": 20,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS DEPLACEMENT\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"FC\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"percent\": null,\n" +
|
||||
"\t\t\t\"totalAmount\": 0.6,\n" +
|
||||
"\t\t\t\"taxPercent\": 10,\n" +
|
||||
"\t\t\t\"reason\": \"FRAIS DEPLACEMENT\",\n" +
|
||||
"\t\t\t\"reasonCode\": \"ADR\",\n" +
|
||||
"\t\t\t\"categoryCode\": \"S\"\n" +
|
||||
"\t\t}\n" +
|
||||
" ],\n" +
|
||||
"\t\t\"tradeSettlement\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"accountName\": null,\n" +
|
||||
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\",\n" +
|
||||
"\t\t\t\"bic\": \"BIC_MONCOMPTE\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"mandate\": \"MANDATE PT\",\n" +
|
||||
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\"\n" +
|
||||
"\t\t}\n" +
|
||||
" ],\n" +
|
||||
"\t\t\"zfitems\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"price\": 60,\n" +
|
||||
"\t\t\t\"quantity\": 1,\n" +
|
||||
"\t\t\t\"basisQuantity\": 1,\n" +
|
||||
"\t\t\t\"product\": {\n" +
|
||||
"\t\t\t\"unit\": \"C62\",\n" +
|
||||
"\t\t\t\t\"name\": \"REMBOURSEMENT AFFRANCHISSEMENT\",\n" +
|
||||
"\t\t\t\t\"description\": \"Description\",\n" +
|
||||
"\t\t\t\t\"taxCategoryCode\": \"Z\",\n" +
|
||||
"\t\t\t\t\"vatpercent\": 0,\n" +
|
||||
"\t\t\t\t\"reverseCharge\": false,\n" +
|
||||
"\t\t\t\t\"intraCommunitySupply\": false,\n" +
|
||||
"\t\t\t\t\"globalID\": \"598785412598745\",\n" +
|
||||
"\t\t\t\t\"globalIDScheme\": \"0160\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\t\"buyerOrderReferencedDocumentLineID\": \"1\",\n" +
|
||||
"\t\t\t\"value\": 60\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"price\": 30,\n" +
|
||||
"\t\t\t\"quantity\": 3,\n" +
|
||||
"\t\t\t\"basisQuantity\": 3,\n" +
|
||||
"\t\t\t\"product\": {\n" +
|
||||
"\t\t\t\"unit\": \"C62\",\n" +
|
||||
"\t\t\t\t\"name\": \"FOURNITURES DIVERSES\",\n" +
|
||||
"\t\t\t\t\"description\": \"Description\",\n" +
|
||||
"\t\t\t\t\"taxCategoryCode\": \"S\",\n" +
|
||||
"\t\t\t\t\"vatpercent\": 20,\n" +
|
||||
"\t\t\t\t\"reverseCharge\": false,\n" +
|
||||
"\t\t\t\t\"intraCommunitySupply\": false\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\t\"buyerOrderReferencedDocumentLineID\": \"3\",\n" +
|
||||
"\t\t\t\"value\": 30\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"price\": 12,\n" +
|
||||
"\t\t\t\"quantity\": 1,\n" +
|
||||
"\t\t\t\"basisQuantity\": 1,\n" +
|
||||
"\t\t\t\"product\": {\n" +
|
||||
"\t\t\t\"unit\": \"C62\",\n" +
|
||||
"\t\t\t\t\"name\": \"APPEL\",\n" +
|
||||
"\t\t\t\t\"description\": \"Description\",\n" +
|
||||
"\t\t\t\t\"taxCategoryCode\": \"S\",\n" +
|
||||
"\t\t\t\t\"vatpercent\": 10,\n" +
|
||||
"\t\t\t\t\"reverseCharge\": false,\n" +
|
||||
"\t\t\t\t\"intraCommunitySupply\": false\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t\t\"buyerOrderReferencedDocumentLineID\": \"2\",\n" +
|
||||
"\t\t\t\"value\": 12\n" +
|
||||
"\t\t}\n" +
|
||||
" ],\n" +
|
||||
"\t\t\"ownStreet\": \"35 rue d'ici\",\n" +
|
||||
"\t\t\"ownCountry\": \"FR\",\n" +
|
||||
"\t\t\"ownZIP\": \"75018\",\n" +
|
||||
"\t\t\"ownLocation\": \"PARIS\",\n" +
|
||||
"\t\t\"ownVATID\": \"FR11123456782\",\n" +
|
||||
"\t\t\"valid\": false\n" +
|
||||
"\t}\n", Invoice.class);
|
||||
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
|
||||
zf2p.setProfile(Profiles.getByName("XRechnung"));
|
||||
zf2p.generateXML(fromJSON);
|
||||
theXML = new String(zf2p.getXML());
|
||||
} catch (Exception e) {
|
||||
exceptions = true;
|
||||
}
|
||||
assertTrue(theXML.contains("pour frais de recouvrement en cas de retard de paiement"));
|
||||
assertFalse(exceptions);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -214,8 +214,10 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
||||
|
||||
public void testForeignImport() {
|
||||
InputStream inputStream = this.getClass().getResourceAsStream("/zugferd_invoice.pdf");
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
|
||||
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter();
|
||||
zi.doRecalculateItemPricesFromLineTotals();
|
||||
zi.doIgnoreCalculationErrors();
|
||||
zi.setInputStream(inputStream);
|
||||
// Reading ZUGFeRD
|
||||
String amount = zi.getAmount();
|
||||
|
||||
|
||||
@@ -106,6 +106,16 @@ public class OXTest extends MustangReaderTestCase {
|
||||
return "DE99XX12345";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansCode() {
|
||||
return "54";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansInformation() {
|
||||
return "Credit Card";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -61,7 +61,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
|
||||
Invoice i = new Invoice()
|
||||
.setIssueDate(new Date())
|
||||
.setSender(
|
||||
new TradeParty().setName(ownOrgName).setCountry("FR")
|
||||
new TradeParty().setName(ownOrgName).setCountry("FR").setVATID("FR555444333222111")
|
||||
.addBankDetails(new BankDetails(ownIBAN, ownBIC)))
|
||||
.setRecipient(recipient)
|
||||
.setNumber(ownNumber)
|
||||
@@ -116,7 +116,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
|
||||
.setIssueDate(new Date())
|
||||
.setDueDate(new Date())
|
||||
.setSender(
|
||||
new TradeParty().setName(ownOrgName).setCountry("FR")
|
||||
new TradeParty().setName(ownOrgName).setCountry("FR").setVATID("FR555444333222111")
|
||||
.addBankDetails(new BankDetails(ownIBAN)))
|
||||
.setRecipient(recipient)
|
||||
.setNumber(ownNumber).setTotalPrepaidAmount(new BigDecimal("1"))
|
||||
@@ -137,7 +137,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM_INV);
|
||||
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("145.37",zi.getAmount());
|
||||
assertEquals("146.37",zi.getAmount());
|
||||
// assertEquals(zi.getBIC(), ownBIC);
|
||||
// assertEquals(zi.getIBAN(), ownIBAN);
|
||||
assertEquals(ownOrgName, zi.getHolder());
|
||||
|
||||
@@ -123,35 +123,8 @@ public class UBLTest extends ResourceCase {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* public void testInvoiceImportOtherUBL() {
|
||||
|
||||
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_1_Teilrechnung.ubl.xml");
|
||||
// File UBLinputFile = getResourceAsFile("ubl/EN16931_2_Teilrechnung.ubl.xml");
|
||||
/* File UBLinputFile = getResourceAsFile("ubl/EN16931_AbweichenderZahlungsempf.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Betriebskostenabrechnung.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Einfach.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Einfach_DueDate.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Einfach_negativePaymentDue.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Elektron.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_ElektronischeAdresse.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Gutschrift.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Haftpflichtversicherung_Versicherungssteuer.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Innergemeinschaftliche_Lieferungen.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Kraftfahrversicherung_Bruttopreise.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Miete.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_OEPNV.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Physiotherapeut.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Rabatte.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Rechnungskorrektur.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_RechnungsUebertragung.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Reisekostenabrechnung.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_Sachversicherung_berechneter_Steuersatz.ubl.xml");
|
||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_SEPA_Prenotification.ubl.xml");
|
||||
|
||||
|
||||
|
||||
public void testEdgeInvoiceImportUBL2() {
|
||||
File UBLinputFile = getResourceAsFile("ubl/04.01a-INVOICE_ubl.xml");
|
||||
boolean hasExceptions = false;
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = null;
|
||||
@@ -160,15 +133,12 @@ public class UBLTest extends ResourceCase {
|
||||
zii = new ZUGFeRDInvoiceImporter(new FileInputStream(UBLinputFile));
|
||||
invoice = zii.extractInvoice();
|
||||
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
hasExceptions = true;
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
// Reading ZUGFeRD
|
||||
assertEquals(new BigDecimal("288.79"), invoice.getZFItems()[0].getPrice());
|
||||
assertEquals("04011000-12345-03", invoice.getReferenceNumber());
|
||||
assertEquals("seller@email.de", invoice.getSender().getContact().getEMail());
|
||||
assertEquals("12345", invoice.getRecipient().getZIP());
|
||||
assertEquals("DE75512108001245126199", invoice.getSender().getBankDetails().get(0).getIBAN());
|
||||
|
||||
}*/
|
||||
assertEquals(new BigDecimal("10000.0"), invoice.getTotalPrepaidAmount());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,174 +1,176 @@
|
||||
|
||||
/** **********************************************************************
|
||||
*
|
||||
* Copyright 2019 Jochen Staerk
|
||||
*
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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 org.mustangproject.ZUGFeRD;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.*;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class VisualizationTest extends ResourceCase {
|
||||
|
||||
public void testCIIVisualizationBasic() {
|
||||
|
||||
// the writing part
|
||||
String sourceFilename = "factur-x.xml";
|
||||
File CIIinputFile = getResourceAsFile(sourceFilename);
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*/
|
||||
result = zvi.visualize(CIIinputFile.getAbsolutePath(),ZUGFeRDVisualizer.Language.FR).replace("\r","").replace("\n","");
|
||||
|
||||
File expectedResult=getResourceAsFile("factur-x-vis.fr.html");
|
||||
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r","").replace("\n","");
|
||||
// remove linebreaks as well...
|
||||
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: "+e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: "+e.getMessage());
|
||||
} catch (TransformerException e) {
|
||||
fail("TransformerException should not happen: "+e.getMessage());
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not happen: "+e.getMessage());
|
||||
} catch (ParserConfigurationException e) {
|
||||
fail("ParserConfigurationException should not happen: "+e.getMessage());
|
||||
} catch (SAXException e) {
|
||||
fail("SAXException should not happen: "+e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
assertNotNull(result);
|
||||
// Reading ZUGFeRD
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
public void testUBLCreditNoteVisualizationBasic() {
|
||||
|
||||
// the writing part
|
||||
File UBLinputFile = getResourceAsFile("ubl-creditnote.xml");
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*/
|
||||
result = zvi.visualize(UBLinputFile.getAbsolutePath(),ZUGFeRDVisualizer.Language.EN).replace("\r","").replace("\n","").replace(" ","").replace("\t","");
|
||||
|
||||
File expectedResult=getResourceAsFile("factur-x-vis-ubl-creditnote.en.html");
|
||||
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r","").replace("\n","").replace(" ","").replace("\t","");
|
||||
// remove linebreaks as well...
|
||||
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: "+e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: "+e.getMessage());
|
||||
} catch (TransformerException e) {
|
||||
fail("TransformerException should not happen: "+e.getMessage());
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not happen: "+e.getMessage());
|
||||
} catch (ParserConfigurationException e) {
|
||||
fail("ParserConfigurationException should not happen: "+e.getMessage());
|
||||
} catch (SAXException e) {
|
||||
fail("SAXException should not happen: "+e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
assertNotNull(result);
|
||||
// Reading ZUGFeRD
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
public void testUBLVisualizationBasic() {
|
||||
|
||||
// the writing part
|
||||
File UBLinputFile = getResourceAsFile("ubl/01.01a-INVOICE.ubl.xml");
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*/
|
||||
result = zvi.visualize(UBLinputFile.getAbsolutePath(),ZUGFeRDVisualizer.Language.EN).replace("\r","").replace("\n","");
|
||||
|
||||
File expectedResult=getResourceAsFile("factur-x-vis-ubl.en.html");
|
||||
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r","").replace("\n","");
|
||||
// remove linebreaks as well...
|
||||
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: "+e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: "+e.getMessage());
|
||||
} catch (TransformerException e) {
|
||||
fail("TransformerException should not happen: "+e.getMessage());
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not happen: "+e.getMessage());
|
||||
} catch (ParserConfigurationException e) {
|
||||
fail("ParserConfigurationException should not happen: "+e.getMessage());
|
||||
} catch (SAXException e) {
|
||||
fail("SAXException should not happen: "+e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
assertNotNull(result);
|
||||
// Reading ZUGFeRD
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
/* public void testPDFVisualization() {
|
||||
|
||||
// the writing part
|
||||
CIIToUBL c2u = new CIIToUBL();
|
||||
String sourceFilename = "factur-x.xml";
|
||||
File CIIinputFile = getResourceAsFile(sourceFilename);
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*
|
||||
zvi.toPDF(CIIinputFile.getAbsolutePath(), "c:\\users\\jstaerk\\temp\\fopy2.pdf");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: "+e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: "+e.getMessage());
|
||||
}
|
||||
|
||||
// assertNotNull(result);
|
||||
// Reading ZUGFeRD
|
||||
// assertEquals(expected, result);
|
||||
}*/
|
||||
|
||||
}
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
* Copyright 2019 Jochen Staerk
|
||||
* <p>
|
||||
* Use is subject to license terms.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* <p>
|
||||
* **********************************************************************
|
||||
*/
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDVisualizer.Language;
|
||||
import org.mustangproject.util.ByteArraySearcher;
|
||||
|
||||
import javax.xml.transform.TransformerException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class VisualizationTest extends ResourceCase {
|
||||
|
||||
final String TARGET_PDF_CII = "./target/testout-Visualization-cii.pdf";
|
||||
final String TARGET_PDF_UBL = "./target/testout-Visualization-cii.pdf";
|
||||
|
||||
public void testCIIVisualizationBasic() {
|
||||
this.runZUGFeRDVisualization("factur-x.xml", "factur-x-vis.fr.html", Language.FR);
|
||||
}
|
||||
|
||||
public void testCIIVisualizationExtended() {
|
||||
this.runZUGFeRDVisualization("factur-x-extended.xml", "factur-x-vis-extended.de.html", Language.DE);
|
||||
}
|
||||
|
||||
public void testUBLCreditNoteVisualizationBasic() {
|
||||
this.runZUGFeRDVisualization("ubl-creditnote.xml", "factur-x-vis-ubl-creditnote.en.html", Language.EN);
|
||||
}
|
||||
|
||||
public void testUBLVisualizationBasic() {
|
||||
this.runZUGFeRDVisualization("ubl/01.01a-INVOICE.ubl.xml", "factur-x-vis-ubl.en.html", Language.EN);
|
||||
}
|
||||
|
||||
private void runZUGFeRDVisualization(String inputFilename, String resultFileName, Language lang) {
|
||||
File CIIinputFile = getResourceAsFile(inputFilename);
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
result = zvi.visualize(CIIinputFile.getAbsolutePath(), lang);
|
||||
Files.write(Paths.get("./target/testout-" + resultFileName), result.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
File expectedResult = getResourceAsFile(resultFileName);
|
||||
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8)
|
||||
;
|
||||
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: " + e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: " + e.getMessage());
|
||||
} catch (TransformerException e) {
|
||||
fail("TransformerException should not happen: " + e.getMessage());
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not happen: " + e.getMessage());
|
||||
} catch (ParserConfigurationException e) {
|
||||
fail("ParserConfigurationException should not happen: " + e.getMessage());
|
||||
}
|
||||
|
||||
assertNotNull(result);
|
||||
/* remove file endings so that tests can also pass after checking
|
||||
out from git with arbitrary options (which may include CSRF changes)
|
||||
*/
|
||||
assertEquals(expected.replace("\r", "")
|
||||
.replace("\n", "")
|
||||
.replace("\t", "")
|
||||
.replace(" ", ""), result.replace("\r", "")
|
||||
.replace("\n", "")
|
||||
.replace("\t", "")
|
||||
.replace(" ", ""));
|
||||
}
|
||||
|
||||
|
||||
public void testPDFVisualizationCII() {
|
||||
|
||||
File CIIinputFile = getResourceAsFile("cii/01.01a-INVOICE.cii.xml");
|
||||
|
||||
// the writing part
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
zvi.toPDF(CIIinputFile.getAbsolutePath(), TARGET_PDF_CII);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: " + e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: " + e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not occur");
|
||||
}
|
||||
}
|
||||
|
||||
public void testPDFVisualizationUBL() {
|
||||
|
||||
File UBLinputFile = getResourceAsFile("ubl/01.01a-INVOICE.ubl.xml");
|
||||
|
||||
// the writing part
|
||||
String sourceFilename = "factur-x.xml";
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
zvi.toPDF(UBLinputFile.getAbsolutePath(), TARGET_PDF_UBL);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: " + e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: " + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not occur");
|
||||
}
|
||||
}
|
||||
|
||||
public void testPDFVisualizationUBLCreditNote() {
|
||||
|
||||
File UBLinputFile = getResourceAsFile("ubl/UBL-CreditNote-2.1-Example.ubl.xml");
|
||||
|
||||
// the writing part
|
||||
String sourceFilename = "factur-x.xml";
|
||||
|
||||
String expected = null;
|
||||
String result = null;
|
||||
try {
|
||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
||||
zvi.toPDF(UBLinputFile.getAbsolutePath(), TARGET_PDF_UBL);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("UnsupportedOperationException should not happen: " + e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail("IllegalArgumentException should not happen: " + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not occur");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import junit.framework.TestCase;
|
||||
import org.mustangproject.*;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
||||
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
@@ -52,12 +53,17 @@ public class XRTest extends TestCase {
|
||||
TradeParty recipient = new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE");
|
||||
recipient.setEmail("quack@ducktown.org");
|
||||
Invoice i = createInvoice(recipient);
|
||||
|
||||
String legalOrgID = "aCustomSellerLegalOrgId";
|
||||
String sellerID = "aSellerTradePartyID";
|
||||
i.getSender().setLegalOrganisation(new LegalOrganisation(legalOrgID));
|
||||
i.getSender().setID(sellerID);
|
||||
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
|
||||
zf2p.setProfile(Profiles.getByName("XRechnung"));
|
||||
zf2p.generateXML(i);
|
||||
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
|
||||
assertTrue(theXML.contains("<ram:ID>" + sellerID + "</ram:ID>"));// must be possible without scheme #
|
||||
assertTrue(theXML.contains("<ram:ID>" + legalOrgID + "</ram:ID>"));// must be possible without scheme #
|
||||
assertThat(theXML).valueByXPath("count(//*[local-name()='IncludedSupplyChainTradeLineItem'])")
|
||||
.asInt()
|
||||
.isEqualTo(1); //2 errors are OK because there is a known bug
|
||||
@@ -76,6 +82,7 @@ public class XRTest extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testXREdgeExport() {
|
||||
|
||||
// the writing part
|
||||
@@ -88,13 +95,14 @@ public class XRTest extends TestCase {
|
||||
|
||||
FileAttachment fe1 = new FileAttachment("one.pdf", "application/pdf", "Alternative", b);
|
||||
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX")))
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX").setAccountName("kontoInhaber")))
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("recipient@sample.org"))
|
||||
.addCashDiscount(new CashDiscount(new BigDecimal(2), 7))
|
||||
.addCashDiscount(new CashDiscount(new BigDecimal(3), 14))
|
||||
.setReferenceNumber("991-01484-64")//leitweg-id
|
||||
// not using any VAT, this is also a test of zero-rated goods:
|
||||
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)))
|
||||
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO).setTaxExemptionReason("Kleinunternehmer"), amount, new BigDecimal(1.0)))
|
||||
.setPayee(new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199")))
|
||||
.embedFileInXML(fe1);
|
||||
|
||||
|
||||
@@ -109,6 +117,9 @@ public class XRTest extends TestCase {
|
||||
.asInt()
|
||||
.isEqualTo(1); //2 errors are OK because there is a known bug
|
||||
|
||||
assertThat(theXML).valueByXPath("count(//*[local-name()='PayeeTradeParty'])")
|
||||
.asInt()
|
||||
.isEqualTo(1);
|
||||
|
||||
assertThat(theXML).valueByXPath("//*[local-name()='DuePayableAmount']")
|
||||
.asDouble()
|
||||
@@ -125,19 +136,18 @@ public class XRTest extends TestCase {
|
||||
Invoice readInvoice = new Invoice();
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
try {
|
||||
|
||||
zii.setRawXML(zf2p.getXML());
|
||||
zii.setRawXML(zf2p.getXML(), false);
|
||||
zii.extractInto(readInvoice);
|
||||
} catch (ParseException | XPathExpressionException xp) {
|
||||
fail("Exception not expected");
|
||||
fail("ParseException not expected");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
List<FileAttachment> attachedFiles=zii.getFileAttachmentsXML();
|
||||
assertNotNull(attachedFiles);
|
||||
assertEquals(attachedFiles.size(), 1);
|
||||
fail("IOException not expected");
|
||||
}
|
||||
FileAttachment[] attachedFiles = readInvoice.getAdditionalReferencedDocuments();
|
||||
assertNotNull(attachedFiles);
|
||||
assertEquals(attachedFiles.length, 1);
|
||||
|
||||
assertTrue(Arrays.equals(attachedFiles.get(0).getData(), b));
|
||||
assertTrue(Arrays.equals(attachedFiles[0].getData(), b));
|
||||
|
||||
|
||||
}
|
||||
@@ -170,6 +180,66 @@ public class XRTest extends TestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testTaxExemptionReasonIssue() {
|
||||
String orgname = "Test company";
|
||||
String number = "123";
|
||||
String amountStr = "1.00";
|
||||
BigDecimal amount = new BigDecimal(amountStr);
|
||||
byte[] b = {12, 13};
|
||||
|
||||
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX").setAccountName("kontoInhaber")))
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("recipient@sample.org"))
|
||||
.setReferenceNumber("991-01484-64")//leitweg-id
|
||||
// not using any VAT, this is also a test of zero-rated goods:
|
||||
.setNumber(number)
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO).setTaxCategoryCode("E").setTaxExemptionReason("Kleinunternehmer"), amount, new BigDecimal(1.0)))
|
||||
.addItem(new Item(new Product("Testprodukt2", "", "C62", BigDecimal.ZERO).setTaxCategoryCode("S"), amount, new BigDecimal(1.0)))
|
||||
.setPayee( new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199")));
|
||||
|
||||
|
||||
|
||||
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
|
||||
|
||||
zf2p.setProfile(Profiles.getByName("XRechnung"));
|
||||
zf2p.generateXML(i);
|
||||
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
|
||||
assertThat(theXML).valueByXPath("count(//*[local-name()='ExemptionReason'])")
|
||||
.asInt()
|
||||
.isEqualTo(2);
|
||||
}
|
||||
|
||||
|
||||
public void testApplicablePercentInUntaxedService() {
|
||||
|
||||
// the writing part
|
||||
TradeParty recipient = new TradeParty("Franz Müller", null, "55232", "Entenhausen", "DE");
|
||||
String orgname = "Test company";
|
||||
String number = "123";
|
||||
String amountStr = "1.00";
|
||||
BigDecimal amount = new BigDecimal(amountStr);
|
||||
var i = new Invoice().setDueDate(new java.util.Date()).setIssueDate(new java.util.Date()).setDeliveryDate(new java.util.Date())
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("DE4711").addVATID("DE0815").setEmail("info@example.org").setContact(new org.mustangproject.Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new org.mustangproject.BankDetails("DE12500105170648489890", "COBADEFXXX")))
|
||||
.setRecipient(recipient)
|
||||
.setReferenceNumber("991-01484-64")//leitweg-id
|
||||
// not using any VAT, this is also a test of zero-rated goods:
|
||||
.setNumber(number).addItem(new org.mustangproject.Item(new org.mustangproject.Product("Testprodukt", "", "C62", java.math.BigDecimal.ZERO).setTaxCategoryCode(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE).setTaxExemptionReason("Expemtion reason"), amount, new java.math.BigDecimal(1.0)));
|
||||
|
||||
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
|
||||
zf2p.setProfile(Profiles.getByName("XRechnung"));
|
||||
zf2p.generateXML(i);
|
||||
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
|
||||
// Untaxed services don't have the field RateApplicablePercent, since it would be always 0. An error is thrown on validation, if 0 is set.
|
||||
assertThat(theXML).valueByXPath("count(//*[local-name()='RateApplicablePercent'])")
|
||||
.asInt()
|
||||
.isEqualTo(0);
|
||||
|
||||
//Exemption reason needs to be set if TaxCategoryCode == "O", reason should be at the product and in the ApplicableTradeTax
|
||||
assertThat(theXML).valueByXPath("count(//*[local-name()='ExemptionReason'])")
|
||||
.asInt()
|
||||
.isEqualTo(2);
|
||||
}
|
||||
|
||||
private org.mustangproject.Invoice createInvoice(TradeParty recipient) {
|
||||
String orgname = "Test company";
|
||||
|
||||
@@ -100,6 +100,16 @@ public class ZF2EdgeTest extends MustangReaderTestCase {
|
||||
return "DE99XX12345";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansCode() {
|
||||
return "54";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentMeansInformation() {
|
||||
return "Credit Card";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -230,13 +240,11 @@ public class ZF2EdgeTest extends MustangReaderTestCase {
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
return
|
||||
new PaymentTerms(
|
||||
"14 Tage 2% Skonto, 30 Tage rein netto",
|
||||
due,// fälligkeitsdatum
|
||||
paymentDiscountTerms //PaymentDiscountTerms
|
||||
);
|
||||
|
||||
return new PaymentTerms(
|
||||
"14 Tage 2% Skonto, 30 Tage rein netto",
|
||||
due,// fälligkeitsdatum
|
||||
paymentDiscountTerms //PaymentDiscountTerms
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -297,7 +305,8 @@ public class ZF2EdgeTest extends MustangReaderTestCase {
|
||||
InputStream SOURCE_PDF = this.getClass()
|
||||
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
|
||||
|
||||
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();ze.ignorePDFAErrors();
|
||||
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
|
||||
ze.ignorePDFAErrors();
|
||||
ze.load(SOURCE_PDF);
|
||||
ze.setProducer("My Application")
|
||||
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("Extended"));
|
||||
@@ -313,7 +322,8 @@ public class ZF2EdgeTest extends MustangReaderTestCase {
|
||||
// now check the contents (like MustangReaderTest)
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
|
||||
String resultXML=zi.getUTF8();
|
||||
assertTrue(resultXML.contains("<ram:TypeCode>59</ram:TypeCode>"));
|
||||
assertTrue(resultXML.contains("<ram:TypeCode>54</ram:TypeCode>"));
|
||||
assertTrue(resultXML.contains("<ram:Information>Credit Card</ram:Information>"));
|
||||
assertTrue(resultXML.contains("<ram:ShipToTradeParty>"));
|
||||
assertTrue(resultXML.contains("<ram:IBANID>DE540815</ram:IBANID>"));
|
||||
assertTrue(resultXML.contains("<ram:ApplicableTradePaymentDiscountTerms"));
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
@@ -29,7 +30,9 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.mustangproject.*;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
@@ -56,13 +59,14 @@ public class ZF2PushTest extends TestCase {
|
||||
final String TARGET_ATTACHMENTSPDF = "./target/testout-ZF2PushAttachments.pdf";
|
||||
final String TARGET_BANKPDF = "./target/testout-ZF2PushBank.pdf";
|
||||
final String TARGET_PUSHEDGE = "./target/testout-ZF2PushEdge.pdf";
|
||||
final String TARGET_INTRACOMMUNITYSUPPLYMANUALPDF = "./target/testout-ZF2PushIntraCommunitySupplyManual.pdf";
|
||||
final String TARGET_INTRACOMMUNITYSUPPLYPDF = "./target/testout-ZF2PushIntraCommunitySupply.pdf";
|
||||
final String TARGET_REVERSECHARGEPDF = "./target/testout-ZF2PushReverseCharge.pdf";
|
||||
|
||||
public void testPushExport() {
|
||||
/***
|
||||
* This writes to a filename like an official sample, please consider when changing (probably better not?)
|
||||
*/
|
||||
/***
|
||||
* This writes to a filename like an official sample, please consider when changing (probably better not?)
|
||||
*/
|
||||
// the writing part
|
||||
String orgname = "Bei Spiel GmbH";
|
||||
String number = "RE-20201121/508";
|
||||
@@ -87,6 +91,7 @@ public class ZF2PushTest extends TestCase {
|
||||
.addItem(new Item(new Product("Design (hours)", "Of a sample invoice", "HUR", new BigDecimal(7)), price, new BigDecimal(1.0)))
|
||||
.addItem(new Item(new Product("Ballons", "various colors, ~2000ml", "H87", new BigDecimal(19)), new BigDecimal("0.79"), new BigDecimal(400.0)))
|
||||
.addItem(new Item(new Product("Hot air „heiße Luft“ (litres)", "", "LTR", new BigDecimal(19)), new BigDecimal("0.025"), new BigDecimal(800.0)))
|
||||
.setRoundingAmount(new BigDecimal("1"))
|
||||
);
|
||||
|
||||
ze.export(TARGET_PDF);
|
||||
@@ -94,6 +99,15 @@ public class ZF2PushTest extends TestCase {
|
||||
fail("Exception should not be raised");
|
||||
}
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PDF);
|
||||
Invoice i = new Invoice();
|
||||
try {
|
||||
zii.extractInto(i);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
// now check the contents (like MustangReaderTest)
|
||||
@@ -125,8 +139,9 @@ public class ZF2PushTest extends TestCase {
|
||||
String number = "123";
|
||||
String priceStr = "1.00";
|
||||
|
||||
String senderDescription = "Kein Kleinunternehmer";
|
||||
String senderDescription = "Kleinunternehmer";
|
||||
String taxID = "9990815";
|
||||
String theNote = "oh lala";
|
||||
BigDecimal price = new BigDecimal(priceStr);
|
||||
try {
|
||||
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
|
||||
@@ -144,7 +159,7 @@ public class ZF2PushTest extends TestCase {
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711")
|
||||
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE")))
|
||||
.setNumber(number)
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)).setTaxExemptionReason("Kleinunternehmer gemäß §19 UStG").setTaxCategoryCode("E"), price, new BigDecimal(1.0)).addNote(theNote))
|
||||
);
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
|
||||
@@ -152,8 +167,8 @@ public class ZF2PushTest extends TestCase {
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not be raised");
|
||||
}
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PDF);
|
||||
Invoice i= null;
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_ATTACHMENTSPDF);
|
||||
Invoice i = null;
|
||||
try {
|
||||
i = zii.extractInvoice();
|
||||
} catch (XPathExpressionException e) {
|
||||
@@ -161,7 +176,9 @@ public class ZF2PushTest extends TestCase {
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
assertEquals(senderDescription,i.getSender().getDescription());
|
||||
|
||||
assertEquals(i.getZFItems()[0].getNotesWithSubjectCode().get(0).getContent(), theNote);
|
||||
assertEquals(senderDescription, i.getSender().getDescription());
|
||||
|
||||
// now check the contents (like MustangReaderTest)
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ATTACHMENTSPDF);
|
||||
@@ -170,7 +187,7 @@ public class ZF2PushTest extends TestCase {
|
||||
assertTrue(zi.getUTF8().contains(taxID));
|
||||
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("1.19", zi.getAmount());
|
||||
assertEquals("1.00", zi.getAmount());
|
||||
assertEquals(orgname, zi.getHolder());
|
||||
assertEquals(number, zi.getForeignReference());
|
||||
try {
|
||||
@@ -232,20 +249,24 @@ public class ZF2PushTest extends TestCase {
|
||||
|
||||
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
|
||||
ze.ignorePDFAErrors().load(SOURCE_PDF);
|
||||
ze.setProfile(Profiles.getByName("Extended"));
|
||||
|
||||
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
|
||||
// ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
|
||||
// .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
|
||||
|
||||
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date())
|
||||
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date())
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")
|
||||
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
|
||||
.setNumber(number)
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1"))))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50))))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1))))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1"))))
|
||||
);
|
||||
.addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AReason").setTaxPercent(new BigDecimal(19)))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1")).setReasonCode("95")))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)).setReason("In love with salesperson")))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AnotherReason")))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("Yet another reason")).addAllowance(new Allowance(new BigDecimal("1")).setReason("Something completely strange")));
|
||||
ze.setTransaction(i);
|
||||
|
||||
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
|
||||
@@ -254,25 +275,28 @@ public class ZF2PushTest extends TestCase {
|
||||
fail("IOException should not be raised");
|
||||
}
|
||||
|
||||
// now check the contents (like MustangReaderTest)
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ITEMCHARGESALLOWANCESPDF);
|
||||
|
||||
assertEquals("EUR", zi.getInvoiceCurrencyCode());
|
||||
assertTrue(zi.getUTF8().contains("0911623562")); // fax number
|
||||
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("18.33", zi.getAmount());
|
||||
assertEquals(orgname, zi.getHolder());
|
||||
assertEquals(number, zi.getForeignReference());
|
||||
try {
|
||||
// now check the contents (like MustangReaderTest)
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ITEMCHARGESALLOWANCESPDF);
|
||||
assertEquals("EUR", zi.getInvoiceCurrencyCode());
|
||||
assertTrue(zi.getUTF8().contains("0911623562")); // fax number
|
||||
assertTrue(zi.getUTF8().contains("ABK"));
|
||||
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("18.92", zi.getAmount());
|
||||
assertEquals(orgname, zi.getHolder());
|
||||
assertEquals(number, zi.getForeignReference());
|
||||
assertEquals(zi.getVersion(), 2);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail("Exception should not be raised");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testIntraCommunitySupplyExport() {
|
||||
/***
|
||||
* you can activate intra community suppliy on item level
|
||||
*/
|
||||
public void testIntraCommunitySupplyItemExport() {
|
||||
|
||||
String orgname = "Test company";
|
||||
String number = "123";
|
||||
@@ -288,7 +312,7 @@ public class ZF2PushTest extends TestCase {
|
||||
// .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
|
||||
|
||||
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addVATID("DE0815").addTaxID ("4711"))
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addVATID("DE0815").addTaxID("4711"))
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816")
|
||||
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
|
||||
.setDeliveryAddress(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816"))
|
||||
@@ -323,6 +347,68 @@ public class ZF2PushTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* or manually, in which case the transaction needs a delivery address outside DE, and the items a 0 tax with reason K and reason code
|
||||
*/
|
||||
|
||||
public void testIntraCommunitySupplyManualExport() {
|
||||
|
||||
String orgname = "Test company";
|
||||
String number = "123";
|
||||
String priceStr = "1.00";
|
||||
|
||||
String taxID = "9990815";
|
||||
BigDecimal price = new BigDecimal(priceStr);
|
||||
try {
|
||||
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
|
||||
|
||||
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
|
||||
ze.ignorePDFAErrors();
|
||||
ze.load(SOURCE_PDF);
|
||||
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2);
|
||||
|
||||
ze.setTransaction(new Invoice().setDeliveryAddress(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "FR")).setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).addVATID("DE0815"))
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "FR").addVATID("DE4711")
|
||||
|
||||
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE")))
|
||||
.setNumber(number)
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)).setTaxExemptionReason("Kein Ausweis der Umsatzsteuer bei innergemeinschaftlichen Lieferungen").setTaxCategoryCode("K"), price, new BigDecimal(1.0)))
|
||||
);
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
|
||||
ze.export(TARGET_INTRACOMMUNITYSUPPLYMANUALPDF);
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not be raised");
|
||||
}
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_INTRACOMMUNITYSUPPLYMANUALPDF);
|
||||
Invoice i = null;
|
||||
try {
|
||||
i = zii.extractInvoice();
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// now check the contents (like MustangReaderTest)
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_INTRACOMMUNITYSUPPLYMANUALPDF);
|
||||
|
||||
assertEquals("EUR", zi.getInvoiceCurrencyCode());
|
||||
assertTrue(zi.getUTF8().contains(taxID));
|
||||
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("1.00", zi.getAmount());
|
||||
assertEquals(orgname, zi.getHolder());
|
||||
assertEquals(number, zi.getForeignReference());
|
||||
try {
|
||||
assertEquals(zi.getVersion(), 2);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testReverseChargeExport() {
|
||||
|
||||
String orgname = "Test company";
|
||||
@@ -394,8 +480,8 @@ public class ZF2PushTest extends TestCase {
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
|
||||
.addCharge(new Charge(new BigDecimal(0.5)).setTaxPercent(new BigDecimal(19)))
|
||||
.addAllowance(new Allowance(new BigDecimal(0.2)).setTaxPercent(new BigDecimal(19)))
|
||||
.addCharge(new Charge(new BigDecimal(0.5)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"))
|
||||
.addAllowance(new Allowance(new BigDecimal(0.2)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"))
|
||||
);
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
|
||||
@@ -446,7 +532,7 @@ public class ZF2PushTest extends TestCase {
|
||||
try {
|
||||
SchemedID gtin = new SchemedID("0160", "2001015001325");
|
||||
SchemedID gln = new SchemedID("0088", "4304171000002");
|
||||
ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
|
||||
ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setPaymentReference("Verwendungszweck").setDocumentName("Rechnung")
|
||||
.setSellerOrderReferencedDocumentID("9384").setBuyerOrderReferencedDocumentID("28934")
|
||||
.setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurrenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurrenceTo))
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).setEmail("sender@test.org").setID(orgID).addVATID("DE0815"))
|
||||
@@ -454,11 +540,12 @@ public class ZF2PushTest extends TestCase {
|
||||
.setContractReferencedDocument(contractID)
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addGlobalID(gln).setEmail("recipient@test.org").addVATID("DE4711")
|
||||
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3"))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")))
|
||||
.addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16)))
|
||||
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
|
||||
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
|
||||
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE)
|
||||
.setInvoiceReferencedDocumentID("abc123").addInvoiceReferencedDocument(new ReferencedDocument("abcd1234"))
|
||||
);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
@@ -487,7 +574,7 @@ public class ZF2PushTest extends TestCase {
|
||||
assertTrue(zi.getUTF8().contains(occurrenceFrom));
|
||||
assertTrue(zi.getUTF8().contains(occurrenceTo));
|
||||
assertTrue(zi.getUTF8().contains(contractID));
|
||||
|
||||
assertEquals(zi.importedInvoice.getZFItems()[0].getId(), "a123");
|
||||
assertTrue(zi.getUTF8().contains("20200113")); // to contain item delivery periods
|
||||
assertTrue(zi.getUTF8().contains("20200115")); // to contain item delivery periods
|
||||
|
||||
@@ -498,14 +585,23 @@ public class ZF2PushTest extends TestCase {
|
||||
assertTrue(zi.getUTF8().contains("++49555123456"));
|
||||
assertTrue(zi.getUTF8().contains("Cash Discount")); // default description for cash discounts
|
||||
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()='ApplicableTradeTax']/*[local-name()='DueDateTypeCode']").asString().isEqualTo(EventTimeCodeTypeConstants.PAYMENT_DATE);
|
||||
assertTrue(zi.getUTF8().contains("<ram:Name>Rechnung</ram:Name>"));
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PUSHEDGE);
|
||||
try {
|
||||
Invoice i = zii.extractInvoice();
|
||||
|
||||
assertEquals("abc123", i.getInvoiceReferencedDocumentID());
|
||||
assertEquals(1, i.getInvoiceReferencedDocuments().size());
|
||||
assertEquals("abcd1234", i.getInvoiceReferencedDocuments().get(0).getIssuerAssignedID());
|
||||
assertEquals("4304171000002", i.getRecipient().getGlobalID());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
||||
assertEquals(occurrenceFrom, sdf.format(i.getDetailedDeliveryPeriodFrom()));
|
||||
assertEquals(occurrenceTo, sdf.format(i.getDetailedDeliveryPeriodTo()));
|
||||
assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID());
|
||||
assertEquals(orgID, i.getSender().getID());
|
||||
assertEquals("Verwendungszweck", i.getPaymentReference());
|
||||
assertEquals("Rechnung", i.getDocumentName());
|
||||
|
||||
} catch (XPathExpressionException e) {
|
||||
fail("XPathExpressionException should not be raised");
|
||||
@@ -533,7 +629,7 @@ public class ZF2PushTest extends TestCase {
|
||||
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
|
||||
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"))
|
||||
.setNumber(number)
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19))))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).addAllowance(new Allowance(BigDecimal.ONE)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19))))
|
||||
.addAllowance(new Allowance(new BigDecimal(600)).setTaxPercent(new BigDecimal(19)))
|
||||
);
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
@@ -549,7 +645,7 @@ public class ZF2PushTest extends TestCase {
|
||||
assertEquals("EUR", zi.getInvoiceCurrencyCode());
|
||||
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("4046.00", zi.getAmount());
|
||||
assertEquals("10805.20", zi.getAmount());
|
||||
assertEquals(orgname, zi.getHolder());
|
||||
assertEquals(number, zi.getForeignReference());
|
||||
try {
|
||||
@@ -579,8 +675,8 @@ public class ZF2PushTest extends TestCase {
|
||||
.setNumber(number)
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19))))
|
||||
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)))
|
||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK")))
|
||||
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
|
||||
);
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
|
||||
@@ -593,7 +689,7 @@ public class ZF2PushTest extends TestCase {
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_RELATIVECHARGESALLOWANCESPDF);
|
||||
|
||||
assertEquals("CHF", zi.getInvoiceCurrencyCode());
|
||||
assertEquals("6.25", zi.getAmount());
|
||||
assertEquals("11.10", zi.getAmount());
|
||||
assertEquals(orgname, zi.getHolder());
|
||||
assertEquals(number, zi.getForeignReference());
|
||||
try {
|
||||
@@ -719,4 +815,5 @@ public class ZF2PushTest extends TestCase {
|
||||
match the read grand total */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
|
||||
/** **********************************************************************
|
||||
*
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
* Copyright 2019 Jochen Staerk
|
||||
*
|
||||
* <p>
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*********************************************************************** */
|
||||
* <p>
|
||||
* **********************************************************************
|
||||
*/
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -99,9 +101,9 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
public IZUGFeRDExportableItem[] getZFItems() {
|
||||
final Item[] allItems = new Item[3];
|
||||
final Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR",
|
||||
new BigDecimal("7.000000"));
|
||||
new BigDecimal("7.000000"));
|
||||
final Product balloonProduct = new Product("", "Bestellerweiterung für E&F Umbau", "C62",
|
||||
new BigDecimal("19.000000"));// test for issue 103
|
||||
new BigDecimal("19.000000"));// test for issue 103
|
||||
final Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
|
||||
|
||||
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
|
||||
@@ -166,12 +168,12 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
// the writing part
|
||||
|
||||
try (InputStream SOURCE_PDF = this.getClass()
|
||||
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
|
||||
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
|
||||
|
||||
ZUGFeRDExporterFromA3 ze = new ZUGFeRDExporterFromA3().setProducer("My Application")
|
||||
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("EN16931")
|
||||
.load(SOURCE_PDF)) {
|
||||
|
||||
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("EN16931")
|
||||
.load(SOURCE_PDF)) {
|
||||
|
||||
ze.setTransaction(this);
|
||||
final String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
|
||||
@@ -190,13 +192,13 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
assertEquals(zi.getInvoiceID(), "RE-20170509/505");
|
||||
assertEquals(zi.getZUGFeRDProfil(), "COMFORT");
|
||||
assertEquals(zi.getInvoiceCurrencyCode(), "EUR");
|
||||
assertEquals(zi.getIssuerAssignedID(),"");
|
||||
assertEquals(zi.getIssuerAssignedID(), "");
|
||||
assertEquals(zi.getIssueDate(), "20170509");
|
||||
assertEquals(zi.getTaxPointDate(), "20170507");
|
||||
assertEquals(zi.getPaymentTerms(), "Zahlbar ohne Abzug bis zum 30.05.2017");
|
||||
assertEquals(zi.getLineTotalAmount(), "496.00");
|
||||
assertEquals(zi.getTaxBasisTotalAmount(), "496.00");
|
||||
assertEquals(zi.getTaxTotalAmount(),"75.04");
|
||||
assertEquals(zi.getTaxTotalAmount(), "75.04");
|
||||
assertEquals(zi.getRoundingAmount(), "");
|
||||
assertEquals(zi.getPaidAmount(), "0.00");
|
||||
assertEquals(zi.getBuyerTradePartyName(), "Theodor Est");
|
||||
@@ -206,8 +208,8 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
assertEquals(zi.getBuyertradePartySpecifiedTaxRegistrationID(), "DE999999999");
|
||||
assertEquals(zi.getIncludedNote(), "");
|
||||
assertEquals(zi.getHolder(), getOwnOrganisationName());
|
||||
assertEquals(zi.getDocumentCode(),"380");
|
||||
assertEquals(zi.getReference(),"AB321");
|
||||
assertEquals(zi.getDocumentCode(), "380");
|
||||
assertEquals(zi.getReference(), "AB321");
|
||||
assertEquals(zi.getAmount(), "571.04");
|
||||
assertEquals(zi.getBIC(), "COBADEFFXXX");
|
||||
assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
|
||||
@@ -244,7 +246,9 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
} /**
|
||||
}
|
||||
|
||||
/**
|
||||
* The exporter test bases on @{code
|
||||
* ./src/test/MustangBeispiel20221026.pdf}, adds
|
||||
* metadata, writes to @{code ./target/testout-*} and then imports to check the
|
||||
@@ -264,7 +268,7 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
assertEquals("Innerhalb von 30 Tagen 2% Skonto, 60 Tage ohne Abzug", zi.getPaymentTerms());
|
||||
assertEquals("804.35", zi.getLineTotalAmount());
|
||||
assertEquals("809.34", zi.getTaxBasisTotalAmount());
|
||||
assertEquals("153.77",zi.getTaxTotalAmount());
|
||||
assertEquals("153.77", zi.getTaxTotalAmount());
|
||||
assertEquals("", zi.getRoundingAmount());
|
||||
assertEquals("0.00", zi.getPaidAmount());
|
||||
assertEquals("Beispiel AG", zi.getBuyerTradePartyName());
|
||||
@@ -273,8 +277,8 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
assertEquals("10000", zi.getBuyerTradePartyID());
|
||||
assertEquals("\n weclapp.com\nSomestreet 42\n08155 Some city\nDE\n ", zi.getIncludedNote());
|
||||
assertEquals("weclapp.com", zi.getHolder());
|
||||
assertEquals("380",zi.getDocumentCode());
|
||||
assertEquals("01-95",zi.getReference());
|
||||
assertEquals("380", zi.getDocumentCode());
|
||||
assertEquals("01-95", zi.getReference());
|
||||
assertEquals("RE1001", zi.getForeignReference());
|
||||
assertEquals("54321", zi.getBuyerTradePartyAddress().getPostcodeCode());
|
||||
assertEquals("Feldstraße 34", zi.getBuyerTradePartyAddress().getLineOne());
|
||||
@@ -284,13 +288,13 @@ public class ZF2Test extends MustangReaderTestCase {
|
||||
assertEquals("DE", zi.getBuyerTradePartyAddress().getCountryID());
|
||||
assertEquals("Hithausen", zi.getBuyerTradePartyAddress().getCityName());
|
||||
assertEquals("Beispiel Lager AG", zi.getDeliveryTradePartyName());
|
||||
assertEquals("54321", zi.getDeliveryTradePartyAddress().getPostcodeCode());
|
||||
assertEquals("Feldstraße 39", zi.getDeliveryTradePartyAddress().getLineOne());
|
||||
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineTwo());
|
||||
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineThree());
|
||||
assertEquals(null, zi.getDeliveryTradePartyAddress().getCountrySubDivisionName());
|
||||
assertEquals("DE", zi.getDeliveryTradePartyAddress().getCountryID());
|
||||
assertEquals("Hithausen", zi.getDeliveryTradePartyAddress().getCityName());
|
||||
assertEquals("54321", zi.getDeliveryTradePartyAddress().getPostcodeCode());
|
||||
assertEquals("Feldstraße 39", zi.getDeliveryTradePartyAddress().getLineOne());
|
||||
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineTwo());
|
||||
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineThree());
|
||||
assertEquals(null, zi.getDeliveryTradePartyAddress().getCountrySubDivisionName());
|
||||
assertEquals("DE", zi.getDeliveryTradePartyAddress().getCountryID());
|
||||
assertEquals("Hithausen", zi.getDeliveryTradePartyAddress().getCityName());
|
||||
assertEquals("08155", zi.getSellerTradePartyAddress().getPostcodeCode());
|
||||
assertEquals("Somestreet 42", zi.getSellerTradePartyAddress().getLineOne());
|
||||
assertEquals(null, zi.getSellerTradePartyAddress().getLineTwo());
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/**
|
||||
* *********************************************************************
|
||||
* <p>
|
||||
@@ -21,11 +20,17 @@
|
||||
*/
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import org.mustangproject.FileAttachment;
|
||||
import org.mustangproject.Invoice;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mustangproject.*;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@@ -33,6 +38,10 @@ import java.nio.file.Paths;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
/***
|
||||
@@ -55,7 +64,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName());
|
||||
assertEquals("Bei Spiel GmbH", invoice.getSender().getName());
|
||||
assertEquals(3, invoice.getZFItems().length);
|
||||
assertEquals("400.0000", invoice.getZFItems()[1].getQuantity().toString());
|
||||
|
||||
@@ -65,6 +74,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
assertEquals("LTR", invoice.getZFItems()[2].getProduct().getUnit());
|
||||
assertEquals("7.00", invoice.getZFItems()[0].getProduct().getVATPercent().toString());
|
||||
assertEquals("RE-20170509/505", invoice.getNumber());
|
||||
assertEquals("Zahlbar ohne Abzug bis zum 30.05.2017", invoice.getPaymentTermDescription());
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
assertEquals("2017-05-09", sdf.format(invoice.getIssueDate()));
|
||||
@@ -91,6 +101,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testInvoiceImportUBL() {
|
||||
|
||||
|
||||
@@ -111,10 +122,12 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName());
|
||||
assertEquals("Bei Spiel GmbH", invoice.getSender().getName());
|
||||
assertEquals(3, invoice.getZFItems().length);
|
||||
assertEquals(invoice.getZFItems()[0].getNotesWithSubjectCode().get(0).getContent(),"Something");
|
||||
assertEquals(invoice.getZFItems()[0].getNotesWithSubjectCode().size(),1);
|
||||
assertEquals("400", invoice.getZFItems()[1].getQuantity().toString());
|
||||
|
||||
assertEquals("Zahlbar ohne Abzug bis zum 30.05.2017", invoice.getPaymentTermDescription());
|
||||
assertEquals("AB321", invoice.getReferenceNumber());
|
||||
assertEquals("160", invoice.getZFItems()[0].getPrice().toString());
|
||||
assertEquals("Heiße Luft pro Liter", invoice.getZFItems()[2].getProduct().getName());
|
||||
@@ -139,6 +152,9 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
assertEquals("DE", invoice.getSender().getCountry());
|
||||
assertEquals("Stadthausen", invoice.getSender().getLocation());
|
||||
|
||||
assertTrue(invoice.getPayee() != null);
|
||||
assertEquals("VR Factoring GmbH", invoice.getPayee().getName());
|
||||
|
||||
TransactionCalculator tc = new TransactionCalculator(invoice);
|
||||
assertEquals(new BigDecimal("571.04"), tc.getGrandTotal());
|
||||
|
||||
@@ -182,7 +198,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
// Reading ZUGFeRD
|
||||
assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName());
|
||||
assertEquals("Bei Spiel GmbH", invoice.getSender().getName());
|
||||
assertEquals(3, invoice.getZFItems().length);
|
||||
assertEquals("400.0000", invoice.getZFItems()[1].getQuantity().toString());
|
||||
|
||||
@@ -215,6 +231,24 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
|
||||
}
|
||||
|
||||
public void testSpecifiedLogisticsChargeImport() {
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
File expectedResult = getResourceAsFile("cii/extended_warenrechnung.xml");
|
||||
|
||||
|
||||
boolean hasExceptions = false;
|
||||
CalculatedInvoice invoice = new CalculatedInvoice();
|
||||
try {
|
||||
zii.setInputStream(new FileInputStream(expectedResult));
|
||||
zii.extractInto(invoice);
|
||||
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
|
||||
hasExceptions = true;
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
TransactionCalculator tc = new TransactionCalculator(invoice);
|
||||
assertEquals(new BigDecimal("518.99"), tc.getGrandTotal());
|
||||
|
||||
}
|
||||
public void testItemAllowancesChargesImport() {
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushItemChargesAllowances.pdf");
|
||||
@@ -228,7 +262,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
TransactionCalculator tc = new TransactionCalculator(invoice);
|
||||
assertEquals(new BigDecimal("18.33"), tc.getGrandTotal());
|
||||
assertEquals(new BigDecimal("18.92"), tc.getGrandTotal());
|
||||
}
|
||||
|
||||
public void testBasisQuantityImport() {
|
||||
@@ -247,6 +281,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
assertEquals(new BigDecimal("337.60"), tc.getGrandTotal());
|
||||
}
|
||||
|
||||
|
||||
public void testAllowancesChargesImport() {
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushChargesAllowances.pdf");
|
||||
@@ -267,12 +302,16 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
public void testXRImport() {
|
||||
boolean hasExceptions = false;
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
ZUGFeRDImporter zii = new ZUGFeRDImporter();
|
||||
|
||||
int version=-1;
|
||||
try {
|
||||
zii.fromXML(new String(Files.readAllBytes(Paths.get("./target/testout-XR-Edge.xml")), StandardCharsets.UTF_8));
|
||||
|
||||
version=zii.getVersion();
|
||||
} catch (IOException e) {
|
||||
hasExceptions = true;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Invoice invoice = null;
|
||||
@@ -282,35 +321,316 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
||||
hasExceptions = true;
|
||||
}
|
||||
assertFalse(hasExceptions);
|
||||
|
||||
|
||||
TransactionCalculator tc = new TransactionCalculator(invoice);
|
||||
assertEquals(new BigDecimal("1.00"), tc.getGrandTotal());
|
||||
|
||||
assertEquals(version,2);
|
||||
assertTrue(new BigDecimal("1").compareTo(invoice.getZFItems()[0].getQuantity()) == 0);
|
||||
LineCalculator lc=new LineCalculator(invoice.getZFItems()[0]);
|
||||
assertTrue(new BigDecimal("1").compareTo(lc.getItemTotalNetAmount()) == 0);
|
||||
|
||||
assertEquals("Z", invoice.getZFItems()[0].getProduct().getTaxCategoryCode());
|
||||
assertEquals("Kleinunternehmer", invoice.getZFItems()[0].getProduct().getTaxExemptionReason());
|
||||
|
||||
assertTrue(invoice.getTradeSettlement().length == 1);
|
||||
assertTrue(invoice.getTradeSettlement()[0] instanceof IZUGFeRDTradeSettlementPayment);
|
||||
IZUGFeRDTradeSettlementPayment paym = (IZUGFeRDTradeSettlementPayment) invoice.getTradeSettlement()[0];
|
||||
assertEquals("DE12500105170648489890", paym.getOwnIBAN());
|
||||
assertEquals("COBADEFXXX", paym.getOwnBIC());
|
||||
assertEquals("kontoInhaber",paym.getAccountName());
|
||||
|
||||
|
||||
assertTrue(invoice.getPayee() != null);
|
||||
assertEquals("VR Factoring GmbH", invoice.getPayee().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* testing if other files embedded in pdf additionally to the invoice can be read correctly
|
||||
* */
|
||||
*/
|
||||
public void testDetach() {
|
||||
boolean hasExceptions = false;
|
||||
|
||||
byte[] fileA=null;
|
||||
byte[] fileB=null;
|
||||
byte[] fileA = null;
|
||||
byte[] fileB = null;
|
||||
boolean facturXFound=false;
|
||||
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushAttachments.pdf");
|
||||
for (FileAttachment fa:zii.getFileAttachmentsPDF()) {
|
||||
for (FileAttachment fa : zii.getFileAttachmentsPDF()) {
|
||||
if (fa.getFilename().equals("one.pdf")) {
|
||||
fileA=fa.getData();
|
||||
fileA = fa.getData();
|
||||
} else if (fa.getFilename().equals("two.pdf")) {
|
||||
fileB=fa.getData();
|
||||
fileB = fa.getData();
|
||||
} else if (fa.getFilename().equals("factur-x.xml")) {
|
||||
facturXFound=true;
|
||||
}
|
||||
}
|
||||
byte[] b = {12, 13}; // the sample data that was used to write the files
|
||||
|
||||
assertTrue(facturXFound);
|
||||
assertTrue(Arrays.equals(fileA, b));
|
||||
assertEquals(fileA.length, 2);
|
||||
assertTrue(Arrays.equals(fileB, b));
|
||||
assertEquals(fileB.length, 2);
|
||||
}
|
||||
|
||||
public void testImportDebit() {
|
||||
File CIIinputFile = getResourceAsFile("cii/minimalDebit.xml");
|
||||
try {
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile));
|
||||
Invoice i = zii.extractInvoice();
|
||||
|
||||
assertEquals("DE21860000000086001055", i.getRecipient().getBankDetails().get(0).getIBAN());
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
String jsonArray = mapper.writeValueAsString(i);
|
||||
|
||||
// assertEquals("",jsonArray);
|
||||
|
||||
} catch (IOException e) {
|
||||
fail("IOException not expected");
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testImportMinimum() {
|
||||
File CIIinputFile = getResourceAsFile("cii/facturFrMinimum.xml");
|
||||
try {
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile));
|
||||
|
||||
|
||||
CalculatedInvoice i = new CalculatedInvoice();
|
||||
zii.extractInto(i);
|
||||
assertEquals("671.15", i.getGrandTotal().toString());
|
||||
|
||||
} catch (IOException e) {
|
||||
fail("IOException not expected");
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testImportUBLCreditnote() { // Confirm some basics also work with UBL credit notes
|
||||
File CIIinputFile = getResourceAsFile("ubl/UBL-CreditNote-2.1-Example.ubl.xml");
|
||||
try {
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile));
|
||||
|
||||
|
||||
CalculatedInvoice i = new CalculatedInvoice();
|
||||
zii.extractInto(i);
|
||||
assertEquals("TOSL108", i.getNumber());
|
||||
assertEquals("1729", i.getGrandTotal().toString());
|
||||
assertEquals("729", i.getDuePayable().toString());
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
fail("IOException not expected");
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testImportUBLPeriods() { // Confirm some basics also work with UBL credit notes
|
||||
File ublinputFile = getResourceAsFile("ubl/periods.ubl.xml");
|
||||
try {
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
zii.doIgnoreCalculationErrors();
|
||||
zii.setInputStream(new FileInputStream(ublinputFile));
|
||||
|
||||
|
||||
CalculatedInvoice i = new CalculatedInvoice();
|
||||
zii.extractInto(i);
|
||||
assertEquals("123", i.getNumber());
|
||||
assertEquals("1.48", i.getGrandTotal().toString());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
assertEquals("2020-10-01", sdf.format(i.getDetailedDeliveryPeriodFrom()));
|
||||
assertEquals("2020-10-05", sdf.format(i.getDetailedDeliveryPeriodTo()));
|
||||
|
||||
} catch (IOException e) {
|
||||
fail("IOException not expected");
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testImportPrepaid() throws XPathExpressionException, ParseException {
|
||||
InputStream inputStream = this.getClass()
|
||||
.getResourceAsStream("/EN16931_1_Teilrechnung.pdf");
|
||||
ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter();
|
||||
importer.doIgnoreCalculationErrors();
|
||||
importer.setInputStream(inputStream);
|
||||
|
||||
CalculatedInvoice invoice = new CalculatedInvoice();
|
||||
importer.extractInto(invoice);
|
||||
|
||||
boolean isBD=invoice.getTotalPrepaidAmount() instanceof BigDecimal;
|
||||
assertTrue(isBD);
|
||||
BigDecimal expectedPrepaid=new BigDecimal(50);
|
||||
BigDecimal expectedLineTotal=new BigDecimal("180.76");
|
||||
BigDecimal expectedDue=new BigDecimal("147.65");
|
||||
if (isBD) {
|
||||
BigDecimal amread=invoice.getTotalPrepaidAmount();
|
||||
BigDecimal importedLineTotal=invoice.getLineTotalAmount();
|
||||
BigDecimal importedDuePayable=invoice.getDuePayable();
|
||||
assertTrue(amread.compareTo(expectedPrepaid) == 0);
|
||||
assertTrue(importedLineTotal.compareTo(expectedLineTotal) == 0);
|
||||
assertTrue(importedDuePayable.compareTo(expectedDue) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testImportPrepaidUBL() throws XPathExpressionException, ParseException {
|
||||
InputStream inputStream = this.getClass()
|
||||
.getResourceAsStream("/ubl/XRECHNUNG_teilrechnung.ubl.xml");
|
||||
ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter();
|
||||
importer.doIgnoreCalculationErrors();
|
||||
importer.setInputStream(inputStream);
|
||||
|
||||
CalculatedInvoice invoice = new CalculatedInvoice();
|
||||
importer.extractInto(invoice);
|
||||
|
||||
assertEquals(0, invoice.getGrandTotal().compareTo(new BigDecimal("529.87")));
|
||||
assertEquals(0, invoice.getLineTotalAmount().compareTo(new BigDecimal("473")));
|
||||
assertEquals(0, invoice.getTotalPrepaidAmount().compareTo(new BigDecimal("500")));
|
||||
assertEquals(0, invoice.getDuePayable().compareTo(new BigDecimal("29.87")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testImportIncludedNotes() throws XPathExpressionException, ParseException {
|
||||
InputStream inputStream = this.getClass()
|
||||
.getResourceAsStream("/EN16931_Einfach.pdf");
|
||||
ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter(inputStream);
|
||||
Invoice invoice = importer.extractInvoice();
|
||||
List<IncludedNote> notesWithSubjectCode = invoice.getNotesWithSubjectCode();
|
||||
assertThat(notesWithSubjectCode).hasSize(2);
|
||||
assertThat(notesWithSubjectCode.get(0).getSubjectCode()).isNull();
|
||||
assertThat(notesWithSubjectCode.get(0).getContent()).isEqualTo("Rechnung gemäß Bestellung vom 01.11.2024.");
|
||||
assertThat(notesWithSubjectCode.get(1).getSubjectCode()).isEqualTo(SubjectCode.REG);
|
||||
assertThat(notesWithSubjectCode.get(1).getContent()).isEqualTo("Lieferant GmbH\t\t\t\t\n"
|
||||
+ "Lieferantenstraße 20\t\t\t\t\n"
|
||||
+ "80333 München\t\t\t\t\n"
|
||||
+ "Deutschland\t\t\t\t\n"
|
||||
+ "Geschäftsführer: Hans Muster\n"
|
||||
+ "Handelsregisternummer: H A 123");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIBANparsing() throws XPathExpressionException, ParseException, FileNotFoundException {
|
||||
|
||||
File inputFile = getResourceAsFile("cii/minimalDebit.xml");
|
||||
|
||||
ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||
Invoice invoice = importer.extractInvoice();
|
||||
assertEquals(1,invoice.getRecipient().getBankDetails().size());
|
||||
// IBAN belongs to recipient in invoice with sepa debit
|
||||
assertEquals("DE21860000000086001055",invoice.getRecipient().getBankDetails().get(0).getIBAN());
|
||||
assertEquals(0,invoice.getSender().getBankDetails().size());
|
||||
|
||||
inputFile = getResourceAsFile("factur-x.xml");
|
||||
|
||||
importer = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||
invoice = importer.extractInvoice();
|
||||
assertEquals(1,invoice.getSender().getBankDetails().size());
|
||||
// IBAN belongs to sender in normal invoice
|
||||
assertEquals("DE88200800000970375700",invoice.getSender().getBankDetails().get(0).getIBAN());
|
||||
assertEquals(0,invoice.getRecipient().getBankDetails().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemsBillingSpecifiedPeriod() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||
File inputFile = getResourceAsFile("factur-x_invoicingPeriod.xml");
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||
|
||||
CalculatedInvoice invoice = new CalculatedInvoice();
|
||||
zii.extractInto(invoice);
|
||||
assertEquals(3, invoice.getZFItems().length);
|
||||
assertEquals(new Date(2022-1900, 8-1, 29), invoice.getZFItems()[0].getDetailedDeliveryPeriodFrom());
|
||||
assertEquals(new Date(2022-1900, 8-1, 31), invoice.getZFItems()[0].getDetailedDeliveryPeriodTo());
|
||||
}
|
||||
|
||||
public void testImportPositionIncludedNotes() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||
File inputFile = getResourceAsFile("ZTESTZUGFERD_1_INVDSS_012015738820PDF-1.pdf");
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||
|
||||
Invoice invoice = zii.extractInvoice();
|
||||
assertEquals(1, invoice.getZFItems().length);
|
||||
assertEquals(8, invoice.getZFItems()[0].getNotesWithSubjectCode().size());
|
||||
assertEquals("FB-LE 9999", invoice.getZFItems()[0].getNotesWithSubjectCode().stream().filter(note -> note.getSubjectCode().equals(SubjectCode.ABZ)).findFirst().get().getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportXRechnungPositionNote() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||
File inputFile = getResourceAsFile("TESTXRECHNUNG_INVDSS_012015776085.XML");
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||
|
||||
Invoice invoice = zii.extractInvoice();
|
||||
assertEquals(1, invoice.getZFItems().length);
|
||||
assertFalse(invoice.getZFItems()[0].getNotes() == null);
|
||||
assertEquals(1, invoice.getZFItems()[0].getNotes().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportXRechnungWithoutCalculationErrors() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||
File inputFile = getResourceAsFile("cii/02.03a-INVOICE_uncefact.xml");
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||
|
||||
assertEquals("0", zii.importedInvoice.getDuePayable().toPlainString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||
File inputFile = getResourceAsFile("ORDER-X_EX01_ORDER_FULL_DATA-COMFORTorder-x.xml");
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
zii.doIgnoreCalculationErrors();
|
||||
zii.setInputStream(new FileInputStream(inputFile));
|
||||
|
||||
Invoice invoice = zii.extractInvoice();
|
||||
assertEquals(3, invoice.getZFItems().length);
|
||||
assertEquals("BUYER_ACCOUNTING_REF", invoice.getZFItems()[0].getAccountingReference());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportExport() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||
File inputFile = getResourceAsFile("cii/Factur-X_basic.xml");
|
||||
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
|
||||
zii.setInputStream(new FileInputStream(inputFile));
|
||||
|
||||
Invoice invoice = zii.extractInvoice();
|
||||
assertTrue(invoice.isValid());
|
||||
|
||||
assertNull(invoice.getDeliveryAddress());
|
||||
assertNull(invoice.getPayee());
|
||||
|
||||
assertNull(invoice.getBuyerOrderReferencedDocumentID());
|
||||
assertNull(invoice.getSellerOrderReferencedDocumentID());
|
||||
assertNull(invoice.getDespatchAdviceReferencedDocumentID());
|
||||
assertNull(invoice.getInvoiceReferencedDocumentID());
|
||||
}
|
||||
}
|
||||
|
||||
BIN
library/src/test/resources/EN16931_1_Teilrechnung.pdf
Normal file
BIN
library/src/test/resources/EN16931_1_Teilrechnung.pdf
Normal file
Binary file not shown.
BIN
library/src/test/resources/EN16931_Einfach.pdf
Executable file
BIN
library/src/test/resources/EN16931_Einfach.pdf
Executable file
Binary file not shown.
345
library/src/test/resources/Extended_fremdwaehrung.xml
Normal file
345
library/src/test/resources/Extended_fremdwaehrung.xml
Normal file
@@ -0,0 +1,345 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- English disclaimer below.-->
|
||||
<!--Nutzungsrechte
|
||||
ZUGFeRD Datenformat Version 2.3.0, 18.09.2024
|
||||
Beispiel Version 18.09.2024
|
||||
|
||||
Zweck des Forums elektronisch Rechnung Deutschland, welches am 31. März 2010 unter der Arbeitsgemeinschaft für
|
||||
wirtschaftliche Verwaltung e. V. gegründet wurde, ist u. a. die Schaffung und Spezifizierung eines offenen Datenformats
|
||||
für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht diskriminierender, standardisierter
|
||||
Technologien („ZUGFeRD Datenformat“).
|
||||
|
||||
Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung
|
||||
frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine
|
||||
Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht
|
||||
diskriminierenden Bedingungen an.
|
||||
|
||||
Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung
|
||||
abrufbar unter www.ferd-net.de.
|
||||
|
||||
Im Einzelnen schließt die Nutzungsgewährung ein:
|
||||
=====================================
|
||||
|
||||
FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils
|
||||
geltenden und akzeptierten Fassung (www.ferd-net.de) ein.
|
||||
Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung,
|
||||
Weiterbearbeitung und Verbindung mit anderen Produkten.
|
||||
Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder
|
||||
anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige
|
||||
Anwendungen und Dienste.
|
||||
Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente
|
||||
und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um
|
||||
notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch
|
||||
die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden.
|
||||
Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares,
|
||||
unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit
|
||||
anderen Produkten einzuräumen.
|
||||
|
||||
Die Lizenz wird kostenfrei zur Verfügung gestellt.
|
||||
|
||||
Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen
|
||||
Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten,
|
||||
Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete,
|
||||
beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der
|
||||
Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können.-->
|
||||
|
||||
<!--Right of use
|
||||
ZUGFeRD Data format version 2.3.0, September 18th, 2024
|
||||
|
||||
The purpose of the Forum elektronische Rechnung Deutschland (FeRD), which was founded on March 31, 2010 under the
|
||||
umbrella of Arbeitsgemeinschaft für wirtschaftliche Verwaltung e. V., is, among other things, to create and specify an
|
||||
open data format for structured electronic data exchange on the basis of open and non discriminatory, standardised
|
||||
technologies ("ZUGFeRD data format").
|
||||
|
||||
The ZUGFeRD data format is used by both companies and public administration according to the FeRD
|
||||
made freely accessible. For this purpose FeRD offers all companies and organisations of the public administration a
|
||||
License to use the copyrighted ZUGFeRD data format in a fair, appropriate and non
|
||||
discriminatory conditions.
|
||||
|
||||
The specification of the FeRD for the implementation of the ZUGFeRD data format is, in its currently valid version
|
||||
available at www.ferd-net.de.
|
||||
|
||||
In detail, the grant of use includes
|
||||
=====================================
|
||||
|
||||
FeRD grants a license for the use of the copyrighted ZUGFeRD data format in the respective
|
||||
valid and accepted version (www.ferd-net.de).
|
||||
The license includes an irrevocable right of use including the right of further development,
|
||||
Further processing and connection with other products.
|
||||
The license applies in particular to the development, design, production, sale, use or
|
||||
other use of the ZUGFeRD data format for hardware and/or software products and other
|
||||
applications and services.
|
||||
This license does not include the essential patents of the members of FeRD. The essential patents are patents
|
||||
and patent applications worldwide which contain one or more claims that are
|
||||
necessary claims. Necessary claims are only those claims of the essential patents which are
|
||||
the implementation of the ZUGFeRD data format would necessarily be violated.
|
||||
The Licensee is entitled to provide its respective group companies with an unlimited, worldwide, non-transferable,
|
||||
irrevocable right of use including the right of further development, further processing and connection with
|
||||
other products.
|
||||
|
||||
The license is provided free of charge.
|
||||
|
||||
Except in the case of intentional fault or gross negligence, FeRD is not liable for loss of use, loss of
|
||||
Profit, loss of data, loss of communication, loss of revenue, loss of contracts, loss of business or for costs
|
||||
damages, losses or liabilities in connection with an interruption of business, nor for concrete,
|
||||
incidental, indirect, punitive or consequential damages, even if the possibility of
|
||||
costs, losses or damages could normally have been foreseen.-->
|
||||
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:BusinessProcessSpecifiedDocumentContextParameter>
|
||||
<ram:ID>Beispielgeschäftsprozess</ram:ID>
|
||||
</ram:BusinessProcessSpecifiedDocumentContextParameter>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>47110815</ram:ID>
|
||||
<ram:Name>RECHNUNG</ram:Name>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20241115</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Mitglieder der Geschäftsleitung
|
||||
H. Meier Geschäftsführer
|
||||
T. Müller Prokurist
|
||||
HRB Braunschweig 12345</ram:Content>
|
||||
<ram:SubjectCode>REG</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Vom 17. Dezember 2024 bis 6. Januar 2025 haben wir Betriebsferien.</ram:Content>
|
||||
<ram:SubjectCode>AAI</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Aus konzern-internen Gründen wird der Steuerbetrag sowohl in der Rechungswährung (EUR) als auch in der Buchwährung (GBP) ausgegeben.</ram:Content>
|
||||
<ram:SubjectCode>TXD</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Materialzertifikat X-234 gem ISO XYZ.
|
||||
Ware bleibt bis zur vollständigen Bezahlung unser Eigentum.
|
||||
</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:SellerAssignedID>CO-123/V2A</ram:SellerAssignedID>
|
||||
<ram:BuyerAssignedID>Toolbox 0815</ram:BuyerAssignedID>
|
||||
<ram:Name>Stahlcoil</ram:Name>
|
||||
<ram:OriginTradeCountry>
|
||||
<ram:ID>DE</ram:ID>
|
||||
</ram:OriginTradeCountry>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:BuyerOrderReferencedDocument>
|
||||
<ram:IssuerAssignedID>ORDER84359</ram:IssuerAssignedID>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:BuyerOrderReferencedDocument>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>100.00</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="H87">1</ram:BasisQuantity>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>100</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="H87">1</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">10</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:CalculationPercent>10</ram:CalculationPercent>
|
||||
<ram:BasisAmount>1000</ram:BasisAmount>
|
||||
<ram:ActualAmount>100</ram:ActualAmount>
|
||||
<ram:ReasonCode>64</ram:ReasonCode>
|
||||
<ram:Reason>Lagerware</ram:Reason>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:BasisAmount>1000</ram:BasisAmount>
|
||||
<ram:ActualAmount>50</ram:ActualAmount>
|
||||
<ram:ReasonCode>70</ram:ReasonCode>
|
||||
<ram:Reason>Direktbelieferung</ram:Reason>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>850</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:ID>12345676</ram:ID>
|
||||
<ram:Name>Rohstoff AG Salzgitter</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>38226</ram:PostcodeCode>
|
||||
<ram:LineOne>Marktstr. 153</ram:LineOne>
|
||||
<ram:CityName>Salzgitter</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE123456789</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:ID>75969813</ram:ID>
|
||||
<ram:Name>Metallbau Leipzig GmbH & Co. KG</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12345</ram:PostcodeCode>
|
||||
<ram:LineOne>Pappelallee 15</ram:LineOne>
|
||||
<ram:LineTwo>Hof 3</ram:LineTwo>
|
||||
<ram:CityName>Leipzig</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:URIUniversalCommunication>
|
||||
<ram:URIID schemeID="0204">04 0 11 000 - 12345 12345 - 35</ram:URIID>
|
||||
</ram:URIUniversalCommunication>
|
||||
</ram:BuyerTradeParty>
|
||||
<ram:SellerTaxRepresentativeTradeParty>
|
||||
<ram:Name>Global Supplies Financial Services</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12345</ram:PostcodeCode>
|
||||
<ram:LineOne>Friedrichstraße 165</ram:LineOne>
|
||||
<ram:CityName>Berlin</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE1334567</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTaxRepresentativeTradeParty>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ShipToTradeParty>
|
||||
<ram:ID>75969815</ram:ID>
|
||||
<ram:Name>Metallbau Leipzig GmbH & Co. KG</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12347</ram:PostcodeCode>
|
||||
<ram:LineOne>Eichenpromenade 37</ram:LineOne>
|
||||
<ram:LineTwo>Tor 1</ram:LineTwo>
|
||||
<ram:CityName>Metallstadt</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:URIUniversalCommunication>
|
||||
<ram:URIID schemeID="0060">999999999</ram:URIID>
|
||||
</ram:URIUniversalCommunication>
|
||||
</ram:ShipToTradeParty>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20241111</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:TaxCurrencyCode>EUR</ram:TaxCurrencyCode>
|
||||
<ram:InvoiceCurrencyCode>GBP</ram:InvoiceCurrencyCode>
|
||||
<ram:PayeeTradeParty>
|
||||
<ram:GlobalID schemeID="0060">432156789</ram:GlobalID>
|
||||
<ram:Name>Global Supplies Financial Services</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12345</ram:PostcodeCode>
|
||||
<ram:LineOne>Friedrichstraße 165</ram:LineOne>
|
||||
<ram:CityName>Berlin</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:PayeeTradeParty>
|
||||
<ram:TaxApplicableTradeCurrencyExchange>
|
||||
<ram:SourceCurrencyCode>GBP</ram:SourceCurrencyCode>
|
||||
<ram:TargetCurrencyCode>EUR</ram:TargetCurrencyCode>
|
||||
<ram:ConversionRate>1.12244</ram:ConversionRate>
|
||||
<ram:ConversionRateDateTime>
|
||||
<udt:DateTimeString format="102">20181031</udt:DateTimeString>
|
||||
</ram:ConversionRateDateTime>
|
||||
</ram:TaxApplicableTradeCurrencyExchange>
|
||||
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:TypeCode>58</ram:TypeCode>
|
||||
<ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:IBANID>DE77 3707 0060 0321 9870 00</ram:IBANID>
|
||||
<ram:AccountName>Global Supplies Financial Services</ram:AccountName>
|
||||
</ram:PayeePartyCreditorFinancialAccount>
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>163.16</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>858.75</ram:BasisAmount>
|
||||
<ram:LineTotalBasisAmount>850</ram:LineTotalBasisAmount>
|
||||
<ram:AllowanceChargeBasisAmount>8.75</ram:AllowanceChargeBasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:BillingSpecifiedPeriod>
|
||||
<ram:StartDateTime>
|
||||
<udt:DateTimeString format="102">20181001</udt:DateTimeString>
|
||||
</ram:StartDateTime>
|
||||
<ram:EndDateTime>
|
||||
<udt:DateTimeString format="102">20181031</udt:DateTimeString>
|
||||
</ram:EndDateTime>
|
||||
</ram:BillingSpecifiedPeriod>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>true</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:ActualAmount>30</ram:ActualAmount>
|
||||
<ram:ReasonCode>ABK</ram:ReasonCode>
|
||||
<ram:Reason>Einwegverpackung</ram:Reason>
|
||||
<ram:CategoryTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
|
||||
</ram:CategoryTradeTax>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:CalculationPercent>2.5</ram:CalculationPercent>
|
||||
<ram:BasisAmount>850</ram:BasisAmount>
|
||||
<ram:ActualAmount>21.25</ram:ActualAmount>
|
||||
<ram:ReasonCode>102</ram:ReasonCode>
|
||||
<ram:Reason>Stammkundenrabatt</ram:Reason>
|
||||
<ram:CategoryTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
|
||||
</ram:CategoryTradeTax>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Zahlbar ohne Abschlag bis </ram:Description>
|
||||
<ram:DueDateDateTime>
|
||||
<udt:DateTimeString format="102">20241201</udt:DateTimeString>
|
||||
</ram:DueDateDateTime>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Zahlbar mit 2% Skonto bis</ram:Description>
|
||||
<ram:DueDateDateTime>
|
||||
<udt:DateTimeString format="102">20241120</udt:DateTimeString>
|
||||
</ram:DueDateDateTime>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>850</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount>30</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount>21.25</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>858.75</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="GBP">163.16</ram:TaxTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">183.14</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>1021.91</ram:GrandTotalAmount>
|
||||
<ram:TotalPrepaidAmount>500</ram:TotalPrepaidAmount>
|
||||
<ram:DuePayableAmount>521.91</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
157
library/src/test/resources/TESTXRECHNUNG_INVDSS_012015776085.XML
Normal file
157
library/src/test/resources/TESTXRECHNUNG_INVDSS_012015776085.XML
Normal file
@@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><ubl:Invoice xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2 http://docs.oasis-open.org/ubl/os-UBL-2.1/xsd/maindoc/UBL-Invoice-2.1.xsd">
|
||||
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
|
||||
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
|
||||
<cbc:ID>2015776085</cbc:ID>
|
||||
<cbc:IssueDate>2024-11-01</cbc:IssueDate>
|
||||
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
|
||||
<cbc:Note>#AAI# Wenn bereits bezahlt, nur zu den Akten legen. Für Verzug und Verzugszinsen gelten die Bestimmungen der §§ 286 - 288 BGB. Der Schuldner einer Entgeltforderung kommt spätestens in Verzug, wenn er nicht innerhalb von 30 Tagen nach Fälligkeit und Zugang einer Rechnung oder gleichwertigen Zahlungsaufstellung leistet. Die Lieferung von Waren und Fahrzeugen erfolgt unter Eigentumsvorbehalt.</cbc:Note>
|
||||
<cbc:Note>#PAI# Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.</cbc:Note>
|
||||
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
|
||||
<cbc:BuyerReference>02-ZZ987654-99</cbc:BuyerReference>
|
||||
<cac:InvoicePeriod>
|
||||
<cbc:StartDate>2024-11-01</cbc:StartDate>
|
||||
<cbc:EndDate>2024-11-30</cbc:EndDate>
|
||||
</cac:InvoicePeriod>
|
||||
<cac:OrderReference>
|
||||
<cbc:ID>N/A</cbc:ID>
|
||||
</cac:OrderReference>
|
||||
<cac:ContractDocumentReference>
|
||||
<cbc:ID>63435555</cbc:ID>
|
||||
</cac:ContractDocumentReference>
|
||||
<cac:AccountingSupplierParty>
|
||||
<cac:Party>
|
||||
<cbc:EndpointID schemeID="9930">DE238574172</cbc:EndpointID>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Alphabet Fuhrparkmanagement GmbH</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Lilienthalallee 26</cbc:StreetName>
|
||||
<cbc:CityName>München</cbc:CityName>
|
||||
<cbc:PostalZone>80786</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
<cac:PartyTaxScheme>
|
||||
<cbc:CompanyID>DE238574172</cbc:CompanyID>
|
||||
<cac:TaxScheme>
|
||||
<cbc:ID>VAT</cbc:ID>
|
||||
</cac:TaxScheme>
|
||||
</cac:PartyTaxScheme>
|
||||
<cac:PartyLegalEntity>
|
||||
<cbc:RegistrationName>Alphabet Fuhrparkmanagement GmbH</cbc:RegistrationName>
|
||||
<cbc:CompanyID>HRB 181098</cbc:CompanyID>
|
||||
</cac:PartyLegalEntity>
|
||||
<cac:Contact>
|
||||
<cbc:Name>Yildiz Tolga</cbc:Name>
|
||||
<cbc:Telephone>+49899--</cbc:Telephone>
|
||||
<cbc:ElectronicMail>Tolga.Yildiz@alphabet.de</cbc:ElectronicMail>
|
||||
</cac:Contact>
|
||||
</cac:Party>
|
||||
</cac:AccountingSupplierParty>
|
||||
<cac:AccountingCustomerParty>
|
||||
<cac:Party>
|
||||
<cbc:EndpointID schemeID="9930">N/A</cbc:EndpointID>
|
||||
<cac:PartyIdentification>
|
||||
<cbc:ID>00987654</cbc:ID>
|
||||
</cac:PartyIdentification>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Muster GmbH</cbc:Name>
|
||||
</cac:PartyName>
|
||||
<cac:PostalAddress>
|
||||
<cbc:StreetName>Musterweg 1</cbc:StreetName>
|
||||
<cbc:CityName>Kiel</cbc:CityName>
|
||||
<cbc:PostalZone>24105</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:PostalAddress>
|
||||
<cac:PartyLegalEntity>
|
||||
<cbc:RegistrationName>Muster GmbH</cbc:RegistrationName>
|
||||
</cac:PartyLegalEntity>
|
||||
<cac:Contact>
|
||||
<cbc:Name>Mustermann Max</cbc:Name>
|
||||
</cac:Contact>
|
||||
</cac:Party>
|
||||
</cac:AccountingCustomerParty>
|
||||
<cac:Delivery>
|
||||
<cbc:ActualDeliveryDate>2024-11-30</cbc:ActualDeliveryDate>
|
||||
<cac:DeliveryLocation>
|
||||
<cbc:ID>00987654</cbc:ID>
|
||||
<cac:Address>
|
||||
<cbc:StreetName>Musterweg 1</cbc:StreetName>
|
||||
<cbc:CityName>Kiel</cbc:CityName>
|
||||
<cbc:PostalZone>24105</cbc:PostalZone>
|
||||
<cac:Country>
|
||||
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||
</cac:Country>
|
||||
</cac:Address>
|
||||
</cac:DeliveryLocation>
|
||||
<cac:DeliveryParty>
|
||||
<cac:PartyName>
|
||||
<cbc:Name>Muster GmbH</cbc:Name>
|
||||
</cac:PartyName>
|
||||
</cac:DeliveryParty>
|
||||
</cac:Delivery>
|
||||
<cac:PaymentMeans>
|
||||
<cbc:PaymentMeansCode>30</cbc:PaymentMeansCode>
|
||||
<cac:PayeeFinancialAccount>
|
||||
<cbc:ID>DE34700700100156919301</cbc:ID>
|
||||
<cbc:Name>Alphabet Fuhrparkmanagement GmbH</cbc:Name>
|
||||
<cac:FinancialInstitutionBranch>
|
||||
<cbc:ID>DEUTDEMMXXX</cbc:ID>
|
||||
</cac:FinancialInstitutionBranch>
|
||||
</cac:PayeeFinancialAccount>
|
||||
</cac:PaymentMeans>
|
||||
<cac:PaymentTerms>
|
||||
<cbc:Note>Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.</cbc:Note>
|
||||
</cac:PaymentTerms>
|
||||
<cac:TaxTotal>
|
||||
<cbc:TaxAmount currencyID="EUR">161.69</cbc:TaxAmount>
|
||||
<cac:TaxSubtotal>
|
||||
<cbc:TaxableAmount currencyID="EUR">851.00</cbc:TaxableAmount>
|
||||
<cbc:TaxAmount currencyID="EUR">161.69</cbc:TaxAmount>
|
||||
<cac:TaxCategory>
|
||||
<cbc:ID>S</cbc:ID>
|
||||
<cbc:Percent>19.00</cbc:Percent>
|
||||
<cac:TaxScheme>
|
||||
<cbc:ID>VAT</cbc:ID>
|
||||
</cac:TaxScheme>
|
||||
</cac:TaxCategory>
|
||||
</cac:TaxSubtotal>
|
||||
</cac:TaxTotal>
|
||||
<cac:LegalMonetaryTotal>
|
||||
<cbc:LineExtensionAmount currencyID="EUR">851.00</cbc:LineExtensionAmount>
|
||||
<cbc:TaxExclusiveAmount currencyID="EUR">851.00</cbc:TaxExclusiveAmount>
|
||||
<cbc:TaxInclusiveAmount currencyID="EUR">1012.69</cbc:TaxInclusiveAmount>
|
||||
<cbc:PayableAmount currencyID="EUR">1012.69</cbc:PayableAmount>
|
||||
</cac:LegalMonetaryTotal>
|
||||
<cac:InvoiceLine>
|
||||
<cbc:ID>1</cbc:ID>
|
||||
<cbc:Note>#AAI# Finanzrate vom 01.11.2024 bis 30.11.2024 #ABZ/Kennzeichen#SH-9 18E #AKG/Fahrgestellnummer#WBY51EJ080CR55555 #BA/Kilometerstand#0 #AKV/LeasingNr#63435555</cbc:Note>
|
||||
<cbc:InvoicedQuantity unitCode="C62">1.00</cbc:InvoicedQuantity>
|
||||
<cbc:LineExtensionAmount currencyID="EUR">851.00</cbc:LineExtensionAmount>
|
||||
<cac:InvoicePeriod>
|
||||
<cbc:StartDate>2024-11-01</cbc:StartDate>
|
||||
<cbc:EndDate>2024-11-30</cbc:EndDate>
|
||||
</cac:InvoicePeriod>
|
||||
<cac:Item>
|
||||
<cbc:Description>FL-Rate</cbc:Description>
|
||||
<cbc:Name>FL-Rate</cbc:Name>
|
||||
<cac:SellersItemIdentification>
|
||||
<cbc:ID>90101</cbc:ID>
|
||||
</cac:SellersItemIdentification>
|
||||
<cac:ClassifiedTaxCategory>
|
||||
<cbc:ID>S</cbc:ID>
|
||||
<cbc:Percent>19.00</cbc:Percent>
|
||||
<cac:TaxScheme>
|
||||
<cbc:ID>VAT</cbc:ID>
|
||||
</cac:TaxScheme>
|
||||
</cac:ClassifiedTaxCategory>
|
||||
</cac:Item>
|
||||
<cac:Price>
|
||||
<cbc:PriceAmount currencyID="EUR">851.00</cbc:PriceAmount>
|
||||
<cbc:BaseQuantity>1.00</cbc:BaseQuantity>
|
||||
</cac:Price>
|
||||
</cac:InvoiceLine>
|
||||
</ubl:Invoice>
|
||||
Binary file not shown.
171
library/src/test/resources/cii/01.01a-INVOICE.cii.xml
Normal file
171
library/src/test/resources/cii/01.01a-INVOICE.cii.xml
Normal file
@@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
|
||||
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
|
||||
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:BusinessProcessSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</ram:ID>
|
||||
</ram:BusinessProcessSpecifiedDocumentContextParameter>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>123456XX</ram:ID>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20160404</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Es gelten unsere Allgem. Geschäftsbedingungen, die Sie unter […] finden.</ram:Content>
|
||||
<ram:SubjectCode>ADU</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>Zeitschrift [...]</ram:LineID>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Die letzte Lieferung im Rahmen des abgerechneten Abonnements erfolgt in 12/2016 Lieferung erfolgt / erfolgte direkt vom Verlag</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:SellerAssignedID>246</ram:SellerAssignedID>
|
||||
<ram:Name>Zeitschrift [...]</ram:Name>
|
||||
<ram:Description>Zeitschrift Inland</ram:Description>
|
||||
<ram:DesignatedProductClassification>
|
||||
<ram:ClassCode listID="IB">0721-880X</ram:ClassCode>
|
||||
</ram:DesignatedProductClassification>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:BuyerOrderReferencedDocument>
|
||||
<ram:LineID>6171175.1</ram:LineID>
|
||||
</ram:BuyerOrderReferencedDocument>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>288.79</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="XPP">1</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:BillingSpecifiedPeriod>
|
||||
<ram:StartDateTime>
|
||||
<udt:DateTimeString format="102">20160101</udt:DateTimeString>
|
||||
</ram:StartDateTime>
|
||||
<ram:EndDateTime>
|
||||
<udt:DateTimeString format="102">20161231</udt:DateTimeString>
|
||||
</ram:EndDateTime>
|
||||
</ram:BillingSpecifiedPeriod>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>288.79</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>Porto + Versandkosten</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Porto + Versandkosten</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>26.07</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="XPP">1</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>26.07</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:BuyerReference>04011000-12345-03</ram:BuyerReference>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:Name>[Seller name]</ram:Name>
|
||||
<ram:Description>123/456/7890, HRA-Eintrag in […]</ram:Description>
|
||||
<ram:SpecifiedLegalOrganization>
|
||||
<ram:ID>[HRA-Eintrag]</ram:ID>
|
||||
<ram:TradingBusinessName>[Seller trading name]</ram:TradingBusinessName>
|
||||
</ram:SpecifiedLegalOrganization>
|
||||
<ram:DefinedTradeContact>
|
||||
<ram:PersonName>nicht vorhanden</ram:PersonName>
|
||||
<ram:TelephoneUniversalCommunication>
|
||||
<ram:CompleteNumber>+49 1234-5678</ram:CompleteNumber>
|
||||
</ram:TelephoneUniversalCommunication>
|
||||
<ram:EmailURIUniversalCommunication>
|
||||
<ram:URIID>seller@email.de</ram:URIID>
|
||||
</ram:EmailURIUniversalCommunication>
|
||||
</ram:DefinedTradeContact>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12345</ram:PostcodeCode>
|
||||
<ram:LineOne>[Seller address line 1]</ram:LineOne>
|
||||
<ram:CityName>[Seller city]</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:URIUniversalCommunication>
|
||||
<ram:URIID schemeID="EM">seller@email.de</ram:URIID>
|
||||
</ram:URIUniversalCommunication>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE 123456789</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:ID>[Buyer identifier]</ram:ID>
|
||||
<ram:Name>[Buyer name]</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12345</ram:PostcodeCode>
|
||||
<ram:LineOne>[Buyer address line 1]</ram:LineOne>
|
||||
<ram:CityName>[Buyer city]</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:URIUniversalCommunication>
|
||||
<ram:URIID schemeID="EM">buyer@info.de</ram:URIID>
|
||||
</ram:URIUniversalCommunication>
|
||||
</ram:BuyerTradeParty>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery/>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:TypeCode>58</ram:TypeCode>
|
||||
<ram:PayeePartyCreditorFinancialAccount>
|
||||
<!-- dies ist eine nicht existerende aber valide IBAN als test dummy -->
|
||||
<ram:IBANID>DE75512108001245126199</ram:IBANID>
|
||||
</ram:PayeePartyCreditorFinancialAccount>
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>22.04</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>314.86</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Zahlbar sofort ohne Abzug.</ram:Description>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>314.86</ram:LineTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>314.86</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">22.04</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>336.9</ram:GrandTotalAmount>
|
||||
<ram:DuePayableAmount>336.9</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
309
library/src/test/resources/cii/02.03a-INVOICE_uncefact.xml
Normal file
309
library/src/test/resources/cii/02.03a-INVOICE_uncefact.xml
Normal file
File diff suppressed because one or more lines are too long
130
library/src/test/resources/cii/Factur-X_basic.xml
Normal file
130
library/src/test/resources/cii/Factur-X_basic.xml
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">
|
||||
<!-- generated by: mustangproject.org vnull-->
|
||||
<rsm:ExchangedDocumentContext>
|
||||
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>471102</ram:ID>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20241115</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Rechnung gemäß Bestellung vom 01.11.2024.</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Lieferant GmbH
|
||||
Lieferantenstraße 20
|
||||
80333 München
|
||||
Deutschland
|
||||
Geschäftsführer: Hans Muster
|
||||
Handelsregisternummer: H A 123</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Unsere GLN: 4000001123452
|
||||
Ihre GLN: 4000001987658
|
||||
Ihre Kundennummer: GE2020211
|
||||
|
||||
|
||||
Zahlbar innerhalb 30 Tagen netto bis 25.12.2024, 3% Skonto innerhalb 10 Tagen bis 25.11.2024.</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0160">4012345001235</ram:GlobalID>
|
||||
<ram:Name>GTIN: 4012345001235
|
||||
Unsere Art.-Nr.: TB100A4
|
||||
Trennblätter A4
|
||||
</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>9.9000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">20.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>198.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:Name>Lieferant GmbH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>80333</ram:PostcodeCode>
|
||||
<ram:LineOne>Lieferantenstraße 20</ram:LineOne>
|
||||
<ram:CityName>München</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE123456789</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="FC">201/113/40209</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:Name>Kunden AG Mitte</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>69876</ram:PostcodeCode>
|
||||
<ram:LineOne>Hans Muster</ram:LineOne>
|
||||
<ram:LineTwo>Kundenstraße 15</ram:LineTwo>
|
||||
<ram:CityName>Frankfurt</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:BuyerTradeParty>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20241114</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>37.62</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>198.00</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Zahlbar innerhalb 30 Tagen netto bis 25.12.2024, 3% Skonto innerhalb 10 Tagen bis 25.11.2024.</ram:Description>
|
||||
<ram:DueDateDateTime>
|
||||
<udt:DateTimeString format="102">20241215</udt:DateTimeString>
|
||||
</ram:DueDateDateTime>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>198.00</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>198.00</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">37.62</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>235.62</ram:GrandTotalAmount>
|
||||
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
|
||||
<ram:DuePayableAmount>235.62</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
567
library/src/test/resources/cii/extended_warenrechnung.xml
Normal file
567
library/src/test/resources/cii/extended_warenrechnung.xml
Normal file
@@ -0,0 +1,567 @@
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<!-- English disclaimer below.-->
|
||||
<!--Nutzungsrechte
|
||||
ZUGFeRD Datenformat Version 2.2.0, 14.02.2022
|
||||
Beispiel Version 14.02.2022
|
||||
|
||||
Zweck des Forums elektronisch Rechnung Deutschland, welches am 31. März 2010 unter der Arbeitsgemeinschaft für
|
||||
wirtschaftliche Verwaltung e. V. gegründet wurde, ist u. a. die Schaffung und Spezifizierung eines offenen Datenformats
|
||||
für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht diskriminierender, standardisierter
|
||||
Technologien („ZUGFeRD Datenformat“).
|
||||
|
||||
Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung
|
||||
frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine
|
||||
Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht
|
||||
diskriminierenden Bedingungen an.
|
||||
|
||||
Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung
|
||||
abrufbar unter www.ferd-net.de.
|
||||
|
||||
Im Einzelnen schließt die Nutzungsgewährung ein:
|
||||
=====================================
|
||||
|
||||
FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils
|
||||
geltenden und akzeptierten Fassung (www.ferd-net.de) ein.
|
||||
Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung,
|
||||
Weiterbearbeitung und Verbindung mit anderen Produkten.
|
||||
Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder
|
||||
anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige
|
||||
Anwendungen und Dienste.
|
||||
Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente
|
||||
und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um
|
||||
notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch
|
||||
die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden.
|
||||
Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares,
|
||||
unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit
|
||||
anderen Produkten einzuräumen.
|
||||
|
||||
Die Lizenz wird kostenfrei zur Verfügung gestellt.
|
||||
|
||||
Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen
|
||||
Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten,
|
||||
Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete,
|
||||
beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der
|
||||
Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können.-->
|
||||
|
||||
<!--Right of use
|
||||
ZUGFeRD Data format version 2.2.0, February 14th, 2022
|
||||
|
||||
The purpose of the Forum elektronische Rechnung Deutschland (FeRD), which was founded on March 31, 2010 under the
|
||||
umbrella of Arbeitsgemeinschaft für wirtschaftliche Verwaltung e. V., is, among other things, to create and specify an
|
||||
open data format for structured electronic data exchange on the basis of open and non discriminatory, standardised
|
||||
technologies ("ZUGFeRD data format").
|
||||
|
||||
The ZUGFeRD data format is used by both companies and public administration according to the FeRD
|
||||
made freely accessible. For this purpose FeRD offers all companies and organisations of the public administration a
|
||||
License to use the copyrighted ZUGFeRD data format in a fair, appropriate and non
|
||||
discriminatory conditions.
|
||||
|
||||
The specification of the FeRD for the implementation of the ZUGFeRD data format is, in its currently valid version
|
||||
available at www.ferd-net.de.
|
||||
|
||||
In detail, the grant of use includes
|
||||
=====================================
|
||||
|
||||
FeRD grants a license for the use of the copyrighted ZUGFeRD data format in the respective
|
||||
valid and accepted version (www.ferd-net.de).
|
||||
The license includes an irrevocable right of use including the right of further development,
|
||||
Further processing and connection with other products.
|
||||
The license applies in particular to the development, design, production, sale, use or
|
||||
other use of the ZUGFeRD data format for hardware and/or software products and other
|
||||
applications and services.
|
||||
This license does not include the essential patents of the members of FeRD. The essential patents are patents
|
||||
and patent applications worldwide which contain one or more claims that are
|
||||
necessary claims. Necessary claims are only those claims of the essential patents which are
|
||||
the implementation of the ZUGFeRD data format would necessarily be violated.
|
||||
The Licensee is entitled to provide its respective group companies with an unlimited, worldwide, non-transferable,
|
||||
irrevocable right of use including the right of further development, further processing and connection with
|
||||
other products.
|
||||
|
||||
The license is provided free of charge.
|
||||
|
||||
Except in the case of intentional fault or gross negligence, FeRD is not liable for loss of use, loss of
|
||||
Profit, loss of data, loss of communication, loss of revenue, loss of contracts, loss of business or for costs
|
||||
damages, losses or liabilities in connection with an interruption of business, nor for concrete,
|
||||
incidental, indirect, punitive or consequential damages, even if the possibility of
|
||||
costs, losses or damages could normally have been foreseen.-->
|
||||
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:TestIndicator>
|
||||
<udt:Indicator>true</udt:Indicator>
|
||||
</ram:TestIndicator>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>R87654321012345</ram:ID>
|
||||
<ram:Name>WARENRECHNUNG</ram:Name>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20180806</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
<ram:IncludedNote>
|
||||
<ram:ContentCode>ST3</ram:ContentCode>
|
||||
<ram:Content>Es bestehen Rabatt- oder Bonusvereinbarungen.</ram:Content>
|
||||
<ram:SubjectCode>AAK</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:ContentCode>EEV</ram:ContentCode>
|
||||
<ram:Content>Der Verkäufer bleibt Eigentümer der Waren bis zu vollständigen Erfüllung der Kaufpreisforderung.</ram:Content>
|
||||
<ram:SubjectCode>AAJ</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>MUSTERLIEFERANT GMBH
|
||||
BAHNHOFSTRASSE 99
|
||||
99199 MUSTERHAUSEN
|
||||
Geschäftsführung:
|
||||
Max Mustermann
|
||||
USt-IdNr: DE123456789
|
||||
Telefon: +49 932 431 0
|
||||
www.musterlieferant.de
|
||||
HRB Nr. 372876
|
||||
Amtsgericht Musterstadt
|
||||
GLN 4304171000002
|
||||
WEEE-Reg-Nr.: DE87654321
|
||||
</ram:Content>
|
||||
<ram:SubjectCode>REG</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Leergutwert: 46,50</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Wichtige Information: Bei Bestellungen bis zum 19.12. ist die Auslieferung bis spätestens 23.12. garantiert.</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0160">4123456000014</ram:GlobalID>
|
||||
<ram:SellerAssignedID>ZS997</ram:SellerAssignedID>
|
||||
<ram:Name>Zitronensäure 100ml</ram:Name>
|
||||
<ram:ApplicableProductCharacteristic>
|
||||
<ram:Description>Verpackungsart</ram:Description>
|
||||
<ram:Value>BO</ram:Value>
|
||||
</ram:ApplicableProductCharacteristic>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>1.0000</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>1.0000</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">100.0000</ram:BilledQuantity>
|
||||
<ram:PackageQuantity unitCode="XCT">4.0000</ram:PackageQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>100.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>2</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0160">4123456000021</ram:GlobalID>
|
||||
<ram:SellerAssignedID>GZ250</ram:SellerAssignedID>
|
||||
<ram:Name>Gelierzucker Extra 250g</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>1.5000</ram:ChargeAmount>
|
||||
<ram:AppliedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:ActualAmount>0.0300</ram:ActualAmount>
|
||||
<ram:Reason>Artikelrabatt 1</ram:Reason>
|
||||
</ram:AppliedTradeAllowanceCharge>
|
||||
<ram:AppliedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:ActualAmount>0.0200</ram:ActualAmount>
|
||||
<ram:Reason>Artikelrabatt 2</ram:Reason>
|
||||
</ram:AppliedTradeAllowanceCharge>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>1.4500</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">50.0000</ram:BilledQuantity>
|
||||
<ram:PackageQuantity unitCode="XCT">1.0000</ram:PackageQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>72.50</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>3</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0160">4123456000021</ram:GlobalID>
|
||||
<ram:SellerAssignedID>GZ250</ram:SellerAssignedID>
|
||||
<ram:Name>Gelierzucker Extra 250g</ram:Name>
|
||||
<ram:Description>Artikel wie vereinbart ohne Berechnung</ram:Description>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0000</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0000</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">10.0000</ram:BilledQuantity>
|
||||
<ram:PackageQuantity unitCode="XCT">1.0000</ram:PackageQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>0.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>4</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0160">4100130013294</ram:GlobalID>
|
||||
<ram:SellerAssignedID>2031</ram:SellerAssignedID>
|
||||
<ram:BuyerAssignedID/>
|
||||
<ram:Name>Bierbrau Pils 20/0500</ram:Name>
|
||||
<ram:Description>EAN-VKE: 4100130913297</ram:Description>
|
||||
<ram:ApplicableProductCharacteristic>
|
||||
<ram:Description>Verpackung</ram:Description>
|
||||
<ram:Value>Kiste</ram:Value>
|
||||
</ram:ApplicableProductCharacteristic>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>12.0000</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>12.0000</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="XBC">15.0000</ram:BilledQuantity>
|
||||
<ram:PackageQuantity unitCode="XBO">20.0000</ram:PackageQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>180.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>5</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0160">2001015001325</ram:GlobalID>
|
||||
<ram:SellerAssignedID>1805</ram:SellerAssignedID>
|
||||
<ram:BuyerAssignedID/>
|
||||
<ram:Name>Leergutpfand 20 x 0,5l</ram:Name>
|
||||
<ram:ApplicableProductCharacteristic>
|
||||
<ram:Description>Verpackung</ram:Description>
|
||||
<ram:Value>unverpackt</ram:Value>
|
||||
</ram:ApplicableProductCharacteristic>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>3.1000</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>3.1000</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="C62">15.0000</ram:BilledQuantity>
|
||||
<ram:PackageQuantity unitCode="XBC">1.0000</ram:PackageQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>46.50</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>6</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0160">4123456000038</ram:GlobalID>
|
||||
<ram:SellerAssignedID>MP107</ram:SellerAssignedID>
|
||||
<ram:Name>Mischpalette Joghurt Karton 3 x 20</ram:Name>
|
||||
<ram:ApplicableProductCharacteristic>
|
||||
<ram:Description>Verpackung</ram:Description>
|
||||
<ram:Value>Karton</ram:Value>
|
||||
</ram:ApplicableProductCharacteristic>
|
||||
<ram:IncludedReferencedProduct>
|
||||
<ram:GlobalID schemeID="0160">4123456001035</ram:GlobalID>
|
||||
<ram:SellerAssignedID>JOG103</ram:SellerAssignedID>
|
||||
<ram:Name>Erdbeer 20 x 150g Becher</ram:Name>
|
||||
<ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity>
|
||||
</ram:IncludedReferencedProduct>
|
||||
<ram:IncludedReferencedProduct>
|
||||
<ram:GlobalID schemeID="0160">4123456002032</ram:GlobalID>
|
||||
<ram:SellerAssignedID>JOG203</ram:SellerAssignedID>
|
||||
<ram:Name>Banane 20 x 150g Becher</ram:Name>
|
||||
<ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity>
|
||||
</ram:IncludedReferencedProduct>
|
||||
<ram:IncludedReferencedProduct>
|
||||
<ram:GlobalID schemeID="0160">4123456003039</ram:GlobalID>
|
||||
<ram:SellerAssignedID>JOG303</ram:SellerAssignedID>
|
||||
<ram:Name>Schoko 20 x 150g Becher</ram:Name>
|
||||
<ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity>
|
||||
</ram:IncludedReferencedProduct>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>30.0000</ram:ChargeAmount>
|
||||
<ram:AppliedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:ActualAmount>0.9000</ram:ActualAmount>
|
||||
<ram:Reason>Artikelrabatt 1</ram:Reason>
|
||||
</ram:AppliedTradeAllowanceCharge>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>29.1000</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="C62">2.0000</ram:BilledQuantity>
|
||||
<ram:PackageQuantity unitCode="XPX">1.0000</ram:PackageQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>58.20</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:ID>549910</ram:ID>
|
||||
<ram:GlobalID schemeID="0088">4333741000005</ram:GlobalID>
|
||||
<ram:Name>MUSTERLIEFERANT GMBH</ram:Name>
|
||||
<ram:DefinedTradeContact>
|
||||
<ram:TelephoneUniversalCommunication>
|
||||
<ram:CompleteNumber>+49 932 431 500</ram:CompleteNumber>
|
||||
</ram:TelephoneUniversalCommunication>
|
||||
<ram:EmailURIUniversalCommunication>
|
||||
<ram:URIID>max.mustermann@musterlieferant.de</ram:URIID>
|
||||
</ram:EmailURIUniversalCommunication>
|
||||
</ram:DefinedTradeContact>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>99199</ram:PostcodeCode>
|
||||
<ram:LineOne>BAHNHOFSTRASSE 99</ram:LineOne>
|
||||
<ram:CityName>MUSTERHAUSEN</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE123456789</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:ID>009420</ram:ID>
|
||||
<ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID>
|
||||
<ram:Name>MUSTER-KUNDE GMBH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>40235</ram:PostcodeCode>
|
||||
<ram:LineOne>KUNDENWEG 88</ram:LineOne>
|
||||
<ram:CityName>DUESSELDORF</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:BuyerTradeParty>
|
||||
<ram:BuyerOrderReferencedDocument>
|
||||
<ram:IssuerAssignedID>B123456789</ram:IssuerAssignedID>
|
||||
</ram:BuyerOrderReferencedDocument>
|
||||
<ram:AdditionalReferencedDocument>
|
||||
<ram:IssuerAssignedID>A456123</ram:IssuerAssignedID>
|
||||
<ram:TypeCode>130</ram:TypeCode>
|
||||
</ram:AdditionalReferencedDocument>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ShipToTradeParty>
|
||||
<ram:GlobalID schemeID="0088">4304171088093</ram:GlobalID>
|
||||
<ram:Name>MUSTER-MARKT</ram:Name>
|
||||
<ram:DefinedTradeContact>
|
||||
<ram:DepartmentName>8211</ram:DepartmentName>
|
||||
</ram:DefinedTradeContact>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>31157</ram:PostcodeCode>
|
||||
<ram:LineOne>HAUPTSTRASSE 44</ram:LineOne>
|
||||
<ram:CityName>SARSTEDT</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:ShipToTradeParty>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20180805</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:DeliveryNoteReferencedDocument>
|
||||
<ram:IssuerAssignedID>L87654321012345</ram:IssuerAssignedID>
|
||||
</ram:DeliveryNoteReferencedDocument>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:InvoiceeTradeParty>
|
||||
<ram:ID>009420</ram:ID>
|
||||
<ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID>
|
||||
<ram:Name>MUSTER-KUNDE GMBH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>40235</ram:PostcodeCode>
|
||||
<ram:LineOne>KUNDENWEG 88</ram:LineOne>
|
||||
<ram:CityName>DUESSELDORF</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:InvoiceeTradeParty>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>61.07</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>321.40</ram:BasisAmount>
|
||||
<ram:LineTotalBasisAmount>326.50</ram:LineTotalBasisAmount>
|
||||
<ram:AllowanceChargeBasisAmount>-5.10</ram:AllowanceChargeBasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>8.93</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>127.59</ram:BasisAmount>
|
||||
<ram:LineTotalBasisAmount>130.70</ram:LineTotalBasisAmount>
|
||||
<ram:AllowanceChargeBasisAmount>-3.11</ram:AllowanceChargeBasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:CalculationPercent>2.00</ram:CalculationPercent>
|
||||
<ram:BasisAmount>280.00</ram:BasisAmount>
|
||||
<ram:ActualAmount>5.60</ram:ActualAmount>
|
||||
<ram:Reason>Rechnungsrabatt 1</ram:Reason>
|
||||
<ram:CategoryTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:CategoryTradeTax>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:CalculationPercent>2.00</ram:CalculationPercent>
|
||||
<ram:BasisAmount>130.70</ram:BasisAmount>
|
||||
<ram:ActualAmount>2.61</ram:ActualAmount>
|
||||
<ram:Reason>Rechnungsrabatt 1</ram:Reason>
|
||||
<ram:CategoryTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:CategoryTradeTax>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:BasisAmount>280.00</ram:BasisAmount>
|
||||
<ram:ActualAmount>2.50</ram:ActualAmount>
|
||||
<ram:Reason>Rechnungsrabatt 2</ram:Reason>
|
||||
<ram:CategoryTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:CategoryTradeTax>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:BasisAmount>130.70</ram:BasisAmount>
|
||||
<ram:ActualAmount>0.50</ram:ActualAmount>
|
||||
<ram:Reason>Rechnungsrabatt 2</ram:Reason>
|
||||
<ram:CategoryTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:CategoryTradeTax>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedLogisticsServiceCharge>
|
||||
<ram:Description>Transportkosten</ram:Description>
|
||||
<ram:AppliedAmount>3.00</ram:AppliedAmount>
|
||||
<ram:AppliedTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:AppliedTradeTax>
|
||||
</ram:SpecifiedLogisticsServiceCharge>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Bei Zahlung innerhalb 14 Tagen gewähren wir 2,0% Skonto.</ram:Description>
|
||||
<ram:ApplicableTradePaymentDiscountTerms>
|
||||
<ram:BasisPeriodMeasure unitCode="DAY">14</ram:BasisPeriodMeasure>
|
||||
<ram:CalculationPercent>2.00</ram:CalculationPercent>
|
||||
</ram:ApplicableTradePaymentDiscountTerms>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>457.20</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount>3.00</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount>11.21</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>448.99</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">70.00</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>518.99</ram:GrandTotalAmount>
|
||||
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
|
||||
<ram:DuePayableAmount>518.99</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
56
library/src/test/resources/cii/facturFrMinimum.xml
Normal file
56
library/src/test/resources/cii/facturFrMinimum.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rsm:CrossIndustryInvoice xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:factur-x.eu:1p0:minimum</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>FA-2017-0010</ram:ID>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20171113</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:Name>Au bon moulin</ram:Name>
|
||||
<ram:SpecifiedLegalOrganization>
|
||||
<ram:ID schemeID="0002">99999999800010</ram:ID>
|
||||
</ram:SpecifiedLegalOrganization>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:CountryID>FR</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">FR11999999998</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:Name>Ma jolie boutique</ram:Name>
|
||||
<ram:SpecifiedLegalOrganization>
|
||||
<ram:ID schemeID="0002">78787878400035</ram:ID>
|
||||
</ram:SpecifiedLegalOrganization>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:CountryID>FR</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">FR19787878784</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:BuyerTradeParty>
|
||||
<ram:BuyerOrderReferencedDocument>
|
||||
<ram:IssuerAssignedID>PO445</ram:IssuerAssignedID>
|
||||
</ram:BuyerOrderReferencedDocument>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery/>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:TaxBasisTotalAmount currencyID="EUR">624.90</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">46.25</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount currencyID="EUR">671.15</ram:GrandTotalAmount>
|
||||
<ram:DuePayableAmount currencyID="EUR">470.15</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
143
library/src/test/resources/cii/minimalDebit.xml
Normal file
143
library/src/test/resources/cii/minimalDebit.xml
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">
|
||||
<!-- generated by: mustangproject.org vnull-->
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>471102</ram:ID>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20180304</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Trennblätter A4</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>9.9000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">20.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>198.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>2</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Joghurt Banane</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>5.5000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">50.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>275.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:Name>Lieferant GmbH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>80333</ram:PostcodeCode>
|
||||
<ram:LineOne>Lieferantenstraße 20</ram:LineOne>
|
||||
<ram:CityName>München</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE123456789</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="FC">201/113/40209</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:Name>Kunden AG Mitte</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>69876</ram:PostcodeCode>
|
||||
<ram:LineOne>Kundenstraße 15</ram:LineOne>
|
||||
<ram:CityName>Frankfurt</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:BuyerTradeParty>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20180304</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:CreditorReferenceID>DE98ZZZ09999999999</ram:CreditorReferenceID>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:TypeCode>59</ram:TypeCode>
|
||||
<ram:PayerPartyDebtorFinancialAccount>
|
||||
<ram:IBANID>DE21860000000086001055</ram:IBANID></ram:PayerPartyDebtorFinancialAccount>
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>19.25</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>275.00</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>37.62</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>198.00</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Der Betrag in Höhe von EUR 529,87 wird am 20.03.2018 von Ihrem Konto per SEPA-Lastschrift eingezogen.
|
||||
</ram:Description>
|
||||
<ram:DirectDebitMandateID>REF A-123</ram:DirectDebitMandateID>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>473.00</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>473.00</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">56.87</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>529.87</ram:GrandTotalAmount>
|
||||
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
|
||||
<ram:DuePayableAmount>529.87</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
430
library/src/test/resources/factur-x-extended.xml
Normal file
430
library/src/test/resources/factur-x-extended.xml
Normal file
@@ -0,0 +1,430 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- English disclaimer below.-->
|
||||
<!--Nutzungsrechte
|
||||
ZUGFeRD Datenformat Version 2.3.0, 18.09.2024
|
||||
Beispiel Version 18.09.2024
|
||||
|
||||
Zweck des Forums elektronisch Rechnung Deutschland, welches am 31. März 2010 unter der Arbeitsgemeinschaft für
|
||||
wirtschaftliche Verwaltung e. V. gegründet wurde, ist u. a. die Schaffung und Spezifizierung eines offenen Datenformats
|
||||
für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht diskriminierender, standardisierter
|
||||
Technologien („ZUGFeRD Datenformat“).
|
||||
|
||||
Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung
|
||||
frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine
|
||||
Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht
|
||||
diskriminierenden Bedingungen an.
|
||||
|
||||
Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung
|
||||
abrufbar unter www.ferd-net.de.
|
||||
|
||||
Im Einzelnen schließt die Nutzungsgewährung ein:
|
||||
=====================================
|
||||
|
||||
FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils
|
||||
geltenden und akzeptierten Fassung (www.ferd-net.de) ein.
|
||||
Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung,
|
||||
Weiterbearbeitung und Verbindung mit anderen Produkten.
|
||||
Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder
|
||||
anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige
|
||||
Anwendungen und Dienste.
|
||||
Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente
|
||||
und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um
|
||||
notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch
|
||||
die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden.
|
||||
Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares,
|
||||
unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit
|
||||
anderen Produkten einzuräumen.
|
||||
|
||||
Die Lizenz wird kostenfrei zur Verfügung gestellt.
|
||||
|
||||
Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen
|
||||
Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten,
|
||||
Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete,
|
||||
beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der
|
||||
Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können.-->
|
||||
|
||||
<!--Right of use
|
||||
ZUGFeRD Data format version 2.3.0, September 18th, 2024
|
||||
|
||||
The purpose of the Forum elektronische Rechnung Deutschland (FeRD), which was founded on March 31, 2010 under the
|
||||
umbrella of Arbeitsgemeinschaft für wirtschaftliche Verwaltung e. V., is, among other things, to create and specify an
|
||||
open data format for structured electronic data exchange on the basis of open and non discriminatory, standardised
|
||||
technologies ("ZUGFeRD data format").
|
||||
|
||||
The ZUGFeRD data format is used by both companies and public administration according to the FeRD
|
||||
made freely accessible. For this purpose FeRD offers all companies and organisations of the public administration a
|
||||
License to use the copyrighted ZUGFeRD data format in a fair, appropriate and non
|
||||
discriminatory conditions.
|
||||
|
||||
The specification of the FeRD for the implementation of the ZUGFeRD data format is, in its currently valid version
|
||||
available at www.ferd-net.de.
|
||||
|
||||
In detail, the grant of use includes
|
||||
=====================================
|
||||
|
||||
FeRD grants a license for the use of the copyrighted ZUGFeRD data format in the respective
|
||||
valid and accepted version (www.ferd-net.de).
|
||||
The license includes an irrevocable right of use including the right of further development,
|
||||
Further processing and connection with other products.
|
||||
The license applies in particular to the development, design, production, sale, use or
|
||||
other use of the ZUGFeRD data format for hardware and/or software products and other
|
||||
applications and services.
|
||||
This license does not include the essential patents of the members of FeRD. The essential patents are patents
|
||||
and patent applications worldwide which contain one or more claims that are
|
||||
necessary claims. Necessary claims are only those claims of the essential patents which are
|
||||
the implementation of the ZUGFeRD data format would necessarily be violated.
|
||||
The Licensee is entitled to provide its respective group companies with an unlimited, worldwide, non-transferable,
|
||||
irrevocable right of use including the right of further development, further processing and connection with
|
||||
other products.
|
||||
|
||||
The license is provided free of charge.
|
||||
|
||||
Except in the case of intentional fault or gross negligence, FeRD is not liable for loss of use, loss of
|
||||
Profit, loss of data, loss of communication, loss of revenue, loss of contracts, loss of business or for costs
|
||||
damages, losses or liabilities in connection with an interruption of business, nor for concrete,
|
||||
incidental, indirect, punitive or consequential damages, even if the possibility of
|
||||
costs, losses or damages could normally have been foreseen.-->
|
||||
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:TestIndicator>
|
||||
<udt:Indicator>true</udt:Indicator>
|
||||
</ram:TestIndicator>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>KR87654321012</ram:ID>
|
||||
<ram:Name>KOSTENRECHNUNG</ram:Name>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20241115</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
<ram:IncludedNote>
|
||||
<ram:ContentCode>ST3</ram:ContentCode>
|
||||
<ram:Content>Es bestehen Rabatt- oder Bonusvereinbarungen.</ram:Content>
|
||||
<ram:SubjectCode>AAK</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:ContentCode>EEV</ram:ContentCode>
|
||||
<ram:Content>Der Verkäufer bleibt Eigentümer der Waren bis zur vollständigen Erfüllung der Kaufpreisforderung.</ram:Content>
|
||||
<ram:SubjectCode>AAJ</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>MUSTERLIEFERANT GMBH
|
||||
BAHNHOFSTRASSE 99
|
||||
99199 MUSTERHAUSEN
|
||||
Geschäftsführung:
|
||||
Max Mustermann
|
||||
USt-IdNr: DE123456789
|
||||
Telefon: +49 932 431 0
|
||||
www.musterlieferant.de
|
||||
HRB Nr. 372876
|
||||
Amtsgericht Musterstadt
|
||||
GLN 4304171000002
|
||||
</ram:Content>
|
||||
<ram:SubjectCode>REG</ram:SubjectCode>
|
||||
</ram:IncludedNote>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0088">4123456000014</ram:GlobalID>
|
||||
<ram:SellerAssignedID>WA997</ram:SellerAssignedID>
|
||||
<ram:Name>Wirkarbeit HT</ram:Name>
|
||||
<ram:ApplicableProductCharacteristic>
|
||||
<ram:Description>Zählpunkt</ram:Description>
|
||||
<ram:Value>DE0001346484600000000000000100038</ram:Value>
|
||||
</ram:ApplicableProductCharacteristic>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0520</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0520</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="KWH">1000.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>52.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>2</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0088">4123456000021</ram:GlobalID>
|
||||
<ram:SellerAssignedID>ÖST250</ram:SellerAssignedID>
|
||||
<ram:Name>Ökosteuer Lieferant</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0205</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0205</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="KWH">1000.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>20.50</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>3</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0088">4260331811362</ram:GlobalID>
|
||||
<ram:Name>Kommissionierer 1250032 D. Muster</ram:Name>
|
||||
<ram:Description>Besteller: Hr. Mayer, Personalnr. 4488</ram:Description>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>15.0000</ram:ChargeAmount>
|
||||
<ram:AppliedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:ActualAmount>4.50</ram:ActualAmount>
|
||||
<ram:Reason>Artikelrabatt 1</ram:Reason>
|
||||
</ram:AppliedTradeAllowanceCharge>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>10.5000</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="HUR">27.5000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>288.75</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>4</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0088">2001015001325</ram:GlobalID>
|
||||
<ram:SellerAssignedID>FB05</ram:SellerAssignedID>
|
||||
<ram:Name>FALTENBEUTEL 16x6x28 CM</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0105</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0105</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">3500.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>36.75</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>5</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:GlobalID schemeID="0088">4123456000038</ram:GlobalID>
|
||||
<ram:SellerAssignedID>KOP05</ram:SellerAssignedID>
|
||||
<ram:Name>Kopierpapier A4</ram:Name>
|
||||
<ram:Description>Zählerstand von-bis: 543210 - 544420</ram:Description>
|
||||
<ram:ApplicableProductCharacteristic>
|
||||
<ram:Description>Zähler-Nr.</ram:Description>
|
||||
<ram:Value>MG-X79318</ram:Value>
|
||||
</ram:ApplicableProductCharacteristic>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0100</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>0.0100</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="H87">1210.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>12.10</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:ID>549910</ram:ID>
|
||||
<ram:GlobalID schemeID="0088">4333741000005</ram:GlobalID>
|
||||
<ram:Name>MUSTERLIEFERANT GMBH</ram:Name>
|
||||
<ram:DefinedTradeContact>
|
||||
<ram:TelephoneUniversalCommunication>
|
||||
<ram:CompleteNumber>+49 932 431 500</ram:CompleteNumber>
|
||||
</ram:TelephoneUniversalCommunication>
|
||||
<ram:EmailURIUniversalCommunication>
|
||||
<ram:URIID>max.mustermann@musterlieferant.de</ram:URIID>
|
||||
</ram:EmailURIUniversalCommunication>
|
||||
</ram:DefinedTradeContact>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>99199</ram:PostcodeCode>
|
||||
<ram:LineOne>BAHNHOFSTRASSE 99</ram:LineOne>
|
||||
<ram:CityName>MUSTERHAUSEN</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="FC">201/113/40209</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:ID>339420</ram:ID>
|
||||
<ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID>
|
||||
<ram:Name>MUSTER-KUNDE GMBH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>40235</ram:PostcodeCode>
|
||||
<ram:LineOne>KUNDENWEG 88</ram:LineOne>
|
||||
<ram:CityName>DUESSELDORF</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:BuyerTradeParty>
|
||||
<ram:AdditionalReferencedDocument>
|
||||
<ram:IssuerAssignedID>A777123</ram:IssuerAssignedID>
|
||||
<ram:TypeCode>130</ram:TypeCode>
|
||||
</ram:AdditionalReferencedDocument>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ShipToTradeParty>
|
||||
<ram:GlobalID schemeID="0088">4304171088093</ram:GlobalID>
|
||||
<ram:Name>MUSTER-MARKT</ram:Name>
|
||||
<ram:DefinedTradeContact>
|
||||
<ram:DepartmentName>7322</ram:DepartmentName>
|
||||
</ram:DefinedTradeContact>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>31157</ram:PostcodeCode>
|
||||
<ram:LineOne>HAUPTSTRASSE 44</ram:LineOne>
|
||||
<ram:CityName>SARSTEDT</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:ShipToTradeParty>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20241030</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:DeliveryNoteReferencedDocument>
|
||||
<ram:IssuerAssignedID>L87654321012</ram:IssuerAssignedID>
|
||||
<ram:FormattedIssueDateTime>
|
||||
<qdt:DateTimeString format="102">20241031</qdt:DateTimeString>
|
||||
</ram:FormattedIssueDateTime>
|
||||
</ram:DeliveryNoteReferencedDocument>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:InvoiceeTradeParty>
|
||||
<ram:ID>339420</ram:ID>
|
||||
<ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID>
|
||||
<ram:Name>MUSTER-KUNDE GMBH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>40235</ram:PostcodeCode>
|
||||
<ram:LineOne>KUNDENWEG 88</ram:LineOne>
|
||||
<ram:CityName>DUESSELDORF</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:InvoiceeTradeParty>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>76.67</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>403.55</ram:BasisAmount>
|
||||
<ram:LineTotalBasisAmount>410.10</ram:LineTotalBasisAmount>
|
||||
<ram:AllowanceChargeBasisAmount>-6.55</ram:AllowanceChargeBasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:ChargeIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:ChargeIndicator>
|
||||
<ram:BasisAmount>410.10</ram:BasisAmount>
|
||||
<ram:ActualAmount>21.55</ram:ActualAmount>
|
||||
<ram:Reason>Sonderrabatt</ram:Reason>
|
||||
<ram:CategoryTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:CategoryTradeTax>
|
||||
</ram:SpecifiedTradeAllowanceCharge>
|
||||
<ram:SpecifiedLogisticsServiceCharge>
|
||||
<ram:Description>Transportkosten: Frachbetrag</ram:Description>
|
||||
<ram:AppliedAmount>15.00</ram:AppliedAmount>
|
||||
<ram:AppliedTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:AppliedTradeTax>
|
||||
</ram:SpecifiedLogisticsServiceCharge>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Skontovereinbarung: 2% bei Zahlung innerhalb 10 Tagen nach Rechnungsdatum</ram:Description>
|
||||
<ram:ApplicableTradePaymentDiscountTerms>
|
||||
<ram:BasisPeriodMeasure unitCode="DAY">10</ram:BasisPeriodMeasure>
|
||||
<ram:CalculationPercent>2.00</ram:CalculationPercent>
|
||||
</ram:ApplicableTradePaymentDiscountTerms>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>410.10</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount>15.00</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount>21.55</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>403.55</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">76.67</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>480.22</ram:GrandTotalAmount>
|
||||
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
|
||||
<ram:DuePayableAmount>480.22</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
2569
library/src/test/resources/factur-x-vis-extended.de.html
Normal file
2569
library/src/test/resources/factur-x-vis-extended.de.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1555,7 +1555,7 @@
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Description:</div>
|
||||
<div id="BT-154" title="BT-154" class="boxdaten wert">Processor: Intel Core 2 Duo SU9400 LV (1.4GHz). RAM:
|
||||
3MB. Screen 1440x900</div>
|
||||
3MB. Screen 1440x900</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Part number:</div>
|
||||
@@ -1665,7 +1665,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Discount (net):</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Net list price:</div>
|
||||
@@ -1977,7 +1977,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Discount (net):</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Net list price:</div>
|
||||
@@ -2133,7 +2133,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Discount (net):</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Net list price:</div>
|
||||
@@ -2354,6 +2354,10 @@
|
||||
<div class="boxdaten legende">Dispatch note ID:</div>
|
||||
<div id="BT-16" title="BT-16" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Delivery note ID:</div>
|
||||
<div id="BT-X-202" title="BT-X-202" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Process ID:</div>
|
||||
<div id="BT-23" title="BT-23" class="boxdaten wert"></div>
|
||||
|
||||
@@ -1219,8 +1219,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
|
||||
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
|
||||
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig first">
|
||||
<div class="boxzeile">
|
||||
<div id="uebersichtZahlungsinformationen" class="box subBox">
|
||||
@@ -1381,7 +1379,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Discount (net):</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Net list price:</div>
|
||||
@@ -1537,7 +1535,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Discount (net):</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Net list price:</div>
|
||||
@@ -1754,6 +1752,10 @@
|
||||
<div class="boxdaten legende">Dispatch note ID:</div>
|
||||
<div id="BT-16" title="BT-16" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Delivery note ID:</div>
|
||||
<div id="BT-X-202" title="BT-X-202" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Process ID:</div>
|
||||
<div id="BT-23" title="BT-23" class="boxdaten wert"></div>
|
||||
|
||||
@@ -1250,8 +1250,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
|
||||
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
|
||||
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig first">
|
||||
<div class="boxzeile">
|
||||
<div id="uebersichtZahlungsinformationen" class="box subBox">
|
||||
@@ -1397,7 +1395,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Remise nette:</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Prix catalogue (net):</div>
|
||||
@@ -1553,7 +1551,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Remise nette:</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Prix catalogue (net):</div>
|
||||
@@ -1709,7 +1707,7 @@
|
||||
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Remise nette:</div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert"></div>
|
||||
<div id="BT-147" title="BT-147" class="boxdaten wert">0,00</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende ">Prix catalogue (net):</div>
|
||||
@@ -1907,6 +1905,55 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxabstand"></div>
|
||||
<div id="zusaetzeLieferung" class="box boxZweispaltig">
|
||||
<div id="BG-13" title="BG-13" class="boxtitel">Informations de livraison</div>
|
||||
<div class="boxtabelle boxinhalt borderSpacing">
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Identification du lieu de livraison:</div>
|
||||
<div id="BT-71" title="BT-71" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Schéma de l'Identifiant:</div>
|
||||
<div id="BT-71-scheme-id" title="BT-71-scheme-id" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Date de livraison:</div>
|
||||
<div id="BT-72" title="BT-72" class="boxdaten wert">10.11.2020</div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Nom du destinataire:</div>
|
||||
<div id="BT-70" title="BT-70" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Rue / Numéro de maison:</div>
|
||||
<div id="BT-75" title="BT-75" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Boîte postale:</div>
|
||||
<div id="BT-76" title="BT-76" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Supplément d'adresse:</div>
|
||||
<div title="BT-165" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Code postal:</div>
|
||||
<div id="BT-78" title="BT-78" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Lieu:</div>
|
||||
<div id="BT-77" title="BT-77" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Région:</div>
|
||||
<div id="BT-79" title="BT-79" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Pays:</div>
|
||||
<div id="BT-80" title="BT-80" class="boxdaten wert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig">
|
||||
@@ -1926,6 +1973,10 @@
|
||||
<div class="boxdaten legende">Identifiant du bordereau d'expédition:</div>
|
||||
<div id="BT-16" title="BT-16" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Identifiant du bon de livraison:</div>
|
||||
<div id="BT-X-202" title="BT-X-202" class="boxdaten wert"></div>
|
||||
</div>
|
||||
<div class="boxzeile">
|
||||
<div class="boxdaten legende">Identifiant processus:</div>
|
||||
<div id="BT-23" title="BT-23" class="boxdaten wert"></div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user