diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/AGLAnalyticExcelAdapterDebitor.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/AGLAnalyticExcelAdapterDebitor.java
new file mode 100644
index 0000000..aa9e948
--- /dev/null
+++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/AGLAnalyticExcelAdapterDebitor.java
@@ -0,0 +1,315 @@
+package com.alexanderlogistics;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.apache.poi.ss.usermodel.CellCopyPolicy;
+import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+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.AdapterException;
+import org.imixs.workflow.exceptions.PluginException;
+import org.imixs.workflow.exceptions.QueryException;
+import org.imixs.workflow.office.config.ConfigService;
+import org.imixs.workflow.poi.POIFindReplaceAdapter;
+import org.imixs.workflow.util.XMLParser;
+
+import jakarta.inject.Inject;
+
+/**
+ * Der AGLAnalyticExcelAdapterDebitor exportiert eine Excel Datei aus einem
+ * Textblock und fügt die offenen Recnungen ein
+ *
+ * Der Adapter wird im Modell wie folgt konfiguriert
+ *
+ *
+ * {@code
+
+ textblock-ref
+ filename
+ filename
+
+ }
+ *
+ *
+ *
+ * Der Adapter erweitert den POIAdapter somit können Felder aktualisiert werden
+ * (siehe POIFineReplaceAdapter).
+ *
+ *
+ * Der Adapter kopiert die ausgangsrechnungen in neue Zeilen, welche ab
+ * Zeilennummer
+ * 16 eingefügt werden.
+ *
+ *
+ * Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
+ *
+ *
+ * @version 1.0
+ * @author rsoika
+ */
+public class AGLAnalyticExcelAdapterDebitor extends POIFindReplaceAdapter {
+
+ private static Logger logger = Logger.getLogger(AGLAnalyticExcelAdapter.class.getName());
+
+ @Inject
+ WorkflowService workflowService;
+
+ @Inject
+ OPListExportService opListExportService;
+
+ @Inject
+ DocumentService documentService;
+
+ @Inject
+ ConfigService configService;
+
+ /**
+ * This method
+ *
+ * @throws PluginException
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public ItemCollection execute(ItemCollection document, ItemCollection event)
+ throws AdapterException, PluginException {
+
+ // ermittle die Hauptwährungen
+ ItemCollection configItemCollection = configService.loadConfiguration("AGL_CONFIGURATION");
+ List currencyList = configItemCollection.getItemValue("currency.out");
+ if (currencyList == null || currencyList.size() < 2) {
+ throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
+ OPListExportService.ERROR_CONFIG,
+ "missing Currency configuration - please check parameters");
+ }
+
+ // read the Steuerbescheide options
+ ItemCollection ausgangsrechnungConfig = workflowService.evalWorkflowResult(event, "soa",
+ document,
+ false);
+ if (ausgangsrechnungConfig == null || !ausgangsrechnungConfig.hasItem("excel-export")) {
+ throw new PluginException(AGLAnalyticExcelAdapterDebitor.class.getSimpleName(), CONFIG_ERROR,
+ "missing soa configuration in model event - please check model configuration");
+ }
+ List excelDefList = ausgangsrechnungConfig.getItemValue("excel-export");
+ ItemCollection excelDefCollection = XMLParser.parseItemStructure(excelDefList.get(0));
+
+ String textblock = excelDefCollection.getItemValueString("textblock");
+ String template = excelDefCollection.getItemValueString("template");
+ String targetName = excelDefCollection.getItemValueString("target-name");
+
+ // adapt text....
+ targetName = workflowService.adaptText(targetName, document);
+
+ try {
+ appendExcelTemplate(document, textblock, template, targetName);
+ insertInvoiceRows(document, targetName);
+
+ logger.info("... loading poi configuration..");
+ // Process POI instructions
+ // read the config
+ ItemCollection poiConfig = workflowService.evalWorkflowResult(event, "poi-update", document,
+ false);
+ if (poiConfig == null || !poiConfig.hasItem("findreplace")) {
+ throw new PluginException(POIFindReplaceAdapter.class.getSimpleName(), CONFIG_ERROR,
+ "missing poi configuration");
+ }
+ List replaceDevList = poiConfig.getItemValue("findreplace");
+ String eval = poiConfig.getItemValueString("eval");
+
+ logger.info("... update template with normal poi information..");
+ this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
+
+ } catch (PluginException | IOException | QueryException e) {
+ throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
+ OPListExportService.ERROR_CONFIG,
+ "failed to update steuerbescheide: " + e.getMessage());
+ }
+ logger.info("... completed!");
+ return document;
+ }
+
+ /**
+ * Hilfsmethode die das fuehrende K/D aus der Debitorennummer entfernt
+ *
+ * @return
+ */
+ private String getDbtNr(ItemCollection workitem) {
+ String dbtNr = workitem.getItemValueString("dbtr.number");
+ if (dbtNr.startsWith("D") || dbtNr.startsWith("K")) {
+ dbtNr = dbtNr.substring(1);
+ }
+ return dbtNr;
+ }
+
+ /**
+ * This helper method inserts a row for each invoice at row 16
+ * into the excel template file
+ *
+ * The method copies the Row A16 as a reference row
+ *
+ * The named cell 'TOTAL' should contain the summary formula. It will be
+ * evaluated at the end.
+ *
+ * @throws PluginException
+ * @throws QueryException
+ */
+ private void insertInvoiceRows(ItemCollection document, String fileName)
+ throws PluginException, QueryException {
+
+ // load dummy rechnungen
+ List invoices = loadInvoices(getDbtNr(document));
+
+ FileData fileData = document.getFileData(fileName);
+
+ // load XSSFWorkbook
+ XSSFWorkbook doc = null;
+ try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
+ doc = new XSSFWorkbook(imputStream);
+ // NOTE: we only take the first sheet !
+ XSSFSheet sheet = doc.getSheetAt(0);
+ CellReference invoiceRefCell = new CellReference("A11");
+ XSSFRow referenceRowInvoice = sheet.getRow(invoiceRefCell.getRow());
+ int referenceRowPos = 10;
+ int rowPos = referenceRowPos;
+ int lastRow = 2999;
+ logger.finest("Last rownum=" + lastRow);
+
+ // jetzt füge alle Rechnungen an.
+ int totalRowCount = invoices.size();
+ sheet.shiftRows(referenceRowPos, lastRow, totalRowCount, true, true);
+ for (ItemCollection invoice : invoices) {
+ logger.fine("......add invoice " + invoice.getUniqueID());
+ // now create a new line..
+ XSSFRow row = sheet.createRow(rowPos);
+ row.copyRowFrom(referenceRowInvoice, new CellCopyPolicy());
+ // insert values
+ row.getCell(0)
+ .setCellValue(invoice.getItemValueDate("$created"));
+ row.getCell(1, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueString("invoice.number"));
+ row.getCell(2, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueDate("invoice.date"));
+ row.getCell(3, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueDate("invoice.duedate"));
+ row.getCell(4, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueString("space.name"));
+ row.getCell(5, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueString("invoice.text"));
+
+ // Waehrung?
+ if (invoice.getItemValueDouble("invoice.rate") == 0) {
+ row.getCell(6, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueDouble("invoice.total"));
+ row.getCell(7, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueDouble("invoice.saldo"));
+ } else {
+ row.getCell(8, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueDouble("invoice.total"));
+ row.getCell(9, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueDouble("invoice.saldo"));
+ }
+ row.getCell(10, MissingCellPolicy.CREATE_NULL_AS_BLANK)
+ .setCellValue(invoice.getItemValueString("$workflowstatus"));
+
+ rowPos++;
+ }
+
+ // Leerzeile
+ // categoryRow = sheet.createRow(rowPos);
+ rowPos++;
+
+ // write back the file
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ doc.write(byteArrayOutputStream);
+
+ byte[] newContent = byteArrayOutputStream.toByteArray();
+ FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(),
+ null);
+ // update the fileData
+ document.addFileData(fileDataNew);
+
+ logger.finest("......new document added");
+
+ } catch (IOException e) {
+ throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
+ OPListExportService.ERROR_CONFIG,
+ "failed to update opliste: " + e.getMessage());
+ } finally {
+ if (doc != null) {
+ try {
+ doc.close();
+ } catch (IOException e) {
+ logger.severe("Failed to close workbook: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * This method loads a text-block for a specified ref and appends the named
+ * fileData object of this document.
+ *
+ * @param document
+ * @throws PluginException
+ */
+ private void appendExcelTemplate(ItemCollection document, String textblockRef, String template,
+ String targetName)
+ throws PluginException {
+
+ if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
+ throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
+ OPListExportService.ERROR_CONFIG,
+ "invalid SOA configuration in model event - textblock/template reference not defined!");
+ }
+
+ // load the text block
+ FileData fileData = opListExportService.loadTextBlockFileData(textblockRef, template);
+
+ // do we found the document?
+ if (fileData == null) {
+ throw new PluginException(AGLAnalyticExcelAdapter.class.getSimpleName(),
+ OPListExportService.ERROR_CONFIG,
+ "invalid SOA configuration in model event - template=" + template
+ + " not found!");
+ }
+ fileData.setName(targetName);
+ // append document
+ logger.info("...append new SOA Template: " + targetName);
+ document.addFileData(fileData);
+
+ }
+
+ /**
+ * Diese Methode läd alle offenen Steuerbescheide
+ *
+ * @return
+ */
+ private List loadInvoices(String dbtrNumber) {
+ List result = new ArrayList<>();
+
+ String query = "(type:workitem) AND dbtr.number:" + dbtrNumber
+ + " AND $modelversion:rechnungsausgang-*";
+ try {
+ result = documentService.find(
+ query, 9999, 0,
+ "invoice.number", false);
+ } catch (QueryException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/templates/soa_template.xlsx b/templates/soa_template.xlsx
new file mode 100644
index 0000000..e1b0fe4
Binary files /dev/null and b/templates/soa_template.xlsx differ
diff --git a/workflow/dwc/analyse-debitor-en-1.0.0.bpmn b/workflow/dwc/analyse-debitor-en-1.0.0.bpmn
index a438b24..a0ca1a8 100644
--- a/workflow/dwc/analyse-debitor-en-1.0.0.bpmn
+++ b/workflow/dwc/analyse-debitor-en-1.0.0.bpmn
@@ -29,7 +29,7 @@
true
-
+
@@ -123,7 +123,6 @@ th { font-weight: bold;}
$workflowgroup - $workflowstatus]]>
SequenceFlow_10
sequenceFlow_OL83kQ
- sequenceFlow_P5vJKg
@@ -164,7 +163,7 @@ th { font-weight: bold;}
$workflowgroup - $workflowstatus]]>
SequenceFlow_4
sequenceFlow_17AQjg
- sequenceFlow_nZPhew
+ sequenceFlow_1K0l0g
@@ -308,24 +307,47 @@ th { font-weight: bold;}
-
+
false
Mahnwesen
-
- Steuerbescheide Template
- steuerbescheid-liste_template.xlsx
- steuerbescheide_$lasteventdate.xlsx
-
+
+ SOA Template
+ soa_template.xlsx
+ soa_dbtr.number_$lasteventdate.xlsx
+
- K6
+ I6
$lasteventdate
date
+
+ D6
+ dbtr.name
+ date
+
+
+ G10
+ Total AED
+
+
+ H10
+ Saldo AED
+
+
+ I10
+ Total USD
+
+
+ J10
+ Saldo USD
+
+
+
TOTAL1;TOTAL2;TOTAL3;TOTAL4
]]>
@@ -333,15 +355,8 @@ th { font-weight: bold;}
- sequenceFlow_nZPhew
- sequenceFlow_P5vJKg
+ sequenceFlow_1K0l0g
-
-
-
-
-
-
@@ -355,7 +370,7 @@ th { font-weight: bold;}
-
+
@@ -365,6 +380,9 @@ th { font-weight: bold;}
+
+
+
@@ -446,15 +464,6 @@ th { font-weight: bold;}
-
-
-
-
-
-
-
-
-
@@ -467,6 +476,10 @@ th { font-weight: bold;}
+
+
+
+