From 1870d0856a888569531c4758396f0db310939f90 Mon Sep 17 00:00:00 2001 From: Ralph Soika Date: Thu, 6 Oct 2022 15:58:26 +0200 Subject: [PATCH] neuer workflow mahnlauf --- .../datev/DatevCargosoftImportAdapter.java | 23 + .../mahnlauf/MahnlaufExecuteAdapter.java | 61 ++ .../mahnlauf/MahnlaufRefAddAdapter.java | 160 ++++ .../mahnlauf/MahnlaufService.java | 95 +++ .../TestPostionsnummernRegex.java | 35 +- workflow/mahnlauf-de-1.0.0.bpmn | 331 ++++++-- workflow/rechnungsausgang-de-1.0.0.bpmn | 725 ++++++++++++------ 7 files changed, 1152 insertions(+), 278 deletions(-) create mode 100644 office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufExecuteAdapter.java create mode 100644 office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufRefAddAdapter.java create mode 100644 office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufService.java diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/datev/DatevCargosoftImportAdapter.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/datev/DatevCargosoftImportAdapter.java index 4931ff2..5f5f558 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/datev/DatevCargosoftImportAdapter.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/datev/DatevCargosoftImportAdapter.java @@ -49,6 +49,7 @@ public class DatevCargosoftImportAdapter implements SignalAdapter { public static final String ENCODING = "ISO-8859-1"; public static final String CHILD_ITEM_PROPERTY = "_ChildItems"; + public static final String REGEX_IMPORTTEXTPATTERN = "^R[1-8] .*$"; @Inject WorkflowService workflowService; @@ -102,6 +103,8 @@ public class DatevCargosoftImportAdapter implements SignalAdapter { int positions = 0; int invoices = 0; int dupplicates = 0; + int rueckstellungen=0; + int eingangsrechnungen=0; String dataLine; // Start Datum Wirtschaftsjahr berechnen (JJJJMMTT) @@ -168,10 +171,22 @@ public class DatevCargosoftImportAdapter implements SignalAdapter { // Skip Eingangsrechnungen if (!gegenKonto.startsWith("1")) { + eingangsrechnungen++; // skip continue; } + // Skip Rückstellung + // text darf nicht mit R1 bis R8 beginnen + // ^R[1-8] . + if (text.matches(REGEX_IMPORTTEXTPATTERN)) { + rueckstellungen++; + // skip + continue; + } + + + positions++; logger.info("...read dbtr: " + gegenKonto + " beleg-nr: " + belegNummer); @@ -236,6 +251,14 @@ public class DatevCargosoftImportAdapter implements SignalAdapter { log(logBuffer, line + " Zeilen eingelesen "); log(logBuffer, positions + " Rechnungspositionen eingelesen "); log(logBuffer, invoices + " Rechnungen importiert "); + + if (rueckstellungen>0) { + log(logBuffer, rueckstellungen + " Rückstellungen wurden übersprungen."); + } + if (eingangsrechnungen>0) { + log(logBuffer, eingangsrechnungen + " Eingangsrechnungen wurden übersprungen."); + } + if (dupplicates > 0) { log(logBuffer, dupplicates + " Rechnungen wurden übersprungen da diese bereits importiert wurden!"); } diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufExecuteAdapter.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufExecuteAdapter.java new file mode 100644 index 0000000..2374a75 --- /dev/null +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufExecuteAdapter.java @@ -0,0 +1,61 @@ +package com.alexanderlogistics.mahnlauf; + +import java.util.List; +import java.util.logging.Logger; + +import javax.ejb.EJB; +import javax.inject.Inject; + +import org.imixs.workflow.ItemCollection; +import org.imixs.workflow.SignalAdapter; +import org.imixs.workflow.engine.ModelService; +import org.imixs.workflow.engine.WorkflowService; +import org.imixs.workflow.exceptions.AdapterException; +import org.imixs.workflow.exceptions.PluginException; + +/** + * The MahnlaufExecuteAdapter triggers the event 300 for all linked invoices + *

+ * + * @version 1.0 + * @author rsoika + */ +public class MahnlaufExecuteAdapter implements SignalAdapter { + + @SuppressWarnings("unused") + private static Logger logger = Logger.getLogger(MahnlaufExecuteAdapter.class.getName()); + + @EJB + ModelService modelService; + + @EJB + WorkflowService workflowService = null; + + @Inject + MahnlaufService mahnlaufService; + + /** + * This method finds all invices ($workitemref) and tirgges event 300 + * + * @throws PluginException + */ + @SuppressWarnings("unchecked") + @Override + public ItemCollection execute(ItemCollection mahnLaufWorkitem, ItemCollection event) + throws AdapterException, PluginException { + + // get all Invoices of this Mahnlauf + List refList = mahnLaufWorkitem.getItemValue("$workitemref"); + + for (String uniqueId : refList) { + ItemCollection invoice = workflowService.getWorkItem(uniqueId); + if (invoice != null && (invoice.getTaskID()>=MahnlaufService.TASK_MAHNLAUF_START && invoice.getTaskID()<=MahnlaufService.TASK_MAHNLAUF_END)) { + mahnlaufService.processInvoice(invoice.event(MahnlaufService.EVENT_MAHNLAUF_EXECUTE)); + } + + } + + return mahnLaufWorkitem; + } + +} \ No newline at end of file diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufRefAddAdapter.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufRefAddAdapter.java new file mode 100644 index 0000000..eba02f7 --- /dev/null +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufRefAddAdapter.java @@ -0,0 +1,160 @@ +package com.alexanderlogistics.mahnlauf; + +import java.util.Date; +import java.util.List; +import java.util.logging.Logger; + +import javax.ejb.EJB; +import javax.inject.Inject; + +import org.imixs.workflow.ItemCollection; +import org.imixs.workflow.Model; +import org.imixs.workflow.SignalAdapter; +import org.imixs.workflow.WorkflowKernel; +import org.imixs.workflow.engine.ModelService; +import org.imixs.workflow.engine.WorkflowService; +import org.imixs.workflow.exceptions.AdapterException; +import org.imixs.workflow.exceptions.ModelException; +import org.imixs.workflow.exceptions.PluginException; +import org.imixs.workflow.exceptions.QueryException; +import org.imixs.workflow.sepa.services.SepaWorkflowService; + +/** + * The MahnlaufRefAddAdapter links an invoice with a Mahnlauf for the + * dbtr.number item . If there is currently no open Mahnlauf for this key, the + * adapter automatically creates a new process instance. If a manhlauf for this + * dbt.number is found, the invoice is just added. + *

+ * If the invoice has already been linked to a Mahnlauf nothing happens. + *

+ * + * @version 1.0 + * @author rsoika + */ +public class MahnlaufRefAddAdapter implements SignalAdapter { + + private static Logger logger = Logger.getLogger(MahnlaufRefAddAdapter.class.getName()); + + @EJB + ModelService modelService; + + @EJB + WorkflowService workflowService = null; + + @Inject + SepaWorkflowService sepaWorkflowService; + + /** + * This method finds or create the Mahnlauf and adds a reference ($workitemref) + * to the current invoice. + * + * @throws PluginException + */ + @SuppressWarnings("unchecked") + @Override + public ItemCollection execute(ItemCollection invoice, ItemCollection event) + throws AdapterException, PluginException { + + String dbtrNumber = invoice.getItemValueString(MahnlaufService.ITEM_DBTR_NUMBER); + ItemCollection mahnLaufWorkitem; + try { + mahnLaufWorkitem = findMahnlauf(dbtrNumber); + + if (mahnLaufWorkitem == null) { + // create one... + mahnLaufWorkitem = createNewMahnlauf(dbtrNumber, invoice, event); + } + + // add Invoice to Mahnlauf + List refList = mahnLaufWorkitem.getItemValue("$workitemref"); + if (!refList.contains(invoice.getUniqueID())) { + mahnLaufWorkitem.appendItemValueUnique("$workitemref", invoice.getUniqueID()); + } + + // set event 100 and process + ItemCollection mahnlaufConfig = workflowService.evalWorkflowResult(event, "mahnlauf", invoice, true); + int eventID = mahnlaufConfig.getItemValueInteger("event"); + + mahnLaufWorkitem.event(eventID); + workflowService.processWorkItem(mahnLaufWorkitem); + + } catch (QueryException | ModelException e) { + throw new PluginException(MahnlaufRefAddAdapter.class.getName(), + MahnlaufService.ERROR_CONFIG, "Unable to create Mahnlauf", e); + } + + // set mahnlauf ref + invoice.setItemValue("dunning.ref", mahnLaufWorkitem.getUniqueID()); + return invoice; + } + + /** + * Helper method finds an open mahnlauf for a debtr.numbre (name) + * + * @param key + * @return + * @throws QueryException + */ + public ItemCollection findMahnlauf(String key) throws QueryException { + String query = "(type:workitem) AND ($modelversion:mahnlauf*) AND (name:\"" + key + "\")"; + List resultList = workflowService.getDocumentService().find(query, 1, 0, "$modified", true); + + if (resultList.size() > 0) { + return resultList.get(0); + } + // no mahnaluffound + return null; + } + + /** + * Helper method to create a new Mahnlauf workitem + * + * @param key + * @param invoice + * @return + * @throws ModelException + * @throws PluginException + */ + public ItemCollection createNewMahnlauf(String key, ItemCollection invoice, ItemCollection event) + throws ModelException, PluginException { + String modelVersion = null; + int taskID = -1; + int eventID=-1; + // test if the event provides a sepa export configuration + ItemCollection mahnlaufConfig = workflowService.evalWorkflowResult(event, "mahnlauf", invoice, true); + if (mahnlaufConfig != null && mahnlaufConfig.hasItem("modelversion") && mahnlaufConfig.hasItem("task")) { + logger.fine("read model information from event"); + modelVersion = mahnlaufConfig.getItemValueString("modelVersion"); + taskID = mahnlaufConfig.getItemValueInteger("task"); + eventID = mahnlaufConfig.getItemValueInteger("event"); + } + + // build the sepa export workitem.... + ItemCollection mahnlaufWorkitem = new ItemCollection().model(modelVersion).task(taskID); + mahnlaufWorkitem.replaceItemValue("name", key); + mahnlaufWorkitem.replaceItemValue(WorkflowKernel.CREATED, new Date()); + mahnlaufWorkitem.replaceItemValue(WorkflowKernel.MODIFIED, new Date()); + // set unqiueid + mahnlaufWorkitem.setItemValue(WorkflowKernel.UNIQUEID, WorkflowKernel.generateUniqueID()); + + // copy dbtr_iban + mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_NAME, invoice.getItemValue(MahnlaufService.ITEM_DBTR_NAME)); + mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_EMAIL, invoice.getItemValue(MahnlaufService.ITEM_DBTR_EMAIL)); + mahnlaufWorkitem.setItemValue(MahnlaufService.ITEM_DBTR_NUMBER, invoice.getItemValue(MahnlaufService.ITEM_DBTR_NUMBER)); + + mahnlaufWorkitem.setItemValue("invoice.language", invoice.getItemValue("invoice.language")); + + + + // set workflow group name from the Task Element to identify document in xslt + Model model = modelService.getModel(modelVersion); + ItemCollection task = model.getTask(taskID); + String modelTaskGroupName = task.getItemValueString("txtworkflowgroup"); // DO NOT CHANGE! + mahnlaufWorkitem.setItemValue(WorkflowKernel.WORKFLOWGROUP, modelTaskGroupName); + + logger.info("...created new mahnlauf " + key + "..."); + + return mahnlaufWorkitem; + } + +} \ No newline at end of file diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufService.java new file mode 100644 index 0000000..b5406ff --- /dev/null +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/mahnlauf/MahnlaufService.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Imixs Workflow + * Copyright (C) 2001, 2011 Imixs Software Solutions GmbH, + * http://www.imixs.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You can receive a copy of the GNU General Public + * License at http://www.gnu.org/licenses/gpl.html + * + * Project: + * http://www.imixs.org + * http://java.net/projects/imixs-workflow + * + * Contributors: + * Imixs Software Solutions GmbH - initial API and implementation + * Ralph Soika - Software Developer + *******************************************************************************/ + +package com.alexanderlogistics.mahnlauf; + +import javax.annotation.security.DeclareRoles; +import javax.annotation.security.RolesAllowed; +import javax.annotation.security.RunAs; +import javax.ejb.Singleton; +import javax.inject.Inject; + +import org.imixs.workflow.ItemCollection; +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; + +/** + * Der MahnlaufService wird vom MahnlaufExecuteAdapter um + * Ausgangsrechnungen zu akutalisieren. + * + * @author rsoika + * + */ + +@DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS", + "org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS", + "org.imixs.ACCESSLEVEL.MANAGERACCESS" }) +@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS", + "org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS", + "org.imixs.ACCESSLEVEL.MANAGERACCESS" }) +@Singleton +@RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS") +public class MahnlaufService { + + + public static final int TASK_MAHNLAUF_START = 5100; + public static final int TASK_MAHNLAUF_END = 5299; + public static final int EVENT_MAHNLAUF_EXECUTE = 300; + + public static final String ITEM_DBTR_NUMBER = "dbtr.number"; + public static final String ITEM_DBTR_NAME = "dbtr.name"; + public static final String ITEM_DBTR_EMAIL = "dbtr.mail"; + public static final String ERROR_CONFIG = "CONFIG_ERROR"; + public static final String ERROR_WORKFLOW = "ERROR_WORKFLOW"; + + + @Inject + WorkflowService workflowService; + + + + /** + * * Diese Method processed eine Invoice mit Manager Rechnten + * + * @throws PluginException + * @throws ModelException + * @throws ProcessingErrorException + * @throws AccessDeniedException + */ + public ItemCollection processInvoice(ItemCollection invoice) throws PluginException { + try { + return workflowService.processWorkItem(invoice); + } catch (AccessDeniedException | ProcessingErrorException | PluginException | ModelException e) { + throw new PluginException(PluginException.class.getName(), ERROR_WORKFLOW, + "Die Rechnung konnte nicht verarbeitet werden - " + e.getMessage(), e); + } + } + +} diff --git a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestPostionsnummernRegex.java b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestPostionsnummernRegex.java index 32c2b47..2e4cda0 100644 --- a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestPostionsnummernRegex.java +++ b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestPostionsnummernRegex.java @@ -2,6 +2,8 @@ package com.alexanderlogistics; import org.junit.Test; +import com.alexanderlogistics.datev.DatevCargosoftImportAdapter; + import junit.framework.Assert; /** @@ -12,18 +14,27 @@ import junit.framework.Assert; */ public class TestPostionsnummernRegex { - /** - * Test positionnummern 'XX-YYY-####-###' - */ - @Test - public void testPutFileToFTP() { + /** + * Test positionnummern 'XX-YYY-####-###' + */ + @Test + public void testPutFileToFTP() { - Assert.assertTrue("AA-BBC-1234-991".matches(InvoicePlugin.REGEX_POSNUMER)); - Assert.assertFalse("aa-BBC-1234-991".matches(InvoicePlugin.REGEX_POSNUMER)); - Assert.assertFalse("CC-BBC-1234-991 ".matches(InvoicePlugin.REGEX_POSNUMER)); - - Assert.assertTrue("IM-ZEL-2101-005".matches(InvoicePlugin.REGEX_POSNUMER)); - - } + Assert.assertTrue("AA-BBC-1234-991".matches(InvoicePlugin.REGEX_POSNUMER)); + Assert.assertFalse("aa-BBC-1234-991".matches(InvoicePlugin.REGEX_POSNUMER)); + Assert.assertFalse("CC-BBC-1234-991 ".matches(InvoicePlugin.REGEX_POSNUMER)); + Assert.assertTrue("IM-ZEL-2101-005".matches(InvoicePlugin.REGEX_POSNUMER)); + + } + + + @Test + public void testCargoImportText() { + + Assert.assertTrue("R3 EX-PRO-2208-054".matches(DatevCargosoftImportAdapter.REGEX_IMPORTTEXTPATTERN)); + Assert.assertTrue("R3 VP".matches(DatevCargosoftImportAdapter.REGEX_IMPORTTEXTPATTERN)); + Assert.assertFalse("R LA-HOL-2208-013".matches(DatevCargosoftImportAdapter.REGEX_IMPORTTEXTPATTERN)); + + } } diff --git a/workflow/mahnlauf-de-1.0.0.bpmn b/workflow/mahnlauf-de-1.0.0.bpmn index 77ff780..b3a55c4 100644 --- a/workflow/mahnlauf-de-1.0.0.bpmn +++ b/workflow/mahnlauf-de-1.0.0.bpmn @@ -32,7 +32,8 @@ - + +