Migration ZUGFeRD1->2 feature: Allowing transformation of complete input directory, with reference check for any ref file existent with line base comparison for better usability. Including several refactoring and tweaks.
This commit is contained in:
@@ -6,8 +6,7 @@
|
||||
*
|
||||
* 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. You can also
|
||||
* obtain a copy of the License at http://odftoolkit.org/docs/license.txt
|
||||
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
|
||||
196
src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java
Normal file
196
src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java
Normal file
@@ -0,0 +1,196 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*********************************************************************** */
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
|
||||
/** This test utility class is providing usability functions for test file resources */
|
||||
public class ResourceUtilities {
|
||||
private static final Logger LOG = Logger.getLogger(ResourceUtilities.class.getName());
|
||||
|
||||
/** Loading a File into a String using a certain encoding and file path */
|
||||
public static String readFile(Charset encoding, String path) throws IOException {
|
||||
byte[] content = Files.readAllBytes(Paths.get(path));
|
||||
return new String(content, encoding);
|
||||
}
|
||||
|
||||
/** Saving a String as a file to a certain file path */
|
||||
public static void saveFile(Charset encoding, String path, String content) throws FileNotFoundException {
|
||||
|
||||
// resources will be released automatically
|
||||
try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(path)), encoding), true)) {
|
||||
out.println(content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** The relative path of the test file will be resolved and the absolute will be returned
|
||||
* @param relativeFilePath Path of the test resource relative to <code>src/test/resource/</code>.
|
||||
* @return the absolute path of the test file
|
||||
* @throws FileNotFoundException If the file could not be found
|
||||
*/
|
||||
public static String getAbsolutePath(String relativeFilePath) throws FileNotFoundException {
|
||||
URI uri = null;
|
||||
try {
|
||||
uri = ResourceUtilities.class.getClassLoader().getResource(relativeFilePath).toURI();
|
||||
uri = new URI(toExternalForm(uri));
|
||||
} catch (URISyntaxException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (uri == null) {
|
||||
throw new FileNotFoundException("Could not find the file '" + relativeFilePath + "'!");
|
||||
}
|
||||
return uri.getPath();
|
||||
}
|
||||
|
||||
/** The relative path of the test file will be resolved and the absolute will be returned
|
||||
* @param relativeFilePath Path of the test resource relative to <code>src/test/resource/</code>.
|
||||
* @return the URI created based on the relativeFilePath
|
||||
* @throws URISyntaxException if no URI could be created from the given relative path
|
||||
*/
|
||||
public static URI getURI(String relativeFilePath) throws URISyntaxException {
|
||||
String filePath = "file:" + ResourceUtilities.class.getClassLoader().getResource(relativeFilePath).getPath();
|
||||
filePath = toExternalForm(new URI(filePath));
|
||||
return new URI(filePath);
|
||||
}
|
||||
|
||||
/** The relative path of the test file will be used to determine an absolute
|
||||
* path to a temporary directory in the output directory.
|
||||
* @param relativeFilePath Path of the test resource relative to <code>src/test/resource/</code>.
|
||||
* @return absolute path to a test output
|
||||
* @throws IOException if no absolute Path could be created.
|
||||
*/
|
||||
public static String getTestOutput(String relativeFilePath) throws IOException {
|
||||
return File.createTempFile(relativeFilePath, null).getAbsolutePath();
|
||||
}
|
||||
|
||||
/** The Input of the test file will be resolved and the absolute will be returned
|
||||
* @param relativeFilePath Path of the test resource relative to <code>src/test/resource/</code>.
|
||||
* @return the absolute path of the test file
|
||||
*/
|
||||
public static InputStream getTestResourceAsStream(String relativeFilePath) {
|
||||
return ResourceUtilities.class.getClassLoader().getResourceAsStream(relativeFilePath);
|
||||
}
|
||||
|
||||
/** Relative to the test output directory a test file will be returned dependent on the relativeFilePath provided.
|
||||
* @param relativeFilePath Path of the test output resource relative to <code>target/test-classes/</code>.
|
||||
* @return the empty <code>File</code> of the test output (to be filled)
|
||||
*/
|
||||
public static File newTestOutputFile(String relativeFilePath) {
|
||||
String filepath = null;
|
||||
try {
|
||||
filepath = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath() + relativeFilePath;
|
||||
} catch (URISyntaxException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return new File(filepath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the absolute path of the test output folder, which is usually <code>target/test-classes/</code>.
|
||||
*/
|
||||
public static String getTestOutputFolder() {
|
||||
String testFolder = null;
|
||||
try {
|
||||
testFolder = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath();
|
||||
} catch (URISyntaxException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return testFolder;
|
||||
}
|
||||
|
||||
public static File getTempTestDirectory() {
|
||||
File tempDir = new File(ResourceUtilities.getTestOutputFolder() + "temp");
|
||||
tempDir.mkdir(); //if it already exist no problem
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* To fix the 3 slashes bug for File URI: For example:
|
||||
* file:/C:/work/test.txt -> file:///C:/work/test.txt
|
||||
*
|
||||
* @param u - the File URI
|
||||
* @return the String of the URI
|
||||
*/
|
||||
public static String toExternalForm(URI u) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (u.getScheme() != null) {
|
||||
sb.append(u.getScheme());
|
||||
sb.append(':');
|
||||
}
|
||||
if (u.isOpaque()) {
|
||||
sb.append(u.getSchemeSpecificPart());
|
||||
} else {
|
||||
if (u.getHost() != null) {
|
||||
sb.append("//");
|
||||
if (u.getUserInfo() != null) {
|
||||
sb.append(u.getUserInfo());
|
||||
sb.append('@');
|
||||
}
|
||||
boolean needBrackets = ((u.getHost().indexOf(':') >= 0) && !u.getHost().startsWith("[") && !u.getHost().endsWith("]"));
|
||||
if (needBrackets)
|
||||
sb.append('[');
|
||||
sb.append(u.getHost());
|
||||
if (needBrackets)
|
||||
sb.append(']');
|
||||
if (u.getPort() != -1) {
|
||||
sb.append(':');
|
||||
sb.append(u.getPort());
|
||||
}
|
||||
} else if (u.getRawAuthority() != null) {
|
||||
sb.append("//");
|
||||
sb.append(u.getRawAuthority());
|
||||
} else {
|
||||
sb.append("//");
|
||||
}
|
||||
if (u.getRawPath() != null)
|
||||
sb.append(u.getRawPath());
|
||||
if (u.getRawQuery() != null) {
|
||||
sb.append('?');
|
||||
sb.append(u.getRawQuery());
|
||||
}
|
||||
}
|
||||
if (u.getFragment() != null) {
|
||||
sb.append('#');
|
||||
sb.append(u.getFragment());
|
||||
}
|
||||
String ret = null;
|
||||
try {
|
||||
ret = new URI(sb.toString()).toASCIIString();
|
||||
} catch (URISyntaxException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
private ResourceUtilities() {
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* Copyright 2018 Jochen Staerk
|
||||
*
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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. You can also
|
||||
* obtain a copy of the License at http://odftoolkit.org/docs/license.txt
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*********************************************************************** */
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class UpdateZUGFeRDTest {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(UpdateZUGFeRDTest.class.getName());
|
||||
|
||||
private static final String TEST_INPUT_NAME = "ZUGFeRD1-invoice_test-input.xml";
|
||||
private static final String TEST_OUTPUT_NAME = "ZUGFeRD2-invoice_test-output.xml";
|
||||
private static final String TEST_REF_NAME = "ZUGFeRD2-invoice_output-reference.xml";
|
||||
|
||||
private static final String TEST_INPUT_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator;
|
||||
private static final String TEST_OUTPUT_DIR = "target" + File.separator + "test-classes" + File.separator;
|
||||
|
||||
private static String readFile(Charset encoding, String path) throws IOException {
|
||||
byte[] encoded = Files.readAllBytes(Paths.get(path));
|
||||
return new String(encoded, encoding);
|
||||
}
|
||||
|
||||
private static void saveFile(String content, String path) throws FileNotFoundException {
|
||||
try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(path)), StandardCharsets.UTF_8), true)) {
|
||||
out.println(content);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMigration() {
|
||||
try {
|
||||
String tmp = new ZUGFeRDMigrator().migrateFromV1ToV2(TEST_INPUT_DIR + TEST_INPUT_NAME);
|
||||
saveFile(tmp, TEST_OUTPUT_DIR + TEST_OUTPUT_NAME);
|
||||
LOG.log(Level.INFO, "***\nZUGFeRD 2.0:\n***\n{0}", tmp);
|
||||
|
||||
// we need to save the string and reload it otherwise two bytes are missing (likely EOF related)
|
||||
String refXML = readFile(StandardCharsets.UTF_8, TEST_INPUT_DIR + TEST_REF_NAME);
|
||||
String outXML = readFile(StandardCharsets.UTF_8, TEST_OUTPUT_DIR + TEST_OUTPUT_NAME);
|
||||
int t = outXML.length();
|
||||
int r = refXML.length();
|
||||
if (t != r || !(outXML.equals(refXML))) {
|
||||
LOG.info("Please compare:"
|
||||
+ "\nZUGFeRD 2.0 Test Output: " + TEST_OUTPUT_DIR + TEST_OUTPUT_NAME
|
||||
+ "\nZUGFeRD 2.0 Test Reference: " + TEST_INPUT_DIR + TEST_REF_NAME);
|
||||
LOG.info("\n\nFile sizes:\n "
|
||||
+ "\nZUGFeRD 2.0 Test Output: " + t
|
||||
+ "\nZUGFeRD 2.0 Test Reference: " + r);
|
||||
Assert.fail("Version update failed, as test result and reference are different!");
|
||||
}else{
|
||||
LOG.log(Level.INFO, "***\nZUGFeRD 2.0 invoice:\n***\n{0}", outXML);
|
||||
}
|
||||
} catch (IOException | TransformerException t) {
|
||||
LOG.log(Level.SEVERE, t.getMessage(), t);
|
||||
Assert.fail("Failed with " + t.getClass().getName() + ": '" + t.getMessage() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* Use is subject to license terms.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*********************************************************************** */
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
|
||||
/**
|
||||
* Every ZUGFeRD 1.0 XML file from <code>src/test/resources/migration/input</code>
|
||||
* will be migrated to <code>src/test/resources/migration/output</code>.
|
||||
* If there is a similar named file as test reference <code>src/test/resources/migration/reference</code> a test
|
||||
* will be triggered for every single file.
|
||||
*
|
||||
* Note: Any 'ZUGFeRD1' will be exchanged to 'ZUGFeRD2' during migration and adequate reference will be searched for.
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class VersionMigrationTest {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(VersionMigrationTest.class.getName());
|
||||
|
||||
private static final String INPUT_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "migration" + File.separator + "input" + File.separator;
|
||||
private static final String REFERENCE_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "migration" + File.separator + "reference" + File.separator;
|
||||
private static final String OUTPUT_DIR = "target" + File.separator + "test-classes" + File.separator + "migration" + File.separator + "output" + File.separator;
|
||||
private File mTestFile = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws Exception {
|
||||
// Creating the output directory for the tests
|
||||
new File(OUTPUT_DIR).mkdirs();
|
||||
}
|
||||
|
||||
public VersionMigrationTest(File testFile) {
|
||||
mTestFile = testFile;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters(name = "Test# {index}: {0}")
|
||||
public static Collection<Object[]> data() {
|
||||
Collection<Object[]> testSuiteData = new ArrayList<Object[]>();
|
||||
addFilesFromFolder(new File(INPUT_DIR), testSuiteData);
|
||||
return testSuiteData;
|
||||
}
|
||||
|
||||
private static void addFilesFromFolder(final File folder, Collection<Object[]> testSuiteData) {
|
||||
String filePath = null;
|
||||
for (final File fileEntry : folder.listFiles()) {
|
||||
filePath = fileEntry.getAbsolutePath();
|
||||
if (fileEntry.isDirectory()) {
|
||||
LOG.log(Level.INFO, "*** testDirectory:{0}", filePath);
|
||||
addFilesFromFolder(fileEntry, testSuiteData);
|
||||
} else {
|
||||
LOG.log(Level.INFO, "*** testFile: {0}", filePath);
|
||||
Object[] testData = new Object[]{fileEntry};
|
||||
testSuiteData.add(testData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* ZUGFeRD 1.0 to 2.0 migration test.
|
||||
* For more information see class description. */
|
||||
public void testFile() {
|
||||
testMigration(mTestFile.getName());
|
||||
}
|
||||
|
||||
private void testMigration(String fileName) {
|
||||
try {
|
||||
String tmp = new ZUGFeRDMigrator().migrateFromV1ToV2(INPUT_DIR + fileName);
|
||||
String newName = fileName.replace("ZUGFeRD1", "ZUGFeRD2");
|
||||
ResourceUtilities.saveFile(StandardCharsets.UTF_8, OUTPUT_DIR + newName, tmp);
|
||||
if(new File(REFERENCE_DIR + newName).exists()){
|
||||
// we need to save the string and reload it otherwise two bytes are missing (likely EOF related)
|
||||
String outXML = ResourceUtilities.readFile(StandardCharsets.UTF_8, OUTPUT_DIR + newName);
|
||||
String refXML = ResourceUtilities.readFile(StandardCharsets.UTF_8, REFERENCE_DIR + newName);
|
||||
int t = outXML.length();
|
||||
int r = refXML.length();
|
||||
if (t != r || !(outXML.equals(refXML))) {
|
||||
LOG.info("There are differences between:"
|
||||
+ "\nZUGFeRD 2.0 Test Output @ " + OUTPUT_DIR + newName
|
||||
+ "\nZUGFeRD 2.0 Test Reference @ " + REFERENCE_DIR + newName);
|
||||
LOG.info("\n\nFile sizes:\n "
|
||||
+ "\nZUGFeRD 2.0 Test Output character count: " + t
|
||||
+ "\nZUGFeRD 2.0 Test Refer. character count: " + r);
|
||||
findLineDiffs(outXML, refXML);
|
||||
Assert.fail("Version update failed, as test result and reference are different!");
|
||||
}else{
|
||||
LOG.log(Level.INFO,"\n*** Tested successfull migration from ZUGFeRD 1.0 to 2.0: '" + newName + "'' ***\n", OUTPUT_DIR);
|
||||
}
|
||||
}else{
|
||||
LOG.log(Level.INFO,"\n*** Migrated from ZUGFeRD 1.0 to 2.0 invoice: '" + newName + "'' ***\n", OUTPUT_DIR);
|
||||
}
|
||||
} catch (IOException | TransformerException t) {
|
||||
LOG.log(Level.SEVERE, t.getMessage(), t);
|
||||
Assert.fail("Failed with " + t.getClass().getName() + ": '" + t.getMessage() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void findLineDiffs(String outXML, String refXML){
|
||||
Scanner outScanner = new Scanner(outXML);
|
||||
Scanner refScanner = new Scanner(refXML);
|
||||
String outLine = null;
|
||||
String refLine = null;
|
||||
while (outScanner.hasNextLine() && refScanner.hasNextLine()) {
|
||||
outLine = outScanner.nextLine();
|
||||
refLine = refScanner.nextLine();
|
||||
if(!outLine.equals(refLine)){
|
||||
LOG.info("First line difference between reference and output file:" +
|
||||
"\nRefLine: " + refLine +
|
||||
"\nOutLine: " + outLine + "\n");
|
||||
}
|
||||
}
|
||||
refScanner.close();
|
||||
outScanner.close();
|
||||
}
|
||||
}
|
||||
197
src/test/resources/migration/input/ZUGFeRD1-invoice-adjusted.xml
Normal file
197
src/test/resources/migration/input/ZUGFeRD1-invoice-adjusted.xml
Normal file
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<rsm:CrossIndustryDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15" xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0">
|
||||
<rsm:SpecifiedExchangedDocumentContext>
|
||||
<ram:TestIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:TestIndicator>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:ferd:CrossIndustryDocument:invoice:1p0:extended</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:SpecifiedExchangedDocumentContext>
|
||||
<rsm:HeaderExchangedDocument>
|
||||
<ram:ID>RE-20170509/506</ram:ID>
|
||||
<ram:Name>RECHNUNG2</ram:Name>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20170510</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
</rsm:HeaderExchangedDocument>
|
||||
<rsm:SpecifiedSupplyChainTradeTransaction>
|
||||
<ram:ApplicableSupplyChainTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:Name>Bei Spiel GmbH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12345</ram:PostcodeCode>
|
||||
<ram:LineOne>Ecke 12</ram:LineOne>
|
||||
<ram:CityName>Stadthausen</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="FC">22/815/0815/4</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE136695976</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:Name>Theodor Est</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>88802</ram:PostcodeCode>
|
||||
<ram:LineOne>Bahnstr. 42</ram:LineOne>
|
||||
<ram:CityName>Spielkreis</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE999999999</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:BuyerTradeParty>
|
||||
</ram:ApplicableSupplyChainTradeAgreement>
|
||||
<ram:ApplicableSupplyChainTradeDelivery>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20170507</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
</ram:ApplicableSupplyChainTradeDelivery>
|
||||
<ram:ApplicableSupplyChainTradeSettlement>
|
||||
<ram:PaymentReference>RE-20170509/505</ram:PaymentReference>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:TypeCode>42</ram:TypeCode>
|
||||
<ram:Information>Überweisung</ram:Information>
|
||||
<ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:IBANID>DE88 2008 0000 0970 3757 00</ram:IBANID>
|
||||
</ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||
<ram:BICID>COBADEFFXXX</ram:BICID>
|
||||
<ram:Name>Commerzbank</ram:Name>
|
||||
</ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount currencyID="EUR">11.20</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount currencyID="EUR">160.00</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:ApplicablePercent>7.00</ram:ApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount currencyID="EUR">63.84</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount currencyID="EUR">336.00</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:ApplicablePercent>19.00</ram:ApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Zahlbar ohne Abzug bis zum 30.05.2017</ram:Description>
|
||||
<ram:DueDateDateTime>
|
||||
<udt:DateTimeString format="102">20170530</udt:DateTimeString>
|
||||
</ram:DueDateDateTime>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">496.00</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount currencyID="EUR">0.00</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount currencyID="EUR">0.00</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount currencyID="EUR">496.00</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">75.04</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount currencyID="EUR">571.04</ram:GrandTotalAmount>
|
||||
<ram:DuePayableAmount currencyID="EUR">571.04</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
</ram:ApplicableSupplyChainTradeSettlement>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedSupplyChainTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedSupplyChainTradeAgreement>
|
||||
<ram:SpecifiedSupplyChainTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="HUR">1.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedSupplyChainTradeDelivery>
|
||||
<ram:SpecifiedSupplyChainTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:ApplicablePercent>7.00</ram:ApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">160.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
</ram:SpecifiedSupplyChainTradeSettlement>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Künstlerische Gestaltung (Stunde): Einer weiteren Beispielrechnung</ram:Name>
|
||||
<ram:Description></ram:Description>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>2</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedSupplyChainTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedSupplyChainTradeAgreement>
|
||||
<ram:SpecifiedSupplyChainTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="C62">400.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedSupplyChainTradeDelivery>
|
||||
<ram:SpecifiedSupplyChainTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:ApplicablePercent>19.00</ram:ApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">316.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
</ram:SpecifiedSupplyChainTradeSettlement>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Luftballon: Bunt, ca. 500ml</ram:Name>
|
||||
<ram:Description></ram:Description>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>3</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedSupplyChainTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedSupplyChainTradeAgreement>
|
||||
<ram:SpecifiedSupplyChainTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="LTR">200.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedSupplyChainTradeDelivery>
|
||||
<ram:SpecifiedSupplyChainTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:ApplicablePercent>19.00</ram:ApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">20.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementMonetarySummation>
|
||||
</ram:SpecifiedSupplyChainTradeSettlement>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Heiße Luft pro Liter</ram:Name>
|
||||
<ram:Description></ram:Description>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
</rsm:SpecifiedSupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryDocument>
|
||||
Reference in New Issue
Block a user