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
+         
+   }
+ * 
+ * + *

+ * 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 - - steuerbescheide_$lasteventdate.xlsx - + + SOA Template + + 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;} + + + +