Skip to content

Commit

Permalink
impl
Browse files Browse the repository at this point in the history
Issue  #215
  • Loading branch information
rsoika committed Nov 3, 2024
1 parent 65e99ad commit d8d3482
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 186 deletions.
5 changes: 0 additions & 5 deletions imixs-archive-documents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,6 @@ The Adapter can be configured in an BPMN event to extract e-invoice data fields








If the type is not set the item value will be treated as a String. Possible types are 'double' and 'date'

If the document is not a e-invoice no items and also the einvoice.type field will be set.
Expand Down
8 changes: 8 additions & 0 deletions imixs-archive-documents/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@
<scope>provided</scope>
</dependency>

<!-- e-invoice mustang-->
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<classifier>shaded</classifier>
<version>2.14.2</version>
</dependency>

</dependencies>
<name>Imixs-Archive Documents</name>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public class EInvoiceAdapter implements SignalAdapter {
DocumentService documentService;

@Inject
private WorkflowService workflowService;
WorkflowService workflowService;

@Inject
SnapshotService snapshotService;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package org.imixs.archive.documents;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.logging.Logger;

import javax.xml.xpath.XPathExpressionException;

import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException;
import org.mustangproject.BankDetails;
import org.mustangproject.Invoice;
import org.mustangproject.TradeParty;
import org.mustangproject.ZUGFeRD.TransactionCalculator;
import org.mustangproject.ZUGFeRD.ZUGFeRDInvoiceImporter;

/**
* The EInvoiceAutoAdapter can detect and extract content from e-invoice
Expand Down Expand Up @@ -67,15 +77,34 @@ private void readEInvoiceContent(FileData eInvoiceFileData,
byte[] xmlData = readXMLContent(eInvoiceFileData);
logger.info("Autodetect e-invoice data...");

createXMLDoc(xmlData);
// createXMLDoc(xmlData);
try {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new ByteArrayInputStream(xmlData));

Invoice invoice = zii.extractInvoice();
workitem.setItemValue("invoice.number", invoice.getNumber());
workitem.setItemValue("cdtr.name", invoice.getOwnOrganisationName());
workitem.setItemValue("invoice.date", invoice.getIssueDate());

TransactionCalculator tc = new TransactionCalculator(invoice);
BigDecimal value = tc.getValue();
workitem.setItemValue("invoice.total.net", tc.getValue());
workitem.setItemValue("invoice.total", tc.getGrandTotal());
workitem.setItemValue("invoice.total.tax", tc.getGrandTotal().floatValue() - tc.getValue().floatValue());

readItem(workitem, "//rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:ID", "text", "invoice.number");
readItem(workitem, "//rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString/text()", "date",
"invoice.date");
readItem(workitem, "//ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:GrandTotalAmount", "double",
"invoice.total");
readItem(workitem, "//ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:Name/text()", "text",
"cdtr.name");
try {
TradeParty payee = invoice.getSender();
BankDetails bankDetails = payee.getBankDetails().get(0);
workitem.setItemValue("cdtr.bic", bankDetails.getBIC());
workitem.setItemValue("cdtr.iban", bankDetails.getIBAN());
} catch (Exception e) {
// no bank data
}

} catch (XPathExpressionException | ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.imixs.workflow.documents;
package org.imixs.archive.documents;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand All @@ -10,53 +10,71 @@
import java.util.List;
import java.util.Map;

import org.imixs.archive.documents.EInvoiceAdapter;
import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.engine.WorkflowMockEnvironment;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockitoAnnotations;
import org.openbpmn.bpmn.BPMNModel;

/**
* This test class is testing the EInvoiceAdapter and tests different
* kind of files
*
*
*/
@ExtendWith(MockitoExtension.class)
class EInvoiceAdapterTest {

@Mock
private DocumentService documentService;

@Mock
private WorkflowService workflowService;

@InjectMocks
private EInvoiceAdapter adapter;
protected EInvoiceAdapter adapter;

private ItemCollection workitem;
private ItemCollection event;
protected ItemCollection workitem;
protected ItemCollection event;
protected WorkflowMockEnvironment workflowEnvironment;
BPMNModel model = null;

@BeforeEach
void setUp() throws PluginException, ModelException {
// MockitoAnnotations.openMocks(this);
public void setUp() throws PluginException, ModelException {
// Ensures that @Mock and @InjectMocks annotations are processed
MockitoAnnotations.openMocks(this);
workflowEnvironment = new WorkflowMockEnvironment();

// register AccessAdapter Mock
workflowEnvironment.registerAdapter(adapter);

// Setup Environment
workflowEnvironment.setUp();
workflowEnvironment.loadBPMNModel("/bpmn/TestZUGFeRD.bpmn");
model = workflowEnvironment.getModelService().getModelManager().getModel("1.0.0");
adapter.workflowService = workflowEnvironment.getWorkflowService();

// prepare data
workitem = new ItemCollection().model("1.0.0").task(100);

workitem = new ItemCollection();
event = new ItemCollection();
// set test txtActivityResult....
String config = "<e-invoice name=\"READ\">\n";
config += " <item>invoice.number=//rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:ID</item>\n";
config += " <item>invoice.date=//rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:IssueDateTime</item>\n";
config += "</e-invoice>";
String config = "<e-invoice name=\"ENTITY\">\n" + //
" <name>invoice.number</name>\n" + //
" <xpath>//rsm:CrossIndustryInvoice/rsm:ExchangedDocument/ram:ID</xpath>\n" + //
"</e-invoice>\n" + //
"<e-invoice name=\"ENTITY\">\n" + //
" <name>invoice.date</name>\n" + //
" <type>date</type>\n" + //
" <xpath>//rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString/text()</xpath>\n" + //
"</e-invoice>\n" + //
"<e-invoice name=\"ENTITY\">\n" + //
" <name>invoice.total</name>\n" + //
" <type>double</type>\n" + //
" <xpath>//ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:GrandTotalAmount</xpath>\n" + //
"</e-invoice>\n" + //
"<e-invoice name=\"ENTITY\">\n" + //
" <name>cdtr.name</name>\n" + //
" <xpath>//ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:Name/text()</xpath>\n" + //
"</e-invoice>";
event.setItemValue("txtActivityResult", config);
}

Expand Down Expand Up @@ -85,6 +103,28 @@ void testExecuteWithStandaloneXML() throws AdapterException, PluginException, IO
assertEquals("Factur-X/ZUGFeRD 2.0", result);
}

/**
* This test uses the xpath expressions form teh workflow event to extract xml
* content.
*
* @throws AdapterException
* @throws PluginException
* @throws IOException
*/
@Test
void testExecuteWithStandaloneXMLExtractData() throws AdapterException, PluginException, IOException {

// Prepare test data
FileData xmlFile = createFileData("e-invoice/Rechnung_R_00010.xml", "application/xml");
workitem.addFileData(xmlFile);

adapter.execute(workitem, event);

assertEquals("R-00010", workitem.getItemValueString("invoice.number"));
assertEquals("Max Mustermann", workitem.getItemValueString("cdtr.name"));

}

@Test
void testExecuteWithZIPContainingXML() throws AdapterException, PluginException, IOException {
// Prepare test data
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.imixs.archive.documents;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;
import java.io.InputStream;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.WorkflowMockEnvironment;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.openbpmn.bpmn.BPMNModel;

/**
* This test class is testing the EInvoiceAutoAdapter and tests different
* kind of files
*
*/
class EInvoiceAutoAdapterTest {

@InjectMocks
protected EInvoiceAutoAdapter adapter;

protected ItemCollection workitem;
protected ItemCollection event;
protected WorkflowMockEnvironment workflowEnvironment;
BPMNModel model = null;

@BeforeEach
public void setUp() throws PluginException, ModelException {
// Ensures that @Mock and @InjectMocks annotations are processed
MockitoAnnotations.openMocks(this);
workflowEnvironment = new WorkflowMockEnvironment();

// register AccessAdapter Mock
workflowEnvironment.registerAdapter(adapter);

// Setup Environment
workflowEnvironment.setUp();
workflowEnvironment.loadBPMNModel("/bpmn/TestZUGFeRD.bpmn");
model = workflowEnvironment.getModelService().getModelManager().getModel("1.0.0");
adapter.workflowService = workflowEnvironment.getWorkflowService();

// prepare data
workitem = new ItemCollection().model("1.0.0").task(100);

event = new ItemCollection();

}

/**
* Simple test that extracts the invoice from a XML file - number and the
* creditor name
*
* @throws AdapterException
* @throws PluginException
* @throws IOException
*/
@Test
void testXMLWithExtraction() throws AdapterException, PluginException, IOException {
// Prepare test data
FileData xmlFile = createFileData("e-invoice/Rechnung_R_00010.xml", "application/xml");
workitem.addFileData(xmlFile);

adapter.execute(workitem, event);

assertEquals("R-00010", workitem.getItemValueString("invoice.number"));
assertEquals("Max Mustermann", workitem.getItemValueString("cdtr.name"));
}

/**
* Simple test that extracts the invoice from a zugferd pdf file - number and
* the creditor name
*
* @throws AdapterException
* @throws PluginException
* @throws IOException
*/
@Test
void testZugferdWithExtraction() throws AdapterException, PluginException, IOException {
// Prepare test data
FileData xmlFile = createFileData("e-invoice/Rechnung_R_00011.pdf", "application/pdf");
workitem.addFileData(xmlFile);

adapter.execute(workitem, event);

assertEquals("R-00011", workitem.getItemValueString("invoice.number"));
assertEquals("Max Mustermann", workitem.getItemValueString("cdtr.name"));
ZonedDateTime expectedZdt = ZonedDateTime.of(2021, 7, 27, 0, 0, 0, 0, ZoneId.of("Europe/Berlin"));
Date expectedDate = Date.from(expectedZdt.toInstant());

assertEquals(expectedDate, workitem.getItemValueDate("invoice.date"));

// Payment data
assertEquals(892.50, workitem.getItemValueFloat("invoice.total"));
assertEquals(750, workitem.getItemValueFloat("invoice.total.net"));
assertEquals(142.5, workitem.getItemValueFloat("invoice.total.tax"));
// assertEquals("xxxxxR-00011", workitem.getItemValueString("cdtr.iban"));
// assertEquals("xxxxxR-00011", workitem.getItemValueString("cdtr.bic"));

}

/**
* Creates a FileData object from a file stored under /test/resources/
*
* @param fileName
* @param contentType
* @return
* @throws IOException
*/
private FileData createFileData(String fileName, String contentType) throws IOException {
byte[] content = null;
ClassLoader classLoader = getClass().getClassLoader();
try (InputStream is = classLoader.getResourceAsStream(fileName)) {
if (is == null) {
throw new IOException("Resource not found: " + fileName);
}
content = is.readAllBytes();
}
Map<String, List<Object>> attributes = new HashMap<>();
return new FileData(fileName, content, contentType, attributes);
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.imixs.workflow.documents;
package org.imixs.archive.documents;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
Expand All @@ -10,7 +10,6 @@
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.imixs.archive.documents.PDFXMLExtractorPlugin;
import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.WorkflowMockEnvironment;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.imixs.workflow.documents;
package org.imixs.archive.documents;

import java.io.IOException;
import java.util.logging.Logger;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.imixs.workflow.documents;
package org.imixs.archive.documents;

import java.io.BufferedReader;
import java.io.FileOutputStream;
Expand Down
Loading

0 comments on commit d8d3482

Please sign in to comment.