Merge remote-tracking branch 'mustang-master/master' into forked-master

# Conflicts:
#	library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java
This commit is contained in:
Sebastian Sieber
2024-12-20 09:01:31 +01:00
22 changed files with 1468 additions and 1292 deletions

View File

@@ -1,8 +1,14 @@
2.15.2
=======
2024-12-19
- correcly write charge reason codes also for non-Xrechnung #617
- correctly import additional referenced documents into invoice/corrected setting of attachments from jackson
- corrected parseException structure
- allow 1p0 as potential xmp version number
- #618 import BT-20
- #599 add tax category code for free export
- #600 Fixes a problem where a stream was not safely closed
2.15.1
=======

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
@@ -12,7 +12,7 @@
should also work for XRechnung/CII.
</name>
<packaging>jar</packaging>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.compilerVersion>11</maven.compiler.compilerVersion>
@@ -23,7 +23,7 @@
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
-->

View File

@@ -3,13 +3,13 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT
@@ -200,21 +200,51 @@
</manifest>
<manifestSections>
<manifestSection>
<name>FreeSans.ttf</name>
<name>SourceSansPro-Regular.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>FreeSerif.ttf</name>
<name>SourceSansPro-It.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>Times-Bold.ttf</name>
<name>SourceSansPro-Bold.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSansPro-BoldIt.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-Regular.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-It.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-Bold.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-BoldIt.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
</manifestSections>

View File

@@ -83,8 +83,9 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
}
protected byte[] filenameToByteArray(String pdfFilename) throws IOException {
FileInputStream fileInputStream = new FileInputStream(pdfFilename);
return inputstreamToByteArray(fileInputStream);
try (FileInputStream fileInputStream = new FileInputStream(pdfFilename)) {
return inputstreamToByteArray(fileInputStream);
}
}
protected byte[] inputstreamToByteArray(InputStream fileInputStream) throws IOException {

View File

@@ -659,6 +659,7 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
*
* @return a List of LineItem instances
*/
@Deprecated
public List<Item> getLineItemList() {
final List<Node> nodeList = getLineItemNodes();
final List<Item> lineItemList = new ArrayList<>();

View File

@@ -1036,6 +1036,7 @@ public class ZUGFeRDInvoiceImporter {
* for PDF embedded files in FX use getFileAttachmentsPDF()
* @deprecated use invoice.getAdditionalReferencedDocuments
*/
@Deprecated
public List<FileAttachment> getFileAttachmentsXML() {
return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
}

View File

@@ -29,6 +29,7 @@ public class TaxCategoryCodeTypeConstants {
public static final String ZEROTAXPRODUCTS = "Z";
public static final String UNTAXEDSERVICE = "O";
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).collect(Collectors.toSet());
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT).collect(Collectors.toSet());
}

Binary file not shown.

Binary file not shown.

View File

@@ -22,16 +22,36 @@
<!-- etc. etc..... -->
<renderers>
<renderer mime="application/pdf">
<fonts><!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
<auto-detect/>
<font kerning="no" embed-url="classpath:FreeSans.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="normal" weight="normal" />
<font-triplet name="Times-Bold" style="normal" weight="normal" />
</font>
</fonts>
<output-profile>classpath:AdobeCompat-v2.icc</output-profile>
</renderer>
</renderers>
<renderer mime="application/pdf">
<fonts>
<!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
<auto-detect/>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-Regular.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="normal" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-It.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="italic" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-Bold.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="normal" weight="700"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-BoldIt.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="italic" weight="700"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-Regular.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="normal" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-It.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="italic" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-Bold.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="normal" weight="700"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-BoldIt.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="italic" weight="700"/>
</font>
</fonts>
<output-profile>classpath:AdobeCompat-v2.icc</output-profile>
</renderer>
</renderers>
</fop>

View File

@@ -12,7 +12,7 @@
== Schriften
=========================================================================== -->
<xsl:variable name="fontSans">SourceSerifPro</xsl:variable>
<xsl:variable name="fontSans">SourceSansPro</xsl:variable>
<xsl:variable name="fontSerif">SourceSerifPro</xsl:variable>
<xsl:variable name="amount-picture" select="xrf:_('amount-format')"/>

View File

@@ -166,11 +166,123 @@ public class DeSerializationTest extends ResourceCase {
}
public void testDeserializedFiles() {
File inputUBL = getResourceAsFile("XRECHNUNG_Elektron.ubl.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
zii.doIgnoreCalculationErrors();
Invoice i = new Invoice();
String exText = null;
try {
zii.fromXML(new String(Files.readAllBytes(inputUBL.toPath()), StandardCharsets.UTF_8));
ObjectMapper mapper = new ObjectMapper();
zii.extractInto(i);
String json = mapper.writeValueAsString(i);
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
assertEquals("181301674", i.getNumber());
assertEquals(newInvoiceFromJSON.getNumber(), i.getNumber());
assertEquals(newInvoiceFromJSON.getAdditionalReferencedDocuments()[0].getFilename(), i.getAdditionalReferencedDocuments()[0].getFilename());
assertEquals(newInvoiceFromJSON.getAdditionalReferencedDocuments().length, 2);
} catch (IOException e) {
exText = e.getMessage();
} catch (XPathExpressionException e) {
exText = e.getMessage();
} catch (ParseException e) {
exText = e.getMessage();
}
assertNull(exText);
}
public void testFileSerialization() {
String base64 = "b25ldHdvdGhyZWU=";
String json = "{\n" +
" \"additionalReferencedDocuments\": [\n" +
" {\n" +
" \"data\": \"" + base64 + "\",\n" +
" \"description\": \"Additional file attachment\",\n" +
" \"filename\": \"text.txt\",\n" +
" \"mimetype\": \"text/plain\",\n" +
" \"relation\": \"Data\"\n" +
" }\n" +
"],\n" +
"\n" +
" \"number\": \"471102\",\n" +
" \"currency\": \"EUR\",\n" +
" \"issueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"dueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"deliveryDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"sender\": {\n" +
" \"name\": \"Lieferant GmbH\",\n" +
" \"zip\": \"80333\",\n" +
" \"street\": \"Lieferantenstraße 20\",\n" +
" \"location\": \"München\",\n" +
" \"country\": \"DE\",\n" +
" \"taxID\": \"201/113/40209\",\n" +
" \"vatID\": \"DE123456789\",\n" +
" \"globalID\": \"4000001123452\",\n" +
" \"globalIDScheme\": \"0088\"\n" +
" },\n" +
" \"recipient\": {\n" +
" \"name\": \"Kunden AG Mitte\",\n" +
" \"zip\": \"69876\",\n" +
" \"street\": \"Kundenstraße 15\",\n" +
" \"location\": \"Frankfurt\",\n" +
" \"country\": \"DE\"\n" +
" },\n" +
" \"zfitems\": [\n" +
" {\n" +
" \"price\": 9.9,\n" +
" \"quantity\": 20,\n" +
" \"product\": {\n" +
" \"unit\": \"H87\",\n" +
" \"name\": \"Trennblätter A4\",\n" +
" \"description\": \"\",\n" +
" \"vatpercent\": 19,\n" +
" \"taxCategoryCode\": \"S\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"price\": 5.5,\n" +
" \"quantity\": 50,\n" +
" \"product\": {\n" +
" \"unit\": \"H87\",\n" +
" \"name\": \"Joghurt Banane\",\n" +
" \"description\": \"\",\n" +
" \"vatpercent\": 7,\n" +
" \"taxCategoryCode\": \"S\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}\n";
ObjectMapper mapper = new ObjectMapper();
try {
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(newInvoiceFromJSON);
String theXML = new String(zf2p.getXML());
assertTrue(theXML.contains("<udt:DateTimeString format=\"102\">20180304</udt:DateTimeString>"));
assertTrue(theXML.contains(base64));
} catch (Exception e) {
fail("No exception expected");
}
}
public void testFull300Roundtrip() {
File inputCII = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.cii.xml");
Invoice i=new Invoice();
String exText=null;
Invoice i = new Invoice();
String exText = null;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
zii.doIgnoreCalculationErrors();
try {
@@ -180,15 +292,15 @@ public class DeSerializationTest extends ResourceCase {
String json = mapper.writeValueAsString(i);
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
assertEquals("Test_EeISI_100",i.getNumber());
assertEquals(newInvoiceFromJSON.getNumber(),i.getNumber());
assertEquals("Test_EeISI_100", i.getNumber());
assertEquals(newInvoiceFromJSON.getNumber(), i.getNumber());
} catch (IOException e) {
exText=e.getMessage();
exText = e.getMessage();
} catch (XPathExpressionException e) {
exText=e.getMessage();
exText = e.getMessage();
} catch (ParseException e) {
exText=e.getMessage();
exText = e.getMessage();
}
assertNull(exText);

View File

@@ -62,9 +62,11 @@ public class VisualizationTest extends ResourceCase {
try {
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
result = zvi.visualize(CIIinputFile.getAbsolutePath(), lang);
Files.write(Paths.get("./target/testout-" + resultFileName), result.getBytes(StandardCharsets.UTF_8));
File expectedResult = getResourceAsFile(resultFileName);
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8);
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8)
;
} catch (UnsupportedOperationException e) {
fail("UnsupportedOperationException should not happen: " + e.getMessage());

View File

@@ -261,7 +261,7 @@ public class ZF2PushTest extends TestCase {
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1"))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("AK")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1"))))
);
@@ -807,12 +807,14 @@ public class ZF2PushTest extends TestCase {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("\\Users\\jstaerk\\temp\\1424413_anonymized.xml");
// ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("\\Users\\jstaerk\\temp\\1424413_anonymized.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(this.getClass().getResourceAsStream("/factur-x.xml"));
try {
Invoice i = zii.extractInvoice();
TransactionCalculator tc=new TransactionCalculator(i);
assertEquals(0,tc.getGrandTotal().compareTo(new BigDecimal("442.83")));
// assertEquals(0,tc.getGrandTotal().compareTo(new BigDecimal("442.83")));
assertEquals(0,tc.getGrandTotal().compareTo(new BigDecimal("571.04")));
} catch (XPathExpressionException e) {
fail("XPathExpressionException should not be raised");

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Mustang</name>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
@@ -11,7 +11,7 @@
<name>Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung)</name>
<packaging>jar</packaging>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
<repositories>
<repository>
<!-- for jargs -->
@@ -38,7 +38,7 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>library</artifactId>
<version>2.15.2-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>