introduced new DataGroups/DataViews
This commit is contained in:
parent
73dd3c37a5
commit
22d23226e4
15 changed files with 21 additions and 1403 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
- Finalisierung Business Partner Interface
|
- Finalisierung Business Partner Interface
|
||||||
|- Neue Plugin Logik (Aktualisierung der BP Nummer und Aktivierung von BP Objekten falls diese archiviert waren)
|
|- Neue Plugin Logik (Aktualisierung der BP Nummer und Aktivierung von BP Objekten falls diese archiviert waren)
|
||||||
- Zoho Schnittstelle
|
- Zoho Schnittstelle
|
||||||
|
- Neues DataView und DataGroups Konzept implementiert
|
||||||
|
|
||||||
### Migration
|
### Migration
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,11 @@ services:
|
||||||
# Tika OCR Service
|
# Tika OCR Service
|
||||||
###############################################
|
###############################################
|
||||||
tika:
|
tika:
|
||||||
image: apache/tika:3.2.0.0-full
|
image: apache/tika:3.2.0.0-full
|
||||||
environment:
|
environment:
|
||||||
TZ: "Europe/Berlin"
|
TZ: "Europe/Berlin"
|
||||||
ports:
|
ports:
|
||||||
- "9998:9998"
|
- "9998:9998"
|
||||||
|
|
||||||
##################
|
##################
|
||||||
# Exporter Service
|
# Exporter Service
|
||||||
|
|
@ -88,10 +88,10 @@ services:
|
||||||
###############################################
|
###############################################
|
||||||
# Imixs-Admin
|
# Imixs-Admin
|
||||||
###############################################
|
###############################################
|
||||||
imixsadmin:
|
# imixsadmin:
|
||||||
image: imixs/imixs-admin
|
# image: imixs/imixs-admin
|
||||||
ports:
|
# ports:
|
||||||
- "8888:8080"
|
# - "8888:8080"
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
# Mailgateway
|
# Mailgateway
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,10 @@
|
||||||
<groupId>org.imixs.workflow</groupId>
|
<groupId>org.imixs.workflow</groupId>
|
||||||
<artifactId>imixs-data-groups</artifactId>
|
<artifactId>imixs-data-groups</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.imixs.workflow</groupId>
|
||||||
|
<artifactId>imixs-data-views</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- SEPA Adapter -->
|
<!-- SEPA Adapter -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,12 @@ import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import org.imixs.workflow.ItemCollection;
|
import org.imixs.workflow.ItemCollection;
|
||||||
|
import org.imixs.workflow.dataview.DataViewExportEvent;
|
||||||
import org.imixs.workflow.engine.DocumentService;
|
import org.imixs.workflow.engine.DocumentService;
|
||||||
import org.imixs.workflow.engine.WorkflowService;
|
import org.imixs.workflow.engine.WorkflowService;
|
||||||
import org.imixs.workflow.exceptions.PluginException;
|
import org.imixs.workflow.exceptions.PluginException;
|
||||||
import org.imixs.workflow.exceptions.QueryException;
|
import org.imixs.workflow.exceptions.QueryException;
|
||||||
import org.imixs.workflow.office.config.ConfigService;
|
import org.imixs.workflow.office.config.ConfigService;
|
||||||
import org.imixs.workflow.office.dataview.DataViewExportEvent;
|
|
||||||
import org.imixs.workflow.poi.POIFindReplaceAdapter;
|
import org.imixs.workflow.poi.POIFindReplaceAdapter;
|
||||||
import org.imixs.workflow.poi.POIUtil;
|
import org.imixs.workflow.poi.POIUtil;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.dataview;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.imixs.workflow.ItemCollection;
|
|
||||||
|
|
||||||
import jakarta.enterprise.context.SessionScoped;
|
|
||||||
import jakarta.inject.Named;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DataViewCache implements a sessionScoped cache for the dataView filter.
|
|
||||||
* The cache uses the cacheId provided in the URL - see DataViewController
|
|
||||||
* onLoad
|
|
||||||
*
|
|
||||||
* @author rsoika
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@SessionScoped
|
|
||||||
public class DataViewCache implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private Map<String, ItemCollection> dataViewStates = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public void put(String key, ItemCollection data) {
|
|
||||||
dataViewStates.put(key, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemCollection get(String key) {
|
|
||||||
ItemCollection result = dataViewStates.get(key);
|
|
||||||
if (result == null) {
|
|
||||||
// init new empty cache object!
|
|
||||||
result = new ItemCollection();
|
|
||||||
dataViewStates.put(key, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,429 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.dataview;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.imixs.archive.core.SnapshotService;
|
|
||||||
import org.imixs.workflow.FileData;
|
|
||||||
import org.imixs.workflow.ItemCollection;
|
|
||||||
import org.imixs.workflow.engine.DocumentService;
|
|
||||||
import org.imixs.workflow.engine.WorkflowService;
|
|
||||||
import org.imixs.workflow.exceptions.ModelException;
|
|
||||||
import org.imixs.workflow.exceptions.PluginException;
|
|
||||||
import org.imixs.workflow.exceptions.QueryException;
|
|
||||||
import org.imixs.workflow.faces.data.ViewController;
|
|
||||||
import org.imixs.workflow.faces.data.ViewHandler;
|
|
||||||
import org.imixs.workflow.faces.data.WorkflowController;
|
|
||||||
import org.imixs.workflow.office.forms.CustomFormController;
|
|
||||||
import org.imixs.workflow.office.forms.CustomFormSection;
|
|
||||||
|
|
||||||
import com.alexanderlogistics.mahnlauf.InkassoExportAdapter;
|
|
||||||
|
|
||||||
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 DataViewController is used to display a data view
|
|
||||||
* <p>
|
|
||||||
* The controller uses the uniqueId from the URL to load the definition.
|
|
||||||
* The bean reads optional cached query data form
|
|
||||||
* a session scoped cache EJB and reloads the last state. This is useful for
|
|
||||||
* situations where the user navigates to a new page (e.g. open a workitem) and
|
|
||||||
* late uses browser history back.
|
|
||||||
* <p>
|
|
||||||
* Note: This bean is ConversationScoped, because it uses the
|
|
||||||
* CustomFormController which expects conversion scope!
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author rsoika
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@ConversationScoped
|
|
||||||
public class DataViewController extends ViewController {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public static final String ERROR_CONFIG = "CONFIG_ERROR";
|
|
||||||
public static final int MAX_ROWS = 9999;
|
|
||||||
|
|
||||||
private List<CustomFormSection> sections = null;
|
|
||||||
private List<ItemCollection> viewItemDefinitions = null;
|
|
||||||
protected ItemCollection dataViewDefinition = null;
|
|
||||||
private ItemCollection filter;
|
|
||||||
private String query;
|
|
||||||
private String errorMessage;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
DataViewCache dataViewCache;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private Conversation conversation;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private DocumentService documentService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private WorkflowService workflowService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
SnapshotService snapshotService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
CustomFormController customFormController;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
WorkflowController workflowController;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
DataViewDefaultExporter dataViewDefaultExporter;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
ViewHandler viewHandler;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
DataViewDefinitionController dataViewDefinitionController;
|
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(DataViewController.class.getName());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
super.init();
|
|
||||||
// this.setQuery(dataViewController.getQuery());
|
|
||||||
this.setSortBy("$modified");
|
|
||||||
this.setSortReverse(false);
|
|
||||||
this.setPageSize(100);
|
|
||||||
this.setLoadStubs(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method loads the custom form sections
|
|
||||||
*/
|
|
||||||
public void onLoad() {
|
|
||||||
String uniqueid = null;
|
|
||||||
|
|
||||||
// Important: start a new conversation beause of the usage of the
|
|
||||||
// CustomFormController!
|
|
||||||
startConversation();
|
|
||||||
|
|
||||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
|
||||||
if (!facesContext.isPostback() && !facesContext.isValidationFailed()) {
|
|
||||||
// ...
|
|
||||||
FacesContext fc = FacesContext.getCurrentInstance();
|
|
||||||
Map<String, String> paramMap = fc.getExternalContext().getRequestParameterMap();
|
|
||||||
// try to extract the uniqueid form the query string...
|
|
||||||
uniqueid = paramMap.get("id");
|
|
||||||
if (uniqueid == null || uniqueid.isEmpty()) {
|
|
||||||
// alternative 'workitem=...'
|
|
||||||
uniqueid = paramMap.get("workitem");
|
|
||||||
}
|
|
||||||
dataViewDefinition = documentService.load(uniqueid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniqueid != null && !uniqueid.isEmpty()) {
|
|
||||||
filter = dataViewCache.get(uniqueid);
|
|
||||||
} else {
|
|
||||||
filter = new ItemCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Init new Filter....
|
|
||||||
if (dataViewDefinition != null) {
|
|
||||||
filter.setItemValue("txtWorkflowEditorCustomForm", dataViewDefinition.getItemValue("form"));
|
|
||||||
filter.setItemValue("name", dataViewDefinition.getItemValueString("name"));
|
|
||||||
filter.setItemValue("description", dataViewDefinition.getItemValueString("description"));
|
|
||||||
viewItemDefinitions = DataViewDefinitionController
|
|
||||||
.computeDataViewItemDefinitions(dataViewDefinition);
|
|
||||||
|
|
||||||
customFormController.computeFieldDefinition(filter);
|
|
||||||
sections = customFormController.getSections();
|
|
||||||
|
|
||||||
// Update View Handler settings
|
|
||||||
String sortBy = dataViewDefinition.getItemValueString("sort.by");
|
|
||||||
if (sortBy.isEmpty()) {
|
|
||||||
sortBy = "$modified";
|
|
||||||
}
|
|
||||||
this.setSortBy(sortBy);
|
|
||||||
this.setSortReverse(dataViewDefinition.getItemValueBoolean("sort.reverse"));
|
|
||||||
this.setPageIndex(filter.getItemValueInteger("pageIndex"));
|
|
||||||
if (!filter.getItemValueString("query").isEmpty()) {
|
|
||||||
query = filter.getItemValueString("query");
|
|
||||||
// Prefetch data to update total count and page count
|
|
||||||
viewHandler.getData(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ModelException | QueryException e) {
|
|
||||||
logger.warning("Failed to load dataview definition: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ItemCollection> loadData() throws QueryException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
return super.loadData();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.severe("Failed to load view: " + e.getMessage());
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemCollection getDataViewDefinition() {
|
|
||||||
return dataViewDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CustomFormSection> getSections() {
|
|
||||||
return sections;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ItemCollection> getViewItemDefinitions() {
|
|
||||||
return viewItemDefinitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemCollection getFilter() {
|
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFilter(ItemCollection filter) {
|
|
||||||
this.filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getErrorMessage() {
|
|
||||||
return errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setErrorMessage(String errorMessage) {
|
|
||||||
this.errorMessage = errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This helper method builds a query from the query definition and the current
|
|
||||||
* filter criteria.
|
|
||||||
*
|
|
||||||
* The method loads the query form the definition and replaces all {<itemname>}
|
|
||||||
* elements with the values from the filter
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @throws QueryException
|
|
||||||
*/
|
|
||||||
public void run() throws PluginException, QueryException {
|
|
||||||
|
|
||||||
reset();
|
|
||||||
|
|
||||||
// build new query from template
|
|
||||||
query = dataViewDefinition.getItemValueString("query");
|
|
||||||
|
|
||||||
query = parseQuery(query, filter);
|
|
||||||
query = parseQuery(query, workflowController.getWorkitem());
|
|
||||||
|
|
||||||
logger.info("query=" + query);
|
|
||||||
filter.setItemValue("query", query);
|
|
||||||
|
|
||||||
// Prefetch data to update total count and page count
|
|
||||||
viewHandler.getData(this);
|
|
||||||
// cache filter
|
|
||||||
dataViewCache.put(dataViewDefinition.getUniqueID(), filter);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String parseQuery(String query, ItemCollection filter) {
|
|
||||||
List<String> filterItems = filter.getItemNames();
|
|
||||||
for (String itemName : filterItems) {
|
|
||||||
String itemValue = filter.getItemValueString(itemName);
|
|
||||||
|
|
||||||
// is date?
|
|
||||||
if (filter.getItemValueDate(itemName) != null) {
|
|
||||||
String sDateFrom = "191401070000"; // because * did not work here
|
|
||||||
String sDateTo = "211401070000";
|
|
||||||
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
|
|
||||||
|
|
||||||
itemValue = dateformat.format(filter.getItemValueDate(itemName));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create regex pattern to match {itemName} (case-sensitive)
|
|
||||||
// The Pattern.quote is used to escape any special regex characters in the
|
|
||||||
// itemName
|
|
||||||
// Replace all occurrences in the query case-insensitive.
|
|
||||||
query = query.replaceAll("(?i)\\{" + Pattern.quote(itemName) + "\\}", itemValue);
|
|
||||||
}
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current query
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getQuery() {
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method navigates back in the page index and caches the current page
|
|
||||||
* index
|
|
||||||
*/
|
|
||||||
public void back() {
|
|
||||||
viewHandler.back(this);
|
|
||||||
filter.setItemValue("pageIndex", this.getPageIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method navigates forward in the page index and caches the current page
|
|
||||||
* index
|
|
||||||
*/
|
|
||||||
public void forward() {
|
|
||||||
viewHandler.forward(this);
|
|
||||||
filter.setItemValue("pageIndex", this.getPageIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 query and prepare dataset
|
|
||||||
run();
|
|
||||||
|
|
||||||
SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmm");
|
|
||||||
String targetFileName = dataViewDefinition.getItemValueString("poi.targetFilename");
|
|
||||||
if (targetFileName.isEmpty()) {
|
|
||||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
|
||||||
"Missing Excel Export definition - check configuration!");
|
|
||||||
}
|
|
||||||
logger.info("start export : " + targetFileName + "...");
|
|
||||||
logger.fine(query);
|
|
||||||
|
|
||||||
// load template
|
|
||||||
FileData fileData = loadTemplate();
|
|
||||||
|
|
||||||
if (fileData == null) {
|
|
||||||
// we did not found the template!
|
|
||||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
|
||||||
"Missing Excel Export Template - check DataView definition!");
|
|
||||||
}
|
|
||||||
targetFileName = targetFileName + "_" + dateformat.format(new Date()) + ".xlsx";
|
|
||||||
try {
|
|
||||||
// test if query exceeds max count
|
|
||||||
int totalCount = documentService.count(query);
|
|
||||||
if (totalCount > MAX_ROWS) {
|
|
||||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
|
||||||
"Data can not be exported into Excel because dataset exceeds " + MAX_ROWS + " rows!");
|
|
||||||
}
|
|
||||||
String sortBy = dataViewDefinition.getItemValueString("sort.by");
|
|
||||||
if (sortBy.isEmpty()) {
|
|
||||||
sortBy = "$modified"; // default
|
|
||||||
}
|
|
||||||
List<ItemCollection> invoices = documentService.find(query, MAX_ROWS, 0, sortBy,
|
|
||||||
dataViewDefinition.getItemValueBoolean("sort.reverse"));
|
|
||||||
if (invoices.size() > 0) {
|
|
||||||
dataViewDefaultExporter.insertDataRows(invoices, dataViewDefinition, viewItemDefinitions, fileData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a temp event
|
|
||||||
ItemCollection event = new ItemCollection().setItemValue("txtActivityResult",
|
|
||||||
dataViewDefinition.getItemValue("poi.update"));
|
|
||||||
ItemCollection poiConfig = workflowService.evalWorkflowResult(event, "poi-update", dataViewDefinition,
|
|
||||||
false);
|
|
||||||
|
|
||||||
// merge workitem fields (Workaround because custom forms did hard coded map to
|
|
||||||
// workflowController instead of workitem
|
|
||||||
filter.copy(workflowController.getWorkitem());
|
|
||||||
DataViewPOIHelper.poiUpdate(filter, fileData, poiConfig, workflowService);
|
|
||||||
|
|
||||||
fileData.setName(targetFileName);
|
|
||||||
|
|
||||||
// See:
|
|
||||||
// https://stackoverflow.com/questions/9391838/how-to-provide-a-file-download-from-a-jsf-backing-bean
|
|
||||||
DataViewPOIHelper.downloadExcelFile(fileData);
|
|
||||||
} catch (IOException | QueryException e) {
|
|
||||||
throw new PluginException(InkassoExportAdapter.class.getSimpleName(), ERROR_CONFIG,
|
|
||||||
"Failed to generate Excel Export: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// return "/pages/admin/excel_export_rechnungsausgang.jsf?faces-redirect=true";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the first excel poi template from the Data Definition
|
|
||||||
*
|
|
||||||
* @param name in attribute txtname
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private FileData loadTemplate() {
|
|
||||||
|
|
||||||
// first filename
|
|
||||||
List<FileData> fileDataList = dataViewDefinition.getFileData();
|
|
||||||
if (fileDataList != null && fileDataList.size() > 0) {
|
|
||||||
String fileName = fileDataList.get(0).getName();
|
|
||||||
return snapshotService.getWorkItemFile(dataViewDefinition.getUniqueID(), fileName);
|
|
||||||
}
|
|
||||||
// no file data available!
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
package org.imixs.workflow.office.dataview;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.CellCopyPolicy;
|
|
||||||
import org.apache.poi.ss.util.CellReference;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.imixs.workflow.FileData;
|
|
||||||
import org.imixs.workflow.ItemCollection;
|
|
||||||
import org.imixs.workflow.exceptions.PluginException;
|
|
||||||
import org.imixs.workflow.office.forms.AnalyticController;
|
|
||||||
|
|
||||||
import jakarta.enterprise.context.ConversationScoped;
|
|
||||||
import jakarta.enterprise.event.Event;
|
|
||||||
import jakarta.inject.Inject;
|
|
||||||
import jakarta.inject.Named;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DataViewDefaultExporter exports a dataset into a excel template. The
|
|
||||||
* exporter sends a DataViewExportEvent. An observer CID bean can implement
|
|
||||||
* alternative exporters.
|
|
||||||
* With the event property 'completed' a client can signal that the export
|
|
||||||
* process is completed. Otherwise the default behavior will be adapted.
|
|
||||||
*
|
|
||||||
* @author rsoika
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@ConversationScoped
|
|
||||||
public class DataViewDefaultExporter implements Serializable {
|
|
||||||
public static final String ERROR_CONFIG = "CONFIG_ERROR";
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private static Logger logger = Logger.getLogger(AnalyticController.class.getName());
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected Event<DataViewExportEvent> dataViewExportEvents;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This helper method inserts a row for each invoice
|
|
||||||
*
|
|
||||||
* @throws PluginException
|
|
||||||
*/
|
|
||||||
public void insertDataRows(List<ItemCollection> dataset, ItemCollection dataViewDefinition,
|
|
||||||
List<ItemCollection> viewItemDefinitions,
|
|
||||||
FileData fileData) throws PluginException {
|
|
||||||
// load XSSFWorkbook
|
|
||||||
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
|
|
||||||
XSSFWorkbook doc = new XSSFWorkbook(imputStream);
|
|
||||||
|
|
||||||
// send DataViewExportEvent....
|
|
||||||
if (dataViewExportEvents != null) {
|
|
||||||
DataViewExportEvent event = new DataViewExportEvent(dataset, dataViewDefinition, viewItemDefinitions,
|
|
||||||
doc);
|
|
||||||
dataViewExportEvents.fire(event); // found FileData?
|
|
||||||
if (!event.isCompleted()) {
|
|
||||||
// Default behavior
|
|
||||||
defaultExport(dataset, dataViewDefinition, viewItemDefinitions, doc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
||||||
// write back the file
|
|
||||||
doc.write(byteArrayOutputStream);
|
|
||||||
doc.close();
|
|
||||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
|
||||||
fileData.setContent(newContent);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginException(DataViewPOIHelper.class.getSimpleName(), ERROR_CONFIG,
|
|
||||||
"failed to update excel export: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the default implementation to insert a dataset into a XSSFSheet
|
|
||||||
*
|
|
||||||
* @param dataset
|
|
||||||
* @param referenceCell
|
|
||||||
* @param viewItemDefinitions
|
|
||||||
* @param doc
|
|
||||||
*/
|
|
||||||
private void defaultExport(List<ItemCollection> dataset, ItemCollection dataViewDefinition,
|
|
||||||
List<ItemCollection> viewItemDefinitions, XSSFWorkbook doc) {
|
|
||||||
String referenceCell = dataViewDefinition.getItemValueString("poi.referenceCell");
|
|
||||||
|
|
||||||
// NOTE: we only take the first sheet !
|
|
||||||
XSSFSheet sheet = doc.getSheetAt(0);
|
|
||||||
|
|
||||||
CellReference cr = new CellReference(referenceCell);
|
|
||||||
XSSFRow referenceRow = sheet.getRow(cr.getRow());
|
|
||||||
int referenceRowPos = referenceRow.getRowNum() + 1;
|
|
||||||
int rowPos = referenceRowPos;
|
|
||||||
// int lastRow = sheet.getLastRowNum();
|
|
||||||
int lastRow = 999;
|
|
||||||
logger.finest("Last rownum=" + lastRow);
|
|
||||||
sheet.shiftRows(rowPos, lastRow, dataset.size(), true, true);
|
|
||||||
|
|
||||||
for (ItemCollection workitem : dataset) {
|
|
||||||
logger.finest("......copy row...");
|
|
||||||
|
|
||||||
// now create a new line..
|
|
||||||
XSSFRow row = sheet.createRow(rowPos);
|
|
||||||
row.copyRowFrom(referenceRow, new CellCopyPolicy());
|
|
||||||
// insert values
|
|
||||||
int cellNum = 0;
|
|
||||||
for (ItemCollection itemDef : viewItemDefinitions) {
|
|
||||||
String type = itemDef.getItemValueString("item.type");
|
|
||||||
String name = itemDef.getItemValueString("item.name");
|
|
||||||
switch (type) {
|
|
||||||
case "xs:double":
|
|
||||||
row.getCell(cellNum).setCellValue(workitem.getItemValueDouble(name));
|
|
||||||
break;
|
|
||||||
case "xs:float":
|
|
||||||
row.getCell(cellNum).setCellValue(workitem.getItemValueFloat(name));
|
|
||||||
break;
|
|
||||||
case "xs:int":
|
|
||||||
row.getCell(cellNum).setCellValue(workitem.getItemValueInteger(name));
|
|
||||||
break;
|
|
||||||
case "xs:date":
|
|
||||||
row.getCell(cellNum).setCellValue(workitem.getItemValueDate(name));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
row.getCell(cellNum).setCellValue(workitem.getItemValueString(name));
|
|
||||||
}
|
|
||||||
cellNum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
rowPos++;
|
|
||||||
}
|
|
||||||
// delete reference row
|
|
||||||
sheet.shiftRows(referenceRowPos, lastRow + dataset.size(), -1, true, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,322 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.dataview;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.imixs.workflow.ItemCollection;
|
|
||||||
import org.imixs.workflow.exceptions.AccessDeniedException;
|
|
||||||
import org.imixs.workflow.exceptions.QueryException;
|
|
||||||
import org.imixs.workflow.faces.data.AbstractDataController;
|
|
||||||
import org.imixs.workflow.faces.data.DocumentController;
|
|
||||||
|
|
||||||
import com.oracle.svm.core.annotate.Inject;
|
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import jakarta.enterprise.context.SessionScoped;
|
|
||||||
import jakarta.faces.context.ExternalContext;
|
|
||||||
import jakarta.faces.context.FacesContext;
|
|
||||||
import jakarta.inject.Named;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DataViewDefinitionController is used to configure a dataview definition
|
|
||||||
*
|
|
||||||
* @author rsoika
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
@Named
|
|
||||||
@SessionScoped
|
|
||||||
public class DataViewDefinitionController extends AbstractDataController {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
protected List<ItemCollection> attributeList = null;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
DocumentController documentController;
|
|
||||||
|
|
||||||
protected List<ItemCollection> dataViewDefinitions = null;
|
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(DataViewDefinitionController.class.getName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ItemCollection> getDefinitions() {
|
|
||||||
if (dataViewDefinitions == null) {
|
|
||||||
// lazy loading
|
|
||||||
String quuery = "(type:\"dataview\")";
|
|
||||||
try {
|
|
||||||
dataViewDefinitions = this.getDocumentService().find(quuery, 999, 0, "name", false);
|
|
||||||
} catch (QueryException e) {
|
|
||||||
logger.severe("Failed to load DataView definition list: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataViewDefinitions;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds all dataview definitions assigned to a process by its name
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<ItemCollection> findDefinitionByProcessRef(String id) {
|
|
||||||
List<ItemCollection> result = new ArrayList<>();
|
|
||||||
if (id == null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDefinitions();
|
|
||||||
for (ItemCollection def : dataViewDefinitions) {
|
|
||||||
if (id.equals(def.getItemValueString("process.ref"))) {
|
|
||||||
result.add(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current workItem. If no workitem is defined the method
|
|
||||||
* Instantiates a empty ItemCollection.
|
|
||||||
*
|
|
||||||
* @return - current workItem or null if not set
|
|
||||||
*/
|
|
||||||
public ItemCollection getData() {
|
|
||||||
// do initialize an empty workItem here if null
|
|
||||||
if (data == null) {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns a unique view URI to be used zu display the View Data.
|
|
||||||
* The uri contains a unique random ID to support caching over different browser
|
|
||||||
* tabs
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getViewURI(ItemCollection dataDef) {
|
|
||||||
return "/pages/dataviews/data.xhtml?id=" + dataDef.getUniqueID() + "&faces-redirect=true";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void load(String uniqueid) {
|
|
||||||
|
|
||||||
super.load(uniqueid);
|
|
||||||
attributeList = computeDataViewItemDefinitions(this.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a List of ItemCollection instances representing the view column
|
|
||||||
* description.
|
|
||||||
* Each column has the items:
|
|
||||||
*
|
|
||||||
* name,label,format,convert
|
|
||||||
*
|
|
||||||
* @param dataViewDefinition
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static List<ItemCollection> computeDataViewItemDefinitions(ItemCollection dataViewDefinition) {
|
|
||||||
|
|
||||||
ArrayList<ItemCollection> result = new ArrayList<ItemCollection>();
|
|
||||||
List<Object> mapItems = dataViewDefinition.getItemValue("dataview.items");
|
|
||||||
for (Object mapOderItem : mapItems) {
|
|
||||||
if (mapOderItem instanceof Map) {
|
|
||||||
ItemCollection itemCol = new ItemCollection((Map) mapOderItem);
|
|
||||||
// check label
|
|
||||||
String itemLabel = itemCol.getItemValueString("item.label");
|
|
||||||
if (itemLabel.isEmpty()) {
|
|
||||||
itemCol.setItemValue("item.label", itemLabel);
|
|
||||||
}
|
|
||||||
// check type
|
|
||||||
String itemType = itemCol.getItemValueString("item.type");
|
|
||||||
if (itemType.isEmpty()) {
|
|
||||||
itemCol.setItemValue("item.type", "xs:string");
|
|
||||||
}
|
|
||||||
result.add(itemCol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no columns are defined we create the default columns
|
|
||||||
if (result.size() == 0) {
|
|
||||||
ItemCollection itemCol = new ItemCollection();
|
|
||||||
itemCol.setItemValue("item.name", "$workflowSummary");
|
|
||||||
itemCol.setItemValue("item.label", "Name");
|
|
||||||
itemCol.setItemValue("item.type", "xs:anyURI");
|
|
||||||
result.add(itemCol);
|
|
||||||
|
|
||||||
itemCol = new ItemCollection();
|
|
||||||
itemCol.setItemValue("item.name", "$modified");
|
|
||||||
itemCol.setItemValue("item.label", "Modified");
|
|
||||||
itemCol.setItemValue("item.type", "xs:date");
|
|
||||||
result.add(itemCol);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates an empty new dataview definition
|
|
||||||
*/
|
|
||||||
public void create() {
|
|
||||||
data = new ItemCollection();
|
|
||||||
data.setType("dataview");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method saves the current document.
|
|
||||||
*
|
|
||||||
* @throws AccessDeniedException - if user has insufficient access rights.
|
|
||||||
*/
|
|
||||||
public void save() throws AccessDeniedException {
|
|
||||||
// save definition ...
|
|
||||||
data.setType("dataview");
|
|
||||||
FacesContext context = FacesContext.getCurrentInstance();
|
|
||||||
ExternalContext externalContext = context
|
|
||||||
.getExternalContext();
|
|
||||||
String sUser = externalContext.getRemoteUser();
|
|
||||||
data.replaceItemValue("$editor", sUser);
|
|
||||||
|
|
||||||
// implode attributes
|
|
||||||
if (attributeList != null) {
|
|
||||||
List<Map> mapItemList = new ArrayList<Map>();
|
|
||||||
logger.fine("Convert attribute items into Map...");
|
|
||||||
for (ItemCollection attrItem : attributeList) {
|
|
||||||
ItemCollection ding = (ItemCollection) attrItem.clone();
|
|
||||||
mapItemList.add(ding.getAllItems());
|
|
||||||
}
|
|
||||||
data.replaceItemValue("dataview.items", mapItemList);
|
|
||||||
}
|
|
||||||
data = this.getDocumentService().save(data);
|
|
||||||
|
|
||||||
// reset view
|
|
||||||
dataViewDefinitions = null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String openTestView() {
|
|
||||||
this.save();
|
|
||||||
return "/pages/dataviews/data.xhtml?id=" + data.getUniqueID() + "&faces-redirect=true";
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ItemCollection> getAttributeList() {
|
|
||||||
if (attributeList == null) {
|
|
||||||
attributeList = new ArrayList<>();
|
|
||||||
}
|
|
||||||
return attributeList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new attribute object.
|
|
||||||
*/
|
|
||||||
public void addAttribute() {
|
|
||||||
if (attributeList == null) {
|
|
||||||
attributeList = new ArrayList<ItemCollection>();
|
|
||||||
}
|
|
||||||
ItemCollection source = new ItemCollection();
|
|
||||||
attributeList.add(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an attribute item from the list
|
|
||||||
*
|
|
||||||
* @param name - name of attribute
|
|
||||||
*/
|
|
||||||
public void removeAttribute(String name) {
|
|
||||||
if (name != null && attributeList != null) {
|
|
||||||
for (ItemCollection item : attributeList) {
|
|
||||||
if (name.equals(item.getItemValueString("item.name"))) {
|
|
||||||
attributeList.remove(item);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves an attribute item up in the list
|
|
||||||
*
|
|
||||||
* List<ItemCollection> attributeList
|
|
||||||
*
|
|
||||||
* @param name - name of attribute
|
|
||||||
*/
|
|
||||||
public void moveAttributeUp(String name) {
|
|
||||||
if (name != null && attributeList != null) {
|
|
||||||
logger.info("move up: " + name);
|
|
||||||
for (int i = 0; i < attributeList.size(); i++) {
|
|
||||||
ItemCollection item = attributeList.get(i);
|
|
||||||
if (name.equals(item.getItemValueString("item.name"))) {
|
|
||||||
// Check if it's not already at the top
|
|
||||||
if (i > 0) {
|
|
||||||
// Swap with previous element
|
|
||||||
Collections.swap(attributeList, i, i - 1);
|
|
||||||
}
|
|
||||||
break; // Exit loop once found and processed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves an attribute item up down the list
|
|
||||||
*
|
|
||||||
* List<ItemCollection> attributeList
|
|
||||||
*
|
|
||||||
* @param name - name of attribute
|
|
||||||
*/
|
|
||||||
public void moveAttributeDown(String name) {
|
|
||||||
if (name != null && attributeList != null) {
|
|
||||||
logger.info("move down: " + name);
|
|
||||||
for (int i = 0; i < attributeList.size(); i++) {
|
|
||||||
ItemCollection item = attributeList.get(i);
|
|
||||||
if (name.equals(item
|
|
||||||
.getItemValueString("item.name"))) {
|
|
||||||
// Check if it's not already at the bottom
|
|
||||||
if (i < attributeList.size() - 1) {
|
|
||||||
// Swap with next element
|
|
||||||
Collections.swap(attributeList, i, i + 1);
|
|
||||||
}
|
|
||||||
break; // Exit loop once found and processed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
package org.imixs.workflow.office.dataview;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.imixs.workflow.ItemCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An DataViewExportEvent is send by the DataViewController during exporting a
|
|
||||||
* data view into a Excel Template.
|
|
||||||
* An observer can customize the export behavior and mark an export as
|
|
||||||
* completed by setting the flag 'completed' to true
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class DataViewExportEvent {
|
|
||||||
|
|
||||||
private List<ItemCollection> dataset = null;
|
|
||||||
private ItemCollection dataViewDefinition = null;
|
|
||||||
private List<ItemCollection> viewItemDefinitions = null;
|
|
||||||
private XSSFWorkbook xssfWorkbook = null;
|
|
||||||
private boolean completed = false;
|
|
||||||
|
|
||||||
public DataViewExportEvent(List<ItemCollection> dataset, ItemCollection dataViewDefinition,
|
|
||||||
List<ItemCollection> viewItemDefinitions,
|
|
||||||
XSSFWorkbook xssfWorkbook) {
|
|
||||||
this.dataset = dataset;
|
|
||||||
this.dataViewDefinition = dataViewDefinition;
|
|
||||||
this.xssfWorkbook = xssfWorkbook;
|
|
||||||
this.viewItemDefinitions = viewItemDefinitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCompleted() {
|
|
||||||
return completed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompleted(boolean completed) {
|
|
||||||
this.completed = completed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ItemCollection> getDataset() {
|
|
||||||
return dataset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDataset(List<ItemCollection> dataset) {
|
|
||||||
this.dataset = dataset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemCollection getDataViewDefinition() {
|
|
||||||
return dataViewDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDataViewDefinition(ItemCollection dataViewDefinition) {
|
|
||||||
this.dataViewDefinition = dataViewDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ItemCollection> getViewItemDefinitions() {
|
|
||||||
return viewItemDefinitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setViewItemDefinitions(List<ItemCollection> viewItemDefinitions) {
|
|
||||||
this.viewItemDefinitions = viewItemDefinitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public XSSFWorkbook getXssfWorkbook() {
|
|
||||||
return xssfWorkbook;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setXssfWorkbook(XSSFWorkbook xssfWorkbook) {
|
|
||||||
this.xssfWorkbook = xssfWorkbook;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,358 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.dataview;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
|
||||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
|
||||||
import org.apache.poi.ss.usermodel.Name;
|
|
||||||
import org.apache.poi.ss.util.CellReference;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
||||||
import org.imixs.workflow.FileData;
|
|
||||||
import org.imixs.workflow.ItemCollection;
|
|
||||||
import org.imixs.workflow.engine.WorkflowService;
|
|
||||||
import org.imixs.workflow.exceptions.PluginException;
|
|
||||||
import org.imixs.workflow.util.XMLParser;
|
|
||||||
|
|
||||||
import jakarta.faces.context.ExternalContext;
|
|
||||||
import jakarta.faces.context.FacesContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DataViewPOIHelper provides methods to update a excel template with the
|
|
||||||
* help of the Apache POI framework.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author rsoika
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DataViewPOIHelper {
|
|
||||||
private static Logger logger = Logger.getLogger(DataViewPOIHelper.class.getName());
|
|
||||||
public static final String ERROR_CONFIG = "CONFIG_ERROR";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to initialize a file download
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static void downloadExcelFile(FileData fileData) throws IOException {
|
|
||||||
|
|
||||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
|
||||||
ExternalContext externalContext = facesContext.getExternalContext();
|
|
||||||
|
|
||||||
externalContext.responseReset();
|
|
||||||
externalContext.setResponseContentType("application/vnd.ms-excel");
|
|
||||||
externalContext.setResponseContentLength(fileData.getContent().length);
|
|
||||||
externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileData.getName() + "\"");
|
|
||||||
|
|
||||||
OutputStream output = externalContext.getResponseOutputStream();
|
|
||||||
|
|
||||||
// Now you can write the InputStream of the file to the above OutputStream the
|
|
||||||
// usual way.
|
|
||||||
output.write(fileData.getContent());
|
|
||||||
|
|
||||||
facesContext.responseComplete(); // Important! Otherwise Faces will attempt to render the response which
|
|
||||||
// obviously will fail since it's already written with a file and closed.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This helper method inserts a row for each invoice
|
|
||||||
*
|
|
||||||
* @throws PluginException
|
|
||||||
*/
|
|
||||||
// public static void insertDataRows(List<ItemCollection> dataset, String
|
|
||||||
// referenceCell,
|
|
||||||
// List<ItemCollection> viewItemDefinitions,
|
|
||||||
// FileData fileData) throws PluginException {
|
|
||||||
// // load XSSFWorkbook
|
|
||||||
// try (InputStream imputStream = new
|
|
||||||
// ByteArrayInputStream(fileData.getContent())) {
|
|
||||||
// XSSFWorkbook doc = new XSSFWorkbook(imputStream);
|
|
||||||
// // NOTE: we only take the first sheet !
|
|
||||||
// XSSFSheet sheet = doc.getSheetAt(0);
|
|
||||||
|
|
||||||
// CellReference cr = new CellReference(referenceCell);
|
|
||||||
// XSSFRow referenceRow = sheet.getRow(cr.getRow());
|
|
||||||
// int referenceRowPos = referenceRow.getRowNum() + 1;
|
|
||||||
// int rowPos = referenceRowPos;
|
|
||||||
// // int lastRow = sheet.getLastRowNum();
|
|
||||||
// int lastRow = 999;
|
|
||||||
// logger.finest("Last rownum=" + lastRow);
|
|
||||||
// sheet.shiftRows(rowPos, lastRow, dataset.size(), true, true);
|
|
||||||
|
|
||||||
// for (ItemCollection workitem : dataset) {
|
|
||||||
// logger.finest("......copy row...");
|
|
||||||
|
|
||||||
// // now create a new line..
|
|
||||||
// XSSFRow row = sheet.createRow(rowPos);
|
|
||||||
// row.copyRowFrom(referenceRow, new CellCopyPolicy());
|
|
||||||
// // insert values
|
|
||||||
// int cellNum = 0;
|
|
||||||
// for (ItemCollection itemDef : viewItemDefinitions) {
|
|
||||||
// String type = itemDef.getItemValueString("item.type");
|
|
||||||
// String name = itemDef.getItemValueString("item.name");
|
|
||||||
// switch (type) {
|
|
||||||
// case "xs:double":
|
|
||||||
// row.getCell(cellNum).setCellValue(workitem.getItemValueDouble(name));
|
|
||||||
// break;
|
|
||||||
// case "xs:float":
|
|
||||||
// row.getCell(cellNum).setCellValue(workitem.getItemValueFloat(name));
|
|
||||||
// break;
|
|
||||||
// case "xs:int":
|
|
||||||
// row.getCell(cellNum).setCellValue(workitem.getItemValueInteger(name));
|
|
||||||
// break;
|
|
||||||
// case "xs:date":
|
|
||||||
// row.getCell(cellNum).setCellValue(workitem.getItemValueDate(name));
|
|
||||||
// break;
|
|
||||||
|
|
||||||
// default:
|
|
||||||
// row.getCell(cellNum).setCellValue(workitem.getItemValueString(name));
|
|
||||||
// }
|
|
||||||
// cellNum++;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// rowPos++;
|
|
||||||
// }
|
|
||||||
// // delete reference row
|
|
||||||
// sheet.shiftRows(referenceRowPos, lastRow + dataset.size(), -1, true, true);
|
|
||||||
|
|
||||||
// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
||||||
// // write back the file
|
|
||||||
// doc.write(byteArrayOutputStream);
|
|
||||||
// doc.close();
|
|
||||||
// byte[] newContent = byteArrayOutputStream.toByteArray();
|
|
||||||
// fileData.setContent(newContent);
|
|
||||||
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// throw new PluginException(DataViewPOIHelper.class.getSimpleName(),
|
|
||||||
// ERROR_CONFIG,
|
|
||||||
// "failed to update excel export: " + e.getMessage());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This helper method applies the POI update defintiions a row for each invoice
|
|
||||||
*
|
|
||||||
* @throws PluginException
|
|
||||||
*/
|
|
||||||
public static void poiUpdate(ItemCollection dataDefinition, FileData fileData,
|
|
||||||
ItemCollection poiConfig, WorkflowService workflowService) throws PluginException {
|
|
||||||
|
|
||||||
// update $modified for Now function
|
|
||||||
dataDefinition.setItemValue("$modified", new Date());
|
|
||||||
|
|
||||||
if (poiConfig == null || !poiConfig.hasItem("findreplace")) {
|
|
||||||
// no config found
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<String> replaceDevList = poiConfig.getItemValue("findreplace");
|
|
||||||
String eval = poiConfig.getItemValueString("eval");
|
|
||||||
|
|
||||||
// load XSSFWorkbook
|
|
||||||
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
|
|
||||||
XSSFWorkbook workbook = new XSSFWorkbook(imputStream);
|
|
||||||
// NOTE: we only take the first sheet !
|
|
||||||
XSSFSheet sheet = workbook.getSheetAt(0);
|
|
||||||
|
|
||||||
updateXSSFWorkbook(workbook, dataDefinition, replaceDevList, workflowService);
|
|
||||||
|
|
||||||
// Update Eval list
|
|
||||||
if (eval != null && !eval.isEmpty()) {
|
|
||||||
// iterate over all cells to be evaluated
|
|
||||||
String[] cellPositions = eval.split(";");
|
|
||||||
for (String cellPos : cellPositions) {
|
|
||||||
evalXSSFSheet(workbook, sheet, cellPos);
|
|
||||||
}
|
|
||||||
logger.fine("formula evaluation completed");
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
||||||
// write back the file
|
|
||||||
workbook.write(byteArrayOutputStream);
|
|
||||||
workbook.close();
|
|
||||||
byte[] newContent = byteArrayOutputStream.toByteArray();
|
|
||||||
fileData.setContent(newContent);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginException(DataViewPOIHelper.class.getSimpleName(), ERROR_CONFIG,
|
|
||||||
"failed to update excel export: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Cell by name or an optional absolute cell postion
|
|
||||||
* <p>
|
|
||||||
* Examples for refs are 'A1', 'AB3', 'MyCell' where 'MyCell' is a named cell.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static XSSFCell getCellByRef(XSSFWorkbook doc, XSSFSheet sheet, String cellReference) {
|
|
||||||
XSSFCell cell = null;
|
|
||||||
|
|
||||||
// first we test if the cellName is a named cell
|
|
||||||
Name aNamedCell = doc.getName(cellReference);
|
|
||||||
if (aNamedCell != null) {
|
|
||||||
// yes its a named cell so we need to get the referrer Formula
|
|
||||||
logger.finest("...resolving named cell = " + aNamedCell.getNameName());
|
|
||||||
cellReference = aNamedCell.getRefersToFormula();
|
|
||||||
// now we can find the cell by its ref
|
|
||||||
}
|
|
||||||
|
|
||||||
CellReference cr = new CellReference(cellReference);
|
|
||||||
XSSFRow row = sheet.getRow(cr.getRow());
|
|
||||||
if (row == null) {
|
|
||||||
logger.severe("Unable to resolve cell ref '" + cellReference + "'!");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
cell = row.getCell(cr.getCol());
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method updates the XSSFWorkbook document. The method can be overwritten
|
|
||||||
* by subclasses to add additional logic
|
|
||||||
*
|
|
||||||
* @param workbook
|
|
||||||
* @param workitem
|
|
||||||
* @param replaceDevList
|
|
||||||
* @throws PluginException
|
|
||||||
*/
|
|
||||||
public static void updateXSSFWorkbook(XSSFWorkbook workbook, ItemCollection workitem, List<String> replaceDevList,
|
|
||||||
WorkflowService workflowService)
|
|
||||||
throws PluginException {
|
|
||||||
|
|
||||||
logger.fine("XSSFWorkbook loaded");
|
|
||||||
// NOTE: we only take the first sheet !
|
|
||||||
XSSFSheet sheet = workbook.getSheetAt(0);
|
|
||||||
|
|
||||||
for (String entityDev : replaceDevList) {
|
|
||||||
ItemCollection entityData = XMLParser.parseItemStructure(entityDev);
|
|
||||||
|
|
||||||
if (entityData != null) {
|
|
||||||
String find = entityData.getItemValueString("find");
|
|
||||||
String replace = entityData.getItemValueString("replace");
|
|
||||||
replace = workflowService.adaptText(replace, workitem);
|
|
||||||
// optional itename
|
|
||||||
String itemname = entityData.getItemValueString("itemname");
|
|
||||||
|
|
||||||
// replace with item value?
|
|
||||||
if (!itemname.isEmpty()) {
|
|
||||||
List<?> valueList = workitem.getItemValue(itemname);
|
|
||||||
if (valueList.size() > 0) {
|
|
||||||
// provide the first value only
|
|
||||||
replaceXSSFSheetItemValue(workbook, sheet, find, valueList.get(0));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
replaceXSSFSheetStringValue(workbook, sheet, find, replace);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method replaces a given cell of a XSSFSheet with a typed item value
|
|
||||||
*
|
|
||||||
* @throws PluginException
|
|
||||||
*/
|
|
||||||
public static void replaceXSSFSheetItemValue(XSSFWorkbook doc, XSSFSheet sheet, String find, Object itemValue)
|
|
||||||
throws PluginException {
|
|
||||||
logger.finest("update cell " + find);
|
|
||||||
XSSFCell cell = getCellByRef(doc, sheet, find);
|
|
||||||
if (cell == null) {
|
|
||||||
logger.warning("Cell " + find + " not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (itemValue instanceof Date) {
|
|
||||||
cell.setCellValue((Date) itemValue);
|
|
||||||
} else if (itemValue instanceof Double) {
|
|
||||||
cell.setCellValue((Double) itemValue);
|
|
||||||
} else {
|
|
||||||
// default to text
|
|
||||||
cell.setCellValue(itemValue.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method replaces a given cell of a XSSFSheet with a string value
|
|
||||||
*
|
|
||||||
* @throws PluginException
|
|
||||||
*/
|
|
||||||
private static void replaceXSSFSheetStringValue(XSSFWorkbook doc, XSSFSheet sheet, String find, String replace)
|
|
||||||
throws PluginException {
|
|
||||||
logger.finest("update cell " + find);
|
|
||||||
XSSFCell cell = getCellByRef(doc, sheet, find);
|
|
||||||
if (cell == null) {
|
|
||||||
logger.warning("Cell " + find + " not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// we try to set first as float value if possible
|
|
||||||
float f = Float.parseFloat(replace);
|
|
||||||
cell.setCellValue(f);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// set value as string
|
|
||||||
cell.setCellValue(replace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluates a given list of cells in a given XSWorkbook
|
|
||||||
*
|
|
||||||
* @param doc
|
|
||||||
* @param sheet
|
|
||||||
* @param cell
|
|
||||||
* @throws PluginException
|
|
||||||
*/
|
|
||||||
public static void evalXSSFSheet(XSSFWorkbook doc, XSSFSheet sheet, String cell) throws PluginException {
|
|
||||||
FormulaEvaluator evaluator = doc.getCreationHelper().createFormulaEvaluator();
|
|
||||||
XSSFCell c = getCellByRef(doc, sheet, cell);
|
|
||||||
if (c == null) {
|
|
||||||
logger.warning("Cell " + cell + " not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (c.getCellType() == CellType.FORMULA) {
|
|
||||||
logger.finest("...eval cell " + cell);
|
|
||||||
try {
|
|
||||||
CellType evalResult = evaluator.evaluateFormulaCell(c);
|
|
||||||
if (evalResult == CellType.ERROR) {
|
|
||||||
logger.warning("...unable to evaluate cell " + cell);
|
|
||||||
}
|
|
||||||
} catch (Exception poie) {
|
|
||||||
logger.warning("...failed to evaluate cell " + cell + " : " + poie.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -14,9 +14,6 @@
|
||||||
<li>
|
<li>
|
||||||
<h:link outcome="/pages/admin/analyse_invoicing">Analyse Rechnungseingang</h:link>
|
<h:link outcome="/pages/admin/analyse_invoicing">Analyse Rechnungseingang</h:link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<h:link outcome="/pages/admin/dataViewDefinitions">Data Views</h:link>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<h:link outcome="/pages/admin/excel_export_rechnungsausgang">Excel Export Rechnungsausgang</h:link>
|
<h:link outcome="/pages/admin/excel_export_rechnungsausgang">Excel Export Rechnungsausgang</h:link>
|
||||||
|
|
|
||||||
6
pom.xml
6
pom.xml
|
|
@ -294,6 +294,12 @@
|
||||||
<version>${org.imixs.data.version}</version>
|
<version>${org.imixs.data.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.imixs.workflow</groupId>
|
||||||
|
<artifactId>imixs-data-views</artifactId>
|
||||||
|
<version>${org.imixs.data.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Melman Version Management hinzufügen -->
|
<!-- Melman Version Management hinzufügen -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue