Merge branch 'master' into issue-830

This commit is contained in:
jayddaniels
2025-06-25 12:46:59 +02:00
committed by GitHub
43 changed files with 3973 additions and 2939 deletions

View File

@@ -3,8 +3,10 @@ package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider;
import java.math.BigDecimal;
import java.math.RoundingMode;
/***
* (absolute) allowances on item and document level
@@ -29,6 +31,22 @@ public class Allowance extends Charge {
}
@Override
public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
if(totalAmount != null) {
return totalAmount;
} else if (percent!=null) {
BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP);
// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
BigDecimal singlePriceDiff=currentItem.getValue().subtract(singlePrice);
return singlePriceDiff;
} else {
throw new RuntimeException("percent must be set");
}
}
/***
* Always to return false for IZUGFeRDAllowanceCharge
* @return false since its not supposed to be calculated negatively

View File

@@ -23,6 +23,14 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
* the "name" of the bank account (holder)
*/
protected String accountName = null;
/**
* payment means code
*/
protected String paymentMeansCode = "58";
/**
* payment means information
*/
protected String paymentMeansInformation = "SEPA credit transfer";
/***
* bean constructor
@@ -123,5 +131,31 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
return accountName;
}
/**
* set payment means code
*
* @param paymentMeansCode the payment means code
* @return fluent setter
*/
public BankDetails setPaymentMeansCode(String paymentMeansCode) {
this.paymentMeansCode = paymentMeansCode;
return this;
}
@Override
public String getPaymentMeansCode() { return paymentMeansCode; }
/**
* set payment means information
*
* @param paymentMeansInformation the payment mean information
* @return fluent setter
*/
public BankDetails setPaymentMeansInformation(String paymentMeansInformation) {
this.paymentMeansInformation = paymentMeansInformation;
return this;
}
@Override
public String getPaymentMeansInformation() { return paymentMeansInformation; }
}

View File

@@ -103,7 +103,6 @@ public class CalculatedInvoice extends Invoice implements Serializable {
* @return a updated transactioncalulator
*/
public TransactionCalculator getCalculation() {
calculate();
return tc;
}

View File

@@ -7,6 +7,7 @@ import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import java.math.BigDecimal;
import java.math.RoundingMode;
/***
* Absolute and relative charges for document and item level
@@ -23,6 +24,10 @@ public class Charge implements IZUGFeRDAllowanceCharge {
* the absolute value if not percentage
*/
protected BigDecimal totalAmount;
/**
* the value the percentage is applied upon
*/
protected BigDecimal basisAmount;
/**
* the tax rate the charge belongs to
*/
@@ -103,6 +108,22 @@ public class Charge implements IZUGFeRDAllowanceCharge {
}
@Override
public BigDecimal getBasisAmount() {
return basisAmount;
}
/***
* sets a potential basis for the potential percentage
* @param basis the basis amount
* @return fluid setter
*/
public Charge setBasisAmount(BigDecimal basis) {
this.basisAmount = basis;
return this;
}
@Override
public String getReasonCode() {
return reasonCode;
@@ -121,10 +142,13 @@ public class Charge implements IZUGFeRDAllowanceCharge {
@Override
public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
if (percent!=null) {
return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100)));
} else if(totalAmount != null) {
if(totalAmount != null) {
return totalAmount;
} else if (percent!=null) {
BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP);
// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
BigDecimal singlePriceDiff=currentItem.getValue().add(singlePrice);
return singlePriceDiff;
} else {
throw new RuntimeException("percent must be set");
}

View File

@@ -72,8 +72,6 @@ public class Item implements IZUGFeRDExportableItem {
//we need: name description unitcode
//and we additionally have vat%
// Bharti's homework 20241126:Streams https://www.youtube.com/watch?v=Lf01cBzmuXw
// and Lambdas https://www.youtube.com/watch?v=HCyx31NW8xg
setProduct(new Product(itemMap.getNode("Item").get()));
icnm.getAsString("Name").ifPresent(product::setName);
icnm.getAsString("Description").ifPresent(product::setDescription);
@@ -86,17 +84,6 @@ public class Item implements IZUGFeRDExportableItem {
BuyersItemIdentification.getAsString("ID").ifPresent(product::setBuyerAssignedID);
});
// String name = icnm.getAsStringOrNull("Name");
// String val = icnm.getAsStringOrNull("Value");
// if (name != null && val != null) {
// if (attributes == null) {
// attributes = new HashMap<>();
// }
// product.attributes.put(name, val);
// }
//icnm.getNode("AdditionalItemProperty").flatMap(n ->n.getAttributes()).ifPresent(product::setAttributes);
icnm.getAsNodeMap("ClassifiedTaxCategory").flatMap(m -> m.getAsBigDecimal("Percent"))
.ifPresent(product::setVATPercent);
});
@@ -175,11 +162,12 @@ public class Item implements IZUGFeRDExportableItem {
.ifPresent(product::setTaxExemptionReason);
icnm.getAllNodes("SpecifiedTradeAllowanceCharge").map(NodeMap::new).forEach(stac -> {
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> { //CII
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> {
String isChargeString = ci.getAsString("Indicator").get();
String percentString = stac.getAsStringOrNull("CalculationPercent");//MultiplierFactorNumeric
String amountString = stac.getAsStringOrNull("ActualAmount");//Amount
String reason = stac.getAsStringOrNull("Reason");//AllowanceChargeReason
String percentString = stac.getAsStringOrNull("CalculationPercent");
String amountString = stac.getAsStringOrNull("ActualAmount");
String basisAmountString = stac.getAsStringOrNull("BasisAmount");
String reason = stac.getAsStringOrNull("Reason");
Charge izac = new Charge();
if (isChargeString.equalsIgnoreCase("false")) {
izac = new Allowance();
@@ -188,6 +176,12 @@ public class Item implements IZUGFeRDExportableItem {
}
if (amountString != null) {
izac.setTotalAmount(new BigDecimal(amountString));
if (percentString!=null&&(percentString!="0")) {
izac.setTotalAmount(new BigDecimal(amountString).divide(getQuantity()));
}
}
if (basisAmountString != null) {
izac.setBasisAmount(new BigDecimal(basisAmountString));
}
if (percentString != null) {
izac.setPercent(new BigDecimal(percentString));
@@ -288,6 +282,16 @@ public class Item implements IZUGFeRDExportableItem {
return this;
}
@Override public IZUGFeRDAllowanceCharge[] getAllowances() {
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Allowances.size()];
return Allowances.toArray(izac);
}
@Override public IZUGFeRDAllowanceCharge[] getCharges() {
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Charges.size()];
return Charges.toArray(izac);
}
/***
* BT 132 (issue https://github.com/ZUGFeRD/mustangproject/issues/247)
* @return the line ID of the order (BT132)
@@ -461,6 +465,7 @@ public class Item implements IZUGFeRDExportableItem {
* @return fluent setter
*/
public Item addAllowance(IZUGFeRDAllowanceCharge izac) {
Allowances.add(izac);
return this;
}

View File

@@ -32,6 +32,8 @@ public class Product implements IZUGFeRDExportableProduct {
protected boolean isIntraCommunitySupply = false;
protected SchemedID globalId = null;
protected String countryOfOrigin = null;
protected ArrayList<Charge> charges=new ArrayList<>();
protected ArrayList<Allowance> allowances=new ArrayList<>();
protected HashMap<String, String> attributes = new HashMap<>();
protected List<IDesignatedProductClassification> classifications = new ArrayList<>();
@@ -393,4 +395,42 @@ public class Product implements IZUGFeRDExportableProduct {
this.classifications.add(classification);
return this;
}
public Product addCharge(Charge e) {
charges.add(e);
return this;
}
public Product addAllowance(Allowance a) {
allowances.add(a);
return this;
}
/***
* returns the AppliedTradeAllowanceCharges of this product which are actually Charges
* @return array of or null, if none
*/
@Override
public Charge[] getCharges() {
if (charges.size()==0) {
return null;
}
Charge[] chargeArr = new Charge[charges.size()];
return charges.toArray(chargeArr);
}
@Override
/***
* returns the AppliedTradeAllowanceCharges of this product which are actually Allowances
* @return array of or null, if none
*/
public Allowance[] getAllowances() {
if (allowances.size()==0) {
return null;
}
Allowance[] allowanceArr = new Allowance[allowances.size()];
return allowances.toArray(allowanceArr);
}
}

View File

@@ -38,6 +38,12 @@ public interface IZUGFeRDAllowanceCharge {
*/
default BigDecimal getPercent() {return null;}
/***
* returns a basis the precentage is calculated from
* @return null or the basis
*/
default BigDecimal getBasisAmount() {return null;}
/***
* get a description for the allowance/charge
* @return the description

View File

@@ -43,7 +43,11 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
* item level discounts
* @return array of the discounts on a single item
*/
@Deprecated
default IZUGFeRDAllowanceCharge[] getItemAllowances() {
if (getProduct()!=null) {
return getProduct().getAllowances();
}
return null;
}
@@ -51,10 +55,27 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
* item level price additions
* @return array of the additional charges on the item
*/
@Deprecated
default IZUGFeRDAllowanceCharge[] getItemCharges() {
if (getProduct()!=null) {
return getProduct().getCharges();
}
return null;
}
@Deprecated
default IZUGFeRDAllowanceCharge[] getAllowances() {
return null;
}
/**
* item level price additions
* @return array of the additional charges on the item
*/
@Deprecated
default IZUGFeRDAllowanceCharge[] getCharges() {
return null;
}
/***
* BT 132 (issue https://github.com/ZUGFeRD/mustangproject/issues/247)
@@ -147,9 +168,9 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
}
/***
* specify allowances amount for the line item total
* get all (allowances and charges) SpecifiedTradeAllowanceCharges
*
* @return the sum of allowances for this item
* @return the real item lecel SpecifiedTradeAllowanceCharges
*/
default IZUGFeRDAllowanceCharge[] getItemTotalAllowances() {
return null;

View File

@@ -166,6 +166,25 @@ public interface IZUGFeRDExportableProduct {
return null;
}
/**
* product level discounts (AppliedTradeAllowanceCharge, will change net price)
* @return array of the discounts on a single product
*/
default IZUGFeRDAllowanceCharge[] getAllowances() {
return null;
}
/**
* product level charges (AppliedTradeAllowanceCharge, will change net price)
* @return array of the additional charges on the product
*/
default IZUGFeRDAllowanceCharge[] getCharges() {
return null;
}
/**
* Detailed information about the product
*

View File

@@ -59,6 +59,16 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
*/
default String getAccountName() { return null; }
/***
* @return payment means code (BT-81 / UNTDID 4461)
*/
default String getPaymentMeansCode() { return null; };
/***
* @return payment means description (BT-82) (optional)
*/
default String getPaymentMeansInformation() { return null; };
@Override
@JsonIgnore
@@ -70,12 +80,14 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
}
String xml = "<ram:SpecifiedTradeSettlementPaymentMeans>"
+ "<ram:TypeCode>58</ram:TypeCode>"
+ "<ram:Information>SEPA credit transfer</ram:Information>"
+ "<ram:PayeePartyCreditorFinancialAccount>"
+ "<ram:IBANID>" + XMLTools.encodeXML(getOwnIBAN()) + "</ram:IBANID>";
xml+= accountNameStr;
xml+= "</ram:PayeePartyCreditorFinancialAccount>";
+ "<ram:TypeCode>" + XMLTools.encodeXML(getPaymentMeansCode()) + "</ram:TypeCode>"
+ "<ram:Information>" + XMLTools.encodeXML(getPaymentMeansInformation()) + "</ram:Information>";
if (getOwnIBAN() != null) {
xml += "<ram:PayeePartyCreditorFinancialAccount>"
+ "<ram:IBANID>" + XMLTools.encodeXML(getOwnIBAN()) + "</ram:IBANID>"
+ accountNameStr
+ "</ram:PayeePartyCreditorFinancialAccount>";
}
if (getOwnBIC()!=null) {
xml+= "<ram:PayeeSpecifiedCreditorFinancialInstitution>"
+ "<ram:BICID>" + XMLTools.encodeXML(getOwnBIC()) + "</ram:BICID>"

View File

@@ -2,30 +2,49 @@ package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
/***
* the linecalculator does the math within an item line, and e.g. calculates quantity*price.
* @see TransactionCalculator
*/
public class LineCalculator {
private final BigDecimal price;
private final BigDecimal priceGross;
private final BigDecimal itemTotalNetAmount;
private final BigDecimal itemTotalVATAmount;
private BigDecimal allowance = BigDecimal.ZERO;
private BigDecimal charge = BigDecimal.ZERO;
private BigDecimal allowanceItemTotal = BigDecimal.ZERO;
protected BigDecimal price;
protected BigDecimal priceGross;
protected BigDecimal itemTotalNetAmount;
protected BigDecimal itemTotalVATAmount;
protected BigDecimal lineAllowance = BigDecimal.ZERO;
protected BigDecimal lineCharge = BigDecimal.ZERO;
protected BigDecimal itemAllowance = BigDecimal.ZERO;
protected BigDecimal itemCharge = BigDecimal.ZERO;
protected BigDecimal allowanceItemTotal = BigDecimal.ZERO;
public LineCalculator(IZUGFeRDExportableItem currentItem) {
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
addAllowance(allowance.getTotalAmount(currentItem));
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleAllowance=allowance.getTotalAmount(currentItem);
addItemAllowance(singleAllowance);
if ((allowance.getPercent()!=null)&&(allowance.getPercent().compareTo(BigDecimal.ZERO)!=0)) {
factor=currentItem.getQuantity();
}
addAllowanceItemTotal(singleAllowance.multiply(factor));
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
addCharge(charge.getTotalAmount(currentItem));
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleCharge=charge.getTotalAmount(currentItem);
addItemCharge(singleCharge);
if ((charge.getPercent()!=null)&&(charge.getPercent().compareTo(BigDecimal.ZERO)!=0)) {
factor=currentItem.getQuantity();
}
subtractAllowanceItemTotal(singleCharge.multiply(factor));
}
}
if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) {
@@ -42,22 +61,41 @@ public class LineCalculator {
vatPercent = BigDecimal.ZERO;
}
BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100));
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
price = priceGross.subtract(allowance).add(charge);
BigDecimal quantity=BigDecimal.ZERO;
if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) {
quantity=currentItem.getQuantity();
}
price=currentItem.getPrice();
priceGross=price;
// price=price.subtract(itemAllowance).add(itemCharge);
// BigDecimal delta=charge.subtract(allowanceItemTotal).subtract(allowance);
// delta=delta.divide(currentItem.getQuantity(), 18, RoundingMode.HALF_UP);
BigDecimal delta=BigDecimal.ZERO;
if(currentItem.getProduct()!=null){
if (currentItem.getProduct().getAllowances()!=null) {
for (IZUGFeRDAllowanceCharge ccaf:currentItem.getProduct().getAllowances()) {
delta=delta.subtract(ccaf.getTotalAmount(currentItem));
}
}
if (currentItem.getProduct().getCharges()!=null) {
for (IZUGFeRDAllowanceCharge ccaf : currentItem.getProduct().getCharges()) {
delta = delta.subtract(ccaf.getTotalAmount(currentItem));
}
}
}
price=price.add(delta);
// Division/Zero occurred here.
// Used the setScale only because that's also done in getBasisQuantity
BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0
? BigDecimal.ONE.setScale(4)
: currentItem.getBasisQuantity();
itemTotalNetAmount = quantity.multiply(price).divide(basisQuantity, 18, RoundingMode.HALF_UP)
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
.add(lineCharge).subtract(lineAllowance).subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);//.setScale(2, RoundingMode.HALF_UP);
}
public BigDecimal getPrice() {
@@ -80,16 +118,27 @@ public class LineCalculator {
return priceGross;
}
public void addAllowance(BigDecimal b) {
allowance = allowance.add(b);
public void addLineAllowance(BigDecimal b) {
lineAllowance = lineAllowance.add(b);
}
public void addCharge(BigDecimal b) {
charge = charge.add(b);
public void addLineCharge(BigDecimal b) {
lineCharge = lineCharge.add(b);
}
public void addItemAllowance(BigDecimal b) {
itemAllowance = itemAllowance.add(b);
}
public void addItemCharge(BigDecimal b) {
itemCharge = itemCharge.add(b);
}
public void addAllowanceItemTotal(BigDecimal b) {
allowanceItemTotal = allowanceItemTotal.add(b);
}
public void subtractAllowanceItemTotal(BigDecimal b) {
allowanceItemTotal = allowanceItemTotal.subtract(b);
}
}

View File

@@ -145,7 +145,7 @@ public class VATAmount {
}
public VATAmount add(VATAmount v) {
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText());
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText() != null ? v.getVatExemptionReasonText(): this.vatExemptionReasonText);
}
public VATAmount subtract(VATAmount v) {

View File

@@ -48,6 +48,7 @@ import org.mustangproject.IncludedNote;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.XMLTools;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -152,12 +153,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if (profile == Profiles.getByName("Minimum")) {
xml += "<ram:ID>" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
} else {
String schemeAttribute="";
if ((party.getLegalOrganisation().getSchemedID().getScheme()!=null)&&(party.getLegalOrganisation().getSchemedID().getScheme().length()>0)) {
schemeAttribute="schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme())+"\"";
String schemeAttribute = "";
if ((party.getLegalOrganisation().getSchemedID().getScheme() != null) && (party.getLegalOrganisation().getSchemedID().getScheme().length() > 0)) {
schemeAttribute = "schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\"";
}
xml += "<ram:ID "+schemeAttribute+">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
xml += "<ram:ID " + schemeAttribute + ">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
}
}
if (party.getLegalOrganisation().getTradingBusinessName() != null) {
@@ -320,11 +321,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
String reason = "";
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
boolean isEN16931=(profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931"));
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || isEN16931)) {
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
}
String reasonCode = "";
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("XRechnung"))) {
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("Extended") || isEN16931)) {
// only in XRechnung profile
reasonCode = "<ram:ReasonCode>" + allowance.getReasonCode() + "</ram:ReasonCode>";
}
@@ -395,20 +397,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "</rsm:ExchangedDocumentContext>"
+ "<rsm:ExchangedDocument>"
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>";
if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) {
xml += "<ram:Name>" + XMLTools.encodeXML(trans.getDocumentName()) + "</ram:Name>";
}
xml += "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
+ "<ram:IssueDateTime>" + DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
+ buildNotes(trans)
+ "</rsm:ExchangedDocument>"
+ "<rsm:SupplyChainTradeTransaction>";
if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) {
xml += "<ram:Name>" + XMLTools.encodeXML(trans.getDocumentName()) + "</ram:Name>";
}
xml += "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
+ "<ram:IssueDateTime>" + DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
+ buildNotes(trans)
+ "</rsm:ExchangedDocument>"
+ "<rsm:SupplyChainTradeTransaction>";
int lineID = 0;
for (final IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
lineID++;
String lineIDStr = Integer.toString(lineID);
if (currentItem.getId()!=null) {
lineIDStr=currentItem.getId();
if (currentItem.getId() != null) {
lineIDStr = currentItem.getId();
}
final LineCalculator lc = new LineCalculator(currentItem);
if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BasicWL"))) {
@@ -432,24 +434,29 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>";
}
String allowanceChargeStr = "";
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
if (currentItem.getProduct().getAllowances() != null && currentItem.getProduct().getAllowances().length > 0) {
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getProduct().getAllowances()) {
allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
if (currentItem.getProduct().getCharges() != null && currentItem.getProduct().getCharges().length > 0) {
for (final IZUGFeRDAllowanceCharge charge : currentItem.getProduct().getCharges()) {
allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);
}
}
String itemTotalAllowanceChargeStr = "";
if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) {
for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getItemTotalAllowances()) {
if (currentItem.getAllowances() != null && currentItem.getAllowances().length > 0) {
for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getAllowances()) {
itemTotalAllowanceChargeStr += getItemTotalAllowanceChargeStr(itemTotalAllowance, currentItem);
}
}
if (currentItem.getCharges() != null && currentItem.getCharges().length > 0) {
for (final IZUGFeRDAllowanceCharge itemTotalCharges : currentItem.getCharges()) {
itemTotalAllowanceChargeStr += getItemTotalAllowanceChargeStr(itemTotalCharges, currentItem);
}
}
xml += "<ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>";
if (currentItem.getProduct().getDescription() != null && currentItem.getProduct().getDescription().length() > 0) {
@@ -531,15 +538,16 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "<ram:SpecifiedLineTradeSettlement>"
+ "<ram:ApplicableTradeTax>"
+ "<ram:TypeCode>VAT</ram:TypeCode>";
if (currentItem.getProduct().getTaxExemptionReason() != null) {
xml += "<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
}
xml += "<ram:CategoryCode>" + currentItem.getProduct().getTaxCategoryCode() + "</ram:CategoryCode>"
+ "<ram:RateApplicablePercent>"
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>"
+ "</ram:ApplicableTradeTax>";
xml += "<ram:CategoryCode>" + currentItem.getProduct().getTaxCategoryCode() + "</ram:CategoryCode>";
if (!currentItem.getProduct().getTaxCategoryCode().equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) {
xml += "<ram:RateApplicablePercent>"
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>";
}
xml += "</ram:ApplicableTradeTax>";
if ((currentItem.getDetailedDeliveryPeriodFrom() != null) || (currentItem.getDetailedDeliveryPeriodTo() != null)) {
xml += "<ram:BillingSpecifiedPeriod>";
if (currentItem.getDetailedDeliveryPeriodFrom() != null) {
@@ -551,7 +559,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
xml += "</ram:BillingSpecifiedPeriod>";
}
xml += itemTotalAllowanceChargeStr;
// item charges/allowances
if (!itemTotalAllowanceChargeStr.isEmpty()) {
xml += itemTotalAllowanceChargeStr ;
}
xml += "<ram:SpecifiedTradeSettlementLineMonetarySummation>"
+ "<ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount())
@@ -725,9 +736,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ exemptionReasonTextXML
+ "<ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>" // currencyID=\"EUR\"
+ "<ram:CategoryCode>" + amountCategoryCode + "</ram:CategoryCode>"
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "")
+ "<ram:RateApplicablePercent>"
+ vatFormat(amount.getApplicablePercent()) + "</ram:RateApplicablePercent></ram:ApplicableTradeTax>";
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "");
if (!amountCategoryCode.equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) {
xml += "<ram:RateApplicablePercent>"
+ vatFormat(amount.getApplicablePercent()) + "</ram:RateApplicablePercent>";
}
xml += "</ram:ApplicableTradeTax>";
}
}
}
@@ -743,7 +757,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
if ((profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")) || (profile == Profiles.getByName("EXTENDED"))) {
if ((profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")) || (profile == Profiles.getByName("EXTENDED"))) {
for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
"<ram:ChargeIndicator>" +
@@ -759,7 +773,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
xml += "<ram:CategoryTradeTax>" +
"<ram:TypeCode>VAT</ram:TypeCode>" +
"<ram:CategoryCode>" + charge.getCategoryCode() + "</ram:CategoryCode>";
if (charge.getTaxPercent() != null) {
if (charge.getTaxPercent() != null && !charge.getCategoryCode().equals(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE)) {
xml += "<ram:RateApplicablePercent>" + vatFormat(charge.getTaxPercent()) + "</ram:RateApplicablePercent>";
}
xml += "</ram:CategoryTradeTax>" +
@@ -842,7 +856,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if (paymentTermsDescription != null) {
xml += "<ram:Description>" + paymentTermsDescription + "</ram:Description>";
}
if (trans.getDueDate() != null) {
xml += "<ram:DueDateDateTime>" // $NON-NLS-2$
+ DATE.udtFormat(trans.getDueDate())
@@ -874,7 +888,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String chargesTotalLine = "<ram:ChargeTotalAmount>" + currencyFormat(calc.getChargesForPercent(null)) + "</ram:ChargeTotalAmount>";
xml += "<ram:SpecifiedTradeSettlementHeaderMonetarySummation>";
if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BASICWL"))) {
if ((getProfile() != Profiles.getByName("Minimum"))) {
xml += "<ram:LineTotalAmount>" + currencyFormat(calc.getTotal()) + "</ram:LineTotalAmount>";
xml += chargesTotalLine
+ allowanceTotalLine;
@@ -910,12 +924,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if (trans.getInvoiceReferencedDocuments() != null) {
for (ReferencedDocument doc : trans.getInvoiceReferencedDocuments()) {
xml += "<ram:InvoiceReferencedDocument>"
+ "<ram:IssuerAssignedID>"
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
+ "<ram:IssuerAssignedID>"
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
if (doc.getFormattedIssueDateTime() != null) {
xml += "<ram:FormattedIssueDateTime>"
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
+ "</ram:FormattedIssueDateTime>";
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
+ "</ram:FormattedIssueDateTime>";
}
xml += "</ram:InvoiceReferencedDocument>";
}

View File

@@ -383,29 +383,7 @@ public class ZUGFeRDInvoiceImporter {
});
});
String street, name, additionalStreet, city, postal, countrySubentity, line, country = null;
/*
String idx = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"ID\"]");
street = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name()=\"Address\"]/*[local-name()=\"StreetName\"]");
additionalStreet = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"AdditionalStreetName\"]");
city = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"CityName\"]");
postal = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"PostalZone\"]");
countrySubentity = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]/*[local-name() = \"CountrySubentity\"]");
line = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]//*[local-name() = \"AddressLine\"]/*[local-name() = \"Line\"]");
country = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"Address\"]//*[local-name() = \"Country\"]/*[local-name() = \"IdentificationCode\"]");
name = extractString("//*[local-name()=\"DeliveryLocation\"]/*[local-name() = \"DeliveryParty\"]//*[local-name() = \"PartyName\"]/*[local-name() = \"Name\"]");
*/
zpp.setDeliveryAddress(delivery);
/*
zpp.setDeliveryAddress(new TradeParty()
.setStreet(street)
.setAdditionalAddress(additionalStreet)
.setLocation(city)
.setZIP(postal)
.setAdditionalAddressExtension(line)
.setCountry(country)
.setName(name)
);
*/
}
@@ -420,14 +398,6 @@ public class ZUGFeRDInvoiceImporter {
XPathExpression shipPayee = xpath.compile("//*[local-name()=\"PayeeParty\"]/*");
NodeList ublPayeeNodes = (NodeList) shipPayee.evaluate(getDocument(), XPathConstants.NODESET);
// if(ublPayeeNodes != null) {
// TradeParty payee = new TradeParty();
// NodeMap nodeMap = new NodeMap(ublPayeeNodes).getAsNodeMap("PayeeParty").get();
// nodeMap.getNode("ID").ifPresent(s -> {
// SchemedID sID = new SchemedID().setScheme(s.getAttributes().getNamedItem("schemeID").getTextContent()).setId(s.getTextContent());
// payee.addGlobalID(sID);
// });
// }
//NodeList UBLpayeeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (ublPayeeNodes.getLength() > 0) {
zpp.setPayee(new TradeParty(ublPayeeNodes));
@@ -598,6 +568,15 @@ public class ZUGFeRDInvoiceImporter {
}
}
String creditorReferenceID = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"CreditorReferenceID\"]").trim();//BT-90
if ((creditorReferenceID == null)||(creditorReferenceID.length()==0)) {
//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)) {
zpp.setCreditorReferenceID(creditorReferenceID);
}
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeDelivery\"]|//*[local-name()=\"Delivery\"]");
NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -836,9 +815,6 @@ public class ZUGFeRDInvoiceImporter {
}
}
}
// if ((paymentMeansChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("DirectDebitMandateID"))) {
// directDebitMandateID = paymentTermChilds.item(paymentTermChildIndex).getTextContent();
// }
if ((paymentMeansChilds.item(meansChildIndex).getLocalName() != null)
&& (paymentMeansChilds.item(meansChildIndex).getLocalName().equals("PaymentMandate"))) {
NodeList paymentMandateChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes();
@@ -974,6 +950,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes();
boolean isCharge = true;
String chargeAmount = null;
String basisAmount = null;
String reason = null;
String reasonCode = null;
String taxPercent = null;
@@ -1001,6 +978,8 @@ public class ZUGFeRDInvoiceImporter {
} else if (chargeChildName.equals("ActualAmount") || chargeChildName.equals("Amount")) {
chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("BasisAmount")) {
basisAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("Reason") || chargeChildName.equals("AllowanceChargeReason")) {
reason = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("ReasonCode") || chargeChildName.equals("AllowanceChargeReasonCode")) {
@@ -1028,6 +1007,9 @@ public class ZUGFeRDInvoiceImporter {
if (taxPercent != null) {
c.setTaxPercent(new BigDecimal(taxPercent));
}
if (basisAmount != null) {
c.setBasisAmount(new BigDecimal(basisAmount));
}
zpp.addCharge(c);
} else {
Allowance a = new Allowance(new BigDecimal(chargeAmount));
@@ -1040,6 +1022,9 @@ public class ZUGFeRDInvoiceImporter {
if (taxPercent != null) {
a.setTaxPercent(new BigDecimal(taxPercent));
}
if (basisAmount != null) {
a.setBasisAmount(new BigDecimal(basisAmount));
}
zpp.addAllowance(a);
}

View File

@@ -1,21 +1,23 @@
/** **********************************************************************
*
/**
* *********************************************************************
* <p>
* Copyright 2018 Jochen Staerk
*
* <p>
* Use is subject to license terms.
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* <p>
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
* <p>
* **********************************************************************
*/
package org.mustangproject.ZUGFeRD.model;
import java.util.Set;
@@ -31,5 +33,5 @@ public class TaxCategoryCodeTypeConstants {
public static final String INTRACOMMUNITY = "K";
public static final String FREEEXPORT = "G";
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT).collect(Collectors.toSet());
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT, UNTAXEDSERVICE).collect(Collectors.toSet());
}

View File

@@ -136,7 +136,7 @@
<entry key="xr:Tender_or_lot_reference" id="BT-17">Vergabenummer</entry>
<entry key="xr:Receiving_advice_reference" id="BT-15">Kennung der Empfangsbestätigung</entry>
<entry key="xr:Despatch_advice_reference" id="BT-16">Kennung der Versandanzeige</entry>
<entry key="xr:Business_process_type_identifier" id="BT-23">Prozesskennung</entry>
<entry key="xr:Business_process_type" id="BT-23">Prozesskennung</entry>
<entry key="xr:Specification_identifier" id="BT-24">Spezifikationskennung</entry>
<entry key="xr:Invoiced_object_identifier" id="BT-18">Objektkennung</entry>
<entry key="xr:Invoiced_object_identifier/@scheme_identifier" id="BT-18_scheme">Schema der Objektkennung</entry>

View File

@@ -99,11 +99,11 @@
<xsl:attribute name="xr:id" select="'BG-2'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:if test="./cbc:ProfileID">
<xr:Business_process_type_identifier>
<xr:Business_process_type>
<xsl:attribute name="xr:id" select="'BT-23'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:value-of select="./cbc:ProfileID"/>
</xr:Business_process_type_identifier>
</xr:Business_process_type>
</xsl:if>
<xr:Specification_identifier>
<xsl:attribute name="xr:id" select="'BT-24'"/>

View File

@@ -98,11 +98,11 @@
<xsl:attribute name="xr:id" select="'BG-2'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:if test="./cbc:ProfileID">
<xr:Business_process_type_identifier>
<xr:Business_process_type>
<xsl:attribute name="xr:id" select="'BT-23'"/>
<xsl:attribute name="xr:src" select="xr:src-path(.)"/>
<xsl:value-of select="./cbc:ProfileID"/>
</xr:Business_process_type_identifier>
</xr:Business_process_type>
</xsl:if>
<xr:Specification_identifier>
<xsl:attribute name="xr:id" select="'BT-24'"/>

View File

@@ -818,7 +818,6 @@
<xsl:apply-templates mode="list-entry" select="xr:Despatch_advice_reference"/>
<xsl:apply-templates mode="list-entry" select="xr:PROCESS_CONTROL/xr:Business_process_type"/>
<xsl:apply-templates mode="list-entry" select="xr:PROCESS_CONTROL/xr:Specification_identifier"/>
<xsl:apply-templates mode="list-entry" select="xr:PROCESS_CONTROL/xr:Business_process_type_identifier"/>
<xsl:apply-templates mode="list-entry" select="xr:Invoiced_object_identifier"/>
<xsl:apply-templates mode="list-entry" select="xr:Invoiced_object_identifier/@scheme_identifier">
<xsl:with-param name="field-mapping-identifier" select="'xr:Invoiced_object_identifier/@scheme_identifier'"/>

View File

@@ -1797,7 +1797,7 @@ function downloadData (element_id) {
<div class="boxtabelle boxinhalt noPaddingTop borderSpacing">
<div class="boxzeile">
<div class="boxdaten legende "><xsl:value-of select="$i18n.bt147"/>:</div>
<div id="BT-147" title="BT-147" class="boxdaten wert"><xsl:value-of select="format-number(xr:PRICE_DETAILS/xr:Item_price_discount,'###.##0,00','decimal')"/></div>
<div id="BT-147" title="BT-147" class="boxdaten wert"><xsl:value-of select="format-number(sum(xr:PRICE_DETAILS/xr:Item_price_discount),'###.##0,00','decimal')"/></div>
</div>
<div class="boxzeile">
<div class="boxdaten legende "><xsl:value-of select="$i18n.bt148"/>:</div>