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
|
||||
|- Neue Plugin Logik (Aktualisierung der BP Nummer und Aktivierung von BP Objekten falls diese archiviert waren)
|
||||
- Zoho Schnittstelle
|
||||
- Neues DataView und DataGroups Konzept implementiert
|
||||
|
||||
### Migration
|
||||
|
||||
|
|
|
|||
|
|
@ -88,10 +88,10 @@ services:
|
|||
###############################################
|
||||
# Imixs-Admin
|
||||
###############################################
|
||||
imixsadmin:
|
||||
image: imixs/imixs-admin
|
||||
ports:
|
||||
- "8888:8080"
|
||||
# imixsadmin:
|
||||
# image: imixs/imixs-admin
|
||||
# ports:
|
||||
# - "8888:8080"
|
||||
|
||||
###############################################
|
||||
# Mailgateway
|
||||
|
|
|
|||
|
|
@ -282,6 +282,10 @@
|
|||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-data-groups</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.imixs.workflow</groupId>
|
||||
<artifactId>imixs-data-views</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SEPA Adapter -->
|
||||
<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.XSSFWorkbook;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.dataview.DataViewExportEvent;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.WorkflowService;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
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.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>
|
||||
<h:link outcome="/pages/admin/analyse_invoicing">Analyse Rechnungseingang</h:link>
|
||||
</li>
|
||||
<li>
|
||||
<h:link outcome="/pages/admin/dataViewDefinitions">Data Views</h:link>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<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>
|
||||
<scope>compile</scope>
|
||||
</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 -->
|
||||
<dependency>
|
||||
|
|
|
|||
Loading…
Reference in a new issue