office-alexander-logistics/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/ZahlungsavisExportAdapter.java

255 lines
No EOL
10 KiB
Java

package com.alexanderlogistics;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
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.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.AdapterException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.poi.POIFindReplaceAdapter;
import jakarta.inject.Inject;
/**
* Der ZahlungsavisAdapter importiert eine Excel Datei aus einem Textblock
*
* <pre>
* {@code
<zahlungsavis name="textblock">textblock-ref</zahlungsavis>
<zahlungsavis name="template">filename</zahlungsavis>
<zahlungsavis name="targetname">filename</zahlungsavis>
}
* </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>
* Dabei werden Gutschriften in spalte E und Rechnungen in Spalte F eingetrgen.
* <p>
* Abschliessend wird die Zelle 'TOTAL' noch aktualisiert.
*
* @version 1.0
* @author rsoika
*/
public class ZahlungsavisExportAdapter extends POIFindReplaceAdapter {
private static Logger logger = Logger.getLogger(ZahlungsavisExportAdapter.class.getName());
public static final String ERROR_CONFIG = "CONFIG_ERROR";
final String TYPE_TEXTBLOCK = "textblock";
@Inject
WorkflowService workflowService;
@Inject
DocumentService documentService;
@Inject
SnapshotService snapshotService;
/**
* 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 zahlungsavis options
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "zahlungsavis", document, false);
if (evalItemCollection == null) {
throw new PluginException(ZahlungsavisExportAdapter.class.getSimpleName(), ERROR_CONFIG,
"missing zahlungsavis 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);
// 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 {
this.updateFileData(document.getFileData(targetName), document, replaceDevList, eval);
} catch (PluginException | IOException e) {
throw new PluginException(ZahlungsavisExportAdapter.class.getSimpleName(), ERROR_CONFIG,
"failed to update zahlungsavis - wrong POI configuraiton: " + e.getMessage());
}
// now we add separate lines for each invoice....
insertInvoiceRows(document, targetName);
return document;
}
/**
* This helper method inserts a row for each invoice of the current Zahlunsavis
* at row 16 into the excel template file
* <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
*/
@SuppressWarnings("unchecked")
private void insertInvoiceRows(ItemCollection document, String fileName) throws PluginException {
List<String> invoiceIDs = document.getItemValue("$workitemref");
FileData fileData = document.getFileData(fileName);
// 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("A16");
XSSFRow referenceRow = sheet.getRow(cr.getRow());
int referenceRowPos = 16;
int rowPos = 16;
// int lastRow = sheet.getLastRowNum();
int lastRow = 999;
logger.finest("Last rownum=" + lastRow);
sheet.shiftRows(rowPos, lastRow, invoiceIDs.size(), true, true);
for (String invoiceID : invoiceIDs) {
logger.finest("......copy row...");
ItemCollection invoice = documentService.load(invoiceID);
// now create a new line..
XSSFRow row = sheet.createRow(rowPos);
row.copyRowFrom(referenceRow, new CellCopyPolicy());
// insert values
row.getCell(0).setCellValue(invoice.getItemValueString("numsequencenumber"));
row.getCell(1).setCellValue(invoice.getItemValueDate("invoice.date"));
row.getCell(2).setCellValue(invoice.getItemValueString("invoice.number"));
row.getCell(3).setCellValue(invoice.getItemValueDate("invoice.duedate"));
if ("credit".equals(invoice.getItemValueString("payment.type"))) {
// Gutschrift
row.getCell(4).setCellValue(invoice.getItemValueDouble("invoice.total"));
row.getCell(5).setCellValue(0.00);
} else {
// Rechnung
row.getCell(4).setCellValue(0.00);
row.getCell(5).setCellValue(invoice.getItemValueDouble("invoice.total"));
}
rowPos++;
}
// delete reference row 16
sheet.shiftRows(referenceRowPos, lastRow + invoiceIDs.size(), -1, true, true);
// finally update the total formula...
evalXSSFSheet(doc, sheet, "TOTAL");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// write back the file
doc.write(byteArrayOutputStream);
doc.close();
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(ZahlungsavisExportAdapter.class.getSimpleName(), ERROR_CONFIG,
"failed to update zahlungsavis: " + e.getMessage());
}
}
/**
* 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(ZahlungsavisExportAdapter.class.getSimpleName(), ERROR_CONFIG,
"invalid zahlungsavis 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(ZahlungsavisExportAdapter.class.getSimpleName(), ERROR_CONFIG,
"invalid zahlungsavis configuration in model event - template=" + template + " not found!");
}
fileData.setName(targetName);
// append document
logger.info("...append new Zahlugnsavis 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;
}
}