diff --git a/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/DataViewSectionController.java b/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/DataViewSectionController.java new file mode 100644 index 0000000..3c0b525 --- /dev/null +++ b/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/DataViewSectionController.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Imixs Workflow Technology + * Copyright (C) 2003, 2008 Imixs Software Solutions GmbH, + * http://www.imixs.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You can receive a copy of the GNU General Public + * License at http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Imixs Software Solutions GmbH - initial API and implementation + * Ralph Soika + * + *******************************************************************************/ +package org.imixs.workflow.office.forms; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.imixs.workflow.dataview.DataViewService; +import org.imixs.workflow.exceptions.QueryException; +import org.imixs.workflow.faces.data.WorkflowController; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.Conversation; +import jakarta.enterprise.context.ConversationScoped; +import jakarta.faces.context.FacesContext; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.servlet.http.HttpServletRequest; + +/** + * The DataViewFormSectionController provides methods to display a data view in + * as a + * custom form section + * + * @see pages/workitems/sections/dataview.xhtml + * @author rsoika + * @version 1.0 + */ + +@Named +@ConversationScoped +public class DataViewSectionController implements Serializable { + private static final long serialVersionUID = 1L; + + public static final int MAX_SEARCH_RESULT = 1000; + public static Logger logger = Logger.getLogger(DataViewSectionController.class.getName()); + + @Inject + WorkflowController workflowController; + + @Inject + private Conversation conversation; + + @Inject + DataViewService dataViewService; + + private Map dataSets = null; + + @PostConstruct + public void init() { + startConversation(); + dataSets = new HashMap<>(); + } + + /** + * Starts a new conversation + */ + protected void startConversation() { + if (conversation.isTransient()) { + conversation.setTimeout( + ((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest()) + .getSession().getMaxInactiveInterval() * 1000); + conversation.begin(); + logger.log(Level.FINEST, "......start new conversation, id={0}", + conversation.getId()); + } + } + + /** + * Returns a single value from a Option key/value list + * + * @param options - options + * @param key - option key + * @return option value + */ + public String getOptionValue(String options, String key) { + // Null checks + if (options == null || key == null || options.trim().isEmpty() || key.trim().isEmpty()) { + return null; + } + + // Split options into key/value pairs (separated by semicolon) + String[] pairs = options.split(";"); + + for (String pair : pairs) { + // Split each pair into key and value (separated by equals sign) + String[] keyValue = pair.split("=", 2); // Limit to 2 in case value contains "=" + + if (keyValue.length == 2) { + String currentKey = keyValue[0].trim(); + String currentValue = keyValue[1].trim(); + + // Check if the searched key was found + if (key.equals(currentKey)) { + return currentValue; + } + } + } + + // Key not found + return null; + } + + /** + * Initializes a new DataViewSectionDataSet based on the given options + * (parameter 'name'). + * + * The expected format of the options string is: + *

+ * "name=DATAVIEWNAME" + *

+ * The method loads the corresponding dataView definition immediately and stores + * the dataSet in a local cache. + * + * @return view result + * @throws QueryException + */ + public DataViewSectionDataSet loadDataSet(String options) throws QueryException { + DataViewSectionDataSet dataSet = dataSets.get(options); + // Extract and set dataViewName from options + if (dataSet == null) { + String _dataViewName = getOptionValue(options, "name"); + if (_dataViewName != null) { + logger.info("...build new dataSet by options: " + options); + dataSet = new DataViewSectionDataSet(_dataViewName, workflowController.getWorkitem(), dataViewService); + dataSets.put(options, dataSet); + } + } + return dataSet; + } + +} diff --git a/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/DataViewSectionDataSet.java b/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/DataViewSectionDataSet.java new file mode 100644 index 0000000..91defb9 --- /dev/null +++ b/office-alexander-logistics-app/src/main/java/org/imixs/workflow/office/forms/DataViewSectionDataSet.java @@ -0,0 +1,260 @@ +package org.imixs.workflow.office.forms; + +import java.io.IOException; +import java.io.Serializable; +import java.util.List; +import java.util.logging.Logger; + +import org.imixs.workflow.FileData; +import org.imixs.workflow.ItemCollection; +import org.imixs.workflow.dataview.DataViewController; +import org.imixs.workflow.dataview.DataViewExportEvent; +import org.imixs.workflow.dataview.DataViewPOIHelper; +import org.imixs.workflow.dataview.DataViewService; +import org.imixs.workflow.exceptions.PluginException; +import org.imixs.workflow.exceptions.QueryException; + +public class DataViewSectionDataSet implements Serializable { + private static final long serialVersionUID = 1L; + + public static Logger logger = Logger.getLogger(DataViewSectionController.class.getName()); + + List data = null; + private ItemCollection dataViewDefinition; + private String dataViewName; + private List viewItemDefinitions = null; + private String query = null; + private boolean endOfList = false; + + private long totalCount = 0; + private long totalPages = 0; + + private String sortBy = null; + private boolean sortReverse = false; + private int pageSize = 10; + private int pageIndex = 0; + + private DataViewService dataViewService; + + private ItemCollection workitem; + + public DataViewSectionDataSet(String dataViewName, ItemCollection workitem, DataViewService dataViewService) { + this.dataViewName = dataViewName; + this.workitem = workitem; + this.dataViewService = dataViewService; + + dataViewDefinition = dataViewService.loadDataViewDefinition(dataViewName); + + boolean debug = dataViewDefinition.getItemValueBoolean("debug"); + if (debug) { + logger.info("resolve query by dataView '" + dataViewName + "'"); + } + + // preload the viewItem definitions + viewItemDefinitions = this.dataViewService.computeDataViewItemDefinitions(dataViewDefinition); + + // resove query by dataView + query = this.dataViewService.parseQuery(dataViewDefinition, this.workitem); + + loadData(); + } + + public void forward() { + if (!isEndOfList()) { + pageIndex++; + loadData(); + } + } + + public void back() { + if (pageIndex > 0) { + pageIndex--; + loadData(); + } + } + + /** + * load current page + */ + private void loadData() { + try { + data = dataViewService.getWorkflowService().getDocumentService().find(query, getPageSize(), getPageIndex(), + getSortBy(), isSortReverse()); + + // The end of a list is reached when the size is below or equal the + // pageSize. See issue #287 + totalCount = dataViewService.getWorkflowService().getDocumentService().count(query); + totalPages = (long) Math.ceil((double) totalCount / pageSize); + + if (data.size() < pageSize) { + setEndOfList(true); + } else { + // look ahead if we have more entries... + int iAhead = (getPageSize() * (getPageIndex() + 1)) + 1; + if (totalCount < iAhead) { + // there is no more data + setEndOfList(true); + } else { + setEndOfList(false); + } + } + } catch (QueryException e) { + logger.warning("Failed to load data: " + e.getMessage()); + } + } + + public List getData() { + return data; + } + + public ItemCollection getDataViewDefinition() { + return dataViewDefinition; + } + + public long getTotalCount() { + return totalCount; + } + + public long getTotalPages() { + return totalPages; + } + + public int getPageIndex() { + return pageIndex; + } + + public void setPageIndex(int pageIndex) { + this.pageIndex = pageIndex; + } + + public boolean isEndOfList() { + return endOfList; + } + + public void setEndOfList(boolean endOfList) { + this.endOfList = endOfList; + } + + public String getDataViewName() { + return dataViewName; + } + + public List getViewItemDefinitions() { + return viewItemDefinitions; + } + + /** + * returns the maximum size of a search result + * + * @return + */ + public int getPageSize() { + return pageSize; + } + + /** + * set the maximum size of a search result + * + * @param searchCount + */ + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public String getSortBy() { + return sortBy; + } + + public void setSortBy(String sortBy) { + this.sortBy = sortBy; + } + + public boolean isSortReverse() { + return sortReverse; + } + + public void setSortReverse(boolean sortReverse) { + this.sortReverse = sortReverse; + } + + /** + * Exports data into a excel template processed by apache-poi. The method sends + * a DataViewExport event to allow clients to adapt the export process. + * + * @see DataViewExportEvent + * + * @throws PluginException + * @throws QueryException + */ + public String export() throws PluginException, QueryException { + + // Build target filename + boolean debug = dataViewDefinition.getItemValueBoolean("debug"); + + // start export + if (debug) { + logger.info("│ ├── Query: " + query); + } + + try { + + // test if query exceeds max count + int totalCount = dataViewService.getWorkflowService().getDocumentService().count(query); + // start export + if (debug) { + logger.info("│ ├── Count: " + totalCount); + } + if (totalCount > DataViewService.MAX_ROWS) { + throw new PluginException(DataViewController.class.getSimpleName(), DataViewService.ERROR_CONFIG, + "Data can not be exported into Excel because dataset exceeds " + DataViewService.MAX_ROWS + + " rows!"); + } + String sortBy = dataViewDefinition.getItemValueString("sort.by"); + if (sortBy.isEmpty()) { + sortBy = "$modified"; // default + } + List workitems = dataViewService.getWorkflowService().getDocumentService().find(query, + DataViewService.MAX_ROWS, 0, sortBy, + dataViewDefinition.getItemValueBoolean("sort.reverse")); + + FileData fileDataExport = dataViewService.poiExport(workitems, dataViewDefinition, viewItemDefinitions); + + // create a temp event + ItemCollection event = new ItemCollection().setItemValue("txtActivityResult", + dataViewDefinition.getItemValue("poi.update")); + ItemCollection poiConfig = dataViewService.getWorkflowService().evalWorkflowResult(event, "poi-update", + dataViewDefinition, + false); + + // merge workitem fields (Workaround because custom forms did hard coded map to + // workflowController instead of workitem + + DataViewPOIHelper.poiUpdate(workitem, fileDataExport, poiConfig, dataViewService.getWorkflowService()); + + if (debug) { + logger.info("├── POI Export completed!"); + } + // See: + // https://stackoverflow.com/questions/9391838/how-to-provide-a-file-download-from-a-jsf-backing-bean + DataViewPOIHelper.downloadExcelFile(fileDataExport); + } catch (IOException | QueryException e) { + throw new PluginException(DataViewController.class.getSimpleName(), DataViewService.ERROR_CONFIG, + "Failed to generate Excel Export: " + e.getMessage()); + } + + // return "/pages/admin/excel_export_rechnungsausgang.jsf?faces-redirect=true"; + return ""; + } + + /** + * Returns true if a poi export is defined + * + * @return + */ + public boolean hasPoiExport() { + if (dataViewDefinition != null && !dataViewDefinition.getItemValueString("poi.targetfilename").isBlank()) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/office-alexander-logistics-app/src/main/webapp/pages/workitems/forms/dataview.xhtml b/office-alexander-logistics-app/src/main/webapp/pages/workitems/forms/dataview.xhtml new file mode 100644 index 0000000..aae15cf --- /dev/null +++ b/office-alexander-logistics-app/src/main/webapp/pages/workitems/forms/dataview.xhtml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + +
#{columnDef.item['item.label']}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #{columnDef.item['item.label']} + + + + +
+ +

+ + + + + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/templates/invoice_outbound_de_template.xlsx b/templates/invoice_outbound_de_template.xlsx new file mode 100644 index 0000000..a0a5e2c Binary files /dev/null and b/templates/invoice_outbound_de_template.xlsx differ diff --git a/templates/invoice_outbound_en_template.xlsx b/templates/invoice_outbound_en_template.xlsx new file mode 100644 index 0000000..0efeb64 Binary files /dev/null and b/templates/invoice_outbound_en_template.xlsx differ diff --git a/workflow/businesspartner-de-1.0.4.bpmn b/workflow/businesspartner-de-1.0.4.bpmn new file mode 100644 index 0000000..29fec32 --- /dev/null +++ b/workflow/businesspartner-de-1.0.4.bpmn @@ -0,0 +1,1143 @@ + + + + + + + association_83sZPw + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + task_ToMZaQ + event_WmkBvw + event_1clvlg + task_Q80A1Q + task_B8Pi7A + event_aSdkwg + event_Tr0aug + dataObject_UQIXAQ + event_vwH0cA + textAnnotation_LyGTCw + event_TuyuwQ + event_h0Kk5g + task_delO7Q + event_1OVorA + event_baWU4w + event_ofjVfg + event_i7yQVw + gateway_uK0c6g + event_6250fg + task_NohgrQ + event_AMs05g + event_feLZFQ + event_GTXFMw + event_u8OBFg + gateway_whpM0w + event_Idvwtg + event_8yN0uw + gateway_Kjobpw + event_pYaI6A + event_00CWpg + textAnnotation_pSbYVQ + event_AOFZ0A + event_4A016g + event_JGwJaQ + + + + + + + + + + + + + + + + + + + + + + sequenceFlow_25otUg + sequenceFlow_S9LVXg + + + + sequenceFlow_25otUg + + + + sequenceFlow_rwdWxw + + + + + + + + + + + partner.name (partner.id)]]> + + + Adresse:
+partner.name
+partner.address
+partner.zip partner.city
+
+ +BPID: partner.id
+Kreditoren-Nr.: cdtr.number
+Debitoren-Nr.: dbtr.number
+]]>
+
+ + + + + + + + + + + + + + + + + + +
+ + sequenceFlow_avahXg + sequenceFlow_9atLFA + sequenceFlow_b4BcVA + sequenceFlow_03b60w + sequenceFlow_0Icsbw + sequenceFlow_e8q82w +
+ + + + partner.name (partner.id)]]> + + + + + + Adresse:
+partner.name
+partner.address
+partner.zip partner.city
+
+ +BPID: partner.id
+Kreditoren-Nr.: cdtr.number
+Debitoren-Nr.: dbtr.number
+]]>
+
+ + + + + + + + + + + + + + + + + + +
+ + sequenceFlow_1mXO8A + sequenceFlow_m9tokw + sequenceFlow_rwdWxw + sequenceFlow_kS2fMA + sequenceFlow_U2uXSQ +
+ + + + + + + + + + Partnermanagement]]> + + + + sequenceFlow_jAU3VA + sequenceFlow_8O1EtQ + + + + + + + + + + + home]]> + + + + + + + sequenceFlow_1mXO8A + sequenceFlow_X4XnjQ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + sequenceFlow_avahXg + + + + + + + + + + + + + + + + + + + + + + + + + + sequenceFlow_9atLFA + + + + + + + + + + + + + + + sequenceFlow_m9tokw + + + + + + + + partner.name (partner.id)]]> + + + Adresse:
+partner.name
+partner.address
+partner.zip partner.city
+
+ +BPID: partner.id
+Kreditoren-Nr.: cdtr.number
+Debitoren-Nr.: dbtr.number
+]]>
+
+ + + + + + + + + + + + + + + + + + + + + +
+ + sequenceFlow_NNbMhg + sequenceFlow_avahXg + sequenceFlow_pvIENQ + sequenceFlow_BWOtzA + sequenceFlow_ofWWuw + sequenceFlow_b0Bj3Q + sequenceFlow_BHsRkQ +
+ + + + + + + + + + Partnermanagement]]> + + + + sequenceFlow_BHsRkQ + sequenceFlow_5pT4Tw + + + + + + + + home]]> + + + + + + + + + + + + + + + + + + + sequenceFlow_pvIENQ + sequenceFlow_b4BcVA + + + + + + + + + + + + + + + + + + sequenceFlow_BWOtzA + + + + + + + + Partnermanagement]]> + + + + + + + sequenceFlow_ofWWuw + + + + + + + + + + sequenceFlow_S9LVXg + sequenceFlow_jAU3VA + sequenceFlow_8BTEtw + + + + + + + + + + + + + + + + sequenceFlow_kS2fMA + + + + + + + + + + + partner.name (partner.id)]]> + + + Adresse:
+partner.name
+partner.address
+partner.zip partner.city
+
+ +BPID: partner.id
+Kreditoren-Nr.: cdtr.number
+Debitoren-Nr.: dbtr.number
+]]>
+
+ + + + + + + + + + + + + + + + + + +
+ + sequenceFlow_9atLFA + sequenceFlow_8O1EtQ + sequenceFlow_QS6m0Q + sequenceFlow_neSsFQ + sequenceFlow_zd6RWA + sequenceFlow_8O1EtQ + sequenceFlow_Zl0LZA + sequenceFlow_BbA3Gg + sequenceFlow_3SU0Xw +
+ + + + + + + sequenceFlow_5pT4Tw + + + + + sequenceFlow_8BTEtw + + + + + + + + + + + sequenceFlow_OwZZBw + + + + + + + + sequenceFlow_zd6RWA + + + + + + + sequenceFlow_b0Bj3Q + sequenceFlow_neSsFQ + sequenceFlow_DC7n0g + sequenceFlow_X4XnjQ + + + + + + + + + + + + + + + sequenceFlow_Zl0LZA + sequenceFlow_0Icsbw + + + + + + + + + + + + + + home]]> + + + + + + + + + + + + + + + + + + + sequenceFlow_RkjrPQ + + sequenceFlow_b0d63g + + + + sequenceFlow_03b60w + sequenceFlow_OwZZBw + sequenceFlow_RkjrPQ + sequenceFlow_DC7n0g + + + + + + + + + + + sequenceFlow_b0d63g + + + + + + + + sequenceFlow_BbA3Gg + + + + + + + + + + + + + + + + + + + + + + sequenceFlow_3SU0Xw + + + + + + + + + mahnlauf-de-1.0 + 1000 + 10 + partner.id,partner.name,dbtr.number,dbtr.mail,partner.name|dbtr.name + /pages/workitems/workitem.jsf?id=$uniqueid +]]> + + + + + + + + + + + sequenceFlow_e8q82w + + + + + + + + + + + + + + home]]> + + + + + + + sequenceFlow_U2uXSQ + sequenceFlow_QS6m0Q + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +