237 lines
No EOL
10 KiB
Java
237 lines
No EOL
10 KiB
Java
package com.alexanderlogistics;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.ListIterator;
|
|
import java.util.Map;
|
|
import java.util.StringTokenizer;
|
|
import java.util.logging.Logger;
|
|
import java.util.regex.Pattern;
|
|
|
|
import org.imixs.workflow.ItemCollection;
|
|
import org.imixs.workflow.SignalAdapter;
|
|
import org.imixs.workflow.WorkflowKernel;
|
|
import org.imixs.workflow.engine.WorkflowService;
|
|
import org.imixs.workflow.engine.plugins.SplitAndJoinPlugin;
|
|
import org.imixs.workflow.exceptions.AdapterException;
|
|
import org.imixs.workflow.exceptions.ModelException;
|
|
import org.imixs.workflow.exceptions.PluginException;
|
|
import org.imixs.workflow.office.util.SequenceService;
|
|
|
|
import jakarta.inject.Inject;
|
|
|
|
/**
|
|
* Der CargosoftSplitAdapter erezeugt anhand der Positionstablelle eignee
|
|
* cargosoft export workitems, getrennt für jede Buchungsperdiode. Dies ist
|
|
* notwendig, da Cargosoft selbst nicht mit unterschiedlichen Buchungsperioden
|
|
* in einer Rechnung umgehen kann.
|
|
* <p>
|
|
* adapter exports the invoice data to a ftp server connected to cargosoft. Da
|
|
* auch eine fortlaufene Rechnungsnummer von Cargosoft zwingend vorgeschrieben
|
|
* ist, erzeugt der adapter auch für jedes weiteres cargosoft export worktiem
|
|
* ein neue Sequencenummer die im Hautpworkitem gespeichert wird.
|
|
* <p>
|
|
* Der Adapter wird im Modell wie folgt konfiguriert
|
|
*
|
|
* <pre>
|
|
* {@code
|
|
<cargosoft>
|
|
<modelversion>cargosoft-export-1.0</modelversion>
|
|
<task>1000</task>
|
|
<event>100</event>
|
|
<items>(?!txtworkflowhistory)(^[a-zA-Z]|^_)</items>
|
|
</cargosoft>
|
|
|
|
}
|
|
* </pre>
|
|
* <p>
|
|
* Because we also export the attachment data to cargosoft, the adaper lookups
|
|
* the conente of the attachment in the snapshot of the origin workitem
|
|
*
|
|
*
|
|
* @version 1.0
|
|
* @author rsoika
|
|
*/
|
|
public class CargosoftSplitAdapter implements SignalAdapter {
|
|
|
|
public static final String CONFIG_ERROR = "CONFIG_ERROR";
|
|
private static Logger logger = Logger.getLogger(CargosoftSplitAdapter.class.getName());
|
|
|
|
@Inject
|
|
WorkflowService workflowService;
|
|
|
|
@Inject
|
|
SequenceService sequenceService;
|
|
|
|
/**
|
|
* This method computes the cargosoft export data file
|
|
*
|
|
* @throws PluginException
|
|
*/
|
|
@SuppressWarnings("rawtypes")
|
|
@Override
|
|
public ItemCollection execute(ItemCollection workitem, ItemCollection event)
|
|
throws AdapterException, PluginException {
|
|
|
|
logger.info("......starting export...");
|
|
try {
|
|
|
|
// read the cargosoft split options
|
|
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "cargosoft", workitem, false);
|
|
|
|
if (evalItemCollection == null) {
|
|
throw new PluginException(CargosoftSplitAdapter.class.getSimpleName(), CONFIG_ERROR,
|
|
"missign cargosoft configuration in model event - please check model configuration");
|
|
}
|
|
String model = evalItemCollection.getItemValueString("model");
|
|
int taskID = evalItemCollection.getItemValueInteger("task");
|
|
int eventID = evalItemCollection.getItemValueInteger("event");
|
|
String items = evalItemCollection.getItemValueString("items");
|
|
|
|
if (model.isEmpty() || taskID == 0 || eventID == 0) {
|
|
throw new PluginException(CargosoftSplitAdapter.class.getSimpleName(), CONFIG_ERROR,
|
|
"missign cargosoft configuration 'model', 'task', 'event' - please check model configuration");
|
|
}
|
|
|
|
// Zunaechst müssen wir festelstellen, ob es mehrere unterschiedliche
|
|
// Buchungsperioden in der Positionstabelle gibt.
|
|
List<String> buchungsPersioden = new ArrayList<String>();
|
|
// add haupt buchungsperiode
|
|
buchungsPersioden.add(workitem.getItemValueString("invoice.period"));
|
|
List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(workitem);
|
|
for (ItemCollection posItem : positionsTabelle) {
|
|
String childPeriod = posItem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD);
|
|
if (!childPeriod.isEmpty() && !buchungsPersioden.contains(childPeriod)) {
|
|
buchungsPersioden.add(childPeriod);
|
|
}
|
|
|
|
}
|
|
|
|
// nun wird für jede Buchungsperiode ein eigener corgosoft Export angestoßen....
|
|
boolean nextSequencenumber = false;
|
|
for (String buchungsPeriode : buchungsPersioden) {
|
|
// nun entnehmen wir aus der positionsTabelle alle einträge die zu dieser
|
|
// Periode passen...
|
|
// (die erste Periode ist die default periode welche wir nehemn wenn keine
|
|
// Periode angegeben wurde).
|
|
ItemCollection workitemSubProcess = new ItemCollection();
|
|
// now clone the field list...
|
|
copyItemList(items, workitem, workitemSubProcess);
|
|
|
|
// in die _childs Liste kommen jetzt nur passende Positionseinträge mit der
|
|
// selben Buchungsperiode
|
|
List<Map> splitPositionen = new ArrayList<Map>();
|
|
ListIterator<ItemCollection> iter = positionsTabelle.listIterator();
|
|
int row = 1;
|
|
float netto = 0;
|
|
float total = 0;
|
|
// float tax=0;
|
|
while (iter.hasNext()) {
|
|
ItemCollection posItem = iter.next();
|
|
String childPeriod = posItem.getItemValueString(InvoiceUtil.ITEM_INVOICE_PERIOD);
|
|
if (childPeriod.isEmpty() || buchungsPeriode.equals(childPeriod)) {
|
|
posItem.setItemValue("numpos", row);
|
|
splitPositionen.add(posItem.getAllItems());
|
|
iter.remove();
|
|
row++;
|
|
netto = netto + posItem.getItemValueFloat("amount");
|
|
total = total + posItem.getItemValueFloat("total");
|
|
|
|
}
|
|
}
|
|
workitemSubProcess.setItemValue(InvoiceUtil.ITEM_INVOICE_PERIOD, buchungsPeriode);
|
|
// jetzt muessen wir die neue Rechnungssumme bilden....
|
|
workitemSubProcess.setItemValue("order.total", total);
|
|
workitemSubProcess.setItemValue("order.total.tax", total - netto);
|
|
workitemSubProcess.setItemValue("order.total.netto", netto);
|
|
|
|
logger.info("......create cargosoft split buchung - invoice.period=" + buchungsPeriode);
|
|
// update the child items (reduzierte Positionstabelle)
|
|
workitemSubProcess.setItemValue(InvoiceUtil.CHILD_ITEM_PROPERTY, splitPositionen);
|
|
|
|
workitemSubProcess.model(model).task(taskID).event(eventID);
|
|
workitemSubProcess.replaceItemValue(WorkflowService.UNIQUEIDREF, workitem.getUniqueID());
|
|
|
|
// ab dem zweiten durchlauf benötigen wir immer eine neue sequencenumer
|
|
if (nextSequencenumber) {
|
|
workitemSubProcess.removeItem("numsequencenumber");
|
|
// wegen numernkreis bildung muss hier die WorkflowGroup kurzfristig auf
|
|
// 'Rechnungseingang' gesetzt werden!
|
|
workitemSubProcess.setItemValue(WorkflowKernel.WORKFLOWGROUP, workitem.getWorkflowGroup());
|
|
sequenceService.computeSequenceNumber(workitemSubProcess);
|
|
logger.info(".......compute new sequence number: "
|
|
+ workitemSubProcess.getItemValueLong("numsequencenumber"));
|
|
workitem.appendItemValueUnique("numsequencenumber_sub",
|
|
workitemSubProcess.getItemValueLong("numsequencenumber"));
|
|
} else {
|
|
nextSequencenumber = true;
|
|
}
|
|
workitemSubProcess = workflowService.processWorkItem(workitemSubProcess);
|
|
// finally add the new workitemRef into the origin
|
|
workitem.appendItemValueUnique(SplitAndJoinPlugin.LINK_PROPERTY, workitemSubProcess.getUniqueID());
|
|
|
|
}
|
|
|
|
} catch (ModelException e) {
|
|
logger.severe("cargosoft split failed: " + e.getMessage());
|
|
throw new PluginException(CargosoftSplitAdapter.class.getSimpleName(), CONFIG_ERROR, e.getMessage(), e);
|
|
}
|
|
|
|
return workitem;
|
|
}
|
|
|
|
/**
|
|
* This Method copies the fields defined in 'items' into the targetWorkitem.
|
|
* Multiple values are separated with comma ','.
|
|
* <p>
|
|
* In case a item name contains '|' the target field name will become the right
|
|
* part of the item name.
|
|
* <p>
|
|
* Example: {@code
|
|
* txttitle,txtfirstname
|
|
*
|
|
* txttitle|newitem1,txtfirstname|newitem2
|
|
*
|
|
* }
|
|
*
|
|
* <p>
|
|
* Optional also reg expressions are supported. In this case mapping of the item
|
|
* name is not supported.
|
|
* <p>
|
|
* Example: {@code
|
|
* (^artikel$|^invoice$),txtTitel|txtNewTitel
|
|
*
|
|
*
|
|
* } A reg expression must be includes in brackets.
|
|
*
|
|
*/
|
|
protected void copyItemList(String items, ItemCollection source, ItemCollection target) {
|
|
// clone the field list...
|
|
StringTokenizer st = new StringTokenizer(items, ",");
|
|
while (st.hasMoreTokens()) {
|
|
String field = st.nextToken().trim();
|
|
|
|
// test if field is a reg ex
|
|
if (field.startsWith("(") && field.endsWith(")")) {
|
|
Pattern itemPattern = Pattern.compile(field);
|
|
Map<String, List<Object>> map = source.getAllItems();
|
|
for (String itemName : map.keySet()) {
|
|
if (itemPattern.matcher(itemName).find()) {
|
|
target.replaceItemValue(itemName, source.getItemValue(itemName));
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// default behavior without reg ex
|
|
int pos = field.indexOf('|');
|
|
if (pos > -1) {
|
|
target.replaceItemValue(field.substring(pos + 1).trim(),
|
|
source.getItemValue(field.substring(0, pos).trim()));
|
|
} else {
|
|
target.replaceItemValue(field, source.getItemValue(field));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} |