fixes debitor analyse
This commit is contained in:
parent
ae7b7abf8e
commit
3973e1ae91
5 changed files with 99 additions and 49 deletions
|
|
@ -96,10 +96,11 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
|
|
||||||
// load all invoices?
|
// load all invoices?
|
||||||
if (invoices == null || (!dbtrNumber.isEmpty() && !dbtrNumber.equals(dbtrNumberLast))) {
|
if (invoices == null || (!dbtrNumber.isEmpty() && !dbtrNumber.equals(dbtrNumberLast))) {
|
||||||
|
resetStats();
|
||||||
|
event.getWorkitem().setItemValue("dbtr.number.last", dbtrNumber);
|
||||||
logger.info("Analyse new debitor data for : " + dbtrNumber);
|
logger.info("Analyse new debitor data for : " + dbtrNumber);
|
||||||
loadRechnungen();
|
loadRechnungen();
|
||||||
event.getWorkitem().setItemValue("dbtr.number.last", dbtrNumber);
|
chartData = buildChartData();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String link = "/pages/workitems/worklist.xhtml" + "?phrase=" + getDbtNr();
|
String link = "/pages/workitems/worklist.xhtml" + "?phrase=" + getDbtNr();
|
||||||
|
|
@ -187,13 +188,15 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
private void loadRechnungen() {
|
private void loadRechnungen() {
|
||||||
if (getDbtNr().isEmpty()) {
|
if (getDbtNr().isEmpty()) {
|
||||||
invoices = new ArrayList();
|
invoices = new ArrayList();
|
||||||
|
stats = null;
|
||||||
} else {
|
} else {
|
||||||
|
logger.info(" ├──load invoices for " + getDbtNr() + "....");
|
||||||
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
|
String query = "(type:workitem) AND dbtr.number:" + getDbtNr()
|
||||||
+ " AND $modelversion:rechnungsausgang-*";
|
+ " AND $modelversion:rechnungsausgang-*";
|
||||||
try {
|
try {
|
||||||
logger.info("...debitor analysis for " + getDbtNr() + "....");
|
logger.info(" ├──refresh invoice stats for " + getDbtNr() + "....");
|
||||||
invoices = documentService.find(query, 999, 0, "$created", false);
|
invoices = documentService.find(query, 999, 0, "$created", false);
|
||||||
refreshStats();
|
calculateStats();
|
||||||
} catch (QueryException e) {
|
} catch (QueryException e) {
|
||||||
logger.warning("Failed to query invoices: " + query + " - Error: " + e.getMessage());
|
logger.warning("Failed to query invoices: " + query + " - Error: " + e.getMessage());
|
||||||
invoices = new ArrayList();
|
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;
|
countAll = 0;
|
||||||
countOpen = 0;
|
countOpen = 0;
|
||||||
countDue = 0;
|
countDue = 0;
|
||||||
countDunning = 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();
|
countAll = invoices.size();
|
||||||
|
|
||||||
for (ItemCollection invoice : invoices) {
|
for (ItemCollection invoice : invoices) {
|
||||||
|
|
@ -264,15 +272,37 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
totalDunningCurrency1 = InvoiceUtil.round(totalDunningCurrency1);
|
totalDunningCurrency1 = InvoiceUtil.round(totalDunningCurrency1);
|
||||||
totalDunningCurrency2 = InvoiceUtil.round(totalDunningCurrency2);
|
totalDunningCurrency2 = InvoiceUtil.round(totalDunningCurrency2);
|
||||||
|
|
||||||
chartData = buildChartData();
|
} else {
|
||||||
// System.out.println(chartData);
|
// 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() {
|
private void getDurchschnittZahlungsziel() {
|
||||||
if (stats == null) {
|
if (stats == null) {
|
||||||
averagePaymentDue = 0;
|
averagePaymentDue = 0;
|
||||||
|
|
@ -335,19 +365,20 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
* Zahlungszeitspanne gruppiert nach monaten
|
* Zahlungszeitspanne gruppiert nach monaten
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Map<String, DebitorStatistikData> getStats() {
|
public Map<String, DebitorStatistikData> loadStats() {
|
||||||
|
|
||||||
if (stats != null) {
|
if (stats != null) {
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info(" ├──load stats for " + getDbtNr() + "....");
|
||||||
// recompute
|
// recompute
|
||||||
stats = new TreeMap<String, DebitorStatistikData>();
|
stats = new TreeMap<String, DebitorStatistikData>();
|
||||||
if (getDbtNr().isEmpty()) {
|
if (getDbtNr().isEmpty()) {
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Letzen 6 Monate
|
// Letzen 12 Monate
|
||||||
LocalDate endDate = LocalDate.now();
|
LocalDate endDate = LocalDate.now();
|
||||||
LocalDate startDate = endDate.minusMonths(12);
|
LocalDate startDate = endDate.minusMonths(12);
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||||
|
|
@ -372,7 +403,7 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
Date invoiceDueDate = invoice.getItemValueDate("invoice.duedate");
|
Date invoiceDueDate = invoice.getItemValueDate("invoice.duedate");
|
||||||
Date paymentDate = findPaymentDateByWorkitem(invoice);
|
Date paymentDate = findPaymentDateByWorkitem(invoice);
|
||||||
if (paymentDate == null) {
|
if (paymentDate == null) {
|
||||||
logger.warning("Es wurde kein Zahlungseingang gefunden");
|
logger.fine("Es wurde kein Zahlungseingang gefunden");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -402,6 +433,10 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
}
|
}
|
||||||
// Step 2: Sort the list based on the alphanumeric order of the keys
|
// Step 2: Sort the list based on the alphanumeric order of the keys
|
||||||
completeMissingMonths();
|
completeMissingMonths();
|
||||||
|
|
||||||
|
// berechne zahluntsziel durchscnitt
|
||||||
|
getDurchschnittZahlungsziel();
|
||||||
|
getDurchschnittZahlungsdauer();
|
||||||
return stats;
|
return stats;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -475,8 +510,8 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
*/
|
*/
|
||||||
public String buildChartData() {
|
public String buildChartData() {
|
||||||
|
|
||||||
getStats();
|
loadStats();
|
||||||
|
logger.info(" ├──build chart for " + getDbtNr() + "....");
|
||||||
// build a list of all lables....
|
// build a list of all lables....
|
||||||
List<String> statusLabels = new ArrayList<String>();
|
List<String> statusLabels = new ArrayList<String>();
|
||||||
|
|
||||||
|
|
@ -488,38 +523,43 @@ public class AGLAnalyticControllerDebitor implements Serializable {
|
||||||
String result = "{\n \"type\": \"bar\",\n \"data\": { ";
|
String result = "{\n \"type\": \"bar\",\n \"data\": { ";
|
||||||
|
|
||||||
// Lables
|
// Lables
|
||||||
result = result + "labels : [ ";
|
result = result + "\"labels\" : [ ";
|
||||||
result = result + statusLabels.stream().collect(Collectors.joining("','", "'", "'"));
|
result = result + statusLabels.stream().collect(Collectors.joining("\",\"", "\"", "\""));
|
||||||
result = result + "],";
|
result = result + "],";
|
||||||
result = result + "datasets: [";
|
result = result + "\"datasets\": [";
|
||||||
|
|
||||||
// Datasets 1
|
// Datasets 1
|
||||||
result = result + "{label: 'Days for payment',borderWidth: 1,";
|
result = result + "{\"label\": \"Days for payment\",\"borderWidth\": 1,";
|
||||||
result = result + " borderColor: [\"#3B6B82\"],";
|
result = result + " \"borderColor\": [\"#3B6B82\"],";
|
||||||
result = result + " \"backgroundColor\" : [\"#CFE9F5\"], fill: true,tension: 0.5,";
|
result = result + " \"backgroundColor\" : [\"#CFE9F5\"], \"fill\": true,\"tension\": 0.5,";
|
||||||
|
|
||||||
result = result + "data: [";
|
result = result + "\"data\": [";
|
||||||
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||||
result = result + entry.getValue().getAverageDueDays() + ",";
|
result = result + entry.getValue().getAverageDueDays() + ",";
|
||||||
}
|
}
|
||||||
// cut last comma
|
// cut last comma
|
||||||
result = result.substring(0, result.length() - 1);
|
if (result.endsWith(",")) {
|
||||||
|
result = result.substring(0, result.length() - 1);
|
||||||
|
}
|
||||||
result = result + "]";
|
result = result + "]";
|
||||||
result = result + "}, ";
|
result = result + "}, ";
|
||||||
|
|
||||||
// Datasets 2
|
// Datasets 2
|
||||||
result = result + "{label: 'Payment duration',borderWidth: 1,";
|
result = result + "{\"label\": \"Payment duration\",\"borderWidth\": 1,";
|
||||||
result = result + " borderColor: [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], tension: 0.5,fill: true,";
|
result = result
|
||||||
|
+ " \"borderColor\": [\"#E73B65\"],\"backgroundColor\" : [\"#70B088\" ], \"tension\": 0.5,\"fill\": true,";
|
||||||
|
|
||||||
result = result
|
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<String, DebitorStatistikData> entry : stats.entrySet()) {
|
for (Map.Entry<String, DebitorStatistikData> entry : stats.entrySet()) {
|
||||||
result = result + entry.getValue().getAveragePaymentDays() + ",";
|
result = result + entry.getValue().getAveragePaymentDays() + ",";
|
||||||
}
|
}
|
||||||
// cut last comma
|
// cut last comma
|
||||||
result = result.substring(0, result.length() - 1);
|
if (result.endsWith(",")) {
|
||||||
|
result = result.substring(0, result.length() - 1);
|
||||||
|
}
|
||||||
result = result + "]";
|
result = result + "]";
|
||||||
result = result + "} ";
|
result = result + "} ";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,22 @@ public class AnalyticController implements Serializable {
|
||||||
return analyticData.getItemValueString("value");
|
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.
|
* Returns a analytic value as a Double for a given key.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -34,27 +34,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
src="#{facesContext.externalContext.requestContextPath}/js/chartjs/chart.min.js?build=#{app.application_build_timestamp}"></script>
|
src="#{facesContext.externalContext.requestContextPath}/js/chartjs/chart.min.js?build=#{app.application_build_timestamp}"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
/*<![CDATA[*/
|
/*<![CDATA[*/
|
||||||
$(document).ready(
|
var ctx = document.getElementById("analytics_canvas_#{item.name}").getContext("2d");
|
||||||
function () {
|
var chartData = #{ analyticController.getAsJson(item.name)};
|
||||||
// update the diagram
|
new Chart(ctx, chartData);
|
||||||
var ctx = document.getElementById("analytics_canvas_#{item.name}").getContext("2d");
|
|
||||||
var chartData = #{ analyticController.getAsString(item.name)
|
|
||||||
};
|
|
||||||
console.log(chartData);
|
|
||||||
//jsObject = JSON.parse(chartData);
|
|
||||||
window.myBar = new Chart(ctx, chartData);
|
|
||||||
});
|
|
||||||
|
|
||||||
/*]]>*/
|
/*]]>*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,12 @@
|
||||||
* Hilfsmethode die nur fur Ajax Events in JSF render verwendet wird
|
* Hilfsmethode die nur fur Ajax Events in JSF render verwendet wird
|
||||||
*/
|
*/
|
||||||
function ajaxUpdateDbtrSearchPart(data) {
|
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') {
|
if (data.status === 'success') {
|
||||||
// add autocomplete feature to dbtr_number_part...
|
// add autocomplete feature to dbtr_number_part...
|
||||||
var creditorField = $("input[data-item='dbtr_number_part']");
|
var creditorField = $("input[data-item='dbtr_number_part']");
|
||||||
|
|
@ -51,7 +57,9 @@
|
||||||
var dbtrName = "#{workflowController.workitem.item['dbtr.name']}";
|
var dbtrName = "#{workflowController.workitem.item['dbtr.name']}";
|
||||||
// append span with dbtr.name....
|
// append span with dbtr.name....
|
||||||
creditorField.after("<span id='dbtr-name-id' class='small'>" + dbtrName + "</p>");
|
creditorField.after("<span id='dbtr-name-id' class='small'>" + dbtrName + "</p>");
|
||||||
//$("[id$=autocomplete-resultlist-cargosoft_part]").hide();
|
|
||||||
|
// remove ajax loader
|
||||||
|
$body.removeClass("loading");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +89,7 @@
|
||||||
|
|
||||||
<h:inputText value="#{workitem.item[item.name]}" pt:data-item="dbtr_number_part"
|
<h:inputText value="#{workitem.item[item.name]}" pt:data-item="dbtr_number_part"
|
||||||
required="#{required?validationController.required:false}" rendered="#{!readonly}">
|
required="#{required?validationController.required:false}" rendered="#{!readonly}">
|
||||||
|
|
||||||
</h:inputText>
|
</h:inputText>
|
||||||
|
|
||||||
<!-- hidden input to store name -->
|
<!-- hidden input to store name -->
|
||||||
|
|
|
||||||
|
|
@ -174,22 +174,20 @@ th { font-weight: bold;}
|
||||||
<imixs-form-section columns="2">
|
<imixs-form-section columns="2">
|
||||||
<item name="dbtr.number" type="custom" path="alexander/debitor_search" required="true" label="Debitor:" />
|
<item name="dbtr.number" type="custom" path="alexander/debitor_search" required="true" label="Debitor:" />
|
||||||
</imixs-form-section>
|
</imixs-form-section>
|
||||||
|
|
||||||
<imixs-form-section columns="4" label="Rechnungen">
|
<imixs-form-section columns="4" label="Rechnungen">
|
||||||
<item name="analytic.invoices.count.all" type="custom" path="alexander/analyze_plain" label="Alle Rechnungen:" />
|
<item name="analytic.invoices.count.all" type="custom" path="alexander/analyze_plain" label="Alle Rechnungen:" />
|
||||||
<item name="analytic.invoices.count.open" type="custom" path="alexander/analyze_plain" label="Offene Rechnungen:" />
|
<item name="analytic.invoices.count.open" type="custom" path="alexander/analyze_plain" label="Offene Rechnungen:" />
|
||||||
<item name="analytic.invoices.count.due" type="custom" path="alexander/analyze_plain" label="Fällige Rechnungen:" />
|
<item name="analytic.invoices.count.due" type="custom" path="alexander/analyze_plain" label="Fällige Rechnungen:" />
|
||||||
<item name="analytic.invoices.count.dunning" type="custom" path="alexander/analyze_plain" label="Rechnungen in Mahnung:" />
|
<item name="analytic.invoices.count.dunning" type="custom" path="alexander/analyze_plain" label="Rechnungen in Mahnung:" />
|
||||||
|
|
||||||
<item name="analytic.payment.avg.due" type="custom" path="alexander/analyze_plain" label="Average term of credit:" />
|
<item name="analytic.payment.avg.due" type="custom" path="alexander/analyze_plain" label="Average term of credit:" />
|
||||||
<item name="analytic.payment.avg.days" type="custom" path="alexander/analyze_plain" label="Average payment duration:" />
|
<item name="analytic.payment.avg.days" type="custom" path="alexander/analyze_plain" label="Average payment duration:" />
|
||||||
|
</imixs-form-section>
|
||||||
</imixs-form-section>
|
|
||||||
|
|
||||||
<imixs-form-section columns="1" label="Trend Zahlungsmoral">
|
<imixs-form-section columns="1" label="Trend Zahlungsmoral">
|
||||||
<item name="analytic.invoices.trend" type="custom" path="alexander/analyze_chart" label="Zahlungen in den letzten 6 Monaten:" />
|
<item name="analytic.invoices.trend" type="custom" path="alexander/analyze_chart" label="Zahlungen in den letzten 6 Monaten:" />
|
||||||
</imixs-form-section>
|
</imixs-form-section>
|
||||||
|
|
||||||
|
|
||||||
</imixs-form>]]></bpmn2:documentation>
|
</imixs-form>]]></bpmn2:documentation>
|
||||||
<bpmn2:dataState id="DataState_1"/>
|
<bpmn2:dataState id="DataState_1"/>
|
||||||
</bpmn2:dataObject>
|
</bpmn2:dataObject>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue