Merge branch 'master' into bugfix/issue841b

This commit is contained in:
Frank Langelage
2025-07-30 11:46:53 +02:00
committed by GitHub
40 changed files with 6751 additions and 1300 deletions

View File

@@ -3,13 +3,13 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT
@@ -137,6 +137,12 @@
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>2.0-rc1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
@@ -173,8 +179,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<runOrder>alphabetical</runOrder>
<argLine>-Duser.timezone=UTC</argLine>
</configuration>
</plugin>
<plugin>

View File

@@ -38,7 +38,7 @@ public class Allowance extends Charge {
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 singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
BigDecimal singlePriceDiff=currentItem.getValue().subtract(singlePrice);
return singlePriceDiff;

View File

@@ -145,10 +145,9 @@ public class Charge implements IZUGFeRDAllowanceCharge {
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;
BigDecimal factor=getPercent().divide(new BigDecimal(100), 18, RoundingMode.HALF_UP);
BigDecimal singlePrice=currentItem.getValue().multiply(factor);
return singlePrice;
} else {
throw new RuntimeException("percent must be set");
}

View File

@@ -0,0 +1,17 @@
package org.mustangproject.Exceptions;
import java.text.ParseException;
/***
* will be thrown if an invoice cant be reproduced numerically
* ArithmetricException for backwards compatibility, was a spelling error
*/
public class ArithmeticException extends ArithmetricException {
public ArithmeticException() {
super();
}
public ArithmeticException(String details) {
super(details);
}
}

View File

@@ -4,6 +4,7 @@ import java.text.ParseException;
/***
* will be thrown if an invoice cant be reproduced numerically
* (deprecated, because of typo)
*/
public class ArithmetricException extends ParseException {
public ArithmetricException() {

View File

@@ -591,11 +591,7 @@ public class Invoice implements IExportableTransaction {
* @return fluent setter
*/
public Invoice setZFAllowances(Allowance[] iza) {
Allowances=new ArrayList<>();
for (IZUGFeRDAllowanceCharge cz:iza) {
Allowances.add(cz);
}
Allowances=new ArrayList<>(Arrays.asList(iza));
return this;
}
@@ -616,9 +612,7 @@ public class Invoice implements IExportableTransaction {
*/
public Invoice setZFCharges(Charge[] iza) {
Charges=new ArrayList<>();
for (IZUGFeRDAllowanceCharge cz:iza) {
Charges.add(cz);
}
Charges.addAll(Arrays.asList(iza));
return this;
}

View File

@@ -1,5 +1,6 @@
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.IReferencedDocument;
@@ -77,20 +78,21 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAsString("Name").ifPresent(product::setName);
icnm.getAsString("Description").ifPresent(product::setDescription);
icnm.getAsNodeMap("SellersItemIdentification").ifPresent(SellersItemIdentification -> {
SellersItemIdentification.getAsString("ID").ifPresent(product::setSellerAssignedID);
});
icnm.getAsNodeMap("SellersItemIdentification")
.flatMap(SellersItemIdentification -> SellersItemIdentification.getAsString("ID"))
.ifPresent(product::setSellerAssignedID);
icnm.getAsNodeMap("BuyersItemIdentification").ifPresent(BuyersItemIdentification -> {
BuyersItemIdentification.getAsString("ID").ifPresent(product::setBuyerAssignedID);
});
icnm.getAsNodeMap("BuyersItemIdentification")
.flatMap(BuyersItemIdentification -> BuyersItemIdentification.getAsString("ID"))
.ifPresent(product::setBuyerAssignedID);
icnm.getAsNodeMap("ClassifiedTaxCategory").flatMap(m -> m.getAsBigDecimal("Percent"))
icnm.getAsNodeMap("ClassifiedTaxCategory")
.flatMap(m -> m.getAsBigDecimal("Percent"))
.ifPresent(product::setVATPercent);
});
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(icnm -> {
icnm.getAsString("LineID").ifPresent(this::setId);
});
itemMap.getAsNodeMap("AssociatedDocumentLineDocument")
.flatMap(icnm -> icnm.getAsString("LineID"))
.ifPresent(this::setId);
itemMap.getAsNodeMap("Price").ifPresent(icnm -> {
// ubl
@@ -118,10 +120,16 @@ public class Item implements IZUGFeRDExportableItem {
itemMap.getAsString("ID")
.ifPresent(this::setId);
itemMap.getAsString("Note")
.ifPresent(this::addNote);
if (product==null) { // CII
if (itemMap.getNode("SpecifiedTradeProduct").isPresent()) {
product = new Product(itemMap.getNode("SpecifiedTradeProduct").get());
} else {
product = new Product();
}
}
itemMap.getAsNodeMap("SpecifiedLineTradeAgreement", "SpecifiedSupplyChainTradeAgreement").ifPresent(icnm -> {
icnm.getAsNodeMap("BuyerOrderReferencedDocument")
@@ -136,14 +144,29 @@ public class Item implements IZUGFeRDExportableItem {
npptpNodes.getAsBigDecimal("ChargeAmount").ifPresent(this::setPrice);
npptpNodes.getAsBigDecimal("BasisQuantity").ifPresent(this::setBasisQuantity);
});
icnm.getAsNodeMap("GrossPriceProductTradePrice").ifPresent(gpptpNodes -> {
gpptpNodes.getAsNodeMap("AppliedTradeAllowanceCharge").ifPresent(gpptpAtacNodes -> {
/** mustang attributes differences between net and gross price to the product */
String chargeIndicator = gpptpAtacNodes.getAsStringOrNull("ChargeIndicator");
if ((chargeIndicator != null)&&(gpptpAtacNodes.getAsBigDecimal("ActualAmount").isPresent())) {
BigDecimal actual = gpptpAtacNodes.getAsBigDecimal("ActualAmount").get();
if (chargeIndicator.equals("true")) {
product.addCharge(new Charge(actual));
setPrice(getPrice().subtract(actual)); // the gross price affects the net price, which is read,
// so if we do not ignore charges|allowances we have to re-compensate the net price
} else {
product.addAllowance(new Allowance(actual));
setPrice(getPrice().add(actual));
}
}
});
});
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"))
@@ -180,7 +203,7 @@ public class Item implements IZUGFeRDExportableItem {
}
if (amountString != null) {
izac.setTotalAmount(new BigDecimal(amountString));
if (percentString!=null&&(percentString!="0")) {
if (percentString != null && (!percentString.equals("0"))) {
izac.setTotalAmount(new BigDecimal(amountString).divide(getQuantity()));
}
}
@@ -210,16 +233,16 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
icnm.getAsString("ReceivableSpecifiedTradeAccountingAccount").ifPresent(s -> this.accountingReference = s == null ? null : s.trim());
icnm.getAsString("ReceivableSpecifiedTradeAccountingAccount").ifPresent(s -> this.accountingReference = 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);
Date start = periodNode.getAsNodeMap("StartDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(XMLTools::tryDate).orElse(null);
Date end = periodNode.getAsNodeMap("EndDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(XMLTools::tryDate).orElse(null);
setDetailedDeliveryPeriod(start, end);
});
});
itemMap.getAllNodes("AllowanceCharge").map(NodeMap::new).forEach(stac -> { //UBL
itemMap.getAllNodes("AllowanceCharge").map(NodeMap::new).forEach(stac -> { //CII
String isChargeString = stac.getAsString("ChargeIndicator").get();
String percentString = stac.getAsStringOrNull("MultiplierFactorNumeric");
@@ -301,13 +324,17 @@ public class Item implements IZUGFeRDExportableItem {
return this;
}
@Override public IZUGFeRDAllowanceCharge[] getAllowances() {
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Allowances.size()];
@JsonIgnore
@Override
public IZUGFeRDAllowanceCharge[] getAllowances() { // in JSON is already returned as itemAllowances (and only read from there)
IZUGFeRDAllowanceCharge[] izac = new IZUGFeRDAllowanceCharge[Allowances.size()];
return Allowances.toArray(izac);
}
@Override public IZUGFeRDAllowanceCharge[] getCharges() {
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Charges.size()];
@JsonIgnore
@Override
public IZUGFeRDAllowanceCharge[] getCharges() { // in JSON is already returned as itemAllowances (and only read from there)
IZUGFeRDAllowanceCharge[] izac = new IZUGFeRDAllowanceCharge[Charges.size()];
return Charges.toArray(izac);
}
@@ -425,9 +452,7 @@ public class Item implements IZUGFeRDExportableItem {
public void setItemAllowances(ArrayList<Allowance> theAllowances) {
if (theAllowances != null) {
Allowances.clear();
for (Allowance theAllowance : theAllowances) {
Allowances.add(theAllowance);
}
Allowances.addAll(theAllowances);
}
}
@@ -437,9 +462,7 @@ public class Item implements IZUGFeRDExportableItem {
public void setItemCharges(ArrayList<Charge> theCharges) {
if (theCharges != null) {
Charges.clear();
for (Charge theCharge : theCharges) {
Charges.add(theCharge);
}
Charges.addAll(theCharges);
}
}

View File

@@ -1,13 +1,10 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.*;
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;
@@ -107,7 +104,10 @@ public class Product implements IZUGFeRDExportableProduct {
classifications.add(new DesignatedProductClassification(classCode, className)));
});
nodeMap.getAsString("OriginTradeCounty").ifPresent(this::setCountryOfOrigin);
nodeMap.getAsNodeMap("OriginTradeCountry")
.flatMap(nodes -> nodes.getNode("ID"))
.map(Node::getTextContent)
.ifPresent(this::setCountryOfOrigin);
}
/***
@@ -406,6 +406,16 @@ public class Product implements IZUGFeRDExportableProduct {
return this;
}
/***
* Jackson courtesy function, please use addCharge if you have the choice
* @return array of or null, if none
*/
public Product setCharges(ArrayList<Charge> charges) {
this.charges=charges;
return this;
}
/***
* returns the AppliedTradeAllowanceCharges of this product which are actually Charges
* @return array of or null, if none
@@ -432,5 +442,13 @@ public class Product implements IZUGFeRDExportableProduct {
return allowances.toArray(allowanceArr);
}
/***
* Jackson courtesy function, please use addAllowance if you have the choice
* @return array of or null, if none
*/
public Product setAllowances(ArrayList<Allowance> allowances) {
this.allowances=allowances;
return this;
}
}

View File

@@ -541,6 +541,32 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
return this;
}
/***
* for jackson, primarily, use addGlobalID(SchemedID) instead
* @param ID the id part without scheme
* @return fluent setter
*/
public TradeParty setGlobalID(String ID) {
if (globalId==null) {
globalId=new SchemedID();
}
globalId.setId(ID);
return this;
}
/***
* for jackson, primarily, use addGlobalID(SchemedID) instead
* @param scheme the scheme part without id
* @return fluent setter
*/
public TradeParty setGlobalIDScheme(String scheme) {
if (globalId==null) {
globalId=new SchemedID();
}
globalId.setScheme(scheme);
return this;
}
public TradeParty addGlobalID(SchemedID schemedID) {
globalId = schemedID;
return this;
@@ -746,7 +772,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
if (bankDetails.isEmpty() && debitDetails.isEmpty()) {
return null;
}
List<IZUGFeRDTradeSettlement> tradeSettlements = Stream.concat(bankDetails.stream(), debitDetails.stream()).map(IZUGFeRDTradeSettlement.class::cast).collect(Collectors.toList());
List<IZUGFeRDTradeSettlement> tradeSettlements = Stream.concat(bankDetails.stream(), debitDetails.stream()).collect(Collectors.toList());
IZUGFeRDTradeSettlement[] result = new IZUGFeRDTradeSettlement[tradeSettlements.size()];
for (int i = 0; i < tradeSettlements.size(); i++) {

View File

@@ -97,12 +97,12 @@ public class DAPullProvider extends ZUGFeRD2PullProvider {
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>";
}
String allowanceChargeStr = "";
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
if (currentItem.getItemAllowances() != null) {
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
if (currentItem.getItemCharges() != null) {
for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);

View File

@@ -22,7 +22,7 @@ public class LineCalculator {
public LineCalculator(IZUGFeRDExportableItem currentItem) {
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
if (currentItem.getItemAllowances() != null) {
for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleAllowance=allowance.getTotalAmount(currentItem);
@@ -35,7 +35,7 @@ public class LineCalculator {
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
if (currentItem.getItemCharges() != null) {
for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleCharge=charge.getTotalAmount(currentItem);
@@ -47,7 +47,7 @@ public class LineCalculator {
}
}
if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) {
if (currentItem.getItemTotalAllowances() != null) {
for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getItemTotalAllowances()) {
addAllowanceItemTotal(itemTotalAllowance.getTotalAmount(currentItem));
}
@@ -94,7 +94,7 @@ public class LineCalculator {
? 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);
.add(lineCharge).subtract(lineAllowance).subtract(allowanceItemTotal.setScale(2, RoundingMode.HALF_UP)).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);//.setScale(2, RoundingMode.HALF_UP);
}

View File

@@ -57,7 +57,7 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
paymentTermsDescription = XMLTools.encodeXML(trans.getPaymentTermDescription());
}
if ((paymentTermsDescription == null) && (trans.getDocumentCode() != CORRECTEDINVOICE)/* && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)*/) {
if (paymentTermsDescription == null && !CORRECTEDINVOICE.equals(trans.getDocumentCode())/* && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)*/) {
paymentTermsDescription = "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
}
@@ -125,12 +125,12 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>";
}
String allowanceChargeStr = "";
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
if (currentItem.getItemAllowances() != null) {
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
if (currentItem.getItemCharges() != null) {
for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);
@@ -313,8 +313,9 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
for (final IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
if (payment != null) {
hasDueDate = true;
// xml += payment.getSettlementXML();
}
break;
// xml += payment.getSettlementXML();
}
}
}
if (trans.getTradeSettlement() != null) {

View File

@@ -89,7 +89,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
private BigDecimal sumAllowanceCharge(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
BigDecimal res = BigDecimal.ZERO;
if ((charges != null) && (charges.length > 0)) {
if (charges != null) {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
if ((percent == null) || (currentCharge.getTaxPercent().compareTo(percent) == 0)) {
res = res.add(currentCharge.getTotalAmount(this));
@@ -172,6 +172,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
* @return item sum +- charges/allowances
*/
public BigDecimal getTaxBasis() {
BigDecimal debug_1=getTotal();
return getTotal().add(getChargesForPercent(null).setScale(2, RoundingMode.HALF_UP))
.subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP))
.setScale(2, RoundingMode.HALF_UP);
@@ -211,7 +212,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges();
if ((charges != null) && (charges.length > 0)) {
if (charges != null) {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
BigDecimal taxPercent = currentCharge.getTaxPercent();
if (taxPercent != null) {
@@ -229,7 +230,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
}
IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances();
if ((allowances != null) && (allowances.length > 0)) {
if (allowances != null) {
for (IZUGFeRDAllowanceCharge currentAllowance : allowances) {
BigDecimal taxPercent = currentAllowance.getTaxPercent();
if (taxPercent != null) {
@@ -285,8 +286,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
final IZUGFeRDAllowanceCharge[] charges = this.trans.getZFCharges();
if (charges != null && charges.length > 0)
{
if (charges != null) {
for (final IZUGFeRDAllowanceCharge currentCharge : charges)
{
final BigDecimal taxPercent = currentCharge.getTaxPercent();
@@ -309,8 +309,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
}
final IZUGFeRDAllowanceCharge[] allowances = this.trans.getZFAllowances();
if (allowances != null && allowances.length > 0)
{
if (allowances != null) {
for (final IZUGFeRDAllowanceCharge currentAllowance : allowances)
{
final BigDecimal taxPercent = currentAllowance.getTaxPercent();

View File

@@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import org.mustangproject.XMLTools;
import org.slf4j.Logger;
@@ -18,7 +19,7 @@ public class XRechnungImporter extends ZUGFeRDImporter {
try {
setRawXML(rawXml);
containsMeta = true;
} catch (final IOException e) {
} catch (final IOException | ParseException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
@@ -30,24 +31,21 @@ public class XRechnungImporter extends ZUGFeRDImporter {
try {
setRawXML(Files.readAllBytes(Paths.get(filename)));
containsMeta = true;
} catch (final IOException e) {
LOGGER.error ("Failed to set raw XML", e);
} catch (final IOException | ParseException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
}
public XRechnungImporter(InputStream fileinput) {
super();
try {
setRawXML(XMLTools.getBytesFromStream(fileinput));
containsMeta = true;
} catch (final IOException e) {
LOGGER.error ("Failed to set raw XML", e);
} catch (final IOException | ParseException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
}

View File

@@ -359,7 +359,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
paymentTermsDescription += discount.getAsXRechnung();
}
} else if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
} else if (paymentTermsDescription == null
&& !DocumentCodeTypeConstants.CORRECTEDINVOICE.equals(trans.getDocumentCode())
&& !DocumentCodeTypeConstants.CREDITNOTE.equals(trans.getDocumentCode())
) {
if (trans.getDueDate() != null) {
paymentTermsDescription = "Please remit until " + germanDateFormat.format(trans.getDueDate());
}
@@ -434,11 +437,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
xml += "<ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>";
if (currentItem.getProduct().getDescription() != null && currentItem.getProduct().getDescription().length() > 0) {
if (currentItem.getProduct().getDescription() != null) {
xml += "<ram:Description>" +
XMLTools.encodeXML(currentItem.getProduct().getDescription()) +
"</ram:Description>";
}
if (currentItem.getProduct().getAttributes() != null) {
for (Entry<String, String> entry : currentItem.getProduct().getAttributes().entrySet()) {
xml += "<ram:ApplicableProductCharacteristic>" +
@@ -447,7 +451,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
"</ram:ApplicableProductCharacteristic>";
}
}
if (currentItem.getProduct().getClassifications() != null && currentItem.getProduct().getClassifications().length > 0) {
if (currentItem.getProduct().getClassifications() != null) {
for (IDesignatedProductClassification classification : currentItem.getProduct().getClassifications()) {
xml += "<ram:DesignatedProductClassification>"
+ "<ram:ClassCode listID=\"" + XMLTools.encodeXML(classification.getClassCode().getListID()) + "\"";
@@ -702,7 +706,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
}
}
if ((trans.getDocumentCode() == DocumentCodeTypeConstants.CORRECTEDINVOICE) || (trans.getDocumentCode() == DocumentCodeTypeConstants.CREDITNOTE)) {
if (DocumentCodeTypeConstants.CORRECTEDINVOICE.equals(trans.getDocumentCode())
|| DocumentCodeTypeConstants.CREDITNOTE.equals(trans.getDocumentCode())
) {
hasDueDate = false;
}
@@ -857,7 +863,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
} else {
xml += buildPaymentTermsXml();
}
if ((profile == Profiles.getByName("Extended")) && (trans.getCashDiscounts() != null) && (trans.getCashDiscounts().length > 0)) {
if (profile == Profiles.getByName("Extended") && trans.getCashDiscounts() != null) {
for (IZUGFeRDCashDiscount discount : trans.getCashDiscounts()
) {
xml += discount.getAsCII();

View File

@@ -564,10 +564,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
// iterate over all pdf pages
for (Object object : doc.getPages()) {
if (object instanceof PDPage) {
for (PDPage page : doc.getPages()) {
if (page != null) {
PDPage page = (PDPage) object;
PDResources res = page.getResources();
// Check for fonts in PDXObjects:

View File

@@ -14,6 +14,7 @@ package org.mustangproject.ZUGFeRD;
* @author jstaerk
*/
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -351,6 +352,16 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
public String getHolder() {
if (importedInvoice!=null && importedInvoice.getTradeSettlement()!=null) {
for (IZUGFeRDTradeSettlement settlement : importedInvoice.getTradeSettlement()) {
if (settlement instanceof IZUGFeRDTradeSettlementPayment) {
String s = ((IZUGFeRDTradeSettlementPayment) settlement).getAccountName();
if ( s != null ) {
return s;
}
}
}
}
return extractString("//*[local-name() = 'SellerTradeParty']/*[local-name() = 'Name']");
}
@@ -452,7 +463,11 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
* @throws IOException if raw can not be set
*/
public void setMeta(String meta) throws IOException {
setRawXML(meta.getBytes());
try {
setRawXML(meta.getBytes());
} catch (ParseException e) {
LOGGER.error("Failed to parse", e);
}
}

View File

@@ -10,7 +10,6 @@ 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.mustangproject.Exceptions.ArithmetricException;
import org.mustangproject.Exceptions.StructureException;
import org.mustangproject.util.NodeMap;
import org.slf4j.Logger;
@@ -127,8 +126,7 @@ public class ZUGFeRDInvoiceImporter {
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
try {
PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream));
try(PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream))) {
// PDDocumentInformation info = doc.getDocumentInformation();
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
//start
@@ -174,7 +172,12 @@ public class ZUGFeRDInvoiceImporter {
} else {
// no PDF probably XML
containsMeta = true;
setRawXML(XMLTools.getBytesFromStream(pdfStream));
try {
setRawXML(XMLTools.getBytesFromStream(pdfStream));
} catch(ParseException e) {
LOGGER.error("Failed to parse PDF", e);
}
}
}
@@ -209,7 +212,16 @@ public class ZUGFeRDInvoiceImporter {
*/
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")) {
Set<String> validFilenames = Set.of(
"ZUGFeRD-invoice.xml",
"zugferd-invoice.xml",
"factur-x.xml",
"xrechnung.xml",
"order-x.xml",
"cida.xml"
);
if (validFilenames.contains(filename)) {
containsMeta = true;
// String embeddedFilename = filePath + filename;
@@ -219,8 +231,11 @@ public class ZUGFeRDInvoiceImporter {
// ByteArrayOutputStream();
// FileOutputStream fos = new FileOutputStream(file);
setRawXML(embeddedFile.toByteArray());
try {
setRawXML(embeddedFile.toByteArray());
} catch (ParseException e) {
LOGGER.error("Failed to parse XML", e);
}
// fos.write(embeddedFile.getByteArray());
// fos.close();
}
@@ -237,7 +252,7 @@ public class ZUGFeRDInvoiceImporter {
* @param doParse automatically parse input for zugferdImporter (not ZUGFeRDInvoiceImporter)
* @throws IOException if parsing xml throws it (unlikely its string based)
*/
public void setRawXML(byte[] rawXML, boolean doParse) throws IOException {
public void setRawXML(byte[] rawXML, boolean doParse) throws IOException, ParseException {
this.containsMeta = true;
this.rawXML = rawXML;
this.version = null;
@@ -245,7 +260,7 @@ public class ZUGFeRDInvoiceImporter {
try {
setDocument();
} catch (ParserConfigurationException | SAXException | ParseException e) {
} catch (ParserConfigurationException | SAXException e) {
LOGGER.error("Failed to parse XML", e);
throw new ZUGFeRDExportException(e);
}
@@ -257,7 +272,7 @@ public class ZUGFeRDInvoiceImporter {
* @param rawXML the cii(?) as a string
* @throws IOException if parsing xml throws it (unlikely its string based)
*/
public void setRawXML(byte[] rawXML) throws IOException {
public void setRawXML(byte[] rawXML) throws IOException, ParseException {
setRawXML(rawXML, true);
}
@@ -353,39 +368,31 @@ public class ZUGFeRDInvoiceImporter {
delivery.addGlobalID(sID);
}
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("StreetName").ifPresent(t -> delivery.setStreet(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("AdditionalStreetName").ifPresent(t -> delivery.setAdditionalAddress(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("CityName").ifPresent(t -> delivery.setLocation(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("PostalZone").ifPresent(t -> delivery.setZIP(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsNodeMap("Country").ifPresent(t -> t.getAsString("IdentificationCode").ifPresent(u -> delivery.setCountry(u)));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsNodeMap("AddressLine").ifPresent(t -> t.getAsString("Line").ifPresent(u -> delivery.setAdditionalAddressExtension(u)));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("AdditionalStreetName").ifPresent(t -> delivery.setAdditionalAddress(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("AdditionalStreetName").ifPresent(t -> delivery.setAdditionalAddress(t));
});
Optional<NodeMap> addressNodeMapp = deliveryLocationNodeMap.getAsNodeMap("Address");
addressNodeMapp.flatMap(s -> s.getAsString("StreetName"))
.ifPresent(delivery::setStreet);
addressNodeMapp.flatMap(s -> s.getAsString("AdditionalStreetName"))
.ifPresent(delivery::setAdditionalAddress);
addressNodeMapp.flatMap(s -> s.getAsString("CityName"))
.ifPresent(delivery::setLocation);
addressNodeMapp.flatMap(s -> s.getAsString("PostalZone"))
.ifPresent(delivery::setZIP);
addressNodeMapp.flatMap(s -> s.getAsNodeMap("Country")).flatMap(t -> t.getAsString("IdentificationCode"))
.ifPresent(delivery::setCountry);
addressNodeMapp.flatMap(s -> s.getAsNodeMap("AddressLine")).flatMap(t -> t.getAsString("Line"))
.ifPresent(delivery::setAdditionalAddressExtension);
addressNodeMapp.flatMap(s -> s.getAsString("AdditionalStreetName"))
.ifPresent(delivery::setAdditionalAddress);
addressNodeMapp.flatMap(s -> s.getAsString("AdditionalStreetName"))
.ifPresent(delivery::setAdditionalAddress);
});
new NodeMap(deliveryNode).getAsNodeMap("DeliveryParty").ifPresent(partyMap -> {
partyMap.getAsNodeMap("PartyName").ifPresent(s -> {
s.getAsString("Name").ifPresent(t -> delivery.setName(t));
});
});
String street, name, additionalStreet, city, postal, countrySubentity, line, country = null;
new NodeMap(deliveryNode).getAsNodeMap("DeliveryParty")
.flatMap(partyMap -> partyMap.getAsNodeMap("PartyName"))
.flatMap(s -> s.getAsString("Name"))
.ifPresent(delivery::setName);
zpp.setDeliveryAddress(delivery);
}
@@ -424,7 +431,7 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"ExchangedDocument\"]|//*[local-name()=\"HeaderExchangedDocument\"]");
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile("//*[local-name()=\"GrandTotalAmount\"]|//*[local-name()=\"TaxInclusiveAmount\"]");
BigDecimal expectedGrandTotal = null;
NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -572,11 +579,11 @@ public class ZUGFeRDInvoiceImporter {
}
String creditorReferenceID = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"CreditorReferenceID\"]").trim();//BT-90
if ((creditorReferenceID == null)||(creditorReferenceID.length()==0)) {
if (creditorReferenceID == null || creditorReferenceID.isEmpty()) {
//maybe it's there in UBL?
creditorReferenceID = extractString("//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyIdentification\"]/*[local-name()=\"ID\"]").trim();
}
if ((creditorReferenceID != null)&&(creditorReferenceID.length()>0)) {
if (creditorReferenceID != null && !creditorReferenceID.isEmpty()) {
zpp.setCreditorReferenceID(creditorReferenceID);
}
@@ -1088,7 +1095,7 @@ public class ZUGFeRDInvoiceImporter {
.collect(Collectors.joining(" + "));
} catch (Exception ignored) {
}
throw new ArithmetricException("Payable total in XML is " + payableTotalFromXml + ", but calculated total is " + calculatedPayableTotal + moreDetails);
throw new ArithmeticException("Payable total in XML is " + payableTotalFromXml + ", but calculated total is " + calculatedPayableTotal + moreDetails);
}
}
}
@@ -1205,7 +1212,7 @@ public class ZUGFeRDInvoiceImporter {
* sets the XML for the importer to parse
* @param XML the UBL or CII
*/
public void fromXML(String XML) {
public void fromXML(String XML) throws ParseException{
try {
containsMeta = true;
setRawXML(XML.getBytes(StandardCharsets.UTF_8));

View File

@@ -12,12 +12,11 @@ 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.io.*;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/***
* tests the linecalculator and transactioncalculator classes
@@ -79,6 +78,56 @@ public class CalculationTest extends ResourceCase {
assertEquals(valueOf(287.9408).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
}
@Test
public void testAllowanceAndChargeEx4() {
/** numbers from en16931 example 4 */
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"));
} catch (Exception e) {
LOGGER.error("Failed to set dates", e);
}
/* trade party (sender) */
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");
invoice.setRecipient(recipient);
/* item */
Product product;
Item item;
product = new Product("Pens", "", "H87", new BigDecimal(25));
product.addAllowance(new Allowance(new BigDecimal(1)));
item = new Item(product, new BigDecimal("9.50"), new BigDecimal(25));
item.addCharge(new Charge(new BigDecimal(10)).setReasonCode("ZZZ").setReason("Zuschlag"));
LineCalculator lc = new LineCalculator(item);
assertEquals(new BigDecimal("222.50"), lc.getItemTotalNetAmount());
invoice.addItem(item);
product = new Product("Paper", "", "H87", new BigDecimal(25));
item = new Item(product, new BigDecimal("4.50"), new BigDecimal(15));
item.addAllowance(new Allowance().setPercent(new BigDecimal(5)).setReasonCode("ZZZ").setReason("Zuschlag"));
lc = new LineCalculator(item);
assertEquals(new BigDecimal("64.12"), lc.getItemTotalNetAmount());
invoice.addItem(item);
invoice.addAllowance(new Allowance().setPercent(new BigDecimal(10)).setTaxPercent(new BigDecimal(25)).setReasonCode("ZZZ").setReason("Mengenrabatt"));
invoice.addCharge(new Charge(new BigDecimal(15)).setReasonCode("ZZZ").setReason("Frachtkosten"));
TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(valueOf(286.62).stripTrailingZeros(), calculator.getTotal());// interestingly, EN16931-1 has 286.63 here?
assertEquals(valueOf(272.96).stripTrailingZeros(), calculator.getTaxBasis()); // and 272.97 here
assertEquals(valueOf(337.45).stripTrailingZeros(), calculator.getDuePayable()); // and 337.46 here???
}
@Test
public void testLineCalculatorForeignCurrencyExample() {
/*** xml of official fx sample with allowances and charges
@@ -88,19 +137,19 @@ public class CalculationTest extends ResourceCase {
*/
File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml");
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter();
Invoice invoice=null;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
Invoice invoice = null;
zii.doIgnoreCalculationErrors();
boolean hasExceptions=false;
boolean hasExceptions = false;
try {
zii.setInputStream(new FileInputStream(inputCII));
invoice=zii.extractInvoice();
invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException e) {
// handle Exceptions
hasExceptions=true;
hasExceptions = true;
} catch (FileNotFoundException e) {
hasExceptions=true;
hasExceptions = true;
}
assertFalse(hasExceptions);
// Reading ZUGFeRD
@@ -152,7 +201,7 @@ public class CalculationTest extends ResourceCase {
Product product;
Item item;
product = new Product("AAA", "", "H84", sales_tax_percent1).setSellerAssignedID("1AAA");
product = new Product("AAA", "", "H87", sales_tax_percent1).setSellerAssignedID("1AAA");
item = new Item(product, new BigDecimal("4.750"), new BigDecimal(5.00));
// set values for additional charge and discount used for next lines
@@ -168,54 +217,23 @@ public class CalculationTest extends ResourceCase {
}
invoice.addItem(item);
// reset values for additional charge and discount used for next lines
item_increase = BigDecimal.ZERO;
item_discount = BigDecimal.ZERO;
product = new Product("BBB", "", "H84", sales_tax_percent1).setSellerAssignedID("2BBB");
product = new Product("BBB", "", "H87", sales_tax_percent1).setSellerAssignedID("2BBB");
item = new Item(product, new BigDecimal("5.750"), new BigDecimal(4.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
product = new Product("CCC", "", "H84", sales_tax_percent1).setSellerAssignedID("3CCC");
product = new Product("CCC", "", "H87", sales_tax_percent1).setSellerAssignedID("3CCC");
item = new Item(product, new BigDecimal("6.750"), new BigDecimal(3.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
product = new Product("DDD", "", "H84", sales_tax_percent1).setSellerAssignedID("4DDD");
product = new Product("DDD", "", "H87", sales_tax_percent1).setSellerAssignedID("4DDD");
item = new Item(product, new BigDecimal("7.750"), new BigDecimal(2.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
product = new Product("EEE", "", "H84", sales_tax_percent1).setSellerAssignedID("5EEE");
product = new Product("EEE", "", "H87", sales_tax_percent1).setSellerAssignedID("5EEE");
item = new Item(product, new BigDecimal("8.750"), new BigDecimal(1.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
// reset values for additional charge and discount used on invoice level
item_increase = BigDecimal.valueOf(3.50);
item_discount = BigDecimal.valueOf(10.00);
if (total_increase_percent.compareTo(BigDecimal.ZERO) > 0) {
invoice.addCharge(new Charge().setPercent(total_increase_percent).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschläge"));
@@ -224,7 +242,7 @@ public class CalculationTest extends ResourceCase {
invoice.addAllowance(new Allowance().setPercent(total_discount_percent).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatte"));
}
TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(valueOf(307.18).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
assertEquals(valueOf(101.85).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
}
public void testSimpleItemPercentAllowance() {
@@ -259,14 +277,64 @@ public class CalculationTest extends ResourceCase {
Product product;
Item item;
product = new Product("AAA", "", "H84", BigDecimal.ZERO);
product = new Product("AAA", "", "H87", 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());
assertEquals(new BigDecimal("4.95"), calculator.getGrandTotal().stripTrailingZeros());
}
public void testSimpleDocumentPercentCharge() {
String orgname = "Test company";
String number = "123";
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
// similar, but slightly less complicated to whats later testted in testRelativeChargesAllowancesExport
Invoice i = new Invoice().setCurrency("CHF").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(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"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"));
// 9+50%=>13,50 expected net
// .addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
TransactionCalculator tc = new TransactionCalculator(i);
assertEquals(new BigDecimal("13.50"), tc.getTaxBasis());
assertEquals(new BigDecimal("16.07"), tc.getDuePayable());
}
public void testSimpleDocumentPercentAllowance() {
String orgname = "Test company";
String number = "123";
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
// similar, but slightly less complicated to whats later testted in testRelativeChargesAllowancesExport
Invoice i = new Invoice().setCurrency("CHF").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(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"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"));
// 9-50%=>4,50 expected net
// .addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
TransactionCalculator tc = new TransactionCalculator(i);
assertEquals(new BigDecimal("4.50"), tc.getTaxBasis());
assertEquals(new BigDecimal("5.36"), tc.getDuePayable());
}
public void testSimpleItemTotalAllowance() {
@@ -301,7 +369,7 @@ public class CalculationTest extends ResourceCase {
Product product;
Item item;
product = new Product("AAA", "", "H84", BigDecimal.ZERO);
product = new Product("AAA", "", "H87", BigDecimal.ZERO);
item = new Item(product, new BigDecimal("1.00"), new BigDecimal(5.00));
item.addAllowance(new Allowance(new BigDecimal(1)).setTaxPercent(BigDecimal.ZERO));
@@ -314,7 +382,7 @@ public class CalculationTest extends ResourceCase {
/**
* LineCalculator should not throw an exception when calculating a non-terminating decimal expansion
* */
*/
@Test
public void testNonTerminatingDecimalExpansion() {
final Product product = new Product();

View File

@@ -21,6 +21,13 @@
*/
package org.mustangproject.ZUGFeRD;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.*;
import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
@@ -29,28 +36,11 @@ 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 static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DeSerializationTest extends ResourceCase {
@@ -71,6 +61,29 @@ public class DeSerializationTest extends ResourceCase {
}
public void testProduct() throws IOException, XPathExpressionException, ParseException {
File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml");
var zii = new ZUGFeRDInvoiceImporter();
zii.doIgnoreCalculationErrors();
zii.fromXML(Files.readString(inputCII.toPath()));
var product = zii.extractInvoice()
.getZFItems()[0]
.getProduct();
assertThat(product.getCountryOfOrigin()).as("Product Country of origin")
.isEqualTo("DE");
assertThat(product.getSellerAssignedID()).as("Product Seller assigned ID")
.isEqualTo("CO-123/V2A");
assertThat(product.getBuyerAssignedID()).as("Product Buyer assigned ID")
.isEqualTo("Toolbox 0815");
assertThat(product.getName()).as("Name")
.isEqualTo("Stahlcoil");
assertThat(product.getAttributes()).as("Product attributes")
.containsKey("LeoID")
.containsValue("704310.0105636504");
}
public void testInvoiceLine() throws JsonProcessingException {
File inputCII = getResourceAsFile("factur-x.xml");
boolean hasExceptions = false;
@@ -79,7 +92,7 @@ public class DeSerializationTest extends ResourceCase {
try {
zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8));
} catch (IOException e) {
} catch (IOException | ParseException e) {
hasExceptions = true;
}
@@ -395,7 +408,7 @@ public class DeSerializationTest extends ResourceCase {
try {
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
TransactionCalculator tc=new TransactionCalculator(newInvoiceFromJSON);
assertEquals(new BigDecimal("18.92"),tc.getGrandTotal());
assertEquals(new BigDecimal("18.33"),tc.getGrandTotal());
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
@@ -414,10 +427,12 @@ public class DeSerializationTest extends ResourceCase {
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");
String json = "";
try {
SchemedID gtin = new SchemedID("0160", "2001015001325");
SchemedID gln = new SchemedID("0088", "4304171000002");
@@ -435,7 +450,7 @@ public class DeSerializationTest extends ResourceCase {
.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);
json = mapper.writeValueAsString(i);
newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
} catch (ParseException e) {
hasExceptions = true;
@@ -444,8 +459,34 @@ public class DeSerializationTest extends ResourceCase {
}
assertEquals(newInvoiceFromJSON.getBuyerOrderReferencedDocumentID(), "28934");
assertFalse(hasExceptions);
}
public void testFromJSON() throws JsonProcessingException {
String globalID = "4000001123452";
String globalIDScheme = "0088";
String itemDeliveryFrom="2022-01-28T23:00:00.000+00:00";
String itemDeliveryTo="2022-01-30T23:00:00.000+00:00";
String json="{\"number\":\"123\",\"buyerOrderReferencedDocumentID\":\"28934\",\"currency\":\"CHF\",\"issueDate\":1752744199178,\"dueDate\":1752744199178,\"deliveryDate\":1604271600000,\"sender\":{\"name\":\"Test company\",\"zip\":\"55232\",\"street\":\"teststr\",\"location\":\"teststadt\",\"country\":\"DE\",\"taxID\":\"9990815\",\"vatID\":\"DE0815\",\"id\":\"0009845\",\"globalID\":\""+globalID+"\",\"globalIDScheme\":\""+globalIDScheme+"\",\"email\":\"sender@test.org\",\"vatid\":\"DE0815\"},\"recipient\":{\"name\":\"Franz Müller\",\"zip\":\"55232\",\"street\":\"teststr.12\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"vatID\":\"DE4711\",\"additionalAddress\":\"Hinterhaus 3\",\"contact\":{\"name\":\"Franz Müller\",\"phone\":\"01779999999\",\"email\":\"franz@mueller.de\",\"zip\":\"55232\",\"street\":\"teststr. 12\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"fax\":\"++49555123456\"},\"globalID\":\"4304171000002\",\"globalIDScheme\":\"0088\",\"email\":\"recipient@test.org\",\"vatid\":\"DE4711\"},\"deliveryAddress\":{\"name\":\"just the other side of the street\",\"zip\":\"55232\",\"street\":\"teststr.12a\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"vatID\":\"DE47110\",\"vatid\":\"DE47110\"},\"cashDiscounts\":[{\"percent\":2,\"days\":14}],\"notes\":[\"document level 1/2\",\"document level 2/2\"],\"sellerOrderReferencedDocumentID\":\"9384\",\"contractReferencedDocument\":\"376zreurzu0983\",\"valid\":true,\"vatdueDateTypeCode\":\"72\",\"zfitems\":[{\"price\":1.00,\"quantity\":1,\"basisQuantity\":1,\"detailedDeliveryPeriodFrom\":\""+itemDeliveryFrom+"\",\"detailedDeliveryPeriodTo\":\""+itemDeliveryTo+"\",\"id\":\"a123\",\"buyerOrderReferencedDocumentLineID\":\"xxx\",\"product\":{\"unit\":\"H87\",\"name\":\"Testprodukt\",\"sellerAssignedID\":\"4711\",\"taxCategoryCode\":\"S\",\"globalID\":\"2001015001325\",\"globalIDScheme\":\"0160\",\"intraCommunitySupply\":false,\"reverseCharge\":false,\"vatpercent\":16},\"notes\":[\"item level 1/1\"],\"notesWithSubjectCode\":[{\"content\":\"item level 1/1\"}],\"itemAllowances\":[{\"totalAmount\":0.0200000000000000004163336342344337026588618755340576171875,\"taxPercent\":16,\"reason\":\"item discount\",\"categoryCode\":\"S\"}],\"value\":1.00}],\"ownVATID\":\"DE0815\",\"detailedDeliveryPeriodFrom\":1601503200000,\"detailedDeliveryPeriodTo\":1601848800000,\"ownTaxID\":\"9990815\",\"ownZIP\":\"55232\",\"ownLocation\":\"teststadt\",\"zfallowances\":[{\"totalAmount\":0.200000000000000011102230246251565404236316680908203125,\"taxPercent\":16,\"reason\":\"discount\",\"categoryCode\":\"S\"}],\"ownStreet\":\"teststr\",\"zfcharges\":[{\"totalAmount\":0.5,\"taxPercent\":16,\"reason\":\"quick delivery charge\",\"categoryCode\":\"S\"}],\"ownCountry\":\"DE\"}";
ObjectMapper mapper = new ObjectMapper();
Invoice fromJSON = mapper.readValue(json, Invoice.class);
assertEquals(globalID, fromJSON.getSender().getGlobalID());
assertEquals(globalIDScheme, fromJSON.getSender().getGlobalIDScheme());
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
assertEquals("2022-01-28", sdf.format(fromJSON.getZFItems()[0].getDetailedDeliveryPeriodFrom()));
assertEquals("2022-01-30", sdf.format(fromJSON.getZFItems()[0].getDetailedDeliveryPeriodTo()));
assertEquals("sender@test.org", fromJSON.getSender().getEmail());
}
public void testGrossFromJSON() throws JsonProcessingException {
String json="{ \"documentCode\": \"380\", \"number\": \"123\", \"currency\": \"EUR\", \"paymentTermDescription\": \"Please remit until 28.07.2025\", \"issueDate\": 1753653600000, \"dueDate\": 1753653600000, \"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\" } }, \"totalPrepaidAmount\": 0.00, \"lineTotalAmount\": 29.00, \"duePayable\": 34.51, \"grandTotal\": 34.51, \"taxBasis\": 29.00, \"valid\": true, \"zfitems\": [ { \"price\": 3.0000, \"quantity\": 10.0000, \"basisQuantity\": 1.0000, \"id\": \"1\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"allowances\": [ { \"totalAmount\": 0.1000, \"categoryCode\": \"S\" } ], \"vatpercent\": 19.00, \"intraCommunitySupply\": false, \"reverseCharge\": false }, \"value\": 3.0000 } ], \"ownVATID\": \"DE0815\", \"ownTaxID\": \"4711\", \"ownLocation\": \"teststadt\", \"ownZIP\": \"55232\", \"ownCountry\": \"DE\", \"ownStreet\": \"teststr\"}";
ObjectMapper mapper = new ObjectMapper();
CalculatedInvoice fromJSON = mapper.readValue(json, CalculatedInvoice.class);
fromJSON.calculate();
assertEquals(new BigDecimal("34.51"),fromJSON.getDuePayable());
}
public void testDueDateRoundtrip() throws JsonProcessingException {

View File

@@ -189,8 +189,7 @@ public class XRTest extends TestCase {
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(i);
final String xmlGen = new String(zf2p.getXML());
System.out.println(xmlGen);
final Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream(zf2p.getXML()));

View File

@@ -53,6 +53,7 @@ public class ZF2PushTest extends TestCase {
final String TARGET_ALLOWANCESPDF = "./target/testout-ZF2PushAllowances.pdf";
final String TARGET_CREDITNOTEPDF = "./target/testout-ZF2PushCreditNote.pdf";
final String TARGET_CORRECTIONPDF = "./target/testout-ZF2PushCorrection.pdf";
final String TARGET_ITEMGROSS = "./target/testout-ZF2PushGross.pdf";
final String TARGET_ITEMCHARGESALLOWANCESPDF = "./target/testout-ZF2PushItemChargesAllowances.pdf";
final String TARGET_CHARGESALLOWANCESPDF = "./target/testout-ZF2PushChargesAllowances.pdf";
final String TARGET_RELATIVECHARGESALLOWANCESPDF = "./target/testout-ZF2PushRelativeChargesAllowances.pdf";
@@ -114,8 +115,8 @@ public class ZF2PushTest extends TestCase {
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("DE88200800000970375700")); //the iban
assertTrue(zi.getUTF8().contains("Max Mustermann")); //account holder
assertTrue(zi.getUTF8().contains("DueDateDateTime")); //account holder
assertTrue(zi.getUTF8().contains("20201212")); //account holder
assertTrue(zi.getUTF8().contains("DueDateDateTime"));
assertTrue(zi.getUTF8().contains("20201212"));
assertTrue(zi.getUTF8().contains("<rsm:CrossIndustryInvoice"));
@@ -124,7 +125,7 @@ public class ZF2PushTest extends TestCase {
// Reading ZUGFeRD
assertEquals("571.04", zi.getAmount());
assertEquals(orgname, zi.getHolder());
assertEquals("Max Mustermann", zi.getHolder());
assertEquals(number, zi.getForeignReference());
try {
assertEquals(zi.getVersion(), 2);
@@ -159,7 +160,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(0)).setTaxExemptionReason("Kleinunternehmer gemäß §19 UStG").setTaxCategoryCode("E"), price, new BigDecimal(1.0)).addNote(theNote))
.addItem(new Item(new Product("Testprodukt", "", "H87", 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"));
@@ -219,7 +220,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", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
Invoice read = new Invoice();
@@ -237,13 +238,12 @@ public class ZF2PushTest extends TestCase {
fail("ParseException should not be raised");
}
}
public void testItemChargesAllowancesExport() {
public void testGross() {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -253,7 +253,71 @@ public class ZF2PushTest extends TestCase {
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)))));
// .addItem(new Item(new Product("Testprodukt", "", "H84", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
BigDecimal qty=new BigDecimal(10.0);
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", "", "H87", new BigDecimal(19)).addAllowance(new Allowance(new BigDecimal("0.1"))), price, qty));
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_ITEMGROSS);
} catch (IOException e) {
fail("IOException should not be raised");
}
try {
// now check the contents (like MustangReaderTest)
ZUGFeRDInvoiceImporter zi = new ZUGFeRDInvoiceImporter(TARGET_ITEMGROSS);
CalculatedInvoice ci=new CalculatedInvoice();
zi.extractInto(ci);
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()=\"GrossPriceProductTradePrice\"]/*[local-name()=\"ChargeAmount\"]")
.asString()
.isEqualTo("3.0000");
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()=\"NetPriceProductTradePrice\"]/*[local-name()=\"ChargeAmount\"]")
.asString()
.isEqualTo("2.9000");
assertEquals("EUR", ci.getCurrency());
assertTrue(zi.getUTF8().contains("0911623562")); // fax number
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(ci);
// Reading ZUGFeRD
assertEquals(new BigDecimal("34.51"), ci.getDuePayable());
} catch (Exception e) {
fail("Exception should not be raised");
}
}
public void testItemChargesAllowancesExport() {
String orgname = "Test company";
String number = "123";
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
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", "", "H84", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
@@ -261,10 +325,10 @@ public class ZF2PushTest extends TestCase {
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setNumber(number)
.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")));
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1")).setReasonCode("95")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)).setReason("In love with salesperson")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AnotherReason")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, 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);
@@ -283,7 +347,7 @@ public class ZF2PushTest extends TestCase {
assertTrue(zi.getUTF8().contains("ABK"));
// Reading ZUGFeRD
assertEquals("18.92", zi.getAmount());
assertEquals("18.33", zi.getAmount());
assertEquals(orgname, zi.getHolder());
assertEquals(number, zi.getForeignReference());
assertEquals(zi.getVersion(), 2);
@@ -300,8 +364,8 @@ public class ZF2PushTest extends TestCase {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -309,7 +373,7 @@ public class ZF2PushTest extends TestCase {
ze.ignorePDFAErrors().load(SOURCE_PDF);
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)))));
// .addItem(new Item(new Product("Testprodukt", "", "H84", 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"))
@@ -317,10 +381,10 @@ public class ZF2PushTest extends TestCase {
.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"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
@@ -373,7 +437,7 @@ public class ZF2PushTest extends TestCase {
.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)))
.addItem(new Item(new Product("Testprodukt", "", "H87", 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"));
@@ -413,8 +477,8 @@ public class ZF2PushTest extends TestCase {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -423,17 +487,17 @@ public class ZF2PushTest extends TestCase {
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)))));
// .addItem(new Item(new Product("Testprodukt", "", "H84", 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"))
.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")))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
@@ -464,8 +528,8 @@ public class ZF2PushTest extends TestCase {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -477,9 +541,9 @@ 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)), 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)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.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"))
);
@@ -540,7 +604,7 @@ 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)).setId("a123").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")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123").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))
@@ -631,7 +695,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)).addAllowance(new Allowance(BigDecimal.ONE)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19))))
.addItem(new Item(new Product("Testprodukt", "", "H87", 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());
@@ -675,10 +739,10 @@ 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)), 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)).setReasonCode("ABK")))
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", 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"));
@@ -691,7 +755,7 @@ public class ZF2PushTest extends TestCase {
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_RELATIVECHARGESALLOWANCESPDF);
assertEquals("CHF", zi.getInvoiceCurrencyCode());
assertEquals("11.10", zi.getAmount());
assertEquals("10.71", zi.getAmount());
assertEquals(orgname, zi.getHolder());
assertEquals(number, zi.getForeignReference());
try {
@@ -726,9 +790,9 @@ 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").addVATID("DE0815"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCorrection("0815");
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty)).setCorrection("0815");
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -777,9 +841,9 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX")))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0815"))
.setNumber(number).setDespatchAdviceReferencedDocumentID(despatchAdviceReferencedDocumentID)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCreditNote();
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty)).setCreditNote();
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -831,7 +895,7 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX")))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0815"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty));
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty));
// empty strings for document id's
i.setSellerOrderReferencedDocumentID("")

View File

@@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.mustangproject.*;
import org.skyscreamer.jsonassert.JSONAssert;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
@@ -38,6 +39,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -264,7 +266,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("18.92"), tc.getGrandTotal());
assertEquals(new BigDecimal("18.33"), tc.getGrandTotal());
}
public void testIBANImport() {
@@ -405,8 +407,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(i);
// assertEquals("",jsonArray);
JSONAssert.assertEquals("{\"documentCode\":\"380\",\"number\":\"471102\",\"currency\":\"EUR\",\"paymentTermDescription\":\"Der Betrag in Höhe von EUR 529,87 wird am 20.03.2018 von Ihrem Konto per SEPA-Lastschrift eingezogen.\\n \",\"issueDate\":1520121600000,\"deliveryDate\":1520121600000,\"sender\":{\"name\":\"Lieferant GmbH\",\"zip\":\"80333\",\"street\":\"Lieferantenstraße 20\",\"location\":\"München\",\"country\":\"DE\",\"taxID\":\"201/113/40209\",\"vatID\":\"DE123456789\",\"debitDetails\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}],\"vatid\":\"DE123456789\"},\"recipient\":{\"name\":\"Kunden AG Mitte\",\"zip\":\"69876\",\"street\":\"Kundenstraße 15\",\"location\":\"Frankfurt\",\"country\":\"DE\",\"bankDetails\":[{\"paymentMeansCode\":\"58\",\"paymentMeansInformation\":\"SEPA credit transfer\",\"iban\":\"DE21860000000086001055\"}]},\"totalPrepaidAmount\":0.00,\"creditorReferenceID\":\"DE98ZZZ09999999999\",\"valid\":false,\"zfitems\":[{\"price\":9.9000,\"quantity\":20.0000,\"basisQuantity\":1.0000,\"id\":\"1\",\"product\":{\"unit\":\"H87\",\"name\":\"Trennblätter A4\",\"taxCategoryCode\":\"S\",\"vatpercent\":19.00,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"value\":9.9000},{\"price\":5.5000,\"quantity\":50.0000,\"basisQuantity\":1.0000,\"id\":\"2\",\"product\":{\"unit\":\"H87\",\"name\":\"Joghurt Banane\",\"taxCategoryCode\":\"S\",\"vatpercent\":7.00,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"value\":5.5000}],\"tradeSettlement\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}],\"ownTaxID\":\"201/113/40209\",\"ownZIP\":\"80333\",\"ownCountry\":\"DE\",\"ownVATID\":\"DE123456789\",\"ownLocation\":\"München\",\"ownStreet\":\"Lieferantenstraße 20\"}",jsonArray,false);
} catch (IOException e) {
fail("IOException not expected");
@@ -415,8 +416,37 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public static Date atStartOfDay(Date date) {
ZoneId tz=ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0));
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), tz);
LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
return Date.from(startOfDay.atZone(tz).toInstant());
}
public void testImportAllowances() {
try {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushItemChargesAllowances.pdf");
Invoice i = zii.extractInvoice();
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(i);
SimpleDateFormat iso=new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat german=new SimpleDateFormat("dd.MM.yyyy");
Date now=new Date();
Date morning=atStartOfDay(now);
String expectedDueDate= String.valueOf(morning.toInstant().getEpochSecond() *1000);
String expectedIssueDate= String.valueOf(morning.toInstant().getEpochSecond() *1000);
String expectedPaymentTermDesciption="Please remit until "+german.format(now);
JSONAssert.assertEquals("{ \"documentCode\": \"380\", \"number\": \"123\", \"currency\": \"EUR\", \"paymentTermDescription\": \""+expectedPaymentTermDesciption+"\", \"issueDate\": "+expectedIssueDate+", \"dueDate\": "+expectedDueDate+", \"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\" } }, \"totalPrepaidAmount\": 0.00, \"valid\": true, \"zfitems\": [ { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"1\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemAllowances\": [ { \"totalAmount\": 0.10, \"taxPercent\": 0, \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"2\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemAllowances\": [ { \"percent\": 50.00, \"totalAmount\": 1.5, \"basisAmount\": 3.00, \"taxPercent\": 0, \"reason\": \"In love with salesperson\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 2.0000, \"basisQuantity\": 1.0000, \"id\": \"3\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemCharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"AnotherReason\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"4\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemCharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"Yet another reason\", \"categoryCode\": \"S\" } ], \"itemAllowances\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"Something completely strange\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 } ], \"ownCountry\": \"DE\", \"zfcharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 19.00, \"reason\": \"AReason\", \"reasonCode\": \"ABK\", \"categoryCode\": \"S\" } ], \"ownVATID\": \"DE0815\", \"ownStreet\": \"teststr\", \"ownTaxID\": \"4711\", \"ownLocation\": \"teststadt\", \"ownZIP\": \"55232\"}",jsonArray,true);
} catch (IOException e) {
fail("IOException not expected");
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public void testImportMinimum() {

View File

@@ -131,6 +131,10 @@ costs, losses or damages could normally have been foreseen.-->
<ram:SellerAssignedID>CO-123/V2A</ram:SellerAssignedID>
<ram:BuyerAssignedID>Toolbox 0815</ram:BuyerAssignedID>
<ram:Name>Stahlcoil</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>LeoID</ram:Description>
<ram:Value>704310.0105636504</ram:Value>
</ram:ApplicableProductCharacteristic>
<ram:OriginTradeCountry>
<ram:ID>DE</ram:ID>
</ram:OriginTradeCountry>