/******************************************************************************* * 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.api; import java.io.Serializable; import java.util.List; import java.util.logging.Logger; import org.imixs.marty.team.TeamService; import org.imixs.workflow.ItemCollection; import org.imixs.workflow.engine.DocumentService; import org.imixs.workflow.engine.WorkflowService; import org.imixs.workflow.engine.index.UpdateService; 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 com.alexanderlogistics.mahnlauf.MahnlaufService; import jakarta.ejb.TransactionAttribute; import jakarta.ejb.TransactionAttributeType; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; /** ** Dieser Service korrigiert falsch importierte Cargosoft daten. * Ausgangsrechnungen die ein falsches Jahr haben. * * Oder DAten die über die XML Schnittstelle falsch reinkamen... * * @author rsoika * @version 1.1 */ @ApplicationScoped @Produces({ MediaType.TEXT_HTML, MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) @Path("/cargosoft") public class CargosoftMigrationRestService implements Serializable { private static final long serialVersionUID = 1L; String log = ""; int errors = 0; int count = 0; boolean isRunning = false; @Inject DocumentService documentService; @Inject WorkflowService workflowService; @Inject MahnlaufService mahnlaufService; @Inject UpdateService updateService; @Inject TeamService teamService; @Inject BusinessPartnerService businessPartnerService; private static Logger logger = Logger.getLogger(CargosoftMigrationRestService.class.getName()); public CargosoftMigrationRestService() { super(); } /** * Dieser agent prüft ob es für Cargosoft Krediotren/Debitoren Daten schon ein * passendes Businesspartner Workitem gibt. * Wenn nicht speichert der Service einmal das cargosft entity was dann zur * automatischen Neuanlage des businesspartner workflows führt. * * * curl -H "Cookie: * JSESSIONID=ShAegfNiXmqLFLSFwcUZ7hrLLQDKZGKiu4oj_xeX.imixs-office-workflow-8586d7d58d-h6k4q" * https://alexander-logistics-dwc.office-workflow.de/api/cargosoft/bp-sync?maxcount=1000 * * @return * @throws QueryException * @throws AccessDeniedException * @throws ProcessingErrorException * @throws PluginException * @throws ModelException */ @GET @Path("/bp-sync") @Produces({ MediaType.TEXT_PLAIN }) public String syncBusinessPartner(@QueryParam("maxcount") int maxcount) throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException { StringBuffer messageBuffer = new StringBuffer(); if (maxcount <= 0) { maxcount = 100; } String query = "(type:cargosoftkreditor)"; int syncs = 0; long l = System.currentTimeMillis(); int batchSize = 100; int totalObjects = 0; log("├── sync business partner objects....", messageBuffer); if (isRunning) { log("├── sync process already running!", messageBuffer); return messageBuffer.toString(); } isRunning = true; int totalCount = documentService.count(query); log("│   ├── found " + totalCount + " cargosoft entries", messageBuffer); // Berechne Anzahl der benötigten Pages int totalPages = (int) Math.ceil((double) totalCount / batchSize); // Verarbeite Page für Page for (int pageIndex = 0; pageIndex < totalPages; pageIndex++) { List cargosoftDataList = documentService.find(query, batchSize, pageIndex); for (ItemCollection cargosoftItemCol : cargosoftDataList) { totalObjects++; if (syncBusinessPartner(cargosoftItemCol)) { syncs++; // Explicit flush the lucene search event log updateService.updateIndex(); } if (syncs >= maxcount) break; } // Fortschritt loggen log("│ ├── Processed page " + (pageIndex + 1) + " of " + totalPages + " (" + syncs + " total syncs)", messageBuffer); // Optional: Kurze Pause nach jedem 5. Batch try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (syncs >= maxcount) break; } long duration = System.currentTimeMillis() - l; double objectsPerSecond = totalObjects / (duration / 1000.0); log("├── Successfully " + syncs + " business partner objects synced in " + duration + "ms (" + String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer); isRunning = false; return messageBuffer.toString(); } /** * Hilfsmethode speichert eine cargoosft kreditor object... * * @param bpID * @param messageBuffer * @return */ @TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW) public boolean syncBusinessPartner(ItemCollection cargosoftItemCol) { String bpip = InvoiceUtil.buildBPID(cargosoftItemCol.getItemValueString("name")); if (businessPartnerService.getBusinessPartnerByID(bpip) == null) { // not available so we save just the cargosoft entry once... documentService.save(cargosoftItemCol); return true; } return false; } /** * Dieser agent löscht einfach alle Businesspartner objekte. Wird eigentlich * nicht mehr benötigt. * * curl -H "Cookie: * JSESSIONID=ShAegfNiXmqLFLSFwcUZ7hrLLQDKZGKiu4oj_xeX.imixs-office-workflow-8586d7d58d-h6k4q" * https://alexander-logistics-dwc.office-workflow.de/api/cargosoft/bp-delete?maxcount=10000 * * @return * @throws QueryException * @throws AccessDeniedException * @throws ProcessingErrorException * @throws PluginException * @throws ModelException */ @GET @Path("/bp-delete") @Produces({ MediaType.TEXT_PLAIN }) public String deleteBusinessPartner(@QueryParam("maxcount") int maxcount) throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException { StringBuffer messageBuffer = new StringBuffer(); String query = "(type:workitem*) AND ($modelversion: businesspartner*)"; int deletions = 0; long l = System.currentTimeMillis(); int batchSize = 100; int totalObjects = 0; log("├── delete old business partner objects....", messageBuffer); if (isRunning) { log("├── sync process already running!", messageBuffer); return messageBuffer.toString(); } isRunning = true; log("│   ├── maxcount= " + maxcount, messageBuffer); int totalCount = documentService.count(query); log("│   ├── found " + totalCount + " entities ", messageBuffer); // Berechne Anzahl der benötigten Pages int totalPages = (int) Math.ceil((double) totalCount / batchSize); // Verarbeite Page für Page int iterations = 0; while (deletions < maxcount) { List cargosoftDataList = documentService.find(query, batchSize, 0); if (cargosoftDataList.size() == 0) { break; } for (ItemCollection cargosoftItemCol : cargosoftDataList) { totalObjects++; if (deleteBusinessPartner(cargosoftItemCol, messageBuffer)) { deletions++; } if (deletions >= maxcount) break; } // Explicit flush the lucene search event log updateService.updateIndex(); // Fortschritt loggen iterations++; log("│ ├── Processed page " + (iterations) + " of " + totalPages + " (" + deletions + " total deletions)", messageBuffer); // Optional: Kurze Pause nach jedem 5. Batch try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (deletions >= maxcount) break; } long duration = System.currentTimeMillis() - l; double objectsPerSecond = totalObjects / (duration / 1000.0); log("├── Successfully " + deletions + " business partner objects deleted in " + duration + "ms (" + String.format("%.1f", objectsPerSecond) + " objects/sec)", messageBuffer); isRunning = false; return messageBuffer.toString(); } /** * Hilfsmethode - löscht ein cargoosoft object... * * @param bpID * @param messageBuffer * @return */ @TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW) public boolean deleteBusinessPartner(ItemCollection cargosoftItemCol, StringBuffer messageBuffer) { documentService.remove(cargosoftItemCol); return true; } private void log(String message, StringBuffer messageLog) { logger.info(message); messageLog.append(message + "\n"); } }