diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportImportService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportImportService.java
index ca2d6bf..9801d28 100644
--- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportImportService.java
+++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportImportService.java
@@ -32,7 +32,11 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.Properties;
+import java.util.TimeZone;
import java.util.logging.Logger;
import javax.ejb.EJB;
@@ -41,6 +45,11 @@ import javax.enterprise.event.Observes;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
@@ -48,6 +57,7 @@ import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPSClient;
import org.imixs.archive.importer.DocumentImportEvent;
import org.imixs.archive.importer.DocumentImportService;
+import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.ModelService;
import org.imixs.workflow.engine.WorkflowService;
@@ -151,105 +161,117 @@ public class CargosoftXMLInvoiceImportImportService {
// set default port
ftpPort = "21";
}
-
- FTPClient ftpClient = null;
try {
- logger.finest("......read directories ...");
-
documentImportService.logMessage("...connecting to FTP server: " + ftpServer, event);
+ documentImportService.logMessage("...working directory: " + ftpPath, event);
+ FTPClient ftpClient = connectServer(ftpServer, Integer.parseInt(ftpPort), ftpUser, ftpPassword);
+ scannFTPDirectory(ftpClient, ftpPath, mandantID, event);
+ } catch (PluginException pe) {
+ documentImportService.logMessage(pe.getMessage(), event);
+ event.setResult(DocumentImportEvent.PROCESSING_ERROR);
+ return;
+ }
+
+ // completed
+ event.setResult(DocumentImportEvent.PROCESSING_COMPLETED);
+
+ }
+
+ /**
+ * Connects to the FTP Server and returns a ftpClient instance.
+ */
+ private FTPClient connectServer(String ftpServer, int ftpPort, String ftpUser, String ftpPassword)
+ throws PluginException {
+ FTPClient ftpClient = null;
+ // TLS
+ ftpClient = new FTPSClient("TLS", false);
+ ftpClient.setControlEncoding("UTF-8");
+ try {
+ ftpClient.connect(ftpServer, ftpPort);
- // TLS
- ftpClient = new FTPSClient("TLS", false);
- ftpClient.setControlEncoding("UTF-8");
- ftpClient.connect(ftpServer, Integer.parseInt(ftpPort));
if (ftpClient.login(ftpUser, ftpPassword) == false) {
- documentImportService.logMessage("FTP file transfer failed: login failed!", event);
- event.setResult(DocumentImportEvent.PROCESSING_ERROR);
- return;
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "FTP_ERROR", "FTP file transfer failed: login failed!");
}
-
ftpClient.enterLocalPassiveMode();
logger.finest("...... FileType=" + FTP.BINARY_FILE_TYPE);
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setControlEncoding("UTF-8");
- // try to enter the working directory....
+ } catch (IOException e) {
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "FTP_ERROR", e.getMessage());
+ }
+
+ return ftpClient;
+ }
+
+ /**
+ * Helper method reads the working FTP directory and starts importing the files.
+ *
+ * @param ftpClient
+ * @param ftpPath
+ * @throws PluginException
+ */
+ private void scannFTPDirectory(FTPClient ftpClient, String ftpPath, String mandantID, DocumentImportEvent event)
+ throws PluginException {
+ try {
+ logger.finest("......read directory " + ftpPath);
+ // try to enter the working directory and read all files...
boolean bWorkingDir = ftpClient.changeWorkingDirectory(ftpPath);
- if (bWorkingDir == true) {
+ if (bWorkingDir == false) {
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "FTP_ERROR", "...failed to change into working directory: ");
+ }
- documentImportService.logMessage("...working directory: " + ftpClient.printWorkingDirectory(), event);
+ FTPFile[] allFiles = ftpClient.listFiles(ftpPath);
- // scann directories...
+ // FTPFile[] allFiles = ftpClient.listFiles();
+ int count = 0;
+ if (allFiles.length > 0) {
+ documentImportService.logMessage("..." + allFiles.length + " files found ", event);
+ for (FTPFile file : allFiles) {
+ // if this is a directory or symlink then we do ignore this entry
+ if (!file.isFile()) {
+ logger.warning("...'" + file.getName() + "' is not a valid file, object will be ignored!");
+ continue;
+ }
+ ItemCollection invoice = null;
+ logger.info("import file " + file.getName() + "...");
+ // String fullFileName = ftpPath + "/" + file.getName();
+ try (ByteArrayOutputStream is = new ByteArrayOutputStream();) {
+ ftpClient.retrieveFile(file.getName(), is);
+ byte[] rawData = is.toByteArray();
+ if (rawData != null && rawData.length > 0) {
+ logger.finest("......file '" + file.getName() + "' successful read - bytes size = "
+ + rawData.length);
+ // create new workitem
+ invoice = createWorkitem(event.getSource(), file.getName(), rawData);
- FTPFile[] subDirectories = ftpClient.listDirectories(ftpPath);
-
- for (FTPFile ftpSubDirectory : subDirectories) {
- ItemCollection space = null;
-
- String ftpSubDirectoryName = ftpSubDirectory.getName();
-
- logger.info("......scan files from path=" + ftpPath
- + ftpSubDirectory.getName());
-
- /*
- * Nun importieren wir alle Files
- */
-
- FTPFile[] allFiles = ftpClient.listFiles(ftpPath + ftpSubDirectory.getName());
-
- /*
- * create a new workitem for each document
- */
-
- int count = 0;
- if (allFiles.length > 0) {
- documentImportService.logMessage("..." + allFiles.length + " files found ", event);
- ftpClient.changeWorkingDirectory(ftpPath + ftpSubDirectory.getName());
-
- for (FTPFile file : allFiles) {
- // if this is a directory or symlink then we do ignore this entry
- if (!file.isFile()) {
- documentImportService.logMessage(
- "...'" + file.getName() + "' is not a valid file, object will be ignored!",
- event);
- continue;
+ // persist workitem only if not exists and with a matching mandant.id
+ if (!invoice.getItemValueString("mandant.id").equals(mandantID)) {
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "FTP_ERROR", "Invoice does not match mandantID " + mandantID);
}
- logger.info("import file " + file.getName() + "...");
- // String fullFileName = ftpPath + "/" + file.getName();
- try (ByteArrayOutputStream is = new ByteArrayOutputStream();) {
- ftpClient.retrieveFile(file.getName(), is);
- byte[] rawData = is.toByteArray();
- if (rawData != null && rawData.length > 0) {
- logger.finest("......file '" + file.getName() + "' successfull read - bytes size = "
- + rawData.length);
- // create new workitem
- createWorkitem(event.getSource(), file.getName(), rawData, space);
- // documentImportService.logMessage("....imported '" + file.getName() + "'",
- // event);
- count++;
- } else {
- documentImportService.logMessage("...Warning - invalid file content '"
- + file.getName() + "' - file will be deleted!", event);
- }
- // finally delete the file....
- ftpClient.deleteFile(file.getName());
- } catch (AccessDeniedException | ProcessingErrorException | PluginException
- | ModelException e) {
- documentImportService.logMessage("...FTP import failed: " + e.getMessage(), event);
- event.setResult(DocumentImportEvent.PROCESSING_ERROR);
- return;
- }
+ count++;
+ } else {
+ logger.warning("...Warning - invalid file content '"
+ + file.getName() + "' - file will be deleted!");
}
- documentImportService.logMessage("..." + count + " new files imported.", event);
- } else {
- documentImportService.logMessage("...no files found, directory '" + ftpPath + "' is empty",
- event);
+ if (invoice != null) {
+ workflowService.processWorkItem(invoice);
+ }
+ // finally delete the file....
+ // ftpClient.deleteFile(file.getName());
+ } catch (AccessDeniedException | ProcessingErrorException | PluginException
+ | ModelException e) {
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "FTP_ERROR", e.getMessage());
}
}
- } else {
- documentImportService.logMessage("...failed to change into working directory: " + ftpPath, event);
+ documentImportService.logMessage("..." + count + " new files imported.", event);
}
} catch (IOException e) {
@@ -257,10 +279,8 @@ public class CargosoftXMLInvoiceImportImportService {
int r = ftpClient.getReplyCode();
logger.severe("FTP ReplyCode=" + r);
- documentImportService.logMessage("...FTP file transfer failed (replyCode=" + r + ") : " + e.getMessage(),
- event);
- event.setResult(DocumentImportEvent.PROCESSING_ERROR);
- return;
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "FTP_ERROR", e.getMessage());
} finally {
// do logout....
@@ -270,14 +290,10 @@ public class CargosoftXMLInvoiceImportImportService {
ftpClient.disconnect();
} catch (IOException e) {
documentImportService.logMessage("...FTP file transfer failed: " + e.getMessage(), event);
- event.setResult(DocumentImportEvent.PROCESSING_ERROR);
- return;
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "FTP_ERROR", e.getMessage());
}
}
-
- // completed
- event.setResult(DocumentImportEvent.PROCESSING_COMPLETED);
-
}
/**
@@ -291,7 +307,7 @@ public class CargosoftXMLInvoiceImportImportService {
* @throws ProcessingErrorException
* @throws AccessDeniedException
*/
- public ItemCollection createWorkitem(ItemCollection source, String fileName, byte[] rawData, ItemCollection space)
+ public ItemCollection createWorkitem(ItemCollection source, String fileName, byte[] rawData)
throws AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
ItemCollection workitem = new ItemCollection();
workitem.model(source.getItemValueString(DocumentImportService.SOURCE_ITEM_MODELVERSION));
@@ -307,12 +323,100 @@ public class CargosoftXMLInvoiceImportImportService {
try {
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = documentBuilder.parse(inputSource);
- Node node = doc.importNode(doc.getDocumentElement(), true);
- } catch (ParserConfigurationException | SAXException | IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+
+ // Now we parse the following item values
+ // invoice.number
+ // invoice.currency
+ // invoice.text
+ // invoice.date
+ // dbtr.number
+ // invoice.duedate
+ // invoice.reminder
+ // payment.term
+ // invoice.rate
+ // invoice.base.amount
+
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Client/Codes/Code", workitem,
+ "mandant.id", String.class);
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/NetAmount/Amount/Value",
+ workitem, "invoice.total", String.class);
+
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceCurrency/Codes/Code",
+ workitem, "invoice.currency", String.class);
+
+ // invoice.date 2024-05-13T00:00:00+02:00
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceDate",
+ workitem, "invoice.date", Date.class);
+
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAddress/Codes/Code",
+ workitem, "dbtr.number", String.class);
+ String dbtrNumber = workitem.getItemValueString("dbtr.number");
+ if (dbtrNumber.startsWith("K") || dbtrNumber.startsWith("D")) {
+ workitem.setItemValue("dbtr.number", dbtrNumber.substring(1));
+ }
+
+ // read filename
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Attachments/Attachment/Filename",
+ workitem, "import.filename", String.class);
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/Attachments/Attachment/Content",
+ workitem, "import.filedata", String.class);
+ String fileDataString = workitem.getItemValueString("import.filedata");
+ byte[] decodedData = java.util.Base64.getDecoder().decode(fileDataString);
+ FileData fileData = new FileData(workitem.getItemValueString("import.filename"),
+ decodedData, "application/pdf", null);
+ workitem.addFileData(fileData);
+ workitem.removeItem("import.filename");
+ workitem.removeItem("import.filedata");
+
+ } catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException e) {
+ throw new PluginException(CargosoftXMLInvoiceImportImportService.class.getName(),
+ "XML_ERROR", e.getMessage());
}
return workitem;
}
+ public void getMist(String itemName, Class itemType) {
+ }
+
+ /**
+ * Reads a tag value from the xml tree and set the value into the given
+ * workitem.
+ *
+ * /Invoices/Invoice/InvoiceHeader/Client/Code
+ *
+ * @param doc - xml doc
+ * @param expression - xpath expression
+ * @param workitem
+ * @param itemName
+ * @param itemType
+ * @throws XPathExpressionException
+ * @throws PluginException
+ */
+ private void readXMLValue(Document doc, String expression, ItemCollection workitem, String itemName,
+ Class itemType) throws XPathExpressionException {
+ // create XPath...
+ XPathFactory xpathFactory = XPathFactory.newInstance();
+ XPath xpath = xpathFactory.newXPath();
+ XPathExpression xPathExpression = xpath.compile(expression);
+ // extract node value
+ Node valueNode = (Node) xPathExpression.evaluate(doc, XPathConstants.NODE);
+ if (valueNode != null) {
+ String value = valueNode.getTextContent();
+
+ if (itemType == Date.class) {
+ // 2024-05-13T00:00:00+02:00
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
+ formatter.setTimeZone(TimeZone.getTimeZone("CET"));
+ try {
+ workitem.setItemValue(itemName, formatter.parse(value));
+ } catch (ParseException e) {
+ logger.warning("Invalid Date Format");
+ }
+
+ } else {
+ workitem.setItemValue(itemName, value);
+ }
+
+ }
+ }
}