package com.alexanderlogistics; import java.io.Serializable; import java.time.LocalDate; 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.WorkflowKernel; import org.imixs.workflow.engine.DocumentService; import org.imixs.workflow.engine.WorkflowService; import org.imixs.workflow.exceptions.PluginException; import org.imixs.workflow.faces.data.WorkflowController; import org.imixs.workflow.faces.data.WorkflowEvent; import jakarta.enterprise.context.ConversationScoped; import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; import jakarta.inject.Named; /** * Der OPListeController dient dazu eine liste aller offenen Ausgangsrechnungen * zu bilden *

* Zusätzlich bietet er die funktionen zum auszifferne. Dies bedeutet, der * controller ermittelt zunächst alle offenen Rechnungen zu einem Debitor. Diese * Rechnungen werden in eine ChildItems Collection überführt. Der User kann nun * im Interface einzelne Rechnungen selektieren. Wird das Workitem gespeichert, * errechnet der Controller die selectieren Invoices und verknpüft diese final * mit dem Zahlungseingang. * * * @author rsoika * */ @Named("opListController") @ConversationScoped public class OPListController implements Serializable { private static final long serialVersionUID = 1L; public static final int TASK_ERSTELLUNG = 1000; private static Logger logger = Logger.getLogger(OPListController.class.getName()); private String lastDbtrNumber = null; private String currencyFilter = "-"; private String lastCurrencyFilter = null; private List invoiceList = null; @Inject protected WorkflowController workflowController; @Inject protected WorkflowService workflowService; @Inject ZahlungseingangService zahlungseingangService; @Inject protected DocumentService documentService; @Inject protected InvoiceService invoiceService; @Inject protected BusinessPartnerService businessPartnerService; /** * Diese Methode wird für Zahlungseingänge und Mahnläufe verwendet. *

* Die Methode liefert die Rechnungen zur gegebenen dbtrNumber. Die Methode * nutzt einen lokalen cache um die Zugriffe zu beschleunigen. *

* Befindet sich ein Zahlungseingang in Erstellung (Task=1000) werden alle * offenen Rechnungen geholt. *

* Befindet sich ein Zahlungseingang nicht mehr in erstellung werden nur die * Rechnugnen aus $workitemRef geholt! *

* Bei verwendung im Mahnlauf werden zusätzlich auch alle diese Rechnungen * vorselektiert (Anforderung von Mary Mwangi). D.h. es werden alle Checkboxen * in der Maske 'selection_opliste_Mahnluaf' angewählt. D.h auch, dass man ggf. * Rechnungen manuell delselktieren muss, wenn man diese nicht im Mahnlauf haben * will. *

* Beim Mahnlauf werden Inkasso Rechnungen ausgenommen. * * * @param _dbtrNumber * @return */ @SuppressWarnings("unchecked") public List getInvoices(String _dbtrNumber) { // if last dbtr number is not equal then reset the current list.... if (invoiceList != null && // (lastDbtrNumber == null || !lastDbtrNumber.equals(_dbtrNumber) // || lastCurrencyFilter == null || !lastCurrencyFilter.equals(currencyFilter)) // ) { invoiceList = null; } if (invoiceList != null) { return invoiceList; } if (_dbtrNumber == null) { return new ArrayList(); } long l = System.currentTimeMillis(); logger.info("...compute getInvoices..."); // Compute all open invoices if TASK_ERSTELLUNG.... if (workflowController.getWorkitem().getTaskID() == 0 || workflowController.getWorkitem().getTaskID() == TASK_ERSTELLUNG) { // return empty list if dbtr is not set if (_dbtrNumber == null || _dbtrNumber.isEmpty()) { invoiceList = new ArrayList(); return invoiceList; } // if last dbtr number is equal then return the current list.... if (invoiceList != null && // lastDbtrNumber != null && lastDbtrNumber.equals(_dbtrNumber) && // lastCurrencyFilter != null && lastCurrencyFilter.equals(currencyFilter) // ) { return invoiceList; } // load new invoice list.... lastDbtrNumber = _dbtrNumber; lastCurrencyFilter = currencyFilter; invoiceList = new ArrayList(); logger.fine("....loading open Invoices for " + _dbtrNumber); List invoiceListTemp = businessPartnerService.findOutgoingInvoices(_dbtrNumber); // Jetzt nur noch die Rechnungen nehmen die zum ausgewählten Währungsfilter // passen invoiceList = new ArrayList(); for (ItemCollection _invoice : invoiceListTemp) { // Test if we have 'invoice.base.amount' and 'invoice.rate' if (!_invoice.hasItem("invoice.base.amount")) { _invoice.setItemValue("invoice.base.amount", 0.0); } if (!_invoice.hasItem("invoice.rate")) { _invoice.setItemValue("invoice.rate", 0.0); } if (currencyFilter == null || currencyFilter.isEmpty() || currencyFilter.equals("-")) { invoiceList.add(_invoice); } else { if (currencyFilter.equals(_invoice.getItemValueString("invoice.currency"))) { invoiceList.add(_invoice); } } } /* * Zahlugnseingang? * * Wir berechnen den saldo. */ if (workflowController.getWorkitem().getModelVersion().startsWith("zahlungseingang")) { // berechnung des Basisumsatzes bei Fremdwährungen for (ItemCollection invoice : invoiceList) { float rate = invoice.getItemValueFloat("invoice.rate"); float maxSaldo = invoice.getItemValueFloat("invoice.saldo"); if (rate != 0) { maxSaldo = InvoiceUtil.roundToFloat(maxSaldo / rate); invoice.setItemValue("invoice.saldo.byrate", maxSaldo); } } } /* * Mahnlauf ? * * Bei einem Mahnlauf selektieren wir alle Rechnungne immer vor. Das ist eine * Anforderung von AGL Der Benutzer kann dann einzelne Rechnungen wieder * abwählen. * * Eine Ausnahme ist hier nur wenn jemand auf Speichern oder mahnen drückt * (Event = 10|20). Dann ändern wir die Liste nicht! * * Hinweis: in der Liste befinden sich keine Inkasso Rechnungen, da man diese * nicht anwählen kann. */ if (workflowController.getWorkitem().getModelVersion().startsWith("mahnlauf")) { // wir selektieren hier immer alle fälligen Rechnungen vor falls wir aus // einer Rechnung mit dem Event 100 (Mahnlauf erstellen) kommen, oder // wenn der Mahnlauf von außen gerate eben neu erzeugt wurde if (workflowController.getWorkitem().getItemValueInteger("$lastevent") == 100 || workflowController.getWorkitem().getItemValueInteger("$lastevent") == 0) { List intialSelection = new ArrayList(); for (ItemCollection invoice : invoiceList) { // ist die Rechnung fällig? if ("workitem".equals(invoice.getType()) && invoice.getTaskID() >= 5100) { intialSelection.add(invoice.getUniqueID()); } } workflowController.getWorkitem().setItemValue("$workitemref", intialSelection); } } } else { // We are no longer in TASK_ERSTELLUNG, so // fetch only selected invoices invoiceList = new ArrayList(); if (!workflowController.getWorkitem().isItemEmpty("$workitemref")) { List selection = workflowController.getWorkitem().getItemValue("$workitemref"); for (String id : selection) { if (id != null && !id.isEmpty()) { ItemCollection _invoice = documentService.load(id); // Test if we have 'invoice.base.amount' and 'invoice.rate' if (!_invoice.hasItem("invoice.base.amount")) { _invoice.setItemValue("invoice.base.amount", 0.0); } if (!_invoice.hasItem("invoice.rate")) { _invoice.setItemValue("invoice.rate", 0.0); } invoiceList.add(_invoice); } } } } // finally we set the 'selection' item depending on the $workitemList // and the payment amount form the 'payment.details' if (invoiceList != null) { List selection = workflowController.getWorkitem().getItemValue("$workitemref"); List paymentList = zahlungseingangService .loadPaymentDetails(workflowController.getWorkitem()); for (ItemCollection invoice : invoiceList) { if (selection.contains(invoice.getUniqueID())) { invoice.setItemValue("selected", true); // set amount for (ItemCollection payment : paymentList) { if (invoice.getUniqueID().equals(payment.getUniqueID())) { invoice.setItemValue("payment.amount", payment.getItemValue("payment.amount")); break; } } } } } else { // empty list invoiceList = new ArrayList(); } logger.info("...compute getInvoices completed in " + (System.currentTimeMillis() - l) + "ms"); return invoiceList; } public void reset() { invoiceList = null; } /** * On Before Process we store the selected invoices in $worktiemRef * * @param workflowEvent */ public void onWorkflowEvent(@Observes WorkflowEvent workflowEvent) { if (workflowEvent == null || workflowEvent.getWorkitem() == null) { return; } // store a collection of child items if you are in a Zahlungseingang if (workflowEvent.getWorkitem().getModelVersion().startsWith("zahlungseingang") && workflowEvent.getEventType() == WorkflowEvent.WORKITEM_BEFORE_PROCESS) { updateChildList(workflowEvent.getWorkitem()); } } public ItemCollection loadInvoice(String id) { return documentService.load(id); } /** * Diese Methode aktualisiert das item ChildWOrkitems mit allen selektierten * Invoices udn berechnet den payment total */ @SuppressWarnings("rawtypes") public void updateChildList(ItemCollection workitem) { double paymentTotal = 0; List mapInvoiceItems = new ArrayList(); logger.fine("Convert child items into Map..."); // iterate over all order items.. List selectionList = new ArrayList(); for (ItemCollection invoice : invoiceList) { if (invoice.getItemValueBoolean("selected")) { logger.fine("calculate - " + invoice.getUniqueID()); selectionList.add(invoice.getUniqueID()); paymentTotal = paymentTotal + invoice.getItemValueDouble("payment.amount"); ItemCollection invoiceStub = new ItemCollection(); invoiceStub.setItemValue(WorkflowKernel.UNIQUEID, invoice.getUniqueID()); invoiceStub.setItemValue("payment.amount", invoice.getItemValue("payment.amount")); mapInvoiceItems.add(invoiceStub.getAllItems()); } } // rond with 2 digits workitem.replaceItemValue("payment.total", InvoiceUtil.round(paymentTotal)); // update childitems workitem.replaceItemValue(ZahlungseingangService.ITEM_PAYMENT_DETAILS, mapInvoiceItems); // Update $workitemref workitem.setItemValue("$workitemref", selectionList); } /** * Hilfsmethode delegates to ZahlungseingangServcie * * @param payment * @return */ public List loadPaymentDetails(ItemCollection payment) { return zahlungseingangService.loadPaymentDetails(payment); } /** * Berechnet den gesammten OP Saldo * * @return */ public double calculateInvoiceTotal() { double result = 0; for (ItemCollection invoice : invoiceList) { result = result + invoice.getItemValueDouble("invoice.total"); } // rond with 2 digits return InvoiceUtil.round(result); } /** * Berechnet die Summer aller Rechnungen zu einer Währung. Es werden nur * Rechnungen berücksichtigt, deren Haupt Währung der übergebenen Währung * entspricht. * * @param currency * @return */ public double calculateInvoiceTotal(String currency) { double result = 0; for (ItemCollection invoice : invoiceList) { if (currency.equals(invoice.getItemValueString("invoice.currency"))) { result = result + invoice.getItemValueDouble("invoice.total"); } } // round with 2 digits return InvoiceUtil.round(result); } /** * Berechnet den gesamten OP Saldo * * @return */ public double calculateInvoiceSaldo() { double result = 0; if (invoiceList != null) { for (ItemCollection invoice : invoiceList) { result = result + invoice.getItemValueDouble("invoice.saldo"); } } // round with 2 digits return InvoiceUtil.round(result); } /** * Berechnet den noch offenen Differenz vom Zahlbetrag * * @return */ public double calculatePaymentDifference() { double paymentAmount = workflowController.getWorkitem().getItemValueDouble("payment.amount"); double paymentDifference = workflowController.getWorkitem().getItemValueDouble("payment.difference"); double paymentTotal = workflowController.getWorkitem().getItemValueDouble("payment.total"); // paymentAmount - calculateInvoiceSaldo(); double result = (paymentAmount + paymentDifference) - paymentTotal; logger.fine("...new PaymentDifference=" + result); // rond with 2 digits return InvoiceUtil.round(result); } /** * Berechnet den Zahlbetrag in der Hauswährung bei Fremdwährungen * * @return */ public double calculatePaymentSaldoMainCurrency() { double result = 0; if (invoiceList != null) { for (ItemCollection invoice : invoiceList) { double rate = invoice.getItemValueDouble("invoice.rate"); double pay = invoice.getItemValueDouble("payment.amount"); if (rate != 0) { result = result + pay / rate; } else { result = result + pay; } } } // rond with 2 digits return InvoiceUtil.round(result); } /** * Returns true if the reminder date is today or in the past * * @param uniqueid * @return */ public boolean isInDue(String uniqueid) { ItemCollection invoice = workflowService.getWorkItem(uniqueid); LocalDate date = invoice.getItemValueLocalDate("invoice.reminder"); return date.compareTo(LocalDate.now()) <= 0; } public String getCurrencyFilter() { return currencyFilter; } public void setCurrencyFilter(String currencyFilter) { this.currencyFilter = currencyFilter; } public List getCurrenciesOut() { try { return invoiceService.getCurrenciesOut(); } catch (PluginException e) { return new ArrayList(); } } public String getCurrenciesOutMain() { try { return invoiceService.getCurrenciesOutMain(); } catch (PluginException e) { return "undefined currency"; } } }