update monitoring
This commit is contained in:
parent
5cd6ba2e07
commit
16c91089b0
7 changed files with 376 additions and 139 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package com.alexanderlogistics;
|
package com.alexanderlogistics;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -8,9 +9,12 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.imixs.marty.team.TeamService;
|
||||||
import org.imixs.workflow.ItemCollection;
|
import org.imixs.workflow.ItemCollection;
|
||||||
import org.imixs.workflow.engine.DocumentService;
|
import org.imixs.workflow.engine.DocumentService;
|
||||||
import org.imixs.workflow.exceptions.QueryException;
|
import org.imixs.workflow.exceptions.QueryException;
|
||||||
|
import org.imixs.workflow.office.forms.AnalyticController;
|
||||||
|
import org.imixs.workflow.office.forms.AnalyticEvent;
|
||||||
|
|
||||||
import jakarta.enterprise.context.RequestScoped;
|
import jakarta.enterprise.context.RequestScoped;
|
||||||
import jakarta.enterprise.event.Observes;
|
import jakarta.enterprise.event.Observes;
|
||||||
|
|
@ -37,28 +41,38 @@ public class AGLAnalyticController implements Serializable {
|
||||||
@Inject
|
@Inject
|
||||||
protected DocumentService documentService;
|
protected DocumentService documentService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
TeamService teamService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected DebitorStatistikController debitorStatistikController;
|
protected DebitorStatistikController debitorStatistikController;
|
||||||
|
|
||||||
List<ItemCollection> steuerbescheide = null;
|
List<ItemCollection> steuerbescheide = null;
|
||||||
|
|
||||||
public void onEvent(@Observes AnalyticEvent event) {
|
public void onEvent(@Observes AnalyticEvent event) {
|
||||||
|
ItemCollection process = teamService.getProcessByName("Mahnwesen");
|
||||||
|
String link = "/pages/workitems/worklist.xhtml?processref=" + process.getUniqueID()
|
||||||
|
+ "&workflowgroup=Steuerbescheid";
|
||||||
|
|
||||||
if ("analytic.steuer.eust".equals(event.getKey())) {
|
if ("analytic.steuer.eust".equals(event.getKey())) {
|
||||||
event.setValue(computeSteuerbescheideEUST());
|
event.setValue(computeSteuerbescheideEUST());
|
||||||
event.setLabel("EUR");
|
event.setLabel("EUR");
|
||||||
event.setDescription("Gesamt Einfuhrumsatzsteuer (EUSt)");
|
event.setDescription("Gesamt Einfuhrumsatzsteuer (EUSt)");
|
||||||
event.getWorkitem().setItemValue("eust.total", event.getValue());
|
event.getWorkitem().setItemValue("eust.total", event.getValue());
|
||||||
|
event.setLink(link);
|
||||||
}
|
}
|
||||||
if ("analytic.steuer.zoll".equals(event.getKey())) {
|
if ("analytic.steuer.zoll".equals(event.getKey())) {
|
||||||
event.setValue(computeSteuerbescheideZoll());
|
event.setValue(computeSteuerbescheideZoll());
|
||||||
event.setLabel("EUR");
|
event.setLabel("EUR");
|
||||||
event.setDescription("Gesamt Zölle (ZOLLEU)");
|
event.setDescription("Gesamt Zölle (ZOLLEU)");
|
||||||
|
|
||||||
|
event.setLink(link);
|
||||||
}
|
}
|
||||||
if ("analytic.steuer.due".equals(event.getKey())) {
|
if ("analytic.steuer.due".equals(event.getKey())) {
|
||||||
event.setValue(computeSteuerbescheideUeberfaellig());
|
event.setValue(computeSteuerbescheideUeberfaellig());
|
||||||
event.setLabel("EUR");
|
event.setLabel("EUR");
|
||||||
event.setDescription("Überfällige Steuerbescheide die noch nicht abgerechnet wurden.");
|
event.setDescription("Überfällige Steuerbescheide die noch nicht abgerechnet wurden.");
|
||||||
|
event.setLink(link + "&workflowstatus=Überfällig");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("analytic.steuer.trend".equals(event.getKey())) {
|
if ("analytic.steuer.trend".equals(event.getKey())) {
|
||||||
|
|
@ -66,6 +80,13 @@ public class AGLAnalyticController implements Serializable {
|
||||||
event.setLabel("Zoll & EUST");
|
event.setLabel("Zoll & EUST");
|
||||||
event.setDescription("Fälligkeiten nach KW");
|
event.setDescription("Fälligkeiten nach KW");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("analytic.steuer.trend.abteilung".equals(event.getKey())) {
|
||||||
|
event.setValue(accumulateSteuerbescheideAbteilungByWeek());
|
||||||
|
event.setLabel("Nach Abteilungen");
|
||||||
|
event.setDescription("Offene Salden nach KW pro Abteilung");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -82,13 +103,6 @@ public class AGLAnalyticController implements Serializable {
|
||||||
|
|
||||||
for (ItemCollection steuerItemCol : list) {
|
for (ItemCollection steuerItemCol : list) {
|
||||||
result = result + getZollBySteuerBeleg(steuerItemCol, "EUST");
|
result = result + getZollBySteuerBeleg(steuerItemCol, "EUST");
|
||||||
// List<ItemCollection> positionsTabelle =
|
|
||||||
// InvoiceUtil.explodeChildList(steuerItemCol);
|
|
||||||
// for (ItemCollection pos : positionsTabelle) {
|
|
||||||
// if ("EUST".equalsIgnoreCase(pos.getItemValueString("activity.type"))) {
|
|
||||||
// result = result + pos.getItemValueDouble("amount");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return InvoiceUtil.round(result);
|
return InvoiceUtil.round(result);
|
||||||
|
|
@ -201,6 +215,7 @@ public class AGLAnalyticController implements Serializable {
|
||||||
// Step 1: Group saldo by week
|
// Step 1: Group saldo by week
|
||||||
for (ItemCollection steuerItemCol : list) {
|
for (ItemCollection steuerItemCol : list) {
|
||||||
double saldo = steuerItemCol.getItemValueDouble("invoice.saldo");
|
double saldo = steuerItemCol.getItemValueDouble("invoice.saldo");
|
||||||
|
double total = steuerItemCol.getItemValueDouble("invoice.total.net");
|
||||||
Date date = steuerItemCol.getItemValueDate("invoice.date");
|
Date date = steuerItemCol.getItemValueDate("invoice.date");
|
||||||
|
|
||||||
// Get the week number and year from the date
|
// Get the week number and year from the date
|
||||||
|
|
@ -213,7 +228,7 @@ public class AGLAnalyticController implements Serializable {
|
||||||
SteuerData steuerDataByWeek = saldoByWeek.getOrDefault(yearWeek, new SteuerData());
|
SteuerData steuerDataByWeek = saldoByWeek.getOrDefault(yearWeek, new SteuerData());
|
||||||
double eust = getZollBySteuerBeleg(steuerItemCol, "EUST");
|
double eust = getZollBySteuerBeleg(steuerItemCol, "EUST");
|
||||||
double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL");
|
double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL");
|
||||||
steuerDataByWeek.add(eust, zoll, saldo);
|
steuerDataByWeek.add(eust, zoll, total, saldo, "");
|
||||||
|
|
||||||
saldoByWeek.put(yearWeek, steuerDataByWeek);
|
saldoByWeek.put(yearWeek, steuerDataByWeek);
|
||||||
|
|
||||||
|
|
@ -283,7 +298,155 @@ public class AGLAnalyticController implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to hold zoll and eust totls in an object. Needed to build
|
* Berechnet Chart daten aller Steuerbescheide bei KW
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
chartCfg = {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
datasets: [{
|
||||||
|
data: [20, 10],
|
||||||
|
}],
|
||||||
|
labels: ['1', '2']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String accumulateSteuerbescheideAbteilungByWeek() {
|
||||||
|
logger.info("accumulate steuer by Abteilung week...");
|
||||||
|
|
||||||
|
String[] colors = {
|
||||||
|
"#36a2eb",
|
||||||
|
"#ff6384",
|
||||||
|
"#4bc0c0",
|
||||||
|
"#ff9f40",
|
||||||
|
"#96f",
|
||||||
|
"#ffcd56",
|
||||||
|
"#c9cbcf"
|
||||||
|
};
|
||||||
|
|
||||||
|
List<ItemCollection> list = getSteuerbescheide();
|
||||||
|
Map<String, SteuerData> totalByWeek = new HashMap<>();
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
int earliestWeek = Integer.MAX_VALUE;
|
||||||
|
int latestWeek = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
List<String> abteilungsListe = new ArrayList<>();
|
||||||
|
|
||||||
|
// Step 1: Group total by week
|
||||||
|
for (ItemCollection steuerItemCol : list) {
|
||||||
|
String abteilung = steuerItemCol.getItemValueString("space.name");
|
||||||
|
if (abteilung.isEmpty()) {
|
||||||
|
abteilung = "Keine Zuordnung";
|
||||||
|
}
|
||||||
|
if (!abteilungsListe.contains(abteilung)) {
|
||||||
|
abteilungsListe.add(abteilung);
|
||||||
|
}
|
||||||
|
double saldo = steuerItemCol.getItemValueDouble("invoice.saldo");
|
||||||
|
double total = steuerItemCol.getItemValueDouble("invoice.total.net");
|
||||||
|
Date date = steuerItemCol.getItemValueDate("invoice.date");
|
||||||
|
|
||||||
|
logger.info(".... " + steuerItemCol.getItemValueString("$workflowSummary") + " = " + total);
|
||||||
|
// 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;
|
||||||
|
String key = abteilung + "~" + yearWeek;// Unique key Import Forest~202405
|
||||||
|
|
||||||
|
// Accumulate the total per week
|
||||||
|
SteuerData steuerDataByWeek = totalByWeek.getOrDefault(key, new SteuerData());
|
||||||
|
double eust = getZollBySteuerBeleg(steuerItemCol, "EUST");
|
||||||
|
double zoll = getZollBySteuerBeleg(steuerItemCol, "ZOLL");
|
||||||
|
steuerDataByWeek.add(eust, zoll, total, saldo, abteilung);
|
||||||
|
|
||||||
|
totalByWeek.put(key, 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 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);
|
||||||
|
|
||||||
|
// Build labels - je eines pro woche
|
||||||
|
while (!startCal.after(endCal)) {
|
||||||
|
int weekNumber = startCal.get(Calendar.WEEK_OF_YEAR);
|
||||||
|
int year = startCal.get(Calendar.YEAR);
|
||||||
|
labelsBuilder.add(weekNumber + "/" + year); // Label as 'week/year'
|
||||||
|
// Move to the next week
|
||||||
|
startCal.add(Calendar.WEEK_OF_YEAR, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Baue die Balken pro abrteilung
|
||||||
|
JsonArrayBuilder datasets = Json.createArrayBuilder();
|
||||||
|
|
||||||
|
JsonObjectBuilder jsonBuilder = Json.createObjectBuilder()
|
||||||
|
.add("type", "bar");
|
||||||
|
|
||||||
|
JsonObjectBuilder dataDing = Json.createObjectBuilder();
|
||||||
|
int iColor = 0;
|
||||||
|
for (String _abteilung : abteilungsListe) {
|
||||||
|
JsonArrayBuilder dataBuilderTotals = Json.createArrayBuilder();
|
||||||
|
|
||||||
|
startCal = Calendar.getInstance();
|
||||||
|
startCal.set(Calendar.YEAR, earliestWeek / 100);
|
||||||
|
startCal.set(Calendar.WEEK_OF_YEAR, earliestWeek % 100);
|
||||||
|
|
||||||
|
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;
|
||||||
|
String key = _abteilung + "~" + yearWeek;// Unique key Import Forest~202405
|
||||||
|
// Add the total for the week or 0.0 if no data
|
||||||
|
SteuerData steuerData = totalByWeek.getOrDefault(key, new SteuerData());
|
||||||
|
logger.info(" " + yearWeek + "=" + steuerData.total);
|
||||||
|
dataBuilderTotals.add(steuerData.total);
|
||||||
|
// Move to the next week
|
||||||
|
startCal.add(Calendar.WEEK_OF_YEAR, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
datasets.add(Json.createObjectBuilder() // First dataset for 'tax'
|
||||||
|
.add("label", _abteilung)
|
||||||
|
.add("backgroundColor", colors[iColor])
|
||||||
|
.add("borderWidth", 1)
|
||||||
|
.add("data", dataBuilderTotals));
|
||||||
|
|
||||||
|
iColor++;
|
||||||
|
if (iColor > colors.length) {
|
||||||
|
iColor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataDing.add("datasets", datasets);
|
||||||
|
dataDing.add("labels", labelsBuilder);
|
||||||
|
|
||||||
|
jsonBuilder.add("data", dataDing);
|
||||||
|
|
||||||
|
// Step 4: Return the JSON structure as a string
|
||||||
|
JsonObject chartCfg = jsonBuilder.build();
|
||||||
|
return chartCfg.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to hold zoll and eust totals in an object. Needed to build
|
||||||
* totals per week.
|
* totals per week.
|
||||||
*/
|
*/
|
||||||
class SteuerData {
|
class SteuerData {
|
||||||
|
|
@ -291,6 +454,7 @@ public class AGLAnalyticController implements Serializable {
|
||||||
double zoll = 0.0;
|
double zoll = 0.0;
|
||||||
double eust = 0.0;
|
double eust = 0.0;
|
||||||
double saldo = 0.0;
|
double saldo = 0.0;
|
||||||
|
String abteilung = "";
|
||||||
|
|
||||||
public SteuerData() {
|
public SteuerData() {
|
||||||
// default constructor
|
// default constructor
|
||||||
|
|
@ -302,12 +466,12 @@ public class AGLAnalyticController implements Serializable {
|
||||||
* @param eustNew eust value to be added
|
* @param eustNew eust value to be added
|
||||||
* @param zollNew zoll value to be added
|
* @param zollNew zoll value to be added
|
||||||
*/
|
*/
|
||||||
public void add(double eustNew, double zollNew, double saldoNew) {
|
public void add(double eustNew, double zollNew, double totalNew, double saldoNew, String abteilungNew) {
|
||||||
eust = eust + eustNew;
|
eust = eust + eustNew;
|
||||||
zoll = zoll + zollNew;
|
zoll = zoll + zollNew;
|
||||||
saldo = saldo + saldoNew;
|
saldo = saldo + saldoNew;
|
||||||
// update total
|
total = total + totalNew;
|
||||||
total = eust + zoll;
|
abteilung = abteilungNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
package com.alexanderlogistics;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.imixs.workflow.faces.data.WorkflowController;
|
|
||||||
|
|
||||||
import jakarta.enterprise.context.ConversationScoped;
|
|
||||||
import jakarta.enterprise.event.Event;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
import jakarta.inject.Named;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The AnalyticController is a conversationScoped controller that provides
|
|
||||||
* values for the analytic-custom parts.
|
|
||||||
* <p>
|
|
||||||
* A custom implementation can react on AnalyticEvent to compute values and
|
|
||||||
* datasets.
|
|
||||||
* <p>
|
|
||||||
* The controller implements a caching mechanism to avoid repeated calls for new
|
|
||||||
* analytic values. If the analytic value is already stored in the current
|
|
||||||
* workitem, no new value will be fired.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author rsoika
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@ConversationScoped
|
|
||||||
public class AnalyticController implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected Event<AnalyticEvent> analyticEvents;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected WorkflowController workflowController;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a analytic value as a String for a given key.
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getAsString(String key) {
|
|
||||||
computeValue(key);
|
|
||||||
return workflowController.getWorkitem().getItemValueString("analytic." + key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a analytic value as a Double for a given key.
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public double getAsDouble(String key) {
|
|
||||||
computeValue(key);
|
|
||||||
return workflowController.getWorkitem().getItemValueDouble("analytic." + key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the analytic label for a given key
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getLabel(String key) {
|
|
||||||
computeValue(key);
|
|
||||||
return workflowController.getWorkitem().getItemValueString("analytic." + key + ".label");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the analytic description for a given key
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getDescription(String key) {
|
|
||||||
computeValue(key);
|
|
||||||
return workflowController.getWorkitem().getItemValueString("analytic." + key + ".description");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes am analytic value. The method cache the value in the item
|
|
||||||
* 'analytic.KEY' to avoid feierring repeated AnalyticEvents.
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected void computeValue(String key) {
|
|
||||||
if (workflowController.getWorkitem() != null) {
|
|
||||||
// try to fetch value from cache
|
|
||||||
if (!workflowController.getWorkitem().hasItem("analytic." + key)) {
|
|
||||||
logger.info("fire analytic event for key '" + key + "'");
|
|
||||||
// Fire the Analytics Event for this key
|
|
||||||
AnalyticEvent event = new AnalyticEvent(key, workflowController.getWorkitem());
|
|
||||||
if (analyticEvents != null) {
|
|
||||||
|
|
||||||
analyticEvents.fire(event);
|
|
||||||
workflowController.getWorkitem().setItemValue("analytic." + key, event.getValue());
|
|
||||||
workflowController.getWorkitem().setItemValue("analytic." + key + ".label", event.getLabel());
|
|
||||||
workflowController.getWorkitem().setItemValue("analytic." + key + ".description",
|
|
||||||
event.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.getValue() == null) {
|
|
||||||
// set dummy value
|
|
||||||
workflowController.getWorkitem().setItemValue("analytic." + key, "");
|
|
||||||
workflowController.getWorkitem().setItemValue("analytic." + key + ".label", "- undefined -");
|
|
||||||
workflowController.getWorkitem().setItemValue("analytic." + key + ".description",
|
|
||||||
"No data available");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// analytic value is already cached!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
package org.imixs.workflow.office.forms;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.imixs.workflow.ItemCollection;
|
||||||
|
import org.imixs.workflow.faces.data.WorkflowController;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ConversationScoped;
|
||||||
|
import jakarta.enterprise.event.Event;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.inject.Named;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AnalyticController is a conversationScoped controller that provides
|
||||||
|
* values for the analytic-custom parts.
|
||||||
|
* <p>
|
||||||
|
* A custom implementation can react on AnalyticEvent to compute values and
|
||||||
|
* datasets.
|
||||||
|
* <p>
|
||||||
|
* The controller implements a caching mechanism to avoid repeated calls for new
|
||||||
|
* analytic values. If the analytic value is already stored in the current
|
||||||
|
* workitem, no new value will be fired.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author rsoika
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Named
|
||||||
|
@ConversationScoped
|
||||||
|
public class AnalyticController implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected Event<AnalyticEvent> analyticEvents;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected WorkflowController workflowController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a analytic value as a String for a given key.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getAsString(String key) {
|
||||||
|
ItemCollection analyticData = computeValue(key);
|
||||||
|
return analyticData.getItemValueString("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a analytic value as a Double for a given key.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public double getAsDouble(String key) {
|
||||||
|
ItemCollection analyticData = computeValue(key);
|
||||||
|
return analyticData.getItemValueDouble("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analytic label for a given key
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getLabel(String key) {
|
||||||
|
ItemCollection analyticData = computeValue(key);
|
||||||
|
return analyticData.getItemValueString("label");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analytic optional link for a given key
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getLink(String key) {
|
||||||
|
ItemCollection analyticData = computeValue(key);
|
||||||
|
return analyticData.getItemValueString("link");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analytic description for a given key
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getDescription(String key) {
|
||||||
|
ItemCollection analyticData = computeValue(key);
|
||||||
|
return analyticData.getItemValueString("description");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes am analytic value. The method cache the value in the item
|
||||||
|
* 'analytic.KEY' to avoid feierring repeated AnalyticEvents.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected ItemCollection computeValue(String key) {
|
||||||
|
if (workflowController.getWorkitem() != null) {
|
||||||
|
// try to fetch value from cache
|
||||||
|
if (!workflowController.getWorkitem().hasItem("analytic." + key)) {
|
||||||
|
logger.info("fire analytic event for key '" + key + "'");
|
||||||
|
// Fire the Analytics Event for this key
|
||||||
|
AnalyticEvent event = new AnalyticEvent(key, workflowController.getWorkitem());
|
||||||
|
if (analyticEvents != null) {
|
||||||
|
analyticEvents.fire(event);
|
||||||
|
ItemCollection details = new ItemCollection();
|
||||||
|
details.setItemValue("value", event.getValue());
|
||||||
|
details.setItemValue("label", event.getLabel());
|
||||||
|
details.setItemValue("description", event.getDescription());
|
||||||
|
details.setItemValue("link", event.getLink());
|
||||||
|
implodeDetails(key, details);
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getValue() == null) {
|
||||||
|
// set dummy value
|
||||||
|
ItemCollection details = new ItemCollection();
|
||||||
|
details.setItemValue("value", "");
|
||||||
|
details.setItemValue("label", "");
|
||||||
|
details.setItemValue("description", "No data available");
|
||||||
|
implodeDetails(key, details);
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// analytic value is already cached!
|
||||||
|
return explodeDetails(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the List of ItemCollections back into a List of Map elements
|
||||||
|
*
|
||||||
|
* @param workitem
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "rawtypes" })
|
||||||
|
public void implodeDetails(String key, ItemCollection details) {
|
||||||
|
// convert the child ItemCollection elements into a List of Map
|
||||||
|
List<Map> detailsList = new ArrayList<Map>();
|
||||||
|
detailsList.add(details.getAllItems());
|
||||||
|
workflowController.getWorkitem().replaceItemValue(key, detailsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* converts the Map List of a workitem into a List of ItemCollectons
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
public ItemCollection explodeDetails(String key) {
|
||||||
|
// convert current list of childItems into ItemCollection elements
|
||||||
|
List<Object> mapOrderItems = workflowController.getWorkitem().getItemValue(key);
|
||||||
|
if (mapOrderItems != null && mapOrderItems.size() > 0) {
|
||||||
|
ItemCollection itemCol = new ItemCollection((Map) mapOrderItems.get(0));
|
||||||
|
return itemCol;
|
||||||
|
}
|
||||||
|
// return empty collection
|
||||||
|
return new ItemCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.alexanderlogistics;
|
package org.imixs.workflow.office.forms;
|
||||||
|
|
||||||
import org.imixs.workflow.ItemCollection;
|
import org.imixs.workflow.ItemCollection;
|
||||||
|
|
||||||
|
|
@ -11,6 +11,7 @@ public class AnalyticEvent {
|
||||||
private Object value = null;
|
private Object value = null;
|
||||||
private String label = "";
|
private String label = "";
|
||||||
private String description = "";
|
private String description = "";
|
||||||
|
private String link = "";
|
||||||
private ItemCollection workitem = null;
|
private ItemCollection workitem = null;
|
||||||
|
|
||||||
public AnalyticEvent(String key, ItemCollection workitem) {
|
public AnalyticEvent(String key, ItemCollection workitem) {
|
||||||
|
|
@ -26,6 +27,14 @@ public class AnalyticEvent {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getLink() {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLink(String link) {
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
public ItemCollection getWorkitem() {
|
public ItemCollection getWorkitem() {
|
||||||
return workitem;
|
return workitem;
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
</style>
|
</style>
|
||||||
<div class="analytic-card">
|
<div class="analytic-card">
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<canvas id="analytics_canvas" style="min-width: 600px;height:200px;"></canvas>
|
<canvas id="analytics_canvas_#{item.name}" style="min-width: 600px;height:200px;"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
$(document).ready(
|
$(document).ready(
|
||||||
function () {
|
function () {
|
||||||
// update the diagram
|
// update the diagram
|
||||||
var ctx = document.getElementById("analytics_canvas").getContext("2d");
|
var ctx = document.getElementById("analytics_canvas_#{item.name}").getContext("2d");
|
||||||
var chartData = #{ analyticController.getAsString(item.name)
|
var chartData = #{ analyticController.getAsString(item.name)
|
||||||
};
|
};
|
||||||
console.log(chartData);
|
console.log(chartData);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,12 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.analytic-card-link {
|
||||||
|
float: right;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="analytic-card">
|
<div class="analytic-card">
|
||||||
<div class="analytic-card-header">
|
<div class="analytic-card-header">
|
||||||
|
|
@ -46,8 +52,16 @@
|
||||||
<div class="analytic-card-content">#{analyticController.getLabel(item.name)}</div>
|
<div class="analytic-card-content">#{analyticController.getLabel(item.name)}</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="analytic-card-footer">#{analyticController.getDescription(item.name)}
|
<div class="analytic-card-footer">
|
||||||
|
<span>#{analyticController.getDescription(item.name)}</span>
|
||||||
|
|
||||||
|
<h:panelGroup styleClass="analytic-card-link" rendered="#{!empty analyticController.getLink(item.name)}">
|
||||||
|
<a href="#{analyticController.getLink(item.name)}"><span class="typcn typcn-zoom-outline" /></a>
|
||||||
|
</h:panelGroup>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ui:composition>
|
</ui:composition>
|
||||||
|
|
@ -180,7 +180,9 @@ th { font-weight: bold;}
|
||||||
</imixs-form-section>
|
</imixs-form-section>
|
||||||
|
|
||||||
<imixs-form-section columns="1">
|
<imixs-form-section columns="1">
|
||||||
<item name="analytic.steuer.trend" type="custom" path="alexander/analyze_chart" label="Zoll/Eust in Kalenderwoche:" />
|
|
||||||
|
<item name="analytic.steuer.trend" type="custom" path="alexander/analyze_chart" label="Zoll/Eust pro KW:" />
|
||||||
|
<item name="analytic.steuer.trend.abteilung" type="custom" path="alexander/analyze_chart" label="Gesamt pro Abteilungen:" />
|
||||||
</imixs-form-section>
|
</imixs-form-section>
|
||||||
|
|
||||||
</imixs-form>]]></bpmn2:documentation>
|
</imixs-form>]]></bpmn2:documentation>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue