diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/AGLAnalyticControllerDebitor.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/AGLAnalyticControllerDebitor.java index 83dbae0..631e973 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/AGLAnalyticControllerDebitor.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/AGLAnalyticControllerDebitor.java @@ -96,10 +96,11 @@ public class AGLAnalyticControllerDebitor implements Serializable { // load all invoices? if (invoices == null || (!dbtrNumber.isEmpty() && !dbtrNumber.equals(dbtrNumberLast))) { + resetStats(); + event.getWorkitem().setItemValue("dbtr.number.last", dbtrNumber); logger.info("Analyse new debitor data for : " + dbtrNumber); loadRechnungen(); - event.getWorkitem().setItemValue("dbtr.number.last", dbtrNumber); - + chartData = buildChartData(); } String link = "/pages/workitems/worklist.xhtml" + "?phrase=" + getDbtNr(); @@ -187,13 +188,15 @@ public class AGLAnalyticControllerDebitor implements Serializable { private void loadRechnungen() { if (getDbtNr().isEmpty()) { invoices = new ArrayList(); + stats = null; } else { + logger.info(" ├──load invoices for " + getDbtNr() + "...."); String query = "(type:workitem) AND dbtr.number:" + getDbtNr() + " AND $modelversion:rechnungsausgang-*"; try { - logger.info("...debitor analysis for " + getDbtNr() + "...."); + logger.info(" ├──refresh invoice stats for " + getDbtNr() + "...."); invoices = documentService.find(query, 999, 0, "$created", false); - refreshStats(); + calculateStats(); } catch (QueryException e) { logger.warning("Failed to query invoices: " + query + " - Error: " + e.getMessage()); invoices = new ArrayList(); @@ -202,12 +205,17 @@ public class AGLAnalyticControllerDebitor implements Serializable { } - private void refreshStats() { + /** + * Läd die statistik daten zu einem debitor aus den aktuellen Rechnungen + */ + private void calculateStats() { countAll = 0; countOpen = 0; countDue = 0; countDunning = 0; - if (invoices != null) { + logger.info(" ├──calculate stats for " + getDbtNr() + "...."); + // do we have data? + if (invoices != null && invoices.size() > 0) { countAll = invoices.size(); for (ItemCollection invoice : invoices) { @@ -264,15 +272,37 @@ public class AGLAnalyticControllerDebitor implements Serializable { totalDunningCurrency1 = InvoiceUtil.round(totalDunningCurrency1); totalDunningCurrency2 = InvoiceUtil.round(totalDunningCurrency2); - chartData = buildChartData(); - // System.out.println(chartData); + } else { + // reset data because no invoices are available ... + resetStats(); - getDurchschnittZahlungsziel(); - getDurchschnittZahlungsdauer(); } } + /** + * Setzt alle Statistikwerte zurück + */ + private void resetStats() { + logger.info(" ├──reset stats for " + getDbtNr() + "...."); + stats = null; + + totalAllCurrency1 = 0; + totalAllCurrency2 = 0; + totalOpenCurrency1 = 0; + totalOpenCurrency2 = 0; + totalDueCurrency1 = 0; + totalDueCurrency2 = 0; + totalDunningCurrency1 = 0; + totalDunningCurrency2 = 0; + + // chartData = null; + chartData = "{}"; + + averagePaymentDue = 0; + averagePaymentDays = 0; + } + private void getDurchschnittZahlungsziel() { if (stats == null) { averagePaymentDue = 0; @@ -335,19 +365,20 @@ public class AGLAnalyticControllerDebitor implements Serializable { * Zahlungszeitspanne gruppiert nach monaten * */ - public Map getStats() { + public Map loadStats() { if (stats != null) { return stats; } + logger.info(" ├──load stats for " + getDbtNr() + "...."); // recompute stats = new TreeMap(); if (getDbtNr().isEmpty()) { return stats; } - // Letzen 6 Monate + // Letzen 12 Monate LocalDate endDate = LocalDate.now(); LocalDate startDate = endDate.minusMonths(12); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); @@ -372,7 +403,7 @@ public class AGLAnalyticControllerDebitor implements Serializable { Date invoiceDueDate = invoice.getItemValueDate("invoice.duedate"); Date paymentDate = findPaymentDateByWorkitem(invoice); if (paymentDate == null) { - logger.warning("Es wurde kein Zahlungseingang gefunden"); + logger.fine("Es wurde kein Zahlungseingang gefunden"); continue; } @@ -402,6 +433,10 @@ public class AGLAnalyticControllerDebitor implements Serializable { } // Step 2: Sort the list based on the alphanumeric order of the keys completeMissingMonths(); + + // berechne zahluntsziel durchscnitt + getDurchschnittZahlungsziel(); + getDurchschnittZahlungsdauer(); return stats; } @@ -475,8 +510,8 @@ public class AGLAnalyticControllerDebitor implements Serializable { */ public String buildChartData() { - getStats(); - + loadStats(); + logger.info(" ├──build chart for " + getDbtNr() + "...."); // build a list of all lables.... List statusLabels = new ArrayList(); @@ -488,38 +523,43 @@ public class AGLAnalyticControllerDebitor implements Serializable { String result = "{\n \"type\": \"bar\",\n \"data\": { "; // Lables - result = result + "labels : [ "; - result = result + statusLabels.stream().collect(Collectors.joining("','", "'", "'")); + result = result + "\"labels\" : [ "; + result = result + statusLabels.stream().collect(Collectors.joining("\",\"", "\"", "\"")); result = result + "],"; - result = result + "datasets: ["; + result = result + "\"datasets\": ["; // Datasets 1 - result = result + "{label: 'Days for payment',borderWidth: 1,"; - result = result + " borderColor: [\"#3B6B82\"],"; - result = result + " \"backgroundColor\" : [\"#CFE9F5\"], fill: true,tension: 0.5,"; + result = result + "{\"label\": \"Days for payment\",\"borderWidth\": 1,"; + result = result + " \"borderColor\": [\"#3B6B82\"],"; + result = result + " \"backgroundColor\" : [\"#CFE9F5\"], \"fill\": true,\"tension\": 0.5,"; - result = result + "data: ["; + result = result + "\"data\": ["; for (Map.Entry entry : stats.entrySet()) { result = result + entry.getValue().getAverageDueDays() + ","; } // cut last comma - result = result.substring(0, result.length() - 1); + if (result.endsWith(",")) { + result = result.substring(0, result.length() - 1); + } result = result + "]"; result = result + "}, "; // Datasets 2 - result = result + "{label: 'Payment duration',borderWidth: 1,"; - result = result + " borderColor: [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], tension: 0.5,fill: true,"; + result = result + "{\"label\": \"Payment duration\",\"borderWidth\": 1,"; + result = result + + " \"borderColor\": [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], \"tension\": 0.5,\"fill\": true,"; result = result - + " trendlineLinear: { colorMin: \"red\", colorMax: \"green\", lineStyle: \"dotted\", width: 2 , projection: true },"; + + " \"trendlineLinear\": { \"colorMin\": \"red\", \"colorMax\": \"green\", \"lineStyle\": \"dotted\", \"width\": 2 , \"projection\": true },"; - result = result + "data: ["; + result = result + "\"data\": ["; for (Map.Entry entry : stats.entrySet()) { result = result + entry.getValue().getAveragePaymentDays() + ","; } // cut last comma - result = result.substring(0, result.length() - 1); + if (result.endsWith(",")) { + result = result.substring(0, result.length() - 1); + } result = result + "]"; result = result + "} "; diff --git a/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/AnalyticController.java b/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/AnalyticController.java index ba049cc..7c435cf 100644 --- a/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/AnalyticController.java +++ b/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/AnalyticController.java @@ -53,6 +53,22 @@ public class AnalyticController implements Serializable { return analyticData.getItemValueString("value"); } + /** + * Returns a analytic value as a Json String for a given key. + * + * @param key + * @return + */ + public String getAsJson(String key) { + ItemCollection analyticData = computeValue(key); + String jsonval = analyticData.getItemValueString("value"); + if (jsonval == null || jsonval.isEmpty()) { + return "null"; + } else { + return jsonval; + } + } + /** * Returns a analytic value as a Double for a given key. * diff --git a/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/analyze_chart.xhtml b/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/analyze_chart.xhtml index 071091f..c0857b6 100644 --- a/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/analyze_chart.xhtml +++ b/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/analyze_chart.xhtml @@ -34,27 +34,14 @@ - - - - - diff --git a/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/debitor_search.xhtml b/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/debitor_search.xhtml index 3bffc75..0d7c309 100644 --- a/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/debitor_search.xhtml +++ b/office-alexander-logistics-app/src/main/webapp/pages/workitems/parts/alexander/debitor_search.xhtml @@ -44,6 +44,12 @@ * Hilfsmethode die nur fur Ajax Events in JSF render verwendet wird */ function ajaxUpdateDbtrSearchPart(data) { + var $body = $("body"); + if (data.status === 'begin') { + // show ajax loader... + //imixsOfficeMain.layoutAjaxEvent(data, '#{customFormComponents.clientId}'); + $body.addClass("loading"); + } if (data.status === 'success') { // add autocomplete feature to dbtr_number_part... var creditorField = $("input[data-item='dbtr_number_part']"); @@ -51,7 +57,9 @@ var dbtrName = "#{workflowController.workitem.item['dbtr.name']}"; // append span with dbtr.name.... creditorField.after("" + dbtrName + "

"); - //$("[id$=autocomplete-resultlist-cargosoft_part]").hide(); + + // remove ajax loader + $body.removeClass("loading"); } } @@ -81,6 +89,7 @@ + diff --git a/workflow/analyse-debitor-de-1.0.0.bpmn b/workflow/analyse-debitor-de-1.0.0.bpmn index 3cf8659..4554a23 100644 --- a/workflow/analyse-debitor-de-1.0.0.bpmn +++ b/workflow/analyse-debitor-de-1.0.0.bpmn @@ -174,22 +174,20 @@ th { font-weight: bold;} + - - - + - ]]>