/* * Imixs-Workflow * * Copyright (C) 2001-2020 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: * https://www.imixs.org * https://github.com/imixs/imixs-workflow * * Contributors: * Imixs Software Solutions GmbH - Project Management * Ralph Soika - Software Developer */ package com.alexanderlogistics.xml; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.imixs.archive.core.SnapshotService; import org.imixs.workflow.ItemCollection; import org.imixs.workflow.WorkflowKernel; import org.imixs.workflow.engine.DocumentEvent; import org.imixs.workflow.engine.DocumentService; import org.imixs.workflow.engine.ModelService; 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 com.alexanderlogistics.BusinessPartnerService; import com.alexanderlogistics.InvoiceUtil; import jakarta.annotation.security.DeclareRoles; import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RunAs; import jakarta.ejb.EJB; import jakarta.ejb.Stateless; import jakarta.enterprise.event.Observes; /** * Der BusinessPartnerImportService hängt sich an den standard CSVImport Service * der die Cargosoft Stammdaten aktualisiert. Es ist ein simples Observer * Pattern das auf das Document Event "ON_DOCUMENT_SAVE" reagiert. Hier hängt * sich der BusinessPartnerImportService ein und prüft ob der Workflow schon * existiert oder ggf. aktualisiert werden muss. *

* Der Service migriert auch die alten zusätzlichen IBAN/BIC felder wenn der * Business partner erstmals neu angelegt wird. *

* Falls bei der ersten Migration erkannt wird, dass die IBAN Nummern nicht * eindeutig sind wir der BusinessPartner mit dem Event 300 angelegt. *

* Im Cargosoft Entity wird zusätzlich das flag NOSNAPSHOT=true gesetzt. Dies * ist nur eine Performance Optimierung. *

* Die Umsetzung erfolgt nach folgendem Prinzip: * Die K- bzw. D-Nummer (K70725 , D10725 ) werden die ersten beiden Stellen * abgeschnitten und mit BP ersetzt. * D.h. K70725 => BP0725 bzw. D10725 => BP0725 * Change: 24.8.2025: Da nun auch K8 und D2 Nummern auftauchen können wird in * diesen Fällen die Nummer hinter BP um 1 erweitert. Also nun auch * D.h. K80725 => BP10725 bzw. D20725 => BP10725 * * @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" }) @RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS") @Stateless public class BusinessPartnerImportService { private static Logger logger = Logger.getLogger(BusinessPartnerImportService.class.getName()); public static final String TYPE_CARGOSOFTKREDITOR = "cargosoftkreditor"; // public static final String OPTION_MANDANT_ID = "mandant.id"; // public static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; // public static final String REGEX_IMPORTTEXTPATTERN = "^R[1-8] .*$"; @EJB WorkflowService workflowService; @EJB DocumentService documentService; @EJB ModelService modelService; /** * Die Methode reagiert auf das CDI DocumentEvent beim Import von cargosoft * cargosoftkreditor documenten. * * */ public void onEvent(@Observes DocumentEvent event) { if (event == null || event.getDocument() == null) { return; } // run only if we have the model 'businesspartner-*'; if (modelService.findVersionsByRegEx("(businesspartner*)").size() == 0) { // no business partner workflow found return; } // check source if ("cargosoftkreditor".equals(event.getDocument().getType())) { if (event.getEventType() == DocumentEvent.ON_DOCUMENT_SAVE) { // set NOSNAPSHOT=true fro cargosoft item (migration) event.getDocument().setItemValue(SnapshotService.NOSNAPSHOT, true); logger.fine("Verify business partner object...."); ItemCollection importDoc = event.getDocument(); syncCargosoftBusinessPartner(importDoc); } if (event.getEventType() == DocumentEvent.ON_DOCUMENT_DELETE) { ItemCollection importDoc = event.getDocument(); String cargosoftID = importDoc.getItemValueString("name"); String partnerID = InvoiceUtil.buildBPID(cargosoftID); ItemCollection businesspartner = lookupBusinessPartner(partnerID); if (businesspartner != null && businesspartner.getTaskID() != 1800) { logger.info("lock business partner object...."); try { businesspartner.setEventID(80); workflowService.processWorkItemByNewTransaction(businesspartner); } catch (Exception e) { logger.warning( "Failed to lock Business Partner Object " + cargosoftID + " - " + e.getMessage()); } } } } } /** * Synchronisiert ein Cargosoft Objekt mit dem neuen Business partner * Objekt * * Die K- bzw. D-Nummer (K70725 , D10725 ) werden die ersten beiden Stellen * abgeschnitten und mit BP ersetzt. * D.h. K70725 => BP0725 bzw. D10725 => BP0725 * D.h. K80725 => BP10725 bzw. D20725 => BP10725 * * Die Methode gibt true zurück wenn sich das BusinessPartner Objekt geändert * oder neu erstellt wurde. * * @param creditor */ public boolean syncCargosoftBusinessPartner(ItemCollection importDoc) { String cargosoftID = importDoc.getItemValueString("name"); // K bedeutet Kreditor D bedeutet Debitor - beides kann vorkommen boolean isCreditor = cargosoftID.toUpperCase().startsWith("K"); // Konvertiere die KNummer in eine BP Nummer String partnerID = InvoiceUtil.buildBPID(cargosoftID); // Prüfen ob es diesen partner schon gibt? ItemCollection businesspartner = lookupBusinessPartner(partnerID); if (businesspartner == null) { businesspartner = createBusinessPartner(partnerID); } ItemCollection oldBussinessPartnerItemColl = (ItemCollection) businesspartner.clone(); // Update Fields... businesspartner.setItemValue("name", partnerID); businesspartner.setItemValue("partner.id", partnerID); if (isCreditor) { businesspartner.setItemValue("cdtr.number", cargosoftID); if (businesspartner.isItemEmpty("cdtr.mail")) { businesspartner.setItemValue("cdtr.mail", importDoc.getItemValueString("_vendor_email")); } } else { businesspartner.setItemValue("dbtr.number", cargosoftID); if (businesspartner.isItemEmpty("dbtr.mail")) { businesspartner.setItemValue("dbtr.mail", importDoc.getItemValueString("_vendor_email")); } } businesspartner.setItemValue("partner.country", importDoc.getItemValueString("_vendor_country")); businesspartner.setItemValue("partner.name", importDoc.getItemValueString("_vendor_name")); businesspartner.setItemValue("partner.phone", importDoc.getItemValueString("_vendor_phone")); businesspartner.setItemValue("partner.address", importDoc.getItemValueString("_vendor_str")); businesspartner.setItemValue("partner.zip", importDoc.getItemValueString("_vendor_zip_code")); businesspartner.setItemValue("partner.city", importDoc.getItemValueString("_vendor_city")); businesspartner.setItemValue("partner.vat", importDoc.getItemValueString("_vendor_vat_registration_id")); // hat sich das Objekt verändert? if (!businesspartner.equals(oldBussinessPartnerItemColl)) { // Prüfe IBAN auf plausibilität List bankList = BusinessPartnerService.getBanks(businesspartner); boolean ibanDublette = false; List dublettenIban = new ArrayList<>(); for (ItemCollection bank : bankList) { String iban = bank.getItemValueString("iban"); // erkenne fehlerhaften kontonummern if (dublettenIban.contains(iban)) { // ACHTUNG - uneindeutige Bankverbindung ibanDublette = true; } else { dublettenIban.add(iban); } } int eventID = 200; // default update // event errechnen if (!businesspartner.hasItem(WorkflowKernel.LASTEVENT)) { // create new! if (ibanDublette) { eventID = 300; // Exception } else { eventID = 100; // new import } } businesspartner.setEventID(eventID); try { workflowService.processWorkItemByNewTransaction(businesspartner); } catch (AccessDeniedException | ProcessingErrorException | PluginException | ModelException e) { logger.warning("Failed to update Business Partner Object " + cargosoftID + " - " + e.getMessage()); } return true; } else { return false; // no changes } } /** * Erstellt ein neues leeres Business Partner Object * * @return */ private ItemCollection createBusinessPartner(String cargosoftID) { ItemCollection businessPartner = new ItemCollection(); businessPartner.setType("workitem"); businessPartner.setWorkflowGroup("Business Partner"); businessPartner.task(1000); // Hier migrieren wir jetzt auch die alten IBAN/BIC Daten try { String query = "(type:" + TYPE_CARGOSOFTKREDITOR + ")"; query = query + " AND ( name:" + cargosoftID + " )"; List oldList = documentService.find(query, 2, 0); // es können 2 Datensätze ankommen // Items: // cdtr.mail (Liste) // cdtr.creditperiod // cdtr.iban , cdtr.iban2 - 4 // cdtr.bic , cdtr.bic2 - 4 List ibanList = new ArrayList<>(); List bicList = new ArrayList<>(); for (ItemCollection oldData : oldList) { if (!oldData.getItemValueString("cdtr.mail").isEmpty()) { businessPartner.setItemValue("cdtr.mail", oldData.getItemValue("cdtr.mail")); businessPartner.setItemValue("dbtr.mail", oldData.getItemValue("cdtr.mail")); } if (!oldData.getItemValueString("cdtr.creditperiod").isEmpty()) { businessPartner.setItemValue("cdtr.creditperiod", oldData.getItemValue("cdtr.creditperiod")); } if (!oldData.getItemValueString("cdtr.iban").isEmpty()) { ibanList.add(oldData.getItemValueString("cdtr.iban")); } if (!oldData.getItemValueString("cdtr.bic").isEmpty()) { bicList.add(oldData.getItemValueString("cdtr.bic")); } if (!oldData.getItemValueString("cdtr.iban2").isEmpty()) { ibanList.add(oldData.getItemValueString("cdtr.iban2")); } if (!oldData.getItemValueString("cdtr.bic2").isEmpty()) { bicList.add(oldData.getItemValueString("cdtr.bic2")); } if (!oldData.getItemValueString("cdtr.iban3").isEmpty()) { ibanList.add(oldData.getItemValueString("cdtr.iban3")); } if (!oldData.getItemValueString("cdtr.bic3").isEmpty()) { bicList.add(oldData.getItemValueString("cdtr.bic3")); } if (!oldData.getItemValueString("cdtr.iban4").isEmpty()) { ibanList.add(oldData.getItemValueString("cdtr.iban4")); } if (!oldData.getItemValueString("cdtr.bic4").isEmpty()) { bicList.add(oldData.getItemValueString("cdtr.bic4")); } } // build partner.iban.list - dublettenprüfung und Trim List dubletten = new ArrayList<>(); List dublettenIban = new ArrayList<>(); if (ibanList.size() > 0) { List bankList = new ArrayList<>(); for (int i = 0; i < ibanList.size(); i++) { String iban = ibanList.get(i); String bic = ""; if (bicList.size() > i) { bic = bicList.get(i); } iban = superTrim(iban); bic = superTrim(bic); if (dubletten.contains(iban + "/" + bic)) { // voll dublette continue; } else { dubletten.add(iban + "/" + bic); } ItemCollection bank = new ItemCollection(); // {cdtr.iban=[A], name=[cdtr1], cdtr.name=[a], cdtr.bic=[a]} bank.setItemValue("id", "bank" + (i + 1)); bank.setItemValue("name", "Bank " + (i + 1)); bank.setItemValue("iban", iban); bank.setItemValue("bic", bic); bankList.add(bank); } Iterator var3 = bankList.iterator(); List mapOrderItems = new ArrayList(); while (var3.hasNext()) { ItemCollection orderItem = (ItemCollection) var3.next(); mapOrderItems.add(orderItem.getAllItems()); } businessPartner.setItemValue(BusinessPartnerService.ITEM_IBAN_LIST, mapOrderItems); } } catch (QueryException e) { // TODO Auto-generated catch block e.printStackTrace(); } return businessPartner; } /** * entfernt alle leerzeichen */ public String superTrim(String data) { String result = data.trim(); result = result.replace(" ", ""); return result; } /** * Sucht nach einem Business partner * * @param id * @return */ private ItemCollection lookupBusinessPartner(String id) { String query = "(type:workitem OR type:workitemarchive) AND ($modelversion:businesspartner*) AND (name:" + id + ")"; try { List result = documentService.find(query, 1, 0, null, false); if (result.size() > 0) { return result.get(0); } } catch (QueryException e) { logger.warning("Failed to query businesspartner: " + query + " - Error: " + e.getMessage()); } return null; } }