diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/InvoicePlugin.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/InvoicePlugin.java index 687cf92..218f574 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/InvoicePlugin.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/InvoicePlugin.java @@ -1,5 +1,6 @@ package com.alexanderlogistics; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -8,6 +9,7 @@ import java.util.logging.Logger; import org.imixs.workflow.ItemCollection; import org.imixs.workflow.engine.plugins.AbstractPlugin; import org.imixs.workflow.exceptions.PluginException; +import org.imixs.workflow.exceptions.QueryException; /** * Das InvoicePlugin prüft die Eingaben auf gültigkeit, so dass diese problemlos @@ -16,20 +18,27 @@ import org.imixs.workflow.exceptions.PluginException; * Konkret geht es darum, das im Status 5200 in den ChildItems keine leeren * Zeilen vorkommen dürfen. *

- * Im Status 5000 muss immer der payment.type ausgewählt werden. Dies wird vom Plugin explizit geprüft + * Im Status 5000 muss immer der payment.type ausgewählt werden. Dies wird vom + * Plugin explizit geprüft + *

+ * Das Plugin prüft auch auf doppelte Rechnungsnummern. Dabei wird Systemweit + * geprüft ob die Rechnungsnummer schon einmal vorkam. Falls ja, wird eine + * Warnung ausgegeben. Der Benutzer kann diese dann skippen. + * * * @author rsoika * @version 1.0 * */ public class InvoicePlugin extends AbstractPlugin { - + public static final int TASK_ERFASSUNG = 5000; public static final int TASK_SACHPRUEFUNG = 5200; public static final int EVENT_FREIGEBEN = 20; public static final String CHILD_ITEM_PROPERTY = "_ChildItems"; public static final String ERROR_MISSING_DATA = "MISSING_DATA"; + public static final String ERROR_DUPPLICATE_INVOICE_NUMBER = "DUPPLICATE_INVOICE_NUMBER"; // XX-YYY-####-### public static final String REGEX_POSNUMER = "([A-Z]{2}-[A-Z]{3}-[0-9]{4}-[0-9]{3})"; @@ -47,15 +56,19 @@ public class InvoicePlugin extends AbstractPlugin { public ItemCollection run(ItemCollection workitem, ItemCollection documentActivity) throws PluginException { // Payment.type muss immer eingetragne werden! - if (workitem.getTaskID() >=TASK_ERFASSUNG) { + if (workitem.getTaskID() >= TASK_ERFASSUNG) { if (workitem.getItemValueString("payment.type").trim().isEmpty()) { // throw a plugin exception! throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, "Eingabefehler - Bitte wählen Sie eine Zahlungsart aus!"); } + // doppelte Rechnungsnummer prüfen + validateInvoiceNumber(workitem); + + // Buchungsperiode auf plausi prüfen + validateBuchungsperiode(workitem); } - - + // die prüfung der positionsnummern und Category erfolgt nur im Status // Sachprüfung (5200) und nur beim Freigeben (20)! if (workitem.getTaskID() == TASK_SACHPRUEFUNG && workitem.getEventID() == EVENT_FREIGEBEN) { @@ -102,6 +115,91 @@ public class InvoicePlugin extends AbstractPlugin { return workitem; } + /** + * Diese Method prüft die Buchungsperiode auf Plausibilität + * + * YYYY(+1)01-12 + * + * z.b. 202110 oder 202107 oder 202201 + * + * @param workitem + * @throws PluginException + */ + private void validateBuchungsperiode(ItemCollection workitem) throws PluginException { + String period = workitem.getItemValueString("invoice.period"); + // buchungsperionde nur prüfen wenn noch nicht archiviert + if (!period.isEmpty() && "workitem".equals(workitem.getType())) { + LocalDate localDate = LocalDate.now(); + int year = localDate.getYear(); + // build regex.... + String regex = "(" + year + "|" + (year + 1) + ")(1[0-2]|0[1-9])"; + + if (!period.matches(regex)) { + // throw a plugin exception - because name is missing! + throw new PluginException(InvoicePlugin.class.getName(), ERROR_MISSING_DATA, + "Eingabefehler - Bitte geben Sie ein gültige Buchungsperiode ein!"); + } + } + } + + /** + * Diese Method prüft ob die "invoice.number" bereits einmal im + * Rechnugnsworkflow vergeben wurde. Falls ja wird eine PluginExcpetion + * ausgelöst. + *

+ * Query Example: + *

+ * NOT $uniqueid:"9f72fa50-4845-41ea-b6b9-ccd518c353be" AND + txtcooperatespace:"9dba107e-f8ef-4150-a832-040d75a6eda7" AND invoice.number:"45" + * + *

+ * in case a duplicate invoice was detected the item invoice.number.duplicate is + * filled. This item is used for a conditional event. The case is displayed as a + * warning in the form. + * + * @throws PluginException + * @throws QueryException + * + */ + private void validateInvoiceNumber(ItemCollection workitem) throws PluginException { + + String invoiceNumber = workitem.getItemValueString("invoice.number"); + String invoiceNumberDuplicate = workitem.getItemValueString("invoice.number.duplicate"); + + // wenn keine Rechnungsnummer eingegeben wurde gehts weiter! + if (invoiceNumber.isEmpty()) { + return; + } + + // rechnungseingang only workitems... + String query = "(type:workitem OR type:workitemarchive) AND ($modelversion:rechnungseingang*) AND NOT ($uniqueid:\"" + + workitem.getUniqueID() + "\") AND (invoice.number:\"" + invoiceNumber + "\")"; + try { + int result = this.getWorkflowService().getDocumentService().count(query, 1); + if (result > 0) { + // wenn _invoicenumber_duplicate bereits gesetzt ist - dann geht es ohne prüfung + // weiter + if (!invoiceNumberDuplicate.isEmpty()) { + logger.warning("...validateion skipped by user with duplicate invoice number: " + invoiceNumber); + } else { + + // set _invoicenumber_duplicate - dadurch wird die warnmeldung ausgegeben und + // der Vorgang nicht weitergeleitet + workitem.replaceItemValue("invoice.number.duplicate", invoiceNumber); + throw new PluginException(InvoicePlugin.class.getName(), ERROR_DUPPLICATE_INVOICE_NUMBER, + "ACHTUNG: Die Rechnungsnummer wurde bereits gebucht. Bitte prüfen Sie den Beleg!"); + } + } else { + // clear ! + workitem.appendItemValue("invoice.number.duplicate.history", + workitem.getItemValueString("invoice.number.duplicate")); + workitem.replaceItemValue("invoice.number.duplicate", ""); + } + } catch (QueryException e) { + throw new PluginException(PluginException.class.getName(), "QUERY ERROR", e.getMessage(), e); + } + } + /** * converts the Map List of a workitem into a List of ItemCollectons */ diff --git a/office-alexander-logistics-app/src/main/resources/imixs.properties b/office-alexander-logistics-app/src/main/resources/imixs.properties index c783330..7d7efa3 100644 --- a/office-alexander-logistics-app/src/main/resources/imixs.properties +++ b/office-alexander-logistics-app/src/main/resources/imixs.properties @@ -4,7 +4,7 @@ lucence.indexDir=${imixs-office.IndexDir} index.fields=txtsearchstring,txtSubject,txtname,txtEmail,txtUserName,namCreator,txtworkflowgroup,txtworkflowstatus,txtWorkflowAbstract,txtWorkflowSummary,txtworkflowhistory,txtspacename,txtprocessname,_subject,_description,_name,_projectnumber,_projectname,_ordernumber,_contractnumber,datDueDate,txtcommentlog,htmldescription,htmldocumentation,dms,dms_names,_childitems,$file.names index.fields.analyze=txtUsername -index.fields.noanalyze=type,$UniqueIDRef,$created,$modified,$ModelVersion,namCreator,$ProcessID,datDate,txtWorkflowGroup,txtemail, datdate, datfrom, datto, numsequencenumber,dms_count +index.fields.noanalyze=type,$UniqueIDRef,$created,$modified,$ModelVersion,namCreator,$ProcessID,datDate,txtWorkflowGroup,txtemail, datdate, datfrom, datto, numsequencenumber,dms_count,invoice.number index.fields.store=process.name,txtProcessName,txtWorkflowImageURL