This commit is contained in:
Ralph Soika 2022-08-31 15:30:23 +02:00
parent 45530d4be5
commit c124d06d74
5 changed files with 363 additions and 212 deletions

View file

@ -3,23 +3,37 @@ package com.alexanderlogistics;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.event.Observes;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
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.QueryException;
import org.imixs.workflow.faces.data.WorkflowController;
import org.imixs.workflow.faces.data.WorkflowEvent;
import org.imixs.workflow.office.forms.ChildItemController;
import org.imixs.workflow.office.forms.WorkitemLinkController;
/**
* Der OPListeController dient dazu eine liste aller offenen Ausgangsrechnungen
* zu bilden
* <p>
* Zusätzlich bietet er die funktionen zum auszifferne..(??)
* 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
*
@ -30,44 +44,61 @@ public class OPListController implements Serializable {
private static final long serialVersionUID = 1L;
public static final int TASK_ERSTELLUNG = 1000;
public static final String ITEM_PAYMENT_DETAILS="payment.details";
private static Logger logger = Logger.getLogger(OPListController.class.getName());
private String lastDbtrNumber = null;
private List<ItemCollection> invoiceCache=null;
private List<ItemCollection> invoiceList = null;
@Inject
protected WorkflowController workflowController;
@Inject
protected WorkflowService workflowService;
@Inject
protected WorkitemLinkController workitemLinkController;
@Inject
protected DocumentService documentService;
/**
* Diese Methode liefert die Rechnungen zur gegebenen dbtrNumber.
* Die Methode nutzt einen lokalen cache um die Zugriffe zu beschleunigen.
* Diese Methode liefert die Rechnungen zur gegebenen dbtrNumber. Die Methode
* nutzt einen lokalen cache um die Zugriffe zu beschleunigen.
* <p>
* Befindet sich der Zahlungseingang in Erstellung (Task=1000) werden alle
* offenen Rechnungen geholt
* <p>
* Befindet sich der Zahlungseingang nicht mehr in erstellung werden nur die
* Rechnugnen aus $workitemRef geholt!
*
* @param _dbtrNumber
* @return
*/
@SuppressWarnings("unchecked")
public List<ItemCollection> getInvoices(String _dbtrNumber) {
// Compute all open invoices if TASK_ERSTELLUNG....
if (workflowController.getWorkitem().getTaskID() == TASK_ERSTELLUNG) {
// return empty cache if data is not
// return empty list if dbtr is not set
if (_dbtrNumber == null || _dbtrNumber.isEmpty()) {
invoiceCache= new ArrayList<ItemCollection>();
return invoiceCache;
invoiceList = new ArrayList<ItemCollection>();
return invoiceList;
}
// if last dbtr number is equal then return the current cache....
if (invoiceCache!=null && lastDbtrNumber!=null && lastDbtrNumber.equals(_dbtrNumber)) {
return invoiceCache;
// if last dbtr number is equal then return the current list....
if (invoiceList != null && lastDbtrNumber != null && lastDbtrNumber.equals(_dbtrNumber)) {
return invoiceList;
}
// refresh cache....
// load new invoice list....
lastDbtrNumber = _dbtrNumber;
invoiceCache= new ArrayList<ItemCollection>();
logger.info("....caching Invoices for " + _dbtrNumber);
invoiceList = new ArrayList<ItemCollection>();
logger.info("....loading open Invoices for " + _dbtrNumber);
// Aus der dbtrNummer muss das führendde D entfernt werden
// wir speichern dieses zwar im Zahlungseingangs Workflow, aber eine
@ -80,83 +111,166 @@ public class OPListController implements Serializable {
+ _dbtrNumber + ")";
try {
invoiceCache = documentService.find(query, 999, 0, "$created", false);
invoiceList = documentService.find(query, 999, 0, "$created", false);
} catch (QueryException e) {
logger.severe("Failed to get op liste:" + e.getMessage());
}
return invoiceCache;
} else {
// We are no longer in TASK_ERSTELLUNG, so
// fetch only selected invoices
invoiceList = new ArrayList<ItemCollection>();
List<String> selection = workflowController.getWorkitem().getItemValue("$workitemref");
for (String id : selection) {
invoiceList.add(documentService.load(id));
}
}
// finally we set the 'selection' item depending on the $workitemList
// and the payment amount form the 'payment.details'
List<String> selection = workflowController.getWorkitem().getItemValue("$workitemref");
List<ItemCollection> paymentList=explodePaymentDetails(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;
}
}
}
}
return invoiceList;
}
// /**
// * Liefert die Payments die mit diesem workitem verbunden sind...
// * @return
// */
// public List<ItemCollection> getPayments() {
// List<ItemCollection> result=new ArrayList();
//
//
// result=workitemLinkController.getExternalReferences("($WorkflowGroup:Zahlungseingang");
//// if (workflowController.getWorkitem()!=null) {
//// List<ItemCollection> liste = workflowService.getWorkListByRef(workflowController.getWorkitem().getUniqueID());
////
//// for (ItemCollection refWorkitem: liste) {
//// if (refWorkitem.getItemValueString(WorkflowKernel.WORKFLOWGROUP).startsWith("Zahlungseingang")) {
//// result.add(refWorkitem);
//// }
//// }
//// }
////
// return result;
// }
/**
* Convert the List of ItemCollections back into a List of Map elements
*
* @param workitem
*/
@SuppressWarnings({ "rawtypes" })
protected List<ItemCollection> explodePaymentDetails(ItemCollection workitem) {
// convert current list of childItems into ItemCollection elements
ArrayList<ItemCollection> childItems = new ArrayList<ItemCollection>();
List<Object> mapOrderItems = workitem.getItemValue(ITEM_PAYMENT_DETAILS);
int pos = 1;
for (Object mapOderItem : mapOrderItems) {
if (mapOderItem instanceof Map) {
ItemCollection itemCol = new ItemCollection((Map) mapOderItem);
itemCol.replaceItemValue("numPos", pos);
childItems.add(itemCol);
pos++;
}
}
return childItems;
}
/**
* 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 (workflowEvent.getEventType() == WorkflowEvent.WORKITEM_BEFORE_PROCESS) {
updateChildList(workflowEvent.getWorkitem());
}
}
public ItemCollection loadInvoice(String id) {
return documentService.load(id);
}
/**
* THis Method is called by cargosft-debitor-serach.xhtml after the user has selected
* a new debitor.
* The meothod updates the dbtr.number of the current workitem.
* The form will rerender the opList seciton
* Diese Methode aktualisiert das item ChildWOrkitems mit allen selektierten
* Invoices udn berechnet den payment total
*/
public void loadOPList() {
@SuppressWarnings("rawtypes")
public void updateChildList(ItemCollection workitem) {
double paymentTotal = 0;
List<Map> mapInvoiceItems = new ArrayList<Map>();
// convert the child ItemCollection elements into a List of Map
logger.info("Convert child items into Map...");
// iterate over all order items..
List<String> selectionList = new ArrayList<String>();
for (ItemCollection invoice : invoiceList) {
if (invoice.getItemValueBoolean("selected")) {
logger.info("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", Math.round(paymentTotal * 100.0) / 100.0);
// update childitems
workitem.replaceItemValue(ITEM_PAYMENT_DETAILS, mapInvoiceItems);
// Update $workitemref
workitem.setItemValue("$workitemref", selectionList);
}
/**
* This JSF backing method is called by cargosft-debitor-serach.xhtml after the
* user has selected a new debitor.
* <p>
* The new dbtrNumber is slected form the curren ajax request param 'dbtrNumber'
* <p>
* The method just updates the dbtr.number of the current workitem. The form
* will than rerender the opList section.
*/
public void updateDbtrNumber() {
FacesContext fc = FacesContext.getCurrentInstance();
String dbtrNumber = fc.getExternalContext().getRequestParameterMap().get("dbtrNumber");
logger.info(".........dbtrNumber = "+dbtrNumber);
logger.fine(".........dbtrNumber = " + dbtrNumber);
workflowController.getWorkitem().setItemValue("dbtr.number", dbtrNumber);
}
/**
* This method computes the sum for a given item in a list of workitems. The
* result is rounded to 2 digits.
* <p>
* Gutschriften werden abgezogen
*
* @param refids - list of workitem uniqueIds
* @param item - name of the item to summarize
* @return sum rounded to 2 digits
*/
public double calculateSum() {
double result = 0;
List<String> refids=workflowController.getWorkitem().getItemValueList("$workitemref",String.class);
for (String id : refids) {
if (id.isEmpty()) {
continue;
}
ItemCollection doc = getInvoiceFromCache(id);
if (doc!=null) {
result = result + doc.getItemValueDouble("invoice.total");
}
}
// rond with 2 digits
return Math.round(result * 100.0) / 100.0;
}
/**
* Hilfsmethode holt eine Rechnung aus dem Cache.
* @param id
* @return
*/
private ItemCollection getInvoiceFromCache(String id) {
if (invoiceCache==null) {
return null;
}
for (ItemCollection invoice: invoiceCache) {
if (invoice.getUniqueID().equals(id)) {
return invoice;
}
}
return null;
}
/**
* Berechnet den gesammten OP Saldo
*
* @return
*/
public double calculateSaldo(List<ItemCollection> invoices ) {
public double calculateInvoiceTotal() {
double result = 0;
for (ItemCollection invoice : invoices) {
for (ItemCollection invoice : invoiceList) {
result = result + invoice.getItemValueDouble("invoice.total");
}
// rond with 2 digits
@ -165,16 +279,4 @@ public class OPListController implements Serializable {
}
/**
* This method removes an uniqueid form the item $workitemref
*/
@SuppressWarnings("unchecked")
public void removeInvoice(String id) {
List<String> refList = workflowController.getWorkitem().getItemValue("$workitemref");
refList.remove(id);
workflowController.getWorkitem().setItemValue("$workitemref", refList);
}
}

View file

@ -23,7 +23,7 @@
-->
<h:commandScript name="cargosoftSearch" action="#{cargosoftController.searchDebitor()}"
render="autocomplete-resultlist-cargosoft" onevent="autocompleteShowResult" />
<h:commandScript name="loadOPList" action="#{opListController.loadOPList()}"
<h:commandScript name="updateDbtrNumber" action="#{opListController.updateDbtrNumber()}"
render="#{opListContainer.clientId}" onevent="ajaxUpdateInvoiceSelection" />
<script type="text/javascript">
/*<![CDATA[*/
@ -63,9 +63,9 @@
}
// finally we do a trick and trigger the commandScript loadOPList which
// finally we do a trick and trigger the commandScript updateDbtrNumber which
// refreshes the op section
loadOPList({ dbtrNumber: dbtrData.no });
updateDbtrNumber({ dbtrNumber: dbtrData.no });
}
/*]]>*/

View file

@ -10,9 +10,11 @@
<!-- Shows the op liste fo rthe current dbtr.number -->
<h:commandScript name="calculateOpSummary" execute="invoiceRefHolder_ID" render="opcalculater_id" />
<h:commandScript name="calculateOpSummary"
execute="invoiceRefHolder_ID" render="opcalculater_id" />
<h:panelGroup layout="block" styleClass="imixs-form-section" id="oplist-table" binding="#{opListContainer}">
<h:panelGroup layout="block" styleClass="imixs-form-section"
id="oplist-table" binding="#{opListContainer}">
<table style="width: 100%; margin: 5px;">
<tr>
@ -22,39 +24,34 @@
<th style="text-align: right;">S/H</th>
<th style="width: 40px;"></th>
<th style="width: 100px;">Saldo</th>
<th style="width:100px;">Teilbetrag</th>
<th style="width: 100px;">Zahlbetrag</th>
<th style=""></th>
</tr>
<ui:param name="invoices" value="#{opListController.getInvoices(workitem.item['dbtr.number'])}"></ui:param>
<ui:param name="invoices"
value="#{opListController.getInvoices(workitem.item['dbtr.number'])}"></ui:param>
<ui:repeat value="#{invoices}" var="invoice">
<tr>
<td><h:link outcome="/pages/workitems/workitem">
#{invoice.item['invoice.number']}
<f:param name="id" value="#{invoice.item['$uniqueid']}" />
</h:link>
</td>
</h:link></td>
<td>
<h:outputText value="#{invoice.item['invoice.date']}">
<td><h:outputText value="#{invoice.item['invoice.date']}">
<f:convertDateTime pattern="#{message.datePatternShort}"
timeZone="#{message.timeZone}" />
</h:outputText>
</td>
</h:outputText></td>
<td><h:outputText value="#{invoice.item['invoice.duedate']}">
<f:convertDateTime pattern="#{message.datePatternShort}"
timeZone="#{message.timeZone}" />
</h:outputText>
</td>
</h:outputText></td>
<!-- Rechnngsbetrag -->
<td style="text-align: right;"><h:outputText
value="#{invoice.item['invoice.total']}">
<f:convertNumber minFractionDigits="2" locale="de" />
</h:outputText>
</td>
</h:outputText></td>
<td><h:outputText value="#{invoice.item['invoice.currency']}" /></td>
@ -66,20 +63,35 @@
value="#{invoice.item['invoice.saldo']}">
<f:convertNumber minFractionDigits="2" locale="de" />
</h:outputText>
</td>
</h:outputText></td>
<!-- Teilbetrag -->
<td>
<input type="text" style="width:100px;text-align: right;">
</input>
<td style="text-align: right;"><h:inputText id="payment_per_invoice" rendered="#{!readonly}"
value="#{invoice.item['payment.amount']}"
style="width:100px;text-align: right;">
<f:convertNumber minFractionDigits="2" locale="de" />
<f:ajax event="change" execute="#{opListContainer.clientId}"
listener="#{opListController.updateChildList(workitem)}"
render="#{opListContainer.clientId}"></f:ajax>
</h:inputText>
<h:outputText rendered="#{readonly}"
value="#{invoice.item['payment.amount']}"
style="width:100px; ">
<f:convertNumber minFractionDigits="2" locale="de" />
</h:outputText>
</td>
<!-- CheckBox -->
<td><input type="checkbox" class="selection_checkbox"
id="#{invoice.uniqueID}" /></td>
<td><h:selectBooleanCheckbox class="invoice_selector" rendered="#{!readonly}"
value="#{invoice.item['selected']}"
onclick="initInvoicePayment(this)">
<f:ajax event="change" execute="#{opListContainer.clientId}"
listener="#{opListController.updateChildList(workitem)}"
render="#{opListContainer.clientId}"></f:ajax>
</h:selectBooleanCheckbox></td>
</tr>
@ -89,28 +101,34 @@
<td />
<td />
<td><strong>Summary</strong></td>
<td style="text-align: right;"><strong><h:outputText
value="#{opListController.calculateSaldo(invoices)}">
<!-- Invoice total -->
<td style="text-align: right;"><strong> <h:panelGroup
id="invoice_total">
<h:outputText value="#{opListController.calculateInvoiceTotal()}">
<f:convertNumber minFractionDigits="2" locale="de" />
</h:outputText></strong></td>
</h:outputText>
</h:panelGroup>
</strong></td>
<td />
<td /> <td style="text-align: right;"><strong>
<h:outputText id="opcalculater_id"
value="#{opListController.calculateSum()}">
<f:convertNumber minFractionDigits="2" locale="de" />
</h:outputText></strong></td>
<td />
<!-- Payment total -->
<td style="text-align: right;"><strong> <h:panelGroup
id="payment_saldo">
<h:outputText value="#{workitem.item['payment.total']}">
<f:convertNumber minFractionDigits="2" locale="de" />
</h:outputText>
</h:panelGroup>
</strong></td>
<td />
</tr>
</table>
<!-- dieses feld speichert die selection der rechnungen -->
<h:inputTextarea id="invoiceRefHolder_ID" converter="org.imixs.VectorConverter" class="invoice_selection_list"
<h:inputTextarea id="invoiceRefHolder_ID"
converter="org.imixs.VectorConverter" class="invoice_selection_list"
style="display:none;" value="#{workitem.itemList['$workitemref']}" />
@ -120,10 +138,31 @@
$(document).ready(
function() {
// update the checkboxes of the stored invoice uniqueIDs
updateInvoiceSelection();
// updateInvoiceSelection();
});
// set the payment amount to the invoice total if the field is still empty
function initInvoicePayment(element) {
console.log('...initInovicePayment...'+element.checked);
var currentTD=$(element).closest('td');
var prevTD=$(currentTD).prev().prev();
var amountValue=$(prevTD).text();
var amountTD=$(currentTD).prev();
var amountInput=$("input",amountTD);
// wenn wir noch keinen wert dann betrag übernehmen
if (element.checked) {
if ($(amountInput).val()=='' || $(amountInput).val()=='0,00') {
$(amountInput).val(amountValue);
}
} else {
// clear value
$(amountInput).val("");
}
}
// This method refreshs the layout of the invoice checkboxes
function updateInvoiceSelection() {
selection = $('.invoice_selection_list').val();

View file

@ -20,27 +20,37 @@
<tr>
<th style="width: 20px;">#</th>
<th style="">Datum<span class="imixs-required">
*</span></th>
<th style="">Datum<span class="imixs-required"> *</span></th>
<th style="width: 100px;">Betrag</th>
<th style="width: 40px;">Währung</th>
</tr>
<ui:param name="payments"
value="#{workitemLinkController.getExternalReferences('($WorkflowGroup:Zahlungseingang)')}"></ui:param>
<ui:repeat var="payment_stub" value="#{payments}">
<ui:param name="payment"
value="#{opListController.loadInvoice(payment_stub.getUniqueID())}"></ui:param>
<tr>
<td><h:link outcome="/pages/workitems/workitem">
#{payment.item['name']}
<f:param name="id" value="#{payment.item['$uniqueid']}" />
</h:link></td>
<td>#{payment.item['payment.total']}
</td>
</tr>
</ui:repeat>
<!-- summary -->
<tr>
<td />
<td style="text-align: right;">Summe:</td>
<td class="orderlist_summary" style="text-align: right;">
<h:outputText
<td class="orderlist_summary" style="text-align: right;"><h:outputText
value="#{workitem.item['invoice.total']}">
<f:convertNumber minFractionDigits="2" locale="de" />
</h:outputText>
</td>
</h:outputText></td>
<td />
</tr>

View file

@ -155,7 +155,7 @@ result.isValid=true;
<imixs:value><![CDATA[typcn-cloud-storage||||typcn-tick,imixs-success]]></imixs:value>
</imixs:item>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[]]></imixs:value>
<imixs:value><![CDATA[form_basic_read]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitemarchive]]></imixs:value>
@ -235,7 +235,7 @@ result.isValid=true;
<imixs:value><![CDATA[typcn-cloud-storage||||typcn-tick,imixs-error]]></imixs:value>
</imixs:item>
<imixs:item name="txteditorid" type="xs:string">
<imixs:value><![CDATA[]]></imixs:value>
<imixs:value><![CDATA[form_basic_read]]></imixs:value>
</imixs:item>
<imixs:item name="txttype" type="xs:string">
<imixs:value><![CDATA[workitemarchive]]></imixs:value>
@ -485,11 +485,11 @@ result.isValid=true;
<imixs-form-section columns="2" label="Zahlungsdaten">
<item name="name" type="text" required="true" label="Referenz:" />
<item name="dbtr.number" type="text" required="true" label="Debitor:" />
<item name="payment.total" type="currency" required="true" label="Zahlbetrag:" />
<item name="payment.amount" type="currency" required="true" label="Zahlbetrag:" />
<item name="payment.currency" type="selectOneMenu" required="true" options="EUR;CHF;SEK;RUB;NOK;GBP;USD;CAD" label="Währung:" />
</imixs-form-section>
<imixs-form-section label="Offene Posten" path="alexander/section_opliste" />
<imixs-form-section label="Offene Posten" path="alexander/section_opliste" readonly="false" />
</imixs-form>]]></bpmn2:documentation>
<bpmn2:dataState id="DataState_1"/>