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

@@ -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));