package com.alexanderlogistics; import java.io.Serializable; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.imixs.workflow.ItemCollection; import org.imixs.workflow.engine.DocumentService; import org.imixs.workflow.exceptions.QueryException; import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.json.Json; import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; /** * Der AGLAnalyticController berechnet verschiedene Analyse Daten * * @author rsoika * */ @Named @RequestScoped public class AGLAnalyticController implements Serializable { private static final long serialVersionUID = 1L; private static Logger logger = Logger.getLogger(AnalyticController.class.getName()); @Inject protected DocumentService documentService; @Inject protected DebitorStatistikController debitorStatistikController; List steuerbescheide = null; public void onEvent(@Observes AnalyticEvent event) { if ("analytic.steuer.eust".equals(event.getKey())) { event.setValue(computeSteuerbescheideEUST()); event.setLabel("EUR"); event.setDescription("Gesamt Einfuhrumsatzsteuer (EUSt)"); event.getWorkitem().setItemValue("eust.total", event.getValue()); } if ("analytic.steuer.zoll".equals(event.getKey())) { event.setValue(computeSteuerbescheideZoll()); event.setLabel("EUR"); event.setDescription("Gesamt Zölle (ZOLLEU)"); } if ("analytic.steuer.due".equals(event.getKey())) { event.setValue(computeSteuerbescheideUeberfaellig()); event.setLabel("EUR"); event.setDescription("Überfällige Steuerbescheide die noch nicht abgerechnet wurden."); } if ("analytic.steuer.trend".equals(event.getKey())) { event.setValue(accumulateSteuerbescheideByWeek()); event.setLabel("Zoll & EUST"); event.setDescription("Fälligkeiten nach KW"); } } /** * Berechnet die Summe aller offenen EUST Beträge * // tax.code=[0], amount=[3885.16], activity.type=[EUST], * // filenumber=[LA-PAP-2408-024]} * * @return */ private double computeSteuerbescheideEUST() { logger.info("compute EUST..."); List list = getSteuerbescheide(); double result = 0; for (ItemCollection steuerItemCol : list) { result = result + getZollBySteuerBeleg(steuerItemCol, "EUST"); // List positionsTabelle = // InvoiceUtil.explodeChildList(steuerItemCol); // for (ItemCollection pos : positionsTabelle) { // if ("EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) { // result = result + pos.getItemValueDouble("amount"); // } // } } return InvoiceUtil.round(result); } /** * Berechnet die Summe aller offenen Zoll Beträge * * @return */ private double computeSteuerbescheideZoll() { logger.info("compute Zoll..."); List list = getSteuerbescheide(); double result = 0; for (ItemCollection steuerItemCol : list) { result = result + getZollBySteuerBeleg(steuerItemCol, "ZOLL"); // List positionsTabelle = // InvoiceUtil.explodeChildList(steuerItemCol); // for (ItemCollection pos : positionsTabelle) { // if ("ZOLL".equalsIgnoreCase(pos.getItemValueString("activity.type"))) { // result = result + pos.getItemValueDouble("amount"); // } // } } return InvoiceUtil.round(result); } /** * Berechnet die Summe aller überfälligen steuer Beträge $taskID=1200 * * @return */ private double computeSteuerbescheideUeberfaellig() { logger.info("compute EUST..."); List list = getSteuerbescheide(); double result = 0; for (ItemCollection steuerItemCol : list) { if (steuerItemCol.getTaskID() == 1200) { result = result + steuerItemCol.getItemValueDouble("invoice.saldo"); } } return InvoiceUtil.round(result); } /** * Berechnet die summ zoll/eust für einen Beleg * * @param steuerItemCol * @return */ private double getZollBySteuerBeleg(ItemCollection steuerItemCol, String type) { double result = 0; List positionsTabelle = InvoiceUtil.explodeChildList(steuerItemCol); for (ItemCollection pos : positionsTabelle) { if (type.equalsIgnoreCase(pos.getItemValueString("activity.type"))) { result = result + pos.getItemValueDouble("amount"); } } return result; } private List getSteuerbescheide() { if (steuerbescheide != null) { return steuerbescheide; } // compute steuerbescheide.... logger.info("Load Steuerbescheide for analytics...."); String query = "(type:workitem ) AND ($workflowgroup:\"Steuerbescheid\")"; try { steuerbescheide = documentService.find(query, 999, 0, "$created", false); return steuerbescheide; } catch (QueryException e) { logger.severe("Failed to get invoices: " + e.getMessage()); } return null; } /** * Berechnet Chart daten aller Steuerbescheide bei KW * *
	 * 
	   chartCfg = {
		  type: 'bar',
		  data: {
			datasets: [{
			  data: [20, 10],
			}],
			labels: ['1', '2']
		  }
	    }
	 * 
	 * 
* * @return */ private String accumulateSteuerbescheideByWeek() { logger.info("accumulate steuer by week..."); List list = getSteuerbescheide(); Map saldoByWeek = new HashMap<>(); Calendar calendar = Calendar.getInstance(); int earliestWeek = Integer.MAX_VALUE; int latestWeek = Integer.MIN_VALUE; // Step 1: Group saldo by week for (ItemCollection steuerItemCol : list) { double saldo = steuerItemCol.getItemValueDouble("invoice.saldo"); Date date = steuerItemCol.getItemValueDate("invoice.date"); // Get the week number and year from the date calendar.setTime(date); int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR); int year = calendar.get(Calendar.YEAR); int yearWeek = year * 100 + weekNumber; // Unique key for each year + week combination // Accumulate the saldo per week SteuerData steuerDataByWeek = saldoByWeek.getOrDefault(yearWeek, new SteuerData()); double eust = getZollBySteuerBeleg(steuerItemCol, "EUST"); double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL"); steuerDataByWeek.add(eust, zoll, saldo); saldoByWeek.put(yearWeek, steuerDataByWeek); // Track the earliest and latest weeks earliestWeek = Math.min(earliestWeek, yearWeek); latestWeek = Math.max(latestWeek, yearWeek); } // Step 2: Prepare the JSON structure and ensure we have all weeks from earliest // to latest JsonArrayBuilder dataBuilderSaldo = Json.createArrayBuilder(); JsonArrayBuilder dataBuilderEust = Json.createArrayBuilder(); JsonArrayBuilder dataBuilderZoll = Json.createArrayBuilder(); JsonArrayBuilder labelsBuilder = Json.createArrayBuilder(); Calendar startCal = Calendar.getInstance(); startCal.set(Calendar.YEAR, earliestWeek / 100); startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100); Calendar endCal = Calendar.getInstance(); endCal.set(Calendar.YEAR, latestWeek / 100); endCal.set(Calendar.WEEK_OF_YEAR, latestWeek % 100); while (!startCal.after(endCal)) { int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR); int year = startCal.get(Calendar.YEAR); int yearWeek = year * 100 + weekNumber; // Add the saldo for the week or 0.0 if no data SteuerData steuerData = saldoByWeek.getOrDefault(yearWeek, new SteuerData()); dataBuilderSaldo.add(steuerData.saldo); dataBuilderEust.add(steuerData.eust); dataBuilderZoll.add(steuerData.zoll); labelsBuilder.add(weekNumber + "/" + year); // Label as 'week/year' // Move to the next week startCal.add(Calendar.WEEK_OF_YEAR, 1); } // Step 3: Prepare the JSON structure JsonObjectBuilder jsonBuilder = Json.createObjectBuilder() .add("type", "bar") .add("data", Json.createObjectBuilder() .add("datasets", Json.createArrayBuilder() .add(Json.createObjectBuilder() // First dataset for 'tax' .add("label", "Zoll") .add("backgroundColor", "#96f") .add("borderWidth", 1) .add("data", dataBuilderZoll)) .add(Json.createObjectBuilder() // Second dataset for 'eust' .add("label", "EUSt") .add("backgroundColor", "#36a2eb") .add("borderWidth", 1) .add("data", dataBuilderEust)) .add(Json.createObjectBuilder() // Third dataset for 'Saldo' .add("label", "Saldo") .add("backgroundColor", "#ff6384") .add("borderWidth", 1) .add("data", dataBuilderSaldo))) .add("labels", labelsBuilder)); // Step 4: Return the JSON structure as a string JsonObject chartCfg = jsonBuilder.build(); return chartCfg.toString(); } /** * Helper method to hold zoll and eust totls in an object. Needed to build * totals per week. */ class SteuerData { double total = 0.0; double zoll = 0.0; double eust = 0.0; double saldo = 0.0; public SteuerData() { // default constructor } /** * Adds new zoll and eust values and updates the total * * @param eustNew eust value to be added * @param zollNew zoll value to be added */ public void add(double eustNew, double zollNew, double saldoNew) { eust = eust + eustNew; zoll = zoll + zollNew; saldo = saldo + saldoNew; // update total total = eust + zoll; } } }