Merge branch 'master' into parse_item_BillingSpecifiedPeriod

This commit is contained in:
ean
2025-02-03 09:48:35 +01:00
18 changed files with 874 additions and 75 deletions

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.IZUGFeRDCashDiscount;
@@ -63,6 +64,7 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
/***
* @return this particular cash discount as cross industry invoice XML
*/
@JsonIgnore
public String getAsCII() {
return "<ram:SpecifiedTradePaymentTerms>"+
"<ram:Description>Cash Discount</ram:Description>"+
@@ -78,6 +80,7 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
* XRechnung CIUS defined it's own proprietary format for a freetext field
* @return this particular cash discount in proprietary xrechnung format
*/
@JsonIgnore
public String getAsXRechnung() {
return "#SKONTO#TAGE="+days+"#PROZENT="+XMLTools.nDigitFormat(percent,2)+"#\n";
}

View File

@@ -69,6 +69,7 @@ public class Invoice implements IExportableTransaction {
protected String vatDueDateTypeCode = null;
protected String creditorReferenceID; // required when direct debit is used.
private BigDecimal roundingAmount=null;
private String paymentReference; // Remittance information / Verwendungszweck, BT-83
public Invoice() {
ZFItems = new ArrayList<>();
@@ -650,6 +651,16 @@ public class Invoice implements IExportableTransaction {
return this;
}
@Override
public String getPaymentReference() {
return paymentReference;
}
public Invoice setPaymentReference(String paymentReference) {
this.paymentReference = paymentReference;
return this;
}
@Override
public TradeParty getDeliveryAddress() {
return deliveryAddress;
@@ -783,11 +794,20 @@ public class Invoice implements IExportableTransaction {
return detailedDeliveryDateStart;
}
public Invoice setDetailedDeliveryPeriodFrom(Date dt) {
detailedDeliveryDateStart=dt;
return this;
}
@Override
public Date getDetailedDeliveryPeriodTo() {
return detailedDeliveryPeriodEnd;
}
public Invoice setDetailedDeliveryPeriodTo(Date dt) {
detailedDeliveryPeriodEnd=dt;
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element

View File

@@ -172,6 +172,9 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAsNodeMap("ApplicableTradeTax")
.flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent"))
.ifPresent(product::setVATPercent);
icnm.getAsNodeMap("ApplicableTradeTax")
.flatMap(cnm -> cnm.getAsString("ExemptionReason"))
.ifPresent(product::setTaxExemptionReason);
icnm.getAsNodeMap("SpecifiedTradeAllowanceCharge").ifPresent(stac -> {
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> {
String isChargeString=ci.getAsString("Indicator").get();
@@ -187,8 +190,12 @@ public class Item implements IZUGFeRDExportableItem {
if (amountString!=null) {
izac.setTotalAmount(new BigDecimal(amountString));
}
if(percentString!=null) {
izac.setPercent(new BigDecimal(percentString));
}
if(reason!=null) {
izac.setReason(reason);
}
if (isChargeString.equalsIgnoreCase("false")) {
addAllowance(izac);

View File

@@ -314,6 +314,10 @@ public interface IExportableTransaction {
return null;
}
default String getPaymentReference() {
return null;
}
/**
* returns if a rebate agreements exists
*

View File

@@ -288,8 +288,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String allowanceChargeStr = "<ram:AppliedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
"<ram:ActualAmount>" + priceFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
reason +
reasonCode +
reason +
"</ram:AppliedTradeAllowanceCharge>";
return allowanceChargeStr;
}
@@ -323,8 +323,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String itemTotalAllowanceChargeStr = "<ram:SpecifiedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
"<ram:ActualAmount>" + currencyFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
reason +
reasonCode +
reason +
"</ram:SpecifiedTradeAllowanceCharge>";
return itemTotalAllowanceChargeStr;
}
@@ -388,14 +388,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "</ram:GuidelineSpecifiedDocumentContextParameter>"
+ "</rsm:ExchangedDocumentContext>"
+ "<rsm:ExchangedDocument>"
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>"
// + "<ram:Name>RECHNUNG</ram:Name>"
// + "<ram:TypeCode>380</ram:TypeCode>"
+ "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
+ "<ram:IssueDateTime>"
+ DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>";
if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) {
xml += "<ram:Name>" + XMLTools.encodeXML(trans.getDocumentName()) + "</ram:Name>";
}
xml += "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
+ "<ram:IssueDateTime>" + DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
+ buildNotes(trans)
+ "</rsm:ExchangedDocument>"
+ "<rsm:SupplyChainTradeTransaction>";
int lineID = 0;
@@ -662,8 +661,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((trans.getCreditorReferenceID() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
xml += "<ram:CreditorReferenceID>" + XMLTools.encodeXML(trans.getCreditorReferenceID()) + "</ram:CreditorReferenceID>";
}
if ((trans.getNumber() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
xml += "<ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>";
if ((trans.getPaymentReference() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
xml += "<ram:PaymentReference>" + XMLTools.encodeXML(trans.getPaymentReference()) + "</ram:PaymentReference>";
}
xml += "<ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>";
if (this.trans.getPayee() != null) {
@@ -744,12 +743,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
"<udt:Indicator>true</udt:Indicator>" +
"</ram:ChargeIndicator>" +
"<ram:ActualAmount>" + currencyFormat(charge.getTotalAmount(calc)) + "</ram:ActualAmount>";
if (charge.getReason() != null) {
xml += "<ram:Reason>" + XMLTools.encodeXML(charge.getReason()) + "</ram:Reason>";
}
if (charge.getReasonCode() != null) {
xml += "<ram:ReasonCode>" + charge.getReasonCode() + "</ram:ReasonCode>";
}
if (charge.getReason() != null) {
xml += "<ram:Reason>" + XMLTools.encodeXML(charge.getReason()) + "</ram:Reason>";
}
xml += "<ram:CategoryTradeTax>" +
"<ram:TypeCode>VAT</ram:TypeCode>" +
"<ram:CategoryCode>" + charge.getCategoryCode() + "</ram:CategoryCode>";

View File

@@ -288,6 +288,7 @@ public class ZUGFeRDInvoiceImporter {
public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseException {
String number = "";
String documentName = null;
String typeCode = null;
String deliveryPeriodStart = null;
String deliveryPeriodEnd = null;
@@ -496,6 +497,9 @@ public class ZUGFeRDInvoiceImporter {
if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) {
number = XMLTools.trimOrNull(item);
}
if ((item.getLocalName() != null) && (item.getLocalName().equals("Name"))) {
documentName = XMLTools.trimOrNull(item);
}
if ((item.getLocalName() != null) && (item.getLocalName().equals("TypeCode"))) {
typeCode = XMLTools.trimOrNull(item);
}
@@ -556,13 +560,13 @@ public class ZUGFeRDInvoiceImporter {
}
zpp.addNotes(includedNotes);
String rootNode = extractString("local-name(/*)");
if (rootNode.equals("Invoice")||rootNode.equals("CreditNote")) {
if (rootNode.equals("Invoice") || rootNode.equals("CreditNote")) {
// UBL...
// //*[local-name()="Invoice" or local-name()="CreditNote"]
number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").trim();
typeCode = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"InvoiceTypeCode\"]").trim();
String issueDateStr = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"IssueDate\"]").trim();
if (issueDateStr.length()>0) {
if (issueDateStr.length() > 0) {
issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(issueDateStr);
}
String dueDt = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"]").trim();
@@ -651,7 +655,7 @@ public class ZUGFeRDInvoiceImporter {
zpp.setCurrency(currency);
String paymentTermsDescription = extractString("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"Description\"]|//*[local-name()=\"PaymentTerms\"]/*[local-name()=\"Note\"]");
if ((paymentTermsDescription!=null)&&(!paymentTermsDescription.isEmpty())) {
if ((paymentTermsDescription != null) && (!paymentTermsDescription.isEmpty())) {
zpp.setPaymentTermDescription(paymentTermsDescription);
}
@@ -668,6 +672,12 @@ public class ZUGFeRDInvoiceImporter {
NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes();
for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) {
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("PaymentReference"))) {
String paymentReference = headerTradeSettlementChilds.item(settlementChildIndex).getTextContent();
zpp.setPaymentReference(paymentReference);
}
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradePaymentTerms"))) {
NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
@@ -802,7 +812,7 @@ public class ZUGFeRDInvoiceImporter {
}
zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode);
zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentName(documentName).setDocumentCode(typeCode);
if ((directDebitMandateID != null) && (IBAN != null)) {
DirectDebit d = new DirectDebit(IBAN, directDebitMandateID);
@@ -848,15 +858,14 @@ public class ZUGFeRDInvoiceImporter {
Node currentItemNode = nodes.item(i);
ReferencedDocument doc = ReferencedDocument.fromNode(currentItemNode);
if (doc != null
&& (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID())
|| !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime())))
{
if (doc != null
&& (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID())
|| !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime()))) {
zpp.addInvoiceReferencedDocument(doc);
}
}
}
zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim());
String rounding = extractString("//*[local-name()=\"SpecifiedTradeSettlementHeaderMonetarySummation\"]/*[local-name()=\"RoundingAmount\"]|//*[local-name()=\"LegalMonetaryTotal\"]/*[local-name()=\"Party\"]/*[local-name()=\"PayableRoundingAmount\"]");
@@ -890,7 +899,7 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"AttachmentBinaryObject\"]|//*[local-name()=\"EmbeddedDocumentBinaryObject\"]");
NodeList attachmentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < attachmentNodes.getLength(); i++) {
FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getMimeDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
zpp.embedFileInXML(fa);
// filename = "Aufmass.png" mimeCode = "image/png"
//EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png"
@@ -976,6 +985,38 @@ public class ZUGFeRDInvoiceImporter {
}
}
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"SpecifiedLogisticsServiceCharge\"]");// UBL unknown
chargeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < chargeNodes.getLength(); i++) {
NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes();
String chargeAmount = null;
String taxPercent = null;
for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) {
String chargeChildName = chargeNodeChilds.item(chargeChildIndex).getLocalName();
if (chargeChildName != null) {
if (chargeChildName.equals("AppliedAmount")) {
chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("AppliedTradeTax")) {
NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
String taxItemName = taxChilds.item(taxChildIndex).getLocalName();
if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent"))) {
taxPercent = XMLTools.trimOrNull(taxChilds.item(taxChildIndex));
}
}
}
}
//appliedAmount
//AppliedTradeTax
}
if (chargeAmount != null) {
Charge c = new Charge(new BigDecimal(chargeAmount));
if (taxPercent != null) {
c.setTaxPercent(new BigDecimal(taxPercent));
}
zpp.addCharge(c);
}
}
TransactionCalculator tc = new TransactionCalculator(zpp);
@@ -1040,7 +1081,7 @@ public class ZUGFeRDInvoiceImporter {
} else if (rootNode.equals("Invoice")) {
return EStandard.ubl;
} else if (rootNode.equals("CreditNote")) {
return EStandard.ubl;
return EStandard.ubl_creditnote;
} else if (rootNode.equals("CrossIndustryInvoice")) {
return EStandard.facturx;
} else if (rootNode.equals("SCRDMCCBDACIDAMessageStructure")) {
@@ -1085,11 +1126,17 @@ public class ZUGFeRDInvoiceImporter {
*
* @return the file attachments embedded in XML (using base64) decoded as byte array,
* for PDF embedded files in FX use getFileAttachmentsPDF()
* may return empty array
* @deprecated use invoice.getAdditionalReferencedDocuments
*/
@Deprecated
public List<FileAttachment> getFileAttachmentsXML() {
return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
if (importedInvoice.getAdditionalReferencedDocuments()!=null) {
return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
} else {
return new ArrayList<>();
}
}
/***

View File

@@ -45,6 +45,9 @@ import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class ZUGFeRDVisualizer {
@@ -254,16 +257,61 @@ public class ZUGFeRDVisualizer {
// the writing part
File XMLinputFile = new File(xmlFilename);
String result = null;
String fopInput = null;
/* remove file endings so that tests can also pass after checking
out from git with arbitrary options (which may include CSRF changes)
*/
try {
result = this.toFOP(XMLinputFile.getAbsolutePath());
fopInput = this.toFOP(XMLinputFile.getAbsolutePath());
} catch (TransformerException | IOException e) {
LOGGER.error("Failed to apply FOP", e);
}
toPDFfromFOP(fopInput, () -> {
try {
return new FileOutputStream(pdfFilename);
} catch (FileNotFoundException e) {
LOGGER.error("Failed to create PDF", e);
}
return null;
}, (OutputStream out) -> {});
}
public byte[] toPDF(String xmlContent) {
String fopInput = null;
/* remove file endings so that tests can also pass after checking
out from git with arbitrary options (which may include CSRF changes)
*/
try {
ByteArrayInputStream fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));
EStandard theStandard = findOutStandardFromRootNode(fis);
fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-(
fopInput = toFOP(fis, theStandard);
} catch (TransformerException | IOException e) {
LOGGER.error("Failed to apply FOP", e);
}
AtomicReference<byte[]> byteHolder = new AtomicReference<>();
ByteArrayOutputStream os = new ByteArrayOutputStream();
toPDFfromFOP(fopInput, () -> new BufferedOutputStream(os), (OutputStream out) -> {
try {
out.flush();
} catch (IOException e) {
LOGGER.error("Failed to create PDF", e);
}
byteHolder.set(os.toByteArray());
});
return byteHolder.get();
}
private void toPDFfromFOP(String fopInput, Supplier<OutputStream> outputStreamDelegate, Consumer<OutputStream> consumerDelegate) {
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg = null;
@@ -291,7 +339,7 @@ public class ZUGFeRDVisualizer {
// Step 2: Set up output stream.
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFilename))) {
try (OutputStream out = new BufferedOutputStream(outputStreamDelegate.get())) {
// Step 3: Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);
@@ -302,13 +350,15 @@ public class ZUGFeRDVisualizer {
// Step 5: Setup input and output for XSLT transformation
// Setup input stream
Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)));
Source src = new StreamSource(new ByteArrayInputStream(fopInput.getBytes(StandardCharsets.UTF_8)));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Step 6: Start XSLT transformation and FOP processing
transformer.transform(src, res);
consumerDelegate.accept(out);
} catch (FOPException | IOException | TransformerException e) {
LOGGER.error("Failed to create PDF", e);

View File

@@ -28,6 +28,14 @@
<xsl:text>red</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="xml_result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:text>Das XML ist valide.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:text>Das XML ist nicht valide.</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="pdf_result_color">
<xsl:if test="/validation/pdf/summary/@status = 'valid'">
<xsl:text>green</xsl:text>
@@ -37,18 +45,26 @@
</xsl:if>
</xsl:variable>
<xsl:variable name="pdf_result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:if test="/validation/pdf/summary/@status = 'valid'">
<xsl:text>Das ZUGFeRD-PDF ist valide.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:if test="/validation/pdf/summary/@status = 'invalid'">
<xsl:text>Das ZUGFeRD-PDF ist nicht valide.</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="result_color">
<xsl:if test="/validation/summary/@status = 'valid'">
<xsl:text>green</xsl:text>
</xsl:if>
<xsl:if test="/validation/summary/@status = 'invalid'">
<xsl:text>red</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:if test="/validation/summary/@status = 'valid'">
<xsl:text>Es wird empfohlen, das Dokument anzunehmen und es weiterzuverarbeiten.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:if test="/validation/summary/@status = 'invalid'">
<xsl:text>Es wird empfohlen, das Dokument zurückzuweisen.</xsl:text>
</xsl:if>
</xsl:variable>
@@ -118,6 +134,7 @@
</fo:table-body>
</fo:table>
<xsl:apply-templates select="./pdf"/>
<xsl:apply-templates select="./xml"/>
<!--
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
@@ -130,7 +147,7 @@
<xsl:with-param name="text"
select="concat('Bewertung: ', $result_text)"/>
<xsl:with-param name="color"
select="$xml_result_color"/>
select="$result_color"/>
</xsl:call-template>
<fo:block>Validierungsergebnisse im Detail:</fo:block>
<fo:table>
@@ -165,8 +182,8 @@
page-break-before="auto"
page-break-inside="avoid">
<xsl:choose>
<xsl:when test="./xml/messages">
<xsl:apply-templates select="./xml/messages"/>
<xsl:when test="./pdf/messages|./xml/messages|./messages">
<xsl:apply-templates select="./pdf/messages|./xml/messages|./messages"/>
</xsl:when>
<xsl:otherwise>
<fo:table-row border-style="solid"
@@ -185,10 +202,10 @@
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="notice|warning|error">
<xsl:template match="notice|warning|error|exception|fatal">
<xsl:variable name="msg_color">
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:when test="name() = 'error' or name() = 'exception' or name() = 'fatal'">
<xsl:text>red</xsl:text>
</xsl:when>
<xsl:when test="name() = 'warning'">
@@ -201,7 +218,7 @@
</xsl:variable>
<xsl:variable name="msg_label">
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:when test="name() = 'error' or name() = 'exception' or name() = 'fatal'">
<xsl:text>Fehler</xsl:text>
</xsl:when>
<xsl:when test="name() = 'warning'">
@@ -291,7 +308,15 @@
<xsl:with-param name="text"
select="concat('ZUGFeRD-PDF: ', $pdf_result_text)"/>
<xsl:with-param name="color"
select="'black'"/>
select="$pdf_result_color"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="xml">
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select="concat('E-Rechnung XML: ', $xml_result_text)"/>
<xsl:with-param name="color"
select="$xml_result_color"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="SubHeader">