office-alexander-logistics/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/SteuerbescheidPlugin.java
2026-04-02 12:34:22 +02:00

199 lines
7.1 KiB
Java

package com.alexanderlogistics;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.plugins.AbstractPlugin;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;
import jakarta.inject.Inject;
/**
* Das SteuerbescheidPlugin prüft ob
*
* - die ATC Nummer aus dem Steuerbescheid in einer Ausgangsrechnung gefunden
* wird ($taskID<5990) - invoice.atc.number - der Betrag "invoice.total.net" -
* die Währung??? - die Positionsnummer ???
*
*
* @author rsoika
* @version 1.0
*
*/
public class SteuerbescheidPlugin extends AbstractPlugin {
private static Logger logger = Logger.getLogger(SteuerbescheidPlugin.class.getName());
@Inject
protected DocumentService documentService;
/**
* Prüft ob der Steuerbetrag abgerechnet ist.
*
*
**/
@Override
public ItemCollection run(ItemCollection workitem, ItemCollection event) throws PluginException {
// Update Fälligkeit
updateFaelligkeit(workitem);
// Update Salden
updateTotalEustZoll(workitem);
updateInvoiceSaldo(workitem);
return workitem;
}
/**
* Aktualisiert die EUST/ZOLL Summen
*
*/
protected void updateTotalEustZoll(ItemCollection workitem) {
double saldoEust = 0;
double saldoZoll = 0;
List<ItemCollection> positionsTabelle = InvoiceUtil.explodeChildList(workitem);
for (ItemCollection pos : positionsTabelle) {
if ("EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
saldoEust = saldoEust + pos.getItemValueDouble("amount");
}
if ("ZOLL".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
saldoZoll = saldoZoll + pos.getItemValueDouble("amount");
}
}
workitem.setItemValue("steuer.eust", saldoEust);
workitem.setItemValue("steuer.zoll", saldoZoll);
}
/**
* Aktualisiert die EUST/ZOLL Fälligkeiten in den Detailtabellen Die Daten
* kommen von der KI und werden auf die Positionsnummern gemappt.
*
*/
protected void updateFaelligkeit(ItemCollection workitem) {
boolean foundZoll = false;
boolean foundEust = false;
Date datEust = null;
Date datZoll = null;
// resolve datEust und datZoll from steuerbescheid.positionen ChildItems....
List<ItemCollection> steuerPositionen = InvoiceUtil.explodeChildList(workitem, "steuerbescheid.position");
for (ItemCollection steuerPos : steuerPositionen) {
if (steuerPos.getItemValueString("key").startsWith("A")) {
datZoll = steuerPos.getItemValueDate("duedate");
}
if (steuerPos.getItemValueString("key").startsWith("B")) {
datEust = steuerPos.getItemValueDate("duedate");
}
}
// Map fälligkeit auf die Cargosoft Positionen
List<ItemCollection> rows = InvoiceUtil.explodeChildList(workitem);
for (ItemCollection pos : rows) {
if (datZoll != null && "ZOLL".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
pos.setItemValue("duedate", datZoll);
foundZoll = true;
}
if (datEust != null && "EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
pos.setItemValue("duedate", datEust);
foundEust = true;
}
}
if (foundEust) {
workitem.setItemValue("steuer.eust.due", datEust);
} else {
workitem.removeItem("steuer.eust.due");
}
if (foundZoll) {
workitem.setItemValue("steuer.zoll.due", datZoll);
} else {
workitem.removeItem("steuer.zoll.due");
}
InvoiceUtil.implodeChildList(workitem, rows);
}
/**
* Aktualisiert den invoice.saldo anhand der ausgehenden Rechnungen zu einer ATC
* Nummer
*
*/
protected void updateInvoiceSaldo(ItemCollection workitem) {
String atcNummer = workitem.getItemValueString("invoice.atc.number");
logger.fine("Verify ATC-Nr.: " + atcNummer);
double amount = workitem.getItemValueDouble("invoice.total.net");
List<ItemCollection> invoices = findInvoices(atcNummer);
// Beträge subtrahieren....
double saldo = amount;
logger.info("Found " + invoices.size() + " matching invoices for ATC-No: " + atcNummer);
for (ItemCollection invoice : invoices) {
workitem.setItemValueUnique("$workitemRef", invoice.getUniqueID());
// suche die Zeile in der die ATC Nummer vorkommt.
List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
for (ItemCollection pos : positionen) {
// if (atcNummer.equals(pos.getItemValueString("atc.number"))) {
// Support both variants....
String posAtcNummer = pos.getItemValueString("atc.number");
if (!posAtcNummer.isEmpty() && atcNummer.startsWith(posAtcNummer)) {
double umsatz = pos.getItemValueDouble("datev.umsatz");
logger.info("...Umsatz=" + umsatz);
saldo = InvoiceUtil.round(saldo - umsatz);
}
}
}
// Update Saldo
workitem.setItemValue("invoice.saldo", InvoiceUtil.round(saldo));
}
/*
* Sucht alle Ausgansrechnungen zu einer ATC Nummer
*/
protected List<ItemCollection> findInvoices(String atcNumber) {
List<ItemCollection> result = new ArrayList<ItemCollection>();
// String query = "(type:workitem OR type:workitemarchive) AND ($taskid:[5000 TO
// 5990])"
// + " AND invoice.atc.number:\"" + atcNumber + "\" " + " AND
// $workflowgroup:\"Rechnungsausgang\" ";
/**
* Änderung 2.4.2026 - die ATC Nummer ist nun häufig eine Kombination
* z.B: 26DE2452CCA004P4R3/ATC400057440320262452
* Relevant ist nur der vordere Teil weil nur der vordere in die Invoice
* geschrieben wurde.
* Deswegen schneiden wir den vorderen Teil ab und suchen mit OR nach beiden
* Schreibweisen
*/
String query = "(type:workitem OR type:workitemarchive) AND ($taskid:[5000 TO 5990])"
+ " AND ($workflowgroup:\"Rechnungsausgang\") ";
if (atcNumber.contains("/")) {
String atcNumberShort = atcNumber.substring(0, atcNumber.indexOf("/"));
query = query + " AND (invoice.atc.number:\"" + atcNumber + "\" OR invoice.atc.number:\"" + atcNumberShort
+ "\") ";
} else {
query = query + " AND (invoice.atc.number:\"" + atcNumber + "\") ";
}
try {
result = documentService.find(query, 999, 0, "$created", false);
return result;
} catch (QueryException e) {
logger.severe("Failed to get invoices: " + e.getMessage());
}
return result;
}
}