From 6de7ef5921e7c97bafcac5f60e4acef901f64e52 Mon Sep 17 00:00:00 2001
From: Ralph Soika
Date: Wed, 12 Jun 2024 16:34:36 +0200
Subject: [PATCH] update
---
.../alexanderlogistics/OPListController.java | 13 +-
.../api/CargosoftMigrationRestService.java | 271 +-
.../xml/CargosoftXMLInvoiceImportService.java | 43 +-
.../forms/alexander/section_payments.xhtml | 67 +-
workflow/rechnungsausgang-de-1.0.8.bpmn | 4109 +++++++++++++++++
5 files changed, 4418 insertions(+), 85 deletions(-)
create mode 100644 workflow/rechnungsausgang-de-1.0.8.bpmn
diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/OPListController.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/OPListController.java
index e33a529..1ed4730 100644
--- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/OPListController.java
+++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/OPListController.java
@@ -171,9 +171,8 @@ public class OPListController implements Serializable {
if (rate != 0) {
maxSaldo = maxSaldo / rate;
invoice.setItemValue("invoice.saldo.byrate", maxSaldo);
- } else {
- invoice.setItemValue("invoice.saldo.byrate", 0.0);
}
+
}
}
@@ -216,7 +215,15 @@ public class OPListController implements Serializable {
List selection = workflowController.getWorkitem().getItemValue("$workitemref");
for (String id : selection) {
if (id != null && !id.isEmpty()) {
- invoiceList.add(documentService.load(id));
+ ItemCollection _invoice = documentService.load(id);
+ // Test if we have 'invoice.base.amount' and 'invoice.rate'
+ if (!_invoice.hasItem("invoice.base.amount")) {
+ _invoice.setItemValue("invoice.base.amount", 0.0);
+ }
+ if (!_invoice.hasItem("invoice.rate")) {
+ _invoice.setItemValue("invoice.rate", 0.0);
+ }
+ invoiceList.add(_invoice);
}
}
}
diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java
index 6472c5d..c0d8a1b 100644
--- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java
+++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java
@@ -27,28 +27,54 @@
package com.alexanderlogistics.api;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.io.Serializable;
-import java.util.Calendar;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
+import java.util.TimeZone;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+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.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
+import org.imixs.workflow.engine.WorkflowService;
+import org.imixs.workflow.exceptions.AccessDeniedException;
+import org.imixs.workflow.exceptions.ModelException;
+import org.imixs.workflow.exceptions.PluginException;
+import org.imixs.workflow.exceptions.ProcessingErrorException;
import org.imixs.workflow.exceptions.QueryException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import com.alexanderlogistics.xml.CargosoftXMLInvoiceImportService;
/**
** Dieser Service korrigiert falsch importierte Cargosoft daten.
* Ausgangsrechnungen die ein falsches Jahr haben.
*
+ * Oder DAten die über die XML Schnittstelle falsch reinkamen...
+ *
* @author rsoika
* @version 1.1
*/
@@ -59,10 +85,18 @@ import org.imixs.workflow.exceptions.QueryException;
public class CargosoftMigrationRestService implements Serializable {
private static final long serialVersionUID = 1L;
+ String log = "";
+ int errors = 0;
+ int count = 0;
+ public static String _QUERY = "($modelversion:rechnungsausgang-de-1.0)\n" + //
+ "AND $created:[20240604 TO 20240613]";
@Inject
DocumentService documentService;
+ @Inject
+ WorkflowService workflowService;
+
private static Logger logger = Logger.getLogger(CargosoftMigrationRestService.class.getName());
public CargosoftMigrationRestService() {
@@ -83,72 +117,231 @@ public class CargosoftMigrationRestService implements Serializable {
@Produces({ MediaType.TEXT_PLAIN })
public String testeFehlerhafteCargosoftDaten() throws QueryException {
- String log;
-
- String query = "($modelversion:rechnungsausgang-de-1.0)\n" + //
- "AND $created:[20240101 TO 20240501]\n" + //
- "AND invoice.date:[20230101 TO 20230501]";
-
- logger.info("query=" + query);
- log = "Query\n" + query;
- List result = documentService.find(query, 100, 0);
+ logger.info("query=" + _QUERY);
+ log = "Query\n" + _QUERY;
+ List result = documentService.find(_QUERY, 999, 0);
log = log + "\n\nCount=" + result.size();
+ if (result.size() > 999) {
+ log = log + "\n\nACHTUNG ES GIBT MEHR ALS 1000 RECHNUNGEN !";
+ }
+
return log;
}
/**
- * This method loads taxonomy data for a workflow group within a given process
- * and builds a ChartJS data structure in JSON format
+ * This method fixes the wrong amount of a imported xml invoice.
*
* @param workflowgroup
* @param task
* @return
* @throws QueryException
+ * @throws ModelException
+ * @throws PluginException
+ * @throws ProcessingErrorException
+ * @throws AccessDeniedException
*/
@GET
- @Path("/fix/{count}")
+ @Path("/fix")
@Produces({ MediaType.TEXT_PLAIN })
- public String fixFehlerhafteCargosoftDaten(@PathParam("count") int count) throws QueryException {
+ public String fixFehlerhafteCargosoftDaten()
+ throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
- String log;
+ logger.info("query=" + _QUERY);
+ log = "Query\n\n" + _QUERY;
- String query = "($modelversion:rechnungsausgang-de-1.0)\n" + //
- "AND $created:[20240101 TO 20240501]\n" + //
- "AND invoice.date:[20230101 TO 20230501]";
-
- logger.info("query=" + query);
- log = "Query\n\n" + query;
-
- log = log + "\n\nMax Count=" + count;
- List result = documentService.find(query, count, 0);
+ List result = documentService.find(_QUERY, 999, 0);
log = log + "\n\nSelection Count=" + result.size();
log = log + "\n\nFixes\n\n";
- for (ItemCollection doc : result) {
+ for (ItemCollection workitem : result) {
+ ItemCollection snapshot = null;
+ // load snapshot
+ String snapshotID = workitem.getItemValueString("$snapshotid");
+ if (!snapshotID.isEmpty()) {
+ snapshot = documentService.load(snapshotID);
+ }
- Date invoiceDate = doc.getItemValueDate("invoice.date");
- doc.setItemValue("invoice.date.wrong", invoiceDate);
+ if (snapshot == null) {
+ logger.warning("Unable to load snapshot for document " + workitem.getUniqueID());
+ log = log + "Unable to load snapshot for document " + workitem.getUniqueID() + " \n";
+ errors++;
+ continue;
+ }
- // Convert to Calendar
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(invoiceDate);
- // Add one year
- calendar.add(Calendar.YEAR, 1);
- // Convert back to Date
- doc.setItemValue("invoice.date", calendar.getTime());
+ // Get raw data....
+ // find the XML Attachment
+ String xmlFileName = null;
+ List fileNames = snapshot.getFileNames();
+ for (String fileName : fileNames) {
+ if (fileName.endsWith(".xml")) {
+ xmlFileName = fileName;
+ break;
+ }
+ }
+ if (xmlFileName == null) {
+ logger.warning("Unable to load XML from document " + workitem.getUniqueID());
+ log = log + "Unable to load XML from document " + workitem.getUniqueID() + " \n";
+ errors++;
+ continue;
+ }
- documentService.save(doc);
- log = log + doc.getUniqueID() + " " + invoiceDate + " ==> " + calendar.getTime() + "\n";
+ FileData xmlFileData = snapshot.getFileData(xmlFileName);
+ Document xmlDoc = createXMLTree(xmlFileData.getContent());
- // break!
+ migrateDocument(workitem, xmlDoc);
}
- log = log + "\n\n=== Completed! ===\n\n";
+ log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n";
return log;
}
+ /**
+ * Diese Methode korrigiert den Saldo um die Netto summe....
+ *
+ * @param workitem
+ * @param xmlDoc
+ * @throws ModelException
+ * @throws PluginException
+ * @throws ProcessingErrorException
+ * @throws AccessDeniedException
+ */
+ private void migrateDocument(ItemCollection workitem, Document doc)
+ throws AccessDeniedException, ProcessingErrorException, PluginException, ModelException {
+
+ // Haben wir schon das neue Feld 'invoice.total.net' mit dem Netto Betrag?
+ if (workitem.hasItem("invoice.total.tax")) {
+ // no migration needed
+ return;
+ }
+
+ // Net und Tax ermitteln
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/NetAmount/Amount/Value",
+ workitem, "invoice.total.net", Double.class);
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/VATInformation/VATAmount/Amount/Value",
+ workitem, "invoice.total.tax", Double.class);
+
+ // Der Total entspricht nun dem Net Amount.
+ // Wenn wir eine Tax haben, dann müssen wir den Total sowie den Saldo um
+ // diese Tax erhöhen.
+ // Damit ist dann die Migration abgeschlossen.
+ double tax = workitem.getItemValueDouble("invoice.total.tax");
+ if (tax > 0) {
+ log = log + "...Migriere " + workitem.getItemValueString("invoice.number") + " Korrektur Betrag " +
+ tax + "\n";
+ double total = workitem.getItemValueDouble("invoice.total");
+ double saldo = workitem.getItemValueDouble("invoice.saldo");
+ // Gutschrift?
+ if (total < 0) {
+ total = total - tax;
+ saldo = saldo - tax;
+
+ } else {
+ // Rechnung
+ total = total + tax;
+ saldo = saldo + tax;
+ }
+ workitem.setItemValue("invoice.total", total);
+ workitem.setItemValue("invoice.saldo", saldo);
+ workitem.setItemValue("cargosoft.fix.xmlerror", tax);
+ log = log + "....... total neu=" + total + " saldo neu=" + saldo + "\n";
+
+ if (5900 == workitem.getTaskID()) {
+ workitem.setEventID(942);
+ workflowService.processWorkItem(workitem);
+
+ } else {
+ // save only
+ documentService.save(workitem);
+ }
+ count++;
+ } else {
+ log = log + "...Keine Migration notwendig " + workitem.getItemValueString("invoice.number") +
+ " tax=" + tax + "\n";
+ }
+ }
+
+ /**
+ * Erzeugt einen XML Baum aus dem XML Raw Daten
+ *
+ * @param snapshot
+ * @return
+ */
+ private Document createXMLTree(byte[] rawData) {
+ Document doc = null;
+ InputStream inputStream = new ByteArrayInputStream(rawData);
+ InputSource inputSource = new InputSource(inputStream);
+
+ DocumentBuilder documentBuilder;
+ try {
+ documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ doc = documentBuilder.parse(inputSource);
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ log = log + "Unable to load XML tree: " + e.getMessage() + " \n";
+ return null;
+ }
+
+ return doc;
+ }
+
+ /**
+ * Reads a tag value from the xml tree and set the value into the given
+ * workitem.
+ *
+ * /Invoices/Invoice/InvoiceHeader/Client/Code
+ *
+ * Beispiel Datum:
+ * 2024-05-13T00:00:00+02:00
+ *
+ * @param doc - xml doc
+ * @param expression - xpath expression
+ * @param workitem
+ * @param itemName
+ * @param itemType
+ */
+ private void readXMLValue(Document doc, String expression, ItemCollection workitem, String itemName,
+ Class itemType) {
+ // create XPath...
+ XPathFactory xpathFactory = XPathFactory.newInstance();
+ XPath xpath = xpathFactory.newXPath();
+ XPathExpression xPathExpression;
+ try {
+ 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(CargosoftXMLInvoiceImportService.DATE_FORMAT);
+ formatter.setTimeZone(TimeZone.getTimeZone("CET"));
+ try {
+ workitem.setItemValue(itemName, formatter.parse(value));
+ } catch (ParseException e) {
+ logger.warning("Invalid Date Format");
+ }
+ return;
+ }
+ if (itemType == Double.class && value != null && !value.isEmpty()) {
+ workitem.setItemValue(itemName, Double.parseDouble(value));
+ return;
+ }
+ if (itemType == Integer.class && value != null && !value.isEmpty()) {
+ workitem.setItemValue(itemName, Integer.parseInt(value));
+ return;
+ }
+ // Default String format
+ workitem.setItemValue(itemName, value);
+
+ }
+ } catch (XPathExpressionException e) {
+ logger.warning("Unable to read data field '" + expression + "' : " + e.getMessage());
+
+ }
+ }
}
diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java
index 2458bee..6353790 100644
--- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java
+++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java
@@ -392,17 +392,27 @@ public class CargosoftXMLInvoiceImportService {
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceType/Codes/Code",
workitem, "invoice.type", String.class);
- // Gutschrift oder Rechnung?
+ // Rechnungssumme errechnen.....
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/NetAmount/Amount/Value",
+ workitem, "invoice.total.net", Double.class);
+ readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/VATInformation/VATAmount/Amount/Value",
+ workitem, "invoice.total.tax", Double.class);
+ if (!workitem.hasItem("invoice.total.tax")) {
+ workitem.setItemValue("invoice.total.tax", 0.0);
+ }
+ // Total = net + tax
+ double _total = workitem.getItemValueDouble("invoice.total.net");
+ _total = _total + workitem.getItemValueDouble("invoice.total.tax");
+ _total = Math.round(_total * 100) / 100.0;
+ workitem.setItemValue("invoice.total", _total);
+ workitem.setItemValue("invoice.saldo", _total);
+
+ // Bei Gutschrift Wert negieren...
if ("G".equals(workitem.getItemValueString("invoice.type"))) {
- readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/NetAmount/Amount/Value",
- workitem, "invoice.total", Double.class);
workitem.setItemValue("invoice.saldo", -workitem.getItemValueDouble("invoice.total"));
workitem.setItemValue("invoice.total", -workitem.getItemValueDouble("invoice.total"));
- } else {
- readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/NetAmount/Amount/Value",
- workitem, "invoice.total", Double.class);
- workitem.setItemValue("invoice.saldo", workitem.getItemValueDouble("invoice.total"));
}
+
// Steuer
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAmount/VATInformation/VAT/VATRate",
workitem, "invoice.vatrate", Double.class);
@@ -574,6 +584,8 @@ public class CargosoftXMLInvoiceImportService {
.compile("InvoiceAmount/ActivityType/Codes/Code[@Type='cs']/text()");
NodeList rowList = doc.getElementsByTagName("InvoiceRow");
+ double _kurs = 0.0;
+ double _baseAmount = 0.0;
for (int i = 0; i < rowList.getLength(); i++) {
ItemCollection childItemCol = new ItemCollection();
Node rowNode = rowList.item(i);
@@ -594,14 +606,21 @@ public class CargosoftXMLInvoiceImportService {
double dUmsatz = Double.parseDouble(umsatz);
childItemCol.setItemValue("datev.umsatz", dUmsatz);
// Kurs
- String kurs = (String) netAmountExchangeRateExpr.evaluate(rowNode, XPathConstants.STRING);
- if (kurs != null && !kurs.isEmpty()) {
- Double dKurs = Double.parseDouble(kurs);
+ String _kursByRow = (String) netAmountExchangeRateExpr.evaluate(rowNode, XPathConstants.STRING);
+ if (_kursByRow != null && !_kursByRow.isEmpty()) {
+ Double dKurs = Double.parseDouble(_kursByRow);
+ _kurs = dKurs;
childItemCol.setItemValue("datev.kurs", dKurs);
// Basisumsatz
if (dKurs != 0) {
double basisUmsatz = dUmsatz / dKurs;
double gerundeterBasisUmsatz = Math.round(basisUmsatz * 100) / 100.0;
+
+ if ("G".equals(workitem.getItemValueString("invoice.type"))) {
+ _baseAmount = _baseAmount - gerundeterBasisUmsatz;
+ } else {
+ _baseAmount = _baseAmount + gerundeterBasisUmsatz;
+ }
childItemCol.setItemValue("datev.basisumsatz", gerundeterBasisUmsatz);
}
}
@@ -621,6 +640,10 @@ public class CargosoftXMLInvoiceImportService {
childItems.add(childItemCol);
}
}
+ // Update invoice.rate und invoice.base.amount
+ workitem.setItemValue("invoice.rate", _kurs);
+ _baseAmount = Math.round(_baseAmount * 100) / 100.0;
+ workitem.setItemValue("invoice.base.amount", _baseAmount);
} catch (XPathExpressionException e) {
logger.warning("Unable to read row : " + e.getMessage());
diff --git a/office-alexander-logistics-app/src/main/webapp/pages/workitems/forms/alexander/section_payments.xhtml b/office-alexander-logistics-app/src/main/webapp/pages/workitems/forms/alexander/section_payments.xhtml
index 1c5c448..8c8b4ff 100644
--- a/office-alexander-logistics-app/src/main/webapp/pages/workitems/forms/alexander/section_payments.xhtml
+++ b/office-alexander-logistics-app/src/main/webapp/pages/workitems/forms/alexander/section_payments.xhtml
@@ -1,15 +1,12 @@
-
-
-
+
+
@@ -25,59 +22,63 @@
-
+
-
+
- |
- #{payment.item['$workflowsummary']}
-
- |
+
+
+ #{payment.item['$workflowsummary']}
+
+
+ |
- |
-
-
+ |
+
+ |
+
+
+
- |
+
+
+ |
-
+
-
+ |
+
|
-
-
+
+
-
+
-
+
+
|
-
+
-
+
|
-
+
diff --git a/workflow/rechnungsausgang-de-1.0.8.bpmn b/workflow/rechnungsausgang-de-1.0.8.bpmn
new file mode 100644
index 0000000..7a7d93c
--- /dev/null
+++ b/workflow/rechnungsausgang-de-1.0.8.bpmn
@@ -0,0 +1,4109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+$workflowstatus
+
+]]>
+
+
+ In case you have already made the payment, please disregard this notice. If you require any information regarding your account, please do not hesitate to contact us.
+Thank you for your cooperation.
+
+Kind regards
Alexander Global Logistics GmbH
+
+