neuer Op-Listen Controller

This commit is contained in:
Ralph Soika 2024-04-10 15:17:31 +02:00
parent cc01330439
commit 77d3e1b391
6 changed files with 1583 additions and 36 deletions

View file

@ -73,7 +73,6 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
@Inject
SnapshotService snapshotService;
/**
* This method finds or create the Zahlungsavis and adds a reference
* ($workitemref) to the current invoice.
@ -115,7 +114,7 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
// now we add separate lines for each invoice....
logger.info("... insert invoices - filter="+filter);
logger.info("... insert invoices - filter=" + filter);
insertInvoiceRows(document, targetName, filter);
} catch (PluginException | IOException | QueryException e) {
throw new PluginException(OPListExportAdapter.class.getSimpleName(), ERROR_CONFIG,
@ -342,10 +341,10 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
}
/**
* Diese Methode groupiert eine Rechnugnsliste nach Debitorennummern
* Diese Methode gruppiert eine Rechnungsliste nach Debitorennummern
*
* Falls 'filter==true' werden nur Rechnungen ab der 2. Mahnung oder mit einer
* Fälligkeit >21 Tage ausgegeben
* Fälligkeit >21 Tage ausgegeben. Dieses Flag wird im Workflowmodell gesetzt
*
* @param spaceID
* @return
@ -372,7 +371,7 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
if (filter) {
Date date = invoice.getItemValueDate("invoice.duedate");
if (OPListExportAdapter.isOverdue(date, invoice.getTaskID())) {
//logger.info("...invoice - " +invoice.getUniqueID() + " is in overdue");
// logger.info("...invoice - " +invoice.getUniqueID() + " is in overdue");
invoiceList.add(invoice);
}
} else {
@ -381,7 +380,7 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
}
// speicher wieder die neue liste wenn es mindestens eine Rechnung gab
if (invoiceList.size()>0) {
if (invoiceList.size() > 0) {
result.put(dbtrNumber, invoiceList);
}
@ -392,13 +391,13 @@ public class OPListExportAdapter extends POIFindReplaceAdapter {
}
return result;
}
}
public static boolean isOverdue(Date date, int taskid) {
Date now = new Date();
long diffInMillies = now.getTime() - date.getTime();
int tage = (int) (diffInMillies / 1000 / 60 / 60 / 24);
//logger.info("...taskid=" + taskid + " date=" + date + " tage=" + tage);
// logger.info("...taskid=" + taskid + " date=" + date + " tage=" + tage);
return ((taskid >= TASK_MAHNUNG_2ND && taskid <= TASK_MAHNUNG_LAST) || tage >= 21);
}

View file

@ -0,0 +1,465 @@
package com.alexanderlogistics;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.inject.Inject;
import org.apache.poi.ss.usermodel.CellCopyPolicy;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.imixs.archive.core.SnapshotService;
import org.imixs.marty.team.TeamService;
import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.ItemCollectionComparator;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.poi.POIFindReplaceAdapter;
/**
* Der OPListExportAdapterByWeek ist ählnlich dem Der OPListExportAdapter. Er
* erzeugt eine Excel tabelle mit allen offenen Rechnungen und gruppiert diese
* nach Abteilungen und KW
*
* Der OPListExportAdapterByWeek importiert eine Excel Datei aus einem Textblock
*
* <pre>
* {@code
<opliste name="textblock">textblock-ref</opliste>
<opliste name="template">filename</opliste>
<opliste name="targetname">filename</opliste>
}
* </pre>
* <p>
* Der Adapter erweitert den POIAdapter somit können felder aktualisiert werden
* (siehe POIFineReplaceAdapter).
*
* <p>
* Der Adapter kopiert die Rechnungsdaten in neue Zeilen, welche ab Zeilnenummer
* 16 eingefügt werden.
* <p>
*
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
*
* @version 1.0
* @author rsoika
*/
public class OPListExportAdapterByWeek extends POIFindReplaceAdapter {
private static Logger logger = Logger.getLogger(OPListExportAdapterByWeek.class.getName());
public static final String ERROR_CONFIG = "CONFIG_ERROR";
public static final int TASK_MAHNUNG_2ND = 5210;
public static final int TASK_MAHNUNG_LAST = 5220;
final String TYPE_TEXTBLOCK = "textblock";
@Inject
WorkflowService workflowService;
@Inject
DocumentService documentService;
@Inject
SnapshotService snapshotService;
@Inject
TeamService teamService;
// cache for all invoices grouped by week
Map<String, List<ItemCollection>> invoiceMap = null;
/**
* This method finds or create the Zahlungsavis and adds a reference
* ($workitemref) to the current invoice.
*
* @throws PluginException
*/
@SuppressWarnings("unchecked")
@Override
public ItemCollection execute(ItemCollection document, ItemCollection event)
throws AdapterException, PluginException {
// read the opliste options
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "opliste", document, false);
if (evalItemCollection == null) {
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), ERROR_CONFIG,
"missing op-list configuration in model event - please check model configuration");
}
String textblock = evalItemCollection.getItemValueString("textblock");
String template = evalItemCollection.getItemValueString("template");
String targetName = evalItemCollection.getItemValueString("target-name");
// adapt text....
targetName = workflowService.adaptText(targetName, document);
appendExcelTemplate(document, textblock, template, targetName);
logger.info("... loading poi configuration..");
// Process POI instructions
// read the config
ItemCollection poiConfig = workflowService.evalWorkflowResult(event, "poi-update", document, false);
if (poiConfig == null || !poiConfig.hasItem("findreplace")) {
throw new PluginException(POIFindReplaceAdapter.class.getSimpleName(), CONFIG_ERROR,
"missing poi configuration");
}
List<String> replaceDevList = poiConfig.getItemValue("findreplace");
String eval = poiConfig.getItemValueString("eval");
try {
logger.info("... update template with normal poi information..");
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
insertInvoiceRows(document, targetName);
} catch (PluginException | IOException | QueryException e) {
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), ERROR_CONFIG,
"failed to update op-liste: " + e.getMessage());
}
logger.info("... completed!");
return document;
}
/**
* This helper method inserts a row for each invoice of the OPListe at row 16
* into the excel template file
* <p>
* First the method computes all Departments and insert them at C10
* <p>
* The method copies the Row A16 as a reference row
* <p>
* The named cell 'TOTAL' should contain the summary formula. It will be
* evaluated at the end.
*
* @throws PluginException
* @throws QueryException
*/
private void insertInvoiceRows(ItemCollection document, String fileName)
throws PluginException, QueryException {
double saldoUSD = 0;
double saldoEUR = 0;
List<String> spaceNames = new ArrayList<String>();
// compute all departments
List<ItemCollection> spaces = teamService.getSpaces();
// sort by space.name
Collections.sort(spaces, new ItemCollectionComparator("space.name", true));
Map<String, WeekInvoiceData> weekDataMap = new HashMap<String, WeekInvoiceData>();
FileData fileData = document.getFileData(fileName);
// load XSSFWorkbook
XSSFWorkbook doc = null;
try (InputStream imputStream = new ByteArrayInputStream(fileData.getContent())) {
doc = new XSSFWorkbook(imputStream);
// compute current week
Calendar calendar = new GregorianCalendar();
calendar.setTime(new Date());
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
int year = calendar.get(Calendar.YEAR);
String currentWeek = year + "/";
if (weekNumber < 10) {
currentWeek = currentWeek + "0" + weekNumber;
} else {
currentWeek = currentWeek + weekNumber;
}
CellStyle headerCellStyle = doc.createCellStyle();
// fill foreground color ...
headerCellStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.index);
// and solid fill pattern produces solid grey cell fill
headerCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// NOTE: we only take the first sheet !
XSSFSheet sheet = doc.getSheetAt(0);
// First we create a column for each Space.....
XSSFRow rowSpacesLabels = sheet.getRow(9);
XSSFCellStyle superDuperStyle = rowSpacesLabels.getCell(0).getCellStyle();
XSSFRow rowSpacesCurrencies = sheet.getRow(10);
XSSFRow rowValues = sheet.getRow(11);
XSSFCell cellSpaceLabelReference = rowSpacesLabels.getCell(1);
XSSFCell cellSpaceCurrencyReference = rowSpacesLabels.getCell(1);
int column = 1;
for (ItemCollection space : spaces) {
String spaceName = space.getItemValueString("space.name");
String spaceID = space.getUniqueID();
spaceNames.add(spaceName);
// Space Labe
XSSFCell cell = rowSpacesLabels.getCell(column);
// cell.copyCellFrom(cellSpaceLabelReference, new CellCopyPolicy());
cell.setCellValue(spaceName);
// Space currency EUR
cell = rowSpacesCurrencies.getCell(column);
cell.copyCellFrom(cellSpaceCurrencyReference, new CellCopyPolicy());
cell.setCellValue("EUR");
// Space currency USD
column++;
cell = rowSpacesCurrencies.getCell(column);
cell.copyCellFrom(cellSpaceCurrencyReference, new CellCopyPolicy());
cell.setCellValue("USD");
// create two new cells...
cell = rowSpacesLabels.createCell(column);
cell.copyCellFrom(cellSpaceLabelReference, new CellCopyPolicy());
cell.setCellValue("");
column++;
cell = rowSpacesLabels.createCell(column);
cell.copyCellFrom(cellSpaceLabelReference, new CellCopyPolicy());
cell.setCellValue("");
logger.info("...grouping invoices by week...");
// collect all invoices for this space grouped by week....
groupInvoicesByWeek(spaceID, spaceName, weekDataMap);
}
// now build a new row for each week and print out the collected invoice data
// first iterate over all objects and collect all known weeks and sort them into
// a ordered list....
List<String> sortedWeekList = new ArrayList<String>();
Iterator<Map.Entry<String, WeekInvoiceData>> iterator = weekDataMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, WeekInvoiceData> entry = iterator.next();
WeekInvoiceData weekInvoiceData = entry.getValue();
if (!sortedWeekList.contains(weekInvoiceData.week)) {
sortedWeekList.add(weekInvoiceData.week);
}
}
Collections.sort(sortedWeekList);
int rowPos = 11;
for (String week : sortedWeekList) {
// now create a new line..
rowPos++;
XSSFRow row = sheet.createRow(rowPos);
row.copyRowFrom(rowValues, new CellCopyPolicy());
// insert values
row.getCell(0).setCellValue(week);
// iterate over all spaceNames and test if we have any data to put it into the
// row cells....
column = 1;
for (String name : spaceNames) {
String key = name + "/" + week;
logger.info("serach WeekInvoiceData for " + key);
// list of invoices
WeekInvoiceData weekData = weekDataMap.get(key);
if (weekData != null) {
logger.info("eur=" + weekData.totalEUR);
row.getCell(column).setCellValue(weekData.totalEUR);
column++;
row.getCell(column).setCellValue(weekData.totalUSD);
} else {
logger.info("...... NOT FOUND");
// skip columns
column = column + 2;
}
}
if (currentWeek.equals(week)) {
for (int i = 0; i < 15; i++) {
row.getCell(i).setCellStyle(superDuperStyle);
}
}
}
// write back the file
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
doc.write(byteArrayOutputStream);
byte[] newContent = byteArrayOutputStream.toByteArray();
FileData fileDataNew = new FileData(fileData.getName(), newContent, fileData.getContentType(), null);
// update the fileData
document.addFileData(fileDataNew);
logger.finest("......new document added");
} catch (IOException e) {
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), ERROR_CONFIG,
"failed to update opliste: " + e.getMessage());
} finally {
if (doc != null) {
try {
doc.close();
} catch (IOException e) {
logger.severe("Failed to close workbook: " + e.getMessage());
e.printStackTrace();
}
}
}
}
/**
* This method loads a text-block for a specified ref and appends the named
* fileData object of this document.
*
* @param document
* @throws PluginException
*/
private void appendExcelTemplate(ItemCollection document, String textblockRef, String template, String targetName)
throws PluginException {
if ((template == null || template.isEmpty()) || (textblockRef == null || textblockRef.isEmpty())) {
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), ERROR_CONFIG,
"invalid op-list configuration in model event - textblock/template reference not defined!");
}
// load the text block
FileData fileData = loadTextBlockFileData(textblockRef, template);
// do we found the document?
if (fileData == null) {
throw new PluginException(OPListExportAdapterByWeek.class.getSimpleName(), ERROR_CONFIG,
"invalid op-list configuration in model event - template=" + template + " not found!");
}
fileData.setName(targetName);
// append document
logger.info("...append new op-list Template: " + targetName);
document.addFileData(fileData);
}
/**
* This method returns a text-block ItemCollection for a specified name.
*
* @param name in attribute txtname
*
*
*/
public FileData loadTextBlockFileData(String name, String fileName) {
ItemCollection textBlockItemCollection = null;
// load text-block by name....
String sQuery = "(type:\"" + TYPE_TEXTBLOCK + "\" AND txtname:\"" + name + "\")";
Collection<ItemCollection> col;
try {
// find the textblock...
col = documentService.find(sQuery, 1, 0);
if (col.size() > 0) {
textBlockItemCollection = col.iterator().next();
// fetch the fileData...
return snapshotService.getWorkItemFile(textBlockItemCollection.getUniqueID(), fileName);
} else {
logger.warning("Missing text-block : '" + name + "'");
}
} catch (QueryException e) {
logger.warning("getTextBlock - invalid query: " + e.getMessage());
}
return null;
}
/**
* Diese Methode gruppiert eine Rechnungsliste nach Kalenderwoche
*
* @param spaceID - Space Ref to select a list of invoices assoicated with a
* space
* @param cache - a local cache storing all invoices by week
*
*
*/
private void groupInvoicesByWeek(String spaceID, String spaceName,
Map<String, WeekInvoiceData> cache) {
logger.info("...group invoices for " + spaceID);
try {
List<ItemCollection> invoices = documentService.find(
"$modelversion:rechnungsausgang-* AND type:workitem AND $uniqueidref:" + spaceID, 9999, 0,
"invoice.number", false);
for (ItemCollection invoice : invoices) {
// compute Week
Date dueDate = invoice.getItemValueDate("invoice.duedate");
Calendar calendar = new GregorianCalendar();
calendar.setTime(dueDate);
int weekNumber = calendar.get(Calendar.WEEK_OF_YEAR);
int year = calendar.get(Calendar.YEAR);
String weekCategory = year + "/";
if (weekNumber < 10) {
weekCategory = weekCategory + "0" + weekNumber;
} else {
weekCategory = weekCategory + weekNumber;
}
// haben wir shon ein listchen?
String key = spaceName + "/" + weekCategory;
logger.info("....building weekInvoiceData object for " + key);
WeekInvoiceData weekData = cache.get(key);
if (weekData == null) {
weekData = new WeekInvoiceData(spaceName, weekCategory);
}
// Jetzt Rechnung addieren
weekData.add(invoice);
cache.put(key, weekData);
}
} catch (
QueryException e) {
e.printStackTrace();
}
}
}
/**
* Data Element for invoice totals per week and space
*/
class WeekInvoiceData {
String week;
String spaceName;
double totalEUR;
double totalUSD;
public WeekInvoiceData(String spaceName, String week) {
this.spaceName = spaceName;
this.week = week;
}
public void add(ItemCollection invoice) {
String spaceName = invoice.getItemValueString("space.name");
String currency = invoice.getItemValueString("invoice.currency");
Double total = invoice.getItemValueDouble("invoice.total");
if ("EUR".equals(currency)) {
totalEUR = totalEUR + total;
} else {
totalUSD = totalUSD + total;
}
}
}

View file

@ -1,4 +1,5 @@
package com.alexanderlogistics;
/*******************************************************************************
* Imixs Workflow Technology
* Copyright (C) 2003, 2008 Imixs Software Solutions GmbH,
@ -25,7 +26,6 @@ package com.alexanderlogistics;
import java.util.logging.Logger;
import javax.ejb.Timer;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
@ -33,20 +33,12 @@ import javax.inject.Named;
import org.imixs.workflow.engine.scheduler.SchedulerController;
/**
* The DatevController is used to configure the DatevScheduler. This service is
* used to generate datev export workitems.
* The OPListExportController is used to configure the OpListeExporterService.
* This service is
* used to export workitems.
* <p>
* The Controller creates a configuration entity "type=configuration;
* txtname=datev".
* <p>
* The following config items are defined:
*
* The following config items are defined:
*
* <pre>
* _model_version = model version for the SEPA export
* _initial_task = inital task ID
* </pre>
* txtname=OPLIST_EXPORT_CONFIGURATION".
*
*
* @author rsoika
@ -61,10 +53,9 @@ public class OPListExportController extends SchedulerController {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(OPListExportController.class.getName());
@Inject
OPListExportScheduler opListExportScheduler;
@Override
public String getName() {
return OPLIST_EXPORT_CONFIGURATION;
@ -83,8 +74,4 @@ public class OPListExportController extends SchedulerController {
return schedulerClass;
}
}

View file

@ -50,7 +50,7 @@ import org.imixs.workflow.exceptions.ProcessingErrorException;
import org.imixs.workflow.exceptions.QueryException;
/**
* The OPListExportScheduler erzeugt für jeden Berich ein neues Workitem mit
* The OPListExportScheduler erzeugt für jeden Bereich ein neues Workitem mit
* einer Excel Datei mit allen offenen Rechnungen.
* <p>
* bei den OP Listen für die Abteilungen dürfen nur Rechnungen aktiviert werden,
@ -71,7 +71,7 @@ public class OPListExportScheduler implements Scheduler {
public static final String OPLIST_ERROR = "OPLIST_ERROR";
public static final int TASK_MAHNUNG_2ND = 5210;
public static final int TASK_MAHNUNG_LAST = 5220;
public static DateFormat dateFormat = new SimpleDateFormat("ddMMyyyy");
public static DecimalFormat decimalFormat = new DecimalFormat("0.00",
new DecimalFormatSymbols(java.util.Locale.GERMANY));
@ -113,7 +113,7 @@ public class OPListExportScheduler implements Scheduler {
workitem.setItemValue(WorkflowKernel.CREATED, new Date());
processOPListe(workitem);
} else {
logger.info("....no invoices in overdue for "+space.getItemValueString("name"));
logger.info("....no invoices in overdue for " + space.getItemValueString("name"));
}
}
@ -150,18 +150,14 @@ public class OPListExportScheduler implements Scheduler {
}
for (ItemCollection invoice : invoices) {
Date date = invoice.getItemValueDate("invoice.duedate");
if (OPListExportAdapter.isOverdue(date,invoice.getTaskID())) {
Date date = invoice.getItemValueDate("invoice.duedate");
if (OPListExportAdapter.isOverdue(date, invoice.getTaskID())) {
return true;
}
}
return false;
}
@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public void processOPListe(ItemCollection workitem)
throws PluginException, AccessDeniedException, ProcessingErrorException, ModelException {

Binary file not shown.

File diff suppressed because it is too large Load diff