Merge branch 'ZUGFeRD:master' into fix-hyphenation

This commit is contained in:
Adrian-Devries
2025-01-10 11:24:27 +01:00
committed by GitHub
11 changed files with 323 additions and 207 deletions

View File

@@ -8,7 +8,14 @@ allow to add includedNotes with type
- 631 multiple invoice referenced documents
- 629
- 630 #296 #565
-
- 657
- 658
- 648
- 651
- 652
- -620
- 653
- 654
2.15.2
=======

View File

@@ -1,38 +1,36 @@
<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
<then>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender" >
<!--<appender name="FILE" class="org.mustangproject.commandline.LazyRollingFileAppender" >-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover -->
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
<!-- Keep 5 years worth of history -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</then>
</if>
<!-- Configure so that it outputs to both console and log file -->
<root level="INFO">
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
<then>
<appender-ref ref="FILE" />
</then>
</if>
<appender-ref ref="STDERR" />
</root>
</configuration>
<configuration>
<appender name="STDERR"
class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
<then>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover -->
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
<!-- Keep 5 years worth of history -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</then>
</if>
<!-- Configure so that it outputs to both console and log file -->
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
<then>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</then>
</if>
<root level="INFO">
<appender-ref ref="STDERR"/>
</root>
</configuration>

View File

@@ -114,7 +114,9 @@ public class Contact implements IZUGFeRDExportableContact {
if (currentItemNode.getLocalName() != null) {
if (currentItemNode.getLocalName().equals("PersonName")/*CII*/||currentItemNode.getLocalName().equals("Name")/*UBL*/) {
setName(currentItemNode.getFirstChild().getNodeValue());
if (currentItemNode.getFirstChild()!=null) {
setName(currentItemNode.getFirstChild().getNodeValue());
}
}
if (currentItemNode.getLocalName().equals("TelephoneUniversalCommunication")) { /*CII*/
NodeList tel = currentItemNode.getChildNodes();

View File

@@ -172,6 +172,32 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAsNodeMap("ApplicableTradeTax")
.flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent"))
.ifPresent(product::setVATPercent);
icnm.getAsNodeMap("SpecifiedTradeAllowanceCharge").ifPresent(stac -> {
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> {
String isChargeString=ci.getAsString("Indicator").get();
String percentString=stac.getAsStringOrNull("CalculationPercent");
String amountString=stac.getAsStringOrNull("ActualAmount");
String reason=stac.getAsStringOrNull("Reason");
Charge izac= new Charge();
if (isChargeString.equalsIgnoreCase("false")) {
izac = new Allowance();
} else {
izac = new Charge();
}
if (amountString!=null) {
izac.setTotalAmount(new BigDecimal(amountString));
}
izac.setPercent(new BigDecimal(percentString));
izac.setReason(reason);
if (isChargeString.equalsIgnoreCase("false")) {
addAllowance(izac);
} else {
addCharge(izac);
}
});
});
if (recalcPrice && !BigDecimal.ZERO.equals(quantity)) {
icnm.getAsNodeMap("SpecifiedTradeSettlementLineMonetarySummation")

View File

@@ -55,7 +55,7 @@ public class LineCalculator {
BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0
? BigDecimal.ONE.setScale(4)
: currentItem.getBasisQuantity();
itemTotalNetAmount = quantity.multiply(getPrice()).divide(basisQuantity, 18, RoundingMode.HALF_UP)
itemTotalNetAmount = quantity.multiply(price).divide(basisQuantity, 18, RoundingMode.HALF_UP)
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
}

View File

@@ -737,7 +737,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
if (profile == Profiles.getByName("XRechnung")) {
if ((profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")) || (profile == Profiles.getByName("EXTENDED"))) {
for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
"<ram:ChargeIndicator>" +

View File

@@ -897,7 +897,7 @@ public class ZUGFeRDInvoiceImporter {
// be read,
// so the invoice remains arithmetically correct
// -> parse document level charges+allowances
xpr = xpath.compile("//*[local-name()=\"SpecifiedTradeAllowanceCharge\"]|//*[local-name()=\"AllowanceCharge\"]");//CII and UBL
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"SpecifiedTradeAllowanceCharge\"]|/*[local-name()=\"AllowanceCharge\"]");//CII and UBL
NodeList chargeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < chargeNodes.getLength(); i++) {
NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes();

View File

@@ -1,33 +1,37 @@
<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
<then>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover -->
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
<!-- Keep 5 years worth of history -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</then>
</if>
<!-- Configure so that it outputs to both console and log file -->
<root level="INFO">
<appender-ref ref="FILE"/>
<appender-ref ref="STDERR"/>
</root>
</configuration>
<configuration>
<appender name="STDERR"
class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
<then>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover -->
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
<!-- Keep 5 years worth of history -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</then>
</if>
<!-- Configure so that it outputs to both console and log file -->
<if condition='property("FILE_APPENDER_ENABLED").contains("true")'>
<then>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</then>
</if>
<root level="INFO">
<appender-ref ref="STDERR"/>
</root>
</configuration>

View File

@@ -9,11 +9,11 @@
<xsl:import href="common-xr.xsl"/>
<xsl:import href="xr-pdf/lib/konstanten.xsl"/>
<!--
FO engine used can be specified.
Specific extensions will be then enabled.
Supported values are:
axf - Antenna House XSL Formatter
fop - Apache FOP
FO engine used can be specified.
Specific extensions will be then enabled.
Supported values are:
axf - Antenna House XSL Formatter
fop - Apache FOP
-->
<xsl:param name="foengine"/>
<xsl:param name="axf.extensions"
@@ -46,7 +46,7 @@
</xsl:variable>
<xsl:variable name="result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:text>Es wird empfohlen, das Dokument anzunehmen und weiterzuverarbeiten.</xsl:text>
<xsl:text>Es wird empfohlen, das Dokument anzunehmen und es weiterzuverarbeiten.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:text>Es wird empfohlen, das Dokument zurückzuweisen.</xsl:text>
@@ -71,47 +71,59 @@
</fo:block>
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select="&#34;Angaben zum geprüften Dokument&#34;"/>
select="'Angaben zum geprüften Dokument'"/>
<xsl:with-param name="color"
select="&#34;black&#34;"/>
select="'black'"/>
</xsl:call-template>
<fo:block>
<fo:block text-align="justify">
<fo:float float="right">
<fo:block>
<xsl:value-of select="/validation/@filename"/>
</fo:block>
</fo:float>
<xsl:text>Referenz:</xsl:text>
</fo:block>
</fo:block>
<fo:block>
<fo:block text-align="justify">
<fo:float float="right">
<fo:block>
<xsl:value-of select="/validation/@datetime"/>
</fo:block>
</fo:float>
<xsl:text>Zeitpunkt der Prüfung:</xsl:text>
</fo:block>
</fo:block>
<fo:block>
<fo:block text-align="justify">
<fo:float float="right">
<fo:block>
<xsl:value-of select="/validation/xml/info/profile"/>
</fo:block>
</fo:float>
<xsl:text>Erkannter Dokumenttyp:</xsl:text>
</fo:block>
</fo:block>
<xsl:apply-templates select="/validation/pdf"/>
<fo:table>
<fo:table-column border-style="none"/>
<fo:table-column column-width="70%"
border-style="none"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block text-align="left">Referenz:</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block text-align="right">
<xsl:value-of select="./@filename"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block text-align="left">Zeitpunkt der Prüfung:</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block text-align="right">
<xsl:value-of select="./@datetime"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block text-align="left">Erkannter Dokumenttyp:</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block text-align="right">
<xsl:call-template name="EnableLineBreaks">
<xsl:with-param name="text"
select="./xml/info/profile"/>
<xsl:with-param name="separator"
select="'#'"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<xsl:apply-templates select="./pdf"/>
<!--
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select='"Konformitätsprüfung:"'/>
select=="'Konformitätsprüfung:'"/>
<xsl:with-param name="color"
select='"black"'/>
select=="'black'"/>
</xsl:call-template>
-->
<xsl:call-template name="SubHeader">
@@ -125,35 +137,44 @@
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<fo:table-column column-width="70%"
border-style="solid"/>
<fo:table-column border-style="solid"
column-width="68%"/>
<fo:table-header>
<fo:table-row background-color="#E0E0E0"
font-weight="bold">
font-weight="bold"
border-style="solid">
<fo:table-cell>
<fo:block>Type</fo:block>
<fo:block margin="0mm"
padding="1mm">Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Code</fo:block>
<fo:block margin="0mm"
padding="1mm">Code</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Schwere</fo:block>
<fo:block margin="0mm"
padding="1mm">Schwere</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Text</fo:block>
<fo:block margin="0mm"
padding="1mm">Text</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-body page-break-after="auto"
page-break-before="auto"
page-break-inside="avoid">
<xsl:choose>
<xsl:when test="/validation/xml/messages">
<xsl:apply-templates select="/validation/xml/messages"/>
<xsl:when test="./xml/messages">
<xsl:apply-templates select="./xml/messages"/>
</xsl:when>
<xsl:otherwise>
<fo:table-row font-size="12px"
border-style="solid">
<fo:table-row border-style="solid"
font-size="12px">
<fo:table-cell number-columns-spanned="4">
<fo:block text-align="center">Es gibt weder Hinweise noch Fehler.</fo:block>
<fo:block margin="0mm"
padding="1mm"
text-align="center">Es gibt keine Hinweise, Warnungen oder Fehler.</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:otherwise>
@@ -164,62 +185,113 @@
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="notice|error">
<fo:table-row font-size="12px"
border-style="solid">
<fo:table-cell number-rows-spanned="2">
<fo:block>
<xsl:value-of select="@type"/>
</fo:block>
</fo:table-cell>
<fo:table-cell number-rows-spanned="2">
<fo:block>
<xsl:call-template name="SUBID">
<xsl:with-param name="myparam"
select="substring-after(.,' [ID ')"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
<fo:table-cell number-rows-spanned="2">
<fo:block>
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:attribute name="color">red</xsl:attribute>
<xsl:text>Fehler</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>Hinweis</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:template match="notice|warning|error">
<xsl:variable name="msg_color">
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:text>red</xsl:text>
</xsl:when>
<xsl:when test="name() = 'warning'">
<xsl:text>orange</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>black</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="msg_label">
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:text>Fehler</xsl:text>
</xsl:when>
<xsl:when test="name() = 'warning'">
<xsl:text>Warnung</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>Hinweis</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="msg_text">
<xsl:choose>
<xsl:when test="contains(., ' [ID ')">
<xsl:value-of select="substring-before(., ' [ID')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="rows-spanned">
<xsl:choose>
<xsl:when test="./@location">
<xsl:value-of select="'2'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'1'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<fo:table-row border-style="solid"
font-size="12px"
keep-with-previous="auto"
keep-with-next="always">
<fo:table-cell number-rows-spanned="{$rows-spanned}">
<fo:block margin="0mm"
padding="1mm">
<xsl:value-of select="./@type"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:if test="name() = 'error'">
<xsl:attribute name="color">red</xsl:attribute>
</xsl:if>
<xsl:value-of select="substring-before(.,' [ID')"/>
<fo:block margin="0mm"
padding="1mm">
<xsl:value-of select="substring-before(substring-after(., ' [ID '), ']')"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row font-size="10px"
border-style="solid">
<fo:table-cell>
<fo:block>
<xsl:if test="name() = 'error'">
<xsl:attribute name="color">red</xsl:attribute>
</xsl:if>
<xsl:value-of select="concat('Pfad: ', @location)"/>
<fo:block color="{$msg_color}"
margin="0mm"
padding="1mm">
<xsl:value-of select="$msg_label"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block color="{$msg_color}"
margin="0mm"
padding="1mm">
<xsl:value-of select="$msg_text"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:if test="./@location">
<fo:table-row border-style="solid"
font-size="8px"
keep-with-previous="always"
keep-with-next="auto">
<fo:table-cell number-columns-spanned="3">
<fo:block color="{$msg_color}"
margin="0mm"
padding="1mm">
<fo:block font-size="12px">
<xsl:value-of select="'Pfad: '"/>
</fo:block>
<xsl:call-template name="EnableLineBreaks">
<xsl:with-param name="text"
select="./@location"/>
<xsl:with-param name="separator"
select="'/'"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:if>
</xsl:template>
<xsl:template match="pdf">
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select="concat('ZUGFeRD-PDF: ', $pdf_result_text)"/>
<xsl:with-param name="color"
select="&#34;black&#34;"/>
select="'black'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="SubHeader">
@@ -234,10 +306,22 @@
<xsl:value-of select="$text"/>
</fo:block>
</xsl:template>
<xsl:template name="SUBID">
<xsl:param name="myparam"/>
<xsl:variable name="myparam.end"
select="substring-before($myparam, ']')"/>
<xsl:value-of select="$myparam.end"/>
<xsl:template name="EnableLineBreaks">
<xsl:param name="text"/>
<xsl:param name="separator"/>
<xsl:for-each select="tokenize($text, $separator)">
<xsl:choose>
<xsl:when test="position() eq 1">
<fo:block>
<xsl:value-of select="."/>
</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block>
<xsl:value-of select="concat($separator, .)"/>
</fo:block>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@@ -40,7 +40,6 @@ import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -103,6 +102,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
public void testInvoiceImportUBL() {

View File

@@ -1,30 +1,25 @@
<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover -->
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
<!-- Keep 5 years worth of history -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Configure so that it outputs to both console and log file -->
<root level="INFO">
<appender-ref ref="FILE" />
<!-- appender-ref ref="STDERR" /-->
</root>
</configuration>
<configuration>
<appender name="STDERR"
class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover -->
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
<!-- Keep 5 years worth of history -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Configure so that it outputs to both console and log file -->
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</configuration>