Einführung BPID und verbesserung Metric service
This commit is contained in:
parent
50f44b851f
commit
eb6808da78
6 changed files with 288 additions and 226 deletions
|
|
@ -8,6 +8,9 @@ import java.util.Map;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
|
||||
import com.alexanderlogistics.metrics.MetricDataService;
|
||||
|
||||
/**
|
||||
* Hilfsmethoden für die Berechnung und Validierung von Ein und
|
||||
|
|
@ -25,6 +28,8 @@ import org.imixs.workflow.ItemCollection;
|
|||
*/
|
||||
public class InvoiceUtil {
|
||||
|
||||
public static final String ERROR_INVALID_INVOICEDATA = "ERROR_INVALID_INVOICEDATA";
|
||||
|
||||
public static final String CHILD_ITEM_PROPERTY = "_ChildItems";
|
||||
public static final String ITEM_INVOICE_PERIOD = "invoice.period";
|
||||
public static final String ITEM_INVOICE_POSITIONS = "invoice.positions";
|
||||
|
|
@ -157,4 +162,84 @@ public class InvoiceUtil {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Hilfsmethode harmonisiert die Debitoren/Kreditoren ID von Cargosoft und
|
||||
* liefert eine Geschäftspartner ID zurück.
|
||||
*
|
||||
* Aus Kreditor K70153 und Debitor D10153 wird die einheitliche ID: BP0153
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static String buildBPID(String key) {
|
||||
key = key.toUpperCase();
|
||||
if (key.startsWith("D") || key.startsWith("K")) {
|
||||
key = key.substring(1);
|
||||
}
|
||||
if (!key.startsWith("BP")) {
|
||||
// cut first digit (debitor/creditor)
|
||||
key = "BP" + key.substring(1);
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Hilfsmethode berechnet die BusinessPartnerID aus einer Invoice
|
||||
*
|
||||
* @param Invoice
|
||||
* @return
|
||||
* @throws PluginException
|
||||
*/
|
||||
public static String getBPId(ItemCollection invoice) throws PluginException {
|
||||
String key = "";
|
||||
if (isCreditorInvoice(invoice)) {
|
||||
// key ist cdtr.number
|
||||
key = invoice.getItemValueString("cdtr.number");
|
||||
} else {
|
||||
// key ist dbtr.number
|
||||
key = invoice.getItemValueString("dbtr.number");
|
||||
}
|
||||
if (key.isEmpty()) {
|
||||
throw new PluginException(MetricDataService.class.getName(), ERROR_INVALID_INVOICEDATA,
|
||||
"Failed to create metrics - missing dbtr/cdtr number!");
|
||||
}
|
||||
|
||||
return InvoiceUtil.buildBPID(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Hilfmethode berechnet die BusinessPartner Namen aus einer Invoice
|
||||
*
|
||||
* @param Invoice
|
||||
* @return
|
||||
*/
|
||||
public static String getBPName(ItemCollection invoice) {
|
||||
String name = "";
|
||||
if (isCreditorInvoice(invoice)) {
|
||||
// key ist cdtr.number
|
||||
name = invoice.getItemValueString("cdtr.name");
|
||||
} else {
|
||||
// key ist dbtr.number
|
||||
name = invoice.getItemValueString("dbtr.name");
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt true zurück wenn es sich um eine Kreditoren Rechnung/Gutschrift handelt.
|
||||
*
|
||||
* @param invoice
|
||||
* @return
|
||||
*/
|
||||
public static boolean isCreditorInvoice(ItemCollection invoice) {
|
||||
boolean result = false;
|
||||
if (invoice.getModelVersion().startsWith("rechnungseingang")
|
||||
|| invoice.getModelVersion().startsWith("gutschriftabgleich")) {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import org.imixs.workflow.engine.DocumentService;
|
|||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
|
||||
import com.alexanderlogistics.InvoiceUtil;
|
||||
|
||||
import jakarta.ejb.Stateless;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
|
|
@ -26,7 +28,7 @@ public class MetricCreditorRestService {
|
|||
DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
MetricCreditorService metricService;
|
||||
MetricCreditorService metricCreditorService;
|
||||
|
||||
@Inject
|
||||
MetricDataService metricDataService;
|
||||
|
|
@ -39,66 +41,41 @@ public class MetricCreditorRestService {
|
|||
return "ping: " + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method refreshes all creditor metrics by iterating through the metric
|
||||
* entities.
|
||||
* This will refresh the metrics view in Wildfly only and not computing the
|
||||
* metrics itself.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@Path("/refresh")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public Response refreshMetrics() {
|
||||
try {
|
||||
// Alle Creditor Metriken laden
|
||||
String query = "(type:" + MetricCreditorService.TYPE_METRIC_CREDITOR + ")";
|
||||
List<ItemCollection> metrics = documentService.find(query, 9999, 0);
|
||||
|
||||
// Metriken initialisieren
|
||||
for (ItemCollection metric : metrics) {
|
||||
metricService.initMetric(metric);
|
||||
}
|
||||
return Response.ok().entity("Initialized " + metrics.size() + " creditor metrics").build();
|
||||
} catch (Exception e) {
|
||||
return Response.serverError()
|
||||
.entity("Failed to initialize metrics: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initializes the metrics for all creditors with open invoices.
|
||||
*
|
||||
* The method deletes all existing metrics and creates new metric entires for
|
||||
* each creditor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@Path("/init")
|
||||
@Path("/rebuild")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public Response initMetrics() {
|
||||
|
||||
public Response rebuildMetrics() {
|
||||
StringBuffer messageBuffer = new StringBuffer();
|
||||
long l = System.currentTimeMillis();
|
||||
logger.info("├── init cdtr metrics...");
|
||||
log("├── init cdtr metrics...", messageBuffer);
|
||||
try {
|
||||
// first clear the metric cache
|
||||
metricService.reset();
|
||||
logger.info("│ ├── reset metric cache");
|
||||
|
||||
metricCreditorService.reset();
|
||||
log("│ ├── reset metric cache", messageBuffer);
|
||||
// run in new transaction!
|
||||
metricDataService.deleteAllMetrics(MetricCreditorService.TYPE_METRIC_CREDITOR);
|
||||
logger.info("│ ├── delete metrics");
|
||||
log("│ ├── delete metrics", messageBuffer);
|
||||
|
||||
groupInvoicesByCreditor();
|
||||
logger.info("│ ├── grouping invoices finished in " + (System.currentTimeMillis() - l) + "ms");
|
||||
computeMetrics();
|
||||
log("│ ├── computing metrics finished in " + (System.currentTimeMillis() - l) + "ms", messageBuffer);
|
||||
|
||||
rebuildMetrics();
|
||||
String message = "├── init cdtr metrics completed in "
|
||||
logger.info("│ ├── save and init metrics...");
|
||||
// run in new transaction!
|
||||
metricCreditorService.refreshGauges();
|
||||
|
||||
String message = "├── rebuild cdtr metrics completed in "
|
||||
+ (System.currentTimeMillis() - l)
|
||||
+ "ms";
|
||||
logger.info(message);
|
||||
return Response.ok().entity(message).build();
|
||||
log(message, messageBuffer);
|
||||
return Response.ok().entity(messageBuffer.toString()).build();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -108,30 +85,16 @@ public class MetricCreditorRestService {
|
|||
}
|
||||
}
|
||||
|
||||
private void rebuildMetrics() throws PluginException {
|
||||
logger.info("│ ├── rebuild metrics...");
|
||||
List<String> keys = metricService.getMetricKeys();
|
||||
for (String hashKey : keys) {
|
||||
ItemCollection metricData = metricService.getMetric(hashKey);
|
||||
// metricCache.get(dbtrNumber);
|
||||
documentService.save(metricData);
|
||||
metricService.initMetric(metricData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode gruppiert eine Rechnungsliste nach creditoren
|
||||
*
|
||||
* @param spaceID - Space Ref to select a list of invoices associated with
|
||||
* a
|
||||
* space
|
||||
* @param metricCache - a local cache storing all invoices by week
|
||||
*
|
||||
* Diese Methode berechnet alle Metriken auf basis der existierenden Rechnungen
|
||||
* neu
|
||||
*
|
||||
*/
|
||||
private void groupInvoicesByCreditor() {
|
||||
logger.info("│ ├── group invoices by creditor...");
|
||||
public void computeMetrics() {
|
||||
|
||||
logger.info("│ │ ├── group invoices by creditor...");
|
||||
try {
|
||||
int count = 0;
|
||||
List<ItemCollection> invoices = documentService.find(
|
||||
"($modelversion:rechnungseingang-* OR $modelversion:gutschriftabgleich-*) " +
|
||||
" AND type:workitem",
|
||||
|
|
@ -139,19 +102,28 @@ public class MetricCreditorRestService {
|
|||
"invoice.number", false);
|
||||
logger.info("│ │ ├──found " + invoices.size() + " open invoices");
|
||||
for (ItemCollection invoice : invoices) {
|
||||
if (invoice.getItemValueString("cdtr.number").trim().isEmpty()) {
|
||||
// skip event
|
||||
continue;
|
||||
}
|
||||
ItemCollection metricData = metricService.getMetricByInvoice(invoice);
|
||||
try {
|
||||
ItemCollection metricData = metricCreditorService.getMetricByInvoice(invoice);
|
||||
// Jetzt Rechnung addieren
|
||||
metricService.addInvoice(metricData, invoice);
|
||||
logger.fine("....put invoice " + invoice.getUniqueID());
|
||||
metricService.putMetric(metricData);
|
||||
metricCreditorService.addInvoice(metricData, invoice);
|
||||
logger.info("│ │ │ ├──update metric " + InvoiceUtil.getBPId(invoice));
|
||||
metricCreditorService.putMetric(metricData);
|
||||
count++;
|
||||
} catch (PluginException e) {
|
||||
// invalid invoice - e.g. no cdtr. number
|
||||
}
|
||||
logger.info("│ │ ├── grouped " + invoices.size() + " invoices.");
|
||||
} catch (QueryException | PluginException e) {
|
||||
|
||||
}
|
||||
logger.info("│ │ ├── updated metric for " + count + " invoices.");
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void log(String message, StringBuffer messageLog) {
|
||||
logger.info(message);
|
||||
messageLog.append(message + "\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import com.alexanderlogistics.KreditorDebitorService;
|
|||
import jakarta.annotation.security.DeclareRoles;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.annotation.security.RunAs;
|
||||
import jakarta.ejb.TransactionAttribute;
|
||||
import jakarta.ejb.TransactionAttributeType;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.enterprise.event.Observes;
|
||||
import jakarta.inject.Inject;
|
||||
|
|
@ -98,33 +100,28 @@ public class MetricCreditorService {
|
|||
return;
|
||||
}
|
||||
|
||||
// double creditorSaldo = 0;
|
||||
ItemCollection invoice = processingEvent.getDocument();
|
||||
if (!invoice.getModelVersion().startsWith("rechnungseingang-")
|
||||
&& !invoice.getModelVersion().startsWith("gutschriftabgleich-")) {
|
||||
if (!InvoiceUtil.isCreditorInvoice(invoice)) {
|
||||
// skip event
|
||||
return;
|
||||
}
|
||||
|
||||
// if we do not have a cdtr.number skip
|
||||
if (invoice.getItemValueString("cdtr.number").trim().isEmpty()) {
|
||||
// skip event
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// update metric and the metric cache
|
||||
if (processingEvent.getEventType() == ProcessingEvent.AFTER_PROCESS) {
|
||||
|
||||
// load the last invoice metric and reduce the saldo...
|
||||
ItemCollection lastInvoice = metricDataService.readDirtyWorkitem(invoice.getUniqueID());
|
||||
if (lastInvoice != null) {
|
||||
try {
|
||||
ItemCollection lastMetricData = getMetricByInvoice(lastInvoice);
|
||||
subtractInvoice(lastMetricData, lastInvoice);
|
||||
putMetric(lastMetricData);
|
||||
metricDataService.saveMetric(lastMetricData);
|
||||
} catch (PluginException e) {
|
||||
// invalid invoice - e.g. no cdtr. number
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// load the invoice metric and add the saldo...
|
||||
ItemCollection metricData = getMetricByInvoice(invoice);
|
||||
// Saldo-Berechnung
|
||||
|
|
@ -135,18 +132,22 @@ public class MetricCreditorService {
|
|||
// Update the Gauge
|
||||
updateGauge(metricData);
|
||||
logger.info("Metric cdtr update took " + (System.currentTimeMillis() - l) + "ms");
|
||||
}
|
||||
} catch (PluginException e) {
|
||||
logger.warning("unable to process metric: " + e.getMessage());
|
||||
// invalid invoice - e.g. no cdtr. number
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding metric data object for an invoice. The method uses
|
||||
* an internal cache. If the metric was not yet cached the method loads the
|
||||
* metric from the database. If not metric exists in the database the method
|
||||
* automatically creates a new metric data object.
|
||||
*
|
||||
* The method throws a PluginException if no metric can be build from this
|
||||
* invoice (e.g. missing cdtr.number).
|
||||
*
|
||||
* @param invoice
|
||||
* @return
|
||||
* @throws PluginException
|
||||
|
|
@ -221,20 +222,20 @@ public class MetricCreditorService {
|
|||
throw new PluginException(PluginException.class.getName(),
|
||||
"Failed to load metric object for invoice " + invoice.getUniqueID() + ": ", e.getMessage(), e);
|
||||
}
|
||||
|
||||
return creditorMetric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty Debitor Meta Data Object (ItemCollection)
|
||||
* Creates an empty Creditor Meta Data Object (ItemCollection)
|
||||
* <p>
|
||||
* The ItemCollection stores the name and number and also all saldos for all
|
||||
* currencies
|
||||
*
|
||||
* @param invoice - invoice ItemCollection
|
||||
* @return
|
||||
* @throws PluginException
|
||||
*/
|
||||
private ItemCollection createMetaData(ItemCollection invoice) {
|
||||
private ItemCollection createMetaData(ItemCollection invoice) throws PluginException {
|
||||
if (invoice == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -242,9 +243,12 @@ public class MetricCreditorService {
|
|||
ItemCollection metricData = new ItemCollection();
|
||||
metricData.setType(TYPE_METRIC_CREDITOR);
|
||||
metricData.setItemValue("name", key);
|
||||
metricData.setItemValue("country", invoice.getItemValueString("invoice.country"));
|
||||
metricData.setItemValue("currency", invoice.getItemValueString("invoice.currency"));
|
||||
metricData.setItemValue("department", invoice.getItemValueString("space.name"));
|
||||
metricData.setItemValue("bp_id", InvoiceUtil.getBPId(invoice));
|
||||
metricData.setItemValue("bp_name", InvoiceUtil.getBPName(invoice));
|
||||
metricData.setItemValue("invoice_country", invoice.getItemValueString("invoice.country"));
|
||||
metricData.setItemValue("invoice_currency", invoice.getItemValueString("invoice.currency"));
|
||||
metricData.setItemValue("invoice_department", invoice.getItemValueString("space.name"));
|
||||
|
||||
return metricData;
|
||||
}
|
||||
|
||||
|
|
@ -254,21 +258,27 @@ public class MetricCreditorService {
|
|||
* @param cdtrNumber - the creditor number
|
||||
* @param cdtrName - the creditor name
|
||||
*/
|
||||
private void updateGauge(ItemCollection metricData) {
|
||||
public void updateGauge(ItemCollection metricData) {
|
||||
|
||||
String metricKey = metricData.getItemValueString("name");
|
||||
String country = metricData.getItemValueString("country");
|
||||
String department = metricData.getItemValueString("department");
|
||||
String currency = metricData.getItemValueString("currency");
|
||||
String bpName = metricData.getItemValueString("bp_name");
|
||||
String bpId = metricData.getItemValueString("bp_id");
|
||||
String country = metricData.getItemValueString("invoice_country");
|
||||
String department = metricData.getItemValueString("invoice_department");
|
||||
String currency = metricData.getItemValueString("invoice_currency");
|
||||
|
||||
// Prüfen ob Gauge bereits registriert ist
|
||||
if (registeredGauges.add(metricKey)) { // returns true newly added
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
tags.add(new Tag("type", "cdtr"));
|
||||
tags.add(new Tag("id", bpId));
|
||||
tags.add(new Tag("name", bpName));
|
||||
tags.add(new Tag("country", country));
|
||||
tags.add(new Tag("currency", currency));
|
||||
tags.add(new Tag("department", department));
|
||||
logger.info("register new metric for department: " + department +
|
||||
logger.fine("register new metric for department: " + department +
|
||||
", " + metricData.getItemValueString(ITEM_SALDO) +
|
||||
" " + metricData.getItemValueString("invoice.currency"));
|
||||
" " + currency);
|
||||
Metadata metadata = Metadata.builder()
|
||||
.withName("cdtr.balance")
|
||||
.withDescription("Creditor Balance")
|
||||
|
|
@ -284,19 +294,6 @@ public class MetricCreditorService {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode um Metriken initial aufzubauen. Wird vom Metric Rest Service
|
||||
* verwendet.
|
||||
*
|
||||
*/
|
||||
protected void initMetric(ItemCollection metric) {
|
||||
String key = metric.getItemValueString("name");
|
||||
// Aktuelle metric cachen
|
||||
metricCache.put(key, metric);
|
||||
logger.info("│ │ ├──init metric for creditor " + key);
|
||||
updateGauge(metric);
|
||||
}
|
||||
|
||||
/**
|
||||
* Addiert den saldo einer Invoice zu einem metricData object
|
||||
*
|
||||
|
|
@ -335,4 +332,17 @@ public class MetricCreditorService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper Method that refreshes all gauges. The method is called by the
|
||||
* RestService during a rebuild.
|
||||
*/
|
||||
@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
|
||||
public void refreshGauges() {
|
||||
List<String> keys = getMetricKeys();
|
||||
for (String hashKey : keys) {
|
||||
ItemCollection metricData = getMetric(hashKey);
|
||||
documentService.save(metricData);
|
||||
updateGauge(metricData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,12 @@ import java.util.Objects;
|
|||
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.index.SearchService;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
|
||||
import com.alexanderlogistics.InvoiceUtil;
|
||||
|
||||
import jakarta.annotation.security.DeclareRoles;
|
||||
import jakarta.annotation.security.RunAs;
|
||||
import jakarta.ejb.Stateless;
|
||||
|
|
@ -57,16 +60,17 @@ public class MetricDataService {
|
|||
* @throws PluginException
|
||||
*
|
||||
*/
|
||||
@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
|
||||
public void deleteAllMetrics(String metricType) throws PluginException {
|
||||
try {
|
||||
String query = "(type:" + metricType + ")";
|
||||
List<ItemCollection> result = documentService.find(query, -1, 0);
|
||||
List<ItemCollection> result = documentService.find(query, SearchService.DEFAULT_MAX_SEARCH_RESULT, 0);
|
||||
for (ItemCollection metric : result) {
|
||||
documentService.remove(metric);
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException | QueryException e) {
|
||||
throw new PluginException(PluginException.class.getName(),
|
||||
throw new PluginException(MetricDataService.class.getName(),
|
||||
"Failed to delete metrics", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
|
@ -75,20 +79,27 @@ public class MetricDataService {
|
|||
* Builds the metric hash key by the invoice attributes. The returned key can be
|
||||
* used for caching the metric.
|
||||
*
|
||||
* The metric key does not include the dbtr/cdtr name as this name is not
|
||||
* relevant for building a hashkey.
|
||||
*
|
||||
* @param invoice - The invoice ItemCollection containing the necessary
|
||||
* attributes
|
||||
* @return A unique hash string based on the invoice attributes
|
||||
* @throws PluginException
|
||||
* @throws IllegalArgumentException if the invoice is null
|
||||
*/
|
||||
public static String buildKeyByInvoice(ItemCollection invoice) {
|
||||
public static String buildKeyByInvoice(ItemCollection invoice) throws PluginException {
|
||||
// Validate input
|
||||
Objects.requireNonNull(invoice, "Invoice must not be null");
|
||||
|
||||
String bpNumber = InvoiceUtil.getBPId(invoice);
|
||||
String country = invoice.getItemValueString("invoice.country");
|
||||
String currency = invoice.getItemValueString("invoice.currency");
|
||||
String department = invoice.getItemValueString("space.name");
|
||||
|
||||
// Concatenate the values and create a hash
|
||||
String combinedValue = String.format("%s::%s::%s",
|
||||
String combinedValue = String.format("%s::%s::%s::%s",
|
||||
bpNumber,
|
||||
country,
|
||||
currency,
|
||||
department);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import org.imixs.workflow.engine.DocumentService;
|
|||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
|
||||
import com.alexanderlogistics.InvoiceUtil;
|
||||
|
||||
import jakarta.ejb.Stateless;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
|
|
@ -26,7 +28,7 @@ public class MetricDebitorRestService {
|
|||
DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
MetricDebitorService metricService;
|
||||
MetricDebitorService metricDebitorService;
|
||||
|
||||
@Inject
|
||||
MetricDataService metricDataService;
|
||||
|
|
@ -39,45 +41,18 @@ public class MetricDebitorRestService {
|
|||
return "ping: " + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method refreshes all debitor metrics by iterating through the metric
|
||||
* entities.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@Path("/refresh")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public Response refreshMetrics() {
|
||||
try {
|
||||
// Alle Debitoren Metriken laden
|
||||
String query = "(type:" + MetricDebitorService.TYPE_METRIC_DEBITOR + ")";
|
||||
List<ItemCollection> metrics = documentService.find(query, 9999, 0);
|
||||
|
||||
// Metriken initialisieren
|
||||
for (ItemCollection metric : metrics) {
|
||||
metricService.initMetric(metric);
|
||||
}
|
||||
|
||||
return Response.ok().entity("Initialized " + metrics.size() + " debitor metrics").build();
|
||||
|
||||
} catch (Exception e) {
|
||||
return Response.serverError()
|
||||
.entity("Failed to initialize metrics: " + e.getMessage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initializes the metrics for all debitors with open invoices.
|
||||
* The method creates or updates the metric entires for each debitor.
|
||||
*
|
||||
* The method first deletes all existing metrics and than creates or updates the
|
||||
* metric entires for each debitor.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@Path("/init")
|
||||
@Path("/rebuild")
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public Response initMetrics() {
|
||||
public Response rebuildMetrics() {
|
||||
// Map<String, ItemCollection> metricCache = new HashMap<String,
|
||||
// ItemCollection>();
|
||||
long l = System.currentTimeMillis();
|
||||
|
|
@ -85,16 +60,20 @@ public class MetricDebitorRestService {
|
|||
|
||||
try {
|
||||
// first clear the metric cache
|
||||
metricService.reset();
|
||||
metricDebitorService.reset();
|
||||
logger.info("│ ├── reset metric cache");
|
||||
// run in new transaction!
|
||||
metricDataService.deleteAllMetrics(MetricDebitorService.TYPE_METRIC_DEBITOR);
|
||||
logger.info("│ ├── delete metrics");
|
||||
|
||||
groupInvoicesByDebitor();
|
||||
logger.info("│ ├── grouping invoices finished in " + (System.currentTimeMillis() - l) + "ms");
|
||||
computeMetrics();
|
||||
logger.info("│ ├── computing metrics finished in " + (System.currentTimeMillis() - l) + "ms");
|
||||
|
||||
rebuildMetrics();
|
||||
String message = "├── init cdtr metrics completed in "
|
||||
logger.info("│ ├── save and init metrics ...");
|
||||
// run in new transaction!
|
||||
metricDebitorService.refreshGauges();
|
||||
|
||||
String message = "├── rebuild dbtr metrics completed in "
|
||||
+ (System.currentTimeMillis() - l)
|
||||
+ "ms";
|
||||
logger.info(message);
|
||||
|
|
@ -108,32 +87,16 @@ public class MetricDebitorRestService {
|
|||
}
|
||||
}
|
||||
|
||||
private void rebuildMetrics() throws PluginException {
|
||||
logger.info("│ ├── rebuild metrics...");
|
||||
|
||||
List<String> keys = metricService.getMetricKeys();
|
||||
for (String hashKey : keys) {
|
||||
ItemCollection metricData = metricService.getMetric(hashKey);
|
||||
// metricCache.get(dbtrNumber);
|
||||
documentService.save(metricData);
|
||||
metricService.initMetric(metricData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode gruppiert eine Rechnungsliste nach debitoren
|
||||
*
|
||||
* @param spaceID - Space Ref to select a list of invoices associated with
|
||||
* a
|
||||
* space
|
||||
* @param metricCache - a local cache storing all invoices by week
|
||||
*
|
||||
* Diese Methode berechnet alle Metriken auf basis der existierenden Rechnungen
|
||||
* neu
|
||||
*
|
||||
*/
|
||||
private void groupInvoicesByDebitor() {
|
||||
public void computeMetrics() {
|
||||
|
||||
logger.info("│ │ ├── group invoices by debitor...");
|
||||
try {
|
||||
int count = 0;
|
||||
List<ItemCollection> invoices = documentService.find(
|
||||
"$modelversion:rechnungsausgang-* AND type:workitem",
|
||||
9999, 0,
|
||||
|
|
@ -141,14 +104,22 @@ public class MetricDebitorRestService {
|
|||
|
||||
logger.info("│ │ ├── found " + invoices.size() + " open invoices");
|
||||
for (ItemCollection invoice : invoices) {
|
||||
ItemCollection metricData = metricService.getMetricByInvoice(invoice);
|
||||
try {
|
||||
|
||||
ItemCollection metricData = metricDebitorService.getMetricByInvoice(invoice);
|
||||
|
||||
// Jetzt Rechnung addieren
|
||||
metricService.addInvoice(metricData, invoice);
|
||||
logger.fine("....put invoice " + invoice.getUniqueID());
|
||||
metricService.putMetric(metricData);
|
||||
metricDebitorService.addInvoice(metricData, invoice);
|
||||
logger.info("│ │ │ ├──update metric " + InvoiceUtil.getBPId(invoice));
|
||||
metricDebitorService.putMetric(metricData);
|
||||
count++;
|
||||
} catch (PluginException e) {
|
||||
// invalid invoice - e.g. no dbtr. number
|
||||
}
|
||||
logger.info("│ │ ├── grouped " + invoices.size() + " invoices.");
|
||||
} catch (QueryException | PluginException e) {
|
||||
|
||||
}
|
||||
logger.info("│ │ ├── updated metric for " + count + " invoices.");
|
||||
} catch (QueryException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import com.alexanderlogistics.InvoiceUtil;
|
|||
import jakarta.annotation.security.DeclareRoles;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.annotation.security.RunAs;
|
||||
import jakarta.ejb.TransactionAttribute;
|
||||
import jakarta.ejb.TransactionAttributeType;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.enterprise.event.Observes;
|
||||
import jakarta.inject.Inject;
|
||||
|
|
@ -90,30 +92,28 @@ public class MetricDebitorService {
|
|||
return;
|
||||
}
|
||||
|
||||
// double debitorSaldo = 0;
|
||||
ItemCollection invoice = processingEvent.getDocument();
|
||||
if (!invoice.getModelVersion().startsWith("rechnungsausgang-")) {
|
||||
// skip event
|
||||
return;
|
||||
}
|
||||
|
||||
// if we do not have a dbtr.number skip
|
||||
if (invoice.getItemValueString("dbtr.number").trim().isEmpty()) {
|
||||
// skip event
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// update metric and the metric cache
|
||||
if (processingEvent.getEventType() == ProcessingEvent.AFTER_PROCESS) {
|
||||
// load the last invoice metric and reduce the saldo...
|
||||
ItemCollection lastInvoice = metricDataService.readDirtyWorkitem(invoice.getUniqueID());
|
||||
if (lastInvoice != null) {
|
||||
try {
|
||||
ItemCollection lastMetricData = getMetricByInvoice(lastInvoice);
|
||||
subtractInvoice(lastMetricData, lastInvoice);
|
||||
putMetric(lastMetricData);
|
||||
metricDataService.saveMetric(lastMetricData);
|
||||
} catch (PluginException e) {
|
||||
// invalid invoice - e.g. no cdtr. number
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// load the invoice metric and add the saldo...
|
||||
ItemCollection metricData = getMetricByInvoice(invoice);
|
||||
// Saldo-Berechnung
|
||||
|
|
@ -124,18 +124,22 @@ public class MetricDebitorService {
|
|||
// Update the Gauge
|
||||
updateGauge(metricData);
|
||||
logger.info("Metric dbtr update took " + (System.currentTimeMillis() - l) + "ms");
|
||||
}
|
||||
} catch (PluginException e) {
|
||||
logger.warning("unable to process metric: " + e.getMessage());
|
||||
// invalid invoice - e.g. no dbtr. number
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding metric data object for an invoice. The method uses
|
||||
* an internal cache. If the metric was not yet cached the method loads the
|
||||
* metric from the database. If not metric exists in the database the method
|
||||
* automatically creates a new metric data object.
|
||||
*
|
||||
* The method throws a PluginException if no metric can be build from this
|
||||
* invoice (e.g. missing dbtr.number).
|
||||
*
|
||||
* @param invoice
|
||||
* @return
|
||||
* @throws PluginException
|
||||
|
|
@ -195,10 +199,10 @@ public class MetricDebitorService {
|
|||
* @throws PluginException
|
||||
*/
|
||||
private ItemCollection loadMetric(ItemCollection invoice) throws PluginException {
|
||||
ItemCollection debitorMetric = null;
|
||||
if (invoice == null) {
|
||||
return null;
|
||||
}
|
||||
ItemCollection debitorMetric = null;
|
||||
try {
|
||||
String metricKey = MetricDataService.buildKeyByInvoice(invoice);
|
||||
String query = "(type:" + TYPE_METRIC_DEBITOR + ") AND (name:" + metricKey + ")";
|
||||
|
|
@ -221,8 +225,9 @@ public class MetricDebitorService {
|
|||
*
|
||||
* @param invoice - invoice ItemCollection
|
||||
* @return
|
||||
* @throws PluginException
|
||||
*/
|
||||
private ItemCollection createMetaData(ItemCollection invoice) {
|
||||
private ItemCollection createMetaData(ItemCollection invoice) throws PluginException {
|
||||
if (invoice == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -230,9 +235,12 @@ public class MetricDebitorService {
|
|||
ItemCollection metricData = new ItemCollection();
|
||||
metricData.setType(TYPE_METRIC_DEBITOR);
|
||||
metricData.setItemValue("name", key);
|
||||
metricData.setItemValue("country", invoice.getItemValueString("invoice.country"));
|
||||
metricData.setItemValue("currency", invoice.getItemValueString("invoice.currency"));
|
||||
metricData.setItemValue("department", invoice.getItemValueString("space.name"));
|
||||
metricData.setItemValue("bp_id", InvoiceUtil.getBPId(invoice));
|
||||
metricData.setItemValue("bp_name", InvoiceUtil.getBPName(invoice));
|
||||
metricData.setItemValue("invoice_country", invoice.getItemValueString("invoice.country"));
|
||||
metricData.setItemValue("invoice_currency", invoice.getItemValueString("invoice.currency"));
|
||||
metricData.setItemValue("invoice_department", invoice.getItemValueString("space.name"));
|
||||
|
||||
return metricData;
|
||||
}
|
||||
|
||||
|
|
@ -241,21 +249,25 @@ public class MetricDebitorService {
|
|||
*
|
||||
* @param metricData - the metricData ItemCollection
|
||||
*/
|
||||
private void updateGauge(ItemCollection metricData) {
|
||||
// String dbtrNumber = metricData.getItemValueString("dbtr.number");
|
||||
// String dbtrName = metricData.getItemValueString("dbtr.name");
|
||||
String country = metricData.getItemValueString("country");
|
||||
String department = metricData.getItemValueString("department");
|
||||
String currency = metricData.getItemValueString("currency");
|
||||
public void updateGauge(ItemCollection metricData) {
|
||||
|
||||
String metricKey = metricData.getItemValueString("name");
|
||||
String bpName = metricData.getItemValueString("bp_name");
|
||||
String bpId = metricData.getItemValueString("bp_id");
|
||||
String country = metricData.getItemValueString("invoice_country");
|
||||
String department = metricData.getItemValueString("invoice_department");
|
||||
String currency = metricData.getItemValueString("invoice_currency");
|
||||
|
||||
// Prüfen ob Gauge bereits registriert ist
|
||||
if (registeredGauges.add(metricKey)) { // returns true newly added
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
tags.add(new Tag("type", "dbtr"));
|
||||
tags.add(new Tag("id", bpId));
|
||||
tags.add(new Tag("name", bpName));
|
||||
tags.add(new Tag("country", country));
|
||||
tags.add(new Tag("currency", currency));
|
||||
tags.add(new Tag("department", department));
|
||||
logger.info("register new metric for department: " + department +
|
||||
logger.fine("register new metric for department: " + department +
|
||||
", " + metricData.getItemValueString(ITEM_SALDO) +
|
||||
" " + currency);
|
||||
Metadata metadata = Metadata.builder()
|
||||
|
|
@ -273,19 +285,6 @@ public class MetricDebitorService {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode um Metriken initial aufzubauen. Wird vom Metric Rest Service
|
||||
* verwendet.
|
||||
*
|
||||
*/
|
||||
protected void initMetric(ItemCollection metric) {
|
||||
String key = metric.getItemValueString("name");
|
||||
// Aktuelle metric cachen
|
||||
metricCache.put(key, metric);
|
||||
logger.info("│ │ ├──init metric for debitor " + key);
|
||||
updateGauge(metric);
|
||||
}
|
||||
|
||||
/**
|
||||
* Addiert den saldo einer Invoice zu einem metricData object
|
||||
*
|
||||
|
|
@ -323,4 +322,18 @@ public class MetricDebitorService {
|
|||
metricData.setItemValue(ITEM_SALDO, InvoiceUtil.round(lastSaldo - invoiceTotal));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper Method that refreshes all gauges. The method is called by the
|
||||
* RestService during a rebuild.
|
||||
*/
|
||||
@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
|
||||
public void refreshGauges() {
|
||||
List<String> keys = getMetricKeys();
|
||||
for (String hashKey : keys) {
|
||||
ItemCollection metricData = getMetric(hashKey);
|
||||
documentService.save(metricData);
|
||||
updateGauge(metricData);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue