office-alexander-logistics/src/main/java/com/alexanderlogistics/ksef/api/KSeFAPIService.java

730 lines
30 KiB
Java

package com.alexanderlogistics.ksef.api;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
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.PluginException;
import org.imixs.workflow.exceptions.QueryException;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RolesAllowed;
import jakarta.annotation.security.RunAs;
import jakarta.ejb.Singleton;
import jakarta.inject.Inject;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import jakarta.json.JsonString;
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.JsonbBuilder;
/**
* THe KSeFAPIService provides methods to open an interactive session and upload
* an invoice.
*
*/
@DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@Singleton
@RunAs("org.imixs.ACCESSLEVEL.MANAGERACCESS")
public class KSeFAPIService {
private static Logger logger = Logger.getLogger(KSeFAPIService.class.getName());
public static final String ERROR_API = "API_ERROR";
public static final String DOCUMENT_ERROR = "DOCUMENT_ERROR";
public static final String CONFIG_ERROR = "CONFIG_ERROR";
final String TYPE_TEXTBLOCK = "textblock";
@Inject
KSeFAuthManager kseFAuthManager;
@Inject
DocumentService documentService;
@Inject
WorkflowService workflowService;
@Inject
SnapshotService snapshotService;
/**
* This method uploads a KSeF Invoice document (XML).
* The response of the upload is a 'referenceNumber' which is stored into the
* item ksef.referenceNumber
*
* @param workitem workitem containing the invoice
* @param fileName name of the XML file to upload
* @return referenceNumber from KSeF
* @throws PluginException
*/
public void uploadInvoice(ItemCollection workitem, String fileName) throws PluginException {
// First open an interactive session (reuses existing if valid)
kseFAuthManager.openSession(workitem);
logger.info("├── 📤 Upload Invoice...");
// Validate session
if (kseFAuthManager.getAccessToken() == null) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"API Error - missing AccessToken!");
}
if (kseFAuthManager.getSessionRefNumber() == null) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"API Error - missing SessionRefNumber!");
}
if (kseFAuthManager.getSessionEncryption() == null) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"API Error - missing Session Encryption!");
}
// Load invoice XML
byte[] invoiceXml = null;
FileData fileData = workitem.getFileData(fileName);
// test if we need to load the snapshot data...
if (fileData.getContent().length == 0) {
fileData = snapshotService.getWorkItemFile(workitem.getUniqueID(), fileName);
if (fileData != null) {
invoiceXml = fileData.getContent();
}
} else {
invoiceXml = fileData.getContent();
}
logger.info("│ ├── XML Invoice loaded - " + invoiceXml.length + " bytes");
try {
// Get the session encryption keys (already sent to KSeF during session
// creation!)
SessionEncryption encryption = kseFAuthManager.getSessionEncryption();
// Encrypt invoice with session keys
byte[] encryptedInvoice = encryptInvoiceWithSessionKeys(invoiceXml, encryption);
// Calculate hashes
String invoiceHash = calculateSHA256Hash(invoiceXml);
workitem.setItemValue("ksef.invoiceHash", invoiceHash);
String encryptedInvoiceHash = calculateSHA256Hash(encryptedInvoice);
workitem.setItemValue("ksef.encryptedInvoiceHash", encryptedInvoiceHash);
// Build JSON request body
String jsonBody = String.format(
"{" +
"\"invoiceHash\": \"%s\"," +
"\"invoiceSize\": %d," +
"\"encryptedInvoiceHash\": \"%s\"," +
"\"encryptedInvoiceSize\": %d," +
"\"encryptedInvoiceContent\": \"%s\"," +
"\"offlineMode\": false" +
"}",
invoiceHash,
invoiceXml.length,
encryptedInvoiceHash,
encryptedInvoice.length,
Base64.getEncoder().encodeToString(encryptedInvoice));
// Send upload request
String uri = kseFAuthManager.getBaseURI() + "/sessions/online/"
+ kseFAuthManager.getSessionRefNumber() + "/invoices";
logger.info("│ ├── POST: " + uri);
if (kseFAuthManager.isDebug()) {
logger.info("│ ├── Request Body: " + jsonBody);
}
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + kseFAuthManager.getAccessToken())
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = kseFAuthManager.getHttpClient().send(
request, HttpResponse.BodyHandlers.ofString());
logger.info("│ ├── HTTP Response: " + response.statusCode());
if (kseFAuthManager.isDebug()) {
logger.info("│ ├── Response Body: " + response.body());
}
if (response.statusCode() != 202) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"Invoice upload failed with status: " + response.statusCode() +
" - " + response.body());
}
// Parse response and get reference number
String referenceNumber = null;
try (Jsonb jsonb = JsonbBuilder.create()) {
JsonObject jsonObject = jsonb.fromJson(response.body(), JsonObject.class);
referenceNumber = jsonObject.getString("referenceNumber");
logger.info("│ ├── Reference Number: " + referenceNumber);
} catch (Exception e) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"Error parsing upload response: " + e.getMessage());
}
// Store reference number in file metadata
List<Object> textlist = new ArrayList<>();
textlist.add(referenceNumber);
fileData.setAttribute("ksef.referenceNumber", textlist);
workitem.setItemValue("ksef.referenceNumber", referenceNumber);
logger.info("├── ✅ Upload successful - Reference: " + referenceNumber);
// Close Session
kseFAuthManager.closeInteractiveSession();
// Status abfragen
// Now we need to wait until auth/{AuthRef} will return 200
int code = -1;
long start = System.currentTimeMillis();
long timeout = 150_000; // 2,5 Minuten
boolean timeoutStatus = true;
while (System.currentTimeMillis() - start < timeout) {
code = kseFAuthManager.checkSessionStatus(workitem);
if (code >= 200) {
timeoutStatus = false;
break; // ok or broken
}
// kleine Pause, um CPU zu schonen
kseFAuthManager.waitSomeTime(3000);
}
if (timeoutStatus) {
logger.severe("├── ⚠️ Status timeout");
throw new PluginException(KSeFAuthManager.class.getSimpleName(), "Session Status: " + code,
"Invoice was not processed within expected timeout " + timeout + " upload canceled");
}
// In case we have an error we print out the reason...
if (code > 200) {
checkSessionStatusInvoices(workitem);
// convert KSeF Error status into a PluginException
String errorCode = workitem.getItemValueString("ksef.status.code");
String errorMessage = workitem.getItemValueString("ksef.status.description");
throw new PluginException(KSeFAuthManager.class.getSimpleName(), errorCode,
errorMessage);
}
// if status code 200 and if we have a ksef.upo.referencenumber we download the
// document
if (code == 200 && !referenceNumber.isEmpty()) {
checkSessionStatusInvoices(workitem);
FileData upoFileData = downloadUOPXML(workitem);
workitem.addFileData(upoFileData);
// store verification url
generateVerificationUrl(workitem);
// store QR Code
generateQRCode(workitem);
// print QR Code to pdf
embedQRCode(workitem);
}
} catch (IOException | NoSuchAlgorithmException | InterruptedException e) {
logger.severe("├── ⚠️ Invoice upload failed: " + e.getMessage());
kseFAuthManager.closeInteractiveSession();
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"Invoice upload failed: " + e.getMessage());
} finally {
// finally we close the session
kseFAuthManager.deleteCurrentAuthSession();
}
}
/**
* This method verifies the actual status of the status of all invoices
*
* The method returns the aut status code (not the HTTP Response code!)
*
* https://ksef-test.mf.gov.pl/docs/v2/index.html#tag/Status-wysylki-i-UPO/paths/~1api~1v2~1sessions~1%7BreferenceNumber%7D/get
*
* @return Session Status Code
* @throws PluginException
*/
public void checkSessionStatusInvoices(ItemCollection workitem) throws PluginException {
logger.info("├── 🚸 KSeF API check session invoice status...");
String uri = kseFAuthManager.getBaseURI() + "/sessions/" + kseFAuthManager.getSessionRefNumber() + "/invoices";
int httpResponse = -1;
int statusCode = -1;
String statusDescription;
logger.info("│ ├── GET: " + uri);
HttpResponse<String> response = null;
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + kseFAuthManager.getAccessToken())
.GET()
.build();
response = kseFAuthManager.getHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"API Error: Unable to request auth status: " + e.getMessage());
}
httpResponse = response.statusCode();
logger.info("│ ├── HTTP Response: " + httpResponse);
logger.info("│ ├── " + response.body());
try (Jsonb jsonb = JsonbBuilder.create()) {
JsonObject jsonObject = jsonb.fromJson(response.body(), JsonObject.class);
// Extract status from the first invoice in the invoices array
if (jsonObject.containsKey("invoices")) {
JsonArray invoicesArray = jsonObject.getJsonArray("invoices");
if (invoicesArray != null && !invoicesArray.isEmpty()) {
JsonObject firstInvoice = invoicesArray.getJsonObject(0);
if (firstInvoice.containsKey("ksefNumber")) {
String ksefNumber = firstInvoice.getString("ksefNumber");
logger.info("│ ├── ksefNumber: " + ksefNumber);
workitem.setItemValue("ksef.number", ksefNumber);
}
// Status Code aus dem status-Objekt extrahieren
if (firstInvoice.containsKey("status")) {
JsonObject statusObject = firstInvoice.getJsonObject("status");
if (statusObject.containsKey("code")) {
statusCode = statusObject.getInt("code");
statusDescription = statusObject.getString("description");
// Convert details array to a single string
if (statusObject.containsKey("details")) {
JsonArray detailsArray = statusObject.getJsonArray("details");
String details = detailsArray.stream()
.map(v -> ((JsonString) v).getString())
.collect(Collectors.joining("; "));
statusDescription = statusDescription + ": " + details;
}
logger.info("│ ├── Status Code: " + statusCode);
workitem.setItemValue("ksef.status.code", statusCode);
workitem.setItemValue("ksef.status.description", statusDescription);
}
}
} else {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"Unable to read invoice status from interactive session!");
}
}
} catch (Exception e) {
logger.severe("├── ⚠️ Error parsing JSON response: " + e.getMessage());
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"Error parsing JSON response: " + e.getMessage());
}
}
/**
* This method downloads the UPO XML document based on the KSeF reference
* number
*
* https://ksef-test.mf.gov.pl/docs/v2/index.html#tag/Status-wysylki-i-UPO/paths/~1api~1v2~1sessions~1%7BreferenceNumber%7D~1invoices~1%7BinvoiceReferenceNumber%7D~1upo/get
*
* @return Session Status Code
* @throws PluginException
*/
public FileData downloadUOPXML(ItemCollection workitem) throws PluginException {
String ksefRefNumber = workitem.getItemValueString("ksef.referenceNumber");
if (ksefRefNumber == null || ksefRefNumber.isEmpty()) {
logger.severe("├── ⚠️ Error parsing ksef.referenceNumber");
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"Error parsing ksef.referenceNumber");
}
logger.info("├── 📥 KSeF API download UPO XML...");
String uri = kseFAuthManager.getBaseURI() + "/sessions/" + kseFAuthManager.getSessionRefNumber()
+ "/invoices/" + ksefRefNumber + "/upo";
int httpResponse = -1;
logger.info("│ ├── GET: " + uri);
HttpResponse<String> response = null;
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + kseFAuthManager.getAccessToken())
.GET()
.build();
response = kseFAuthManager.getHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"API Error: Unable to request auth status: " + e.getMessage());
}
httpResponse = response.statusCode();
logger.info("│ ├── HTTP Response: " + httpResponse);
if (kseFAuthManager.isDebug()) {
logger.info("│ ├── " + response.body());
}
FileData fileData = new FileData(ksefRefNumber + ".xml", response.body().getBytes(), "application/xml", null);
return fileData;
}
/**
* Generate KSeF verification URL for QR code (KOD I) and stores the URL into
* the item ksef.VerificationUrl
*
* @param workitem
*/
public void generateVerificationUrl(ItemCollection workitem) throws NoSuchAlgorithmException {
logger.info("├── 🔲 Generate QR-Code...");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
String invoiceDate = formatter.format(workitem.getItemValueLocalDate("invoice.date"));
String baseURL = kseFAuthManager.getBaseURI();
String invoiceHash = workitem.getItemValueString("ksef.invoiceHash");
byte[] decoded = Base64.getDecoder().decode(invoiceHash);
// Base64URL ohne Padding
String base64Url = Base64.getUrlEncoder().withoutPadding().encodeToString(decoded);
// Die Client App URL muss angepasst werden. Das /v2/ element aus der Basis URL
// muss mit 'client-app/invoice' ausgetauscht werden.
// Es entsteht dann https://api-test.ksef.mf.gov.pl/client-app/invoice/
// BASE URL: https://api.ksef.mf.gov.pl/api/v2"
// /api/v2 muss ersetzt werden:
baseURL = baseURL.replace("/api/v2", "/client-app/invoice");
// remove resource /api/
// https://api.ksef.mf.gov.pl/api/client-app/invoice/9552521552/01-04-2026/88Yl-F_6vhLeMUONRz2LBcAHF21NpbLk7ikm4ZqV1bg
// =>
// https://api.ksef.mf.gov.pl/client-app/invoice/9552521552/01-04-2026/88Yl-F_6vhLeMUONRz2LBcAHF21NpbLk7ikm4ZqV1bg
// Build verification URL
workitem.setItemValue("ksef.VerificationUrl",
baseURL + "/" + kseFAuthManager.getKsefNip() + "/" + invoiceDate + "/"
+ base64Url);
}
/**
* Generates a QR code image.
*
* If the generation fails we simply print a warning but do not stop the
* complete process.
*
* @param text
* @param width
* @param height
* @param filePath
* @throws PluginException
* @throws WriterException
* @throws IOException
*/
public void generateQRCode(ItemCollection workitem) {
QRCodeWriter qrCodeWriter = new QRCodeWriter();
String text = workitem.getItemValueString("ksef.verificationurl");
BitMatrix bitMatrix;
try {
bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, 300, 300);
ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
// store qr code
String ksefRefNumber = workitem.getItemValueString("ksef.referenceNumber");
FileData fileData = new FileData(ksefRefNumber + ".png", pngOutputStream.toByteArray(), "image/png", null);
workitem.addFileData(fileData);
} catch (WriterException | IOException e) {
logger.warning("├── ⚠️ Failed to generate QR Code:: " + e.getMessage());
}
}
/**
* This helper method prints the QR Code on the AGL Invoice document
*
* @param workitem
* @throws PluginException
*/
public void embedQRCode(ItemCollection workitem) {
try {
FileData pdfFileData = this.loadPDF(workitem);
String ksefRefNumber = workitem.getItemValueString("ksef.referenceNumber");
FileData qrCodeFileData = workitem.getFileData(ksefRefNumber + ".png");
if (qrCodeFileData.getContent().length == 0) {
qrCodeFileData = snapshotService.getWorkItemFile(workitem.getUniqueID(), ksefRefNumber + ".png");
}
// now we have the QR Code (qrCodeFileData) and the PDF (pdfFileData)
PDDocument document = PDDocument.load(pdfFileData.getContent());
logger.info("pdf file loaded, embed qrcode...");
// place thee PNG on the first page 10x10 cm from left upper corner
// ....
PDPage page = document.getPage(0);
PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, qrCodeFileData.getContent(),
pdfFileData.getName());
// PDPageContentStream contentStream = new PDPageContentStream(document, page);
PDPageContentStream contentStream = new PDPageContentStream(
document,
page,
PDPageContentStream.AppendMode.APPEND, // Append statt Overwrite
true, // compress
true // resetContext - wichtig für konsistente Grafik-Zustände
);
// Mit Größenangabe (Breite und Höhe in Points):
// QR-Code zeichnen
// Seitenhöhe auslesen
float pageHeight = page.getMediaBox().getHeight();
// Position von OBEN berechnen (z.B. 50 Points vom oberen Rand)
float marginFromTop = 230;
float imageWidth = 50;
float imageHeight = 50;
float imageX = 350;
float imageY = pageHeight - marginFromTop - imageHeight; // Von oben berechnet!
contentStream.drawImage(pdImage, imageX, imageY, imageWidth, imageHeight);
// Text darunter schreiben
String text = "KSeF-No.: " + workitem.getItemValueString("ksef.number");
float fontSize = 7;
PDType1Font font = PDType1Font.COURIER;
float textX = imageX + 5;
float textY = imageY - 5; // 10 Points unter dem Bild
contentStream.beginText();
contentStream.setFont(font, fontSize);
contentStream.newLineAtOffset(textX, textY);
contentStream.showText(text);
contentStream.endText();
contentStream.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.save(baos);
byte[] eInvoiceData = baos.toByteArray();
document.close();
baos.close();
pdfFileData.setContent(eInvoiceData);
// finally update the pdf file
workitem.removeFile(pdfFileData.getName());
// set new pdf file...
workitem.addFileData(pdfFileData);
} catch (IOException | PluginException e) {
logger.warning("Failed to embed QR Code on PDF file: " + e.getMessage());
}
}
/**
* Encrypt invoice XML with the session encryption keys
*
* @param invoiceXml the invoice XML content
* @param encryption the session encryption containing AES key and IV
* @return encrypted invoice bytes
* @throws PluginException if encryption fails
*/
private byte[] encryptInvoiceWithSessionKeys(byte[] invoiceXml, SessionEncryption encryption)
throws PluginException {
try {
logger.info("│ ├── Encrypting invoice with session keys...");
// Use the SAME keys that were sent during session creation!
SecretKeySpec aesKey = new SecretKeySpec(encryption.getAesKeyBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(encryption.getInitializationVector());
// Encrypt with AES-256-CBC
Cipher aesCipher;
aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey, iv);
byte[] encryptedData = aesCipher.doFinal(invoiceXml);
logger.info("│ ├── Invoice encrypted - " + encryptedData.length + " bytes");
return encryptedData;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"Error encrypt Invoice: " + e.getMessage());
}
}
/**
* Calculate SHA-256 hash of data
*
* @param data byte array to hash
* @return Base64-encoded hash
* @throws NoSuchAlgorithmException if SHA-256 is not available
*/
private String calculateSHA256Hash(byte[] data) throws NoSuchAlgorithmException {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = sha256.digest(data);
return Base64.getEncoder().encodeToString(hashBytes);
}
/**
* This helper method tries to find the pdf file matching the item
* 'cargosoft.import.filename'. If not found the method returns the first .pdf
* file form the list of attachments. The method returns null if no pdf file
* exits
*
* @param workitem
* @return the pdf FileData object
* @throws PluginException if not pdf file was found
*/
public FileData loadPDF(ItemCollection workitem) throws PluginException {
FileData pdfFileData = null;
String cargosoftFileName = workitem.getItemValueString("cargosoft.import.filename");
if (!cargosoftFileName.isEmpty()) {
cargosoftFileName = cargosoftFileName.replace(".xml", ".pdf");
// try to load filedata....
pdfFileData = snapshotService.getWorkItemFile(workitem.getUniqueID(), cargosoftFileName);
}
if (pdfFileData == null) {
// take first pdf file available
List<String> fileNames = workitem.getFileNames();
for (String filename : fileNames) {
if (filename.toLowerCase().endsWith(".pdf")) {
pdfFileData = snapshotService.getWorkItemFile(workitem.getUniqueID(), filename);
break;
}
}
}
if (pdfFileData == null) {
throw new PluginException(KSeFAPIService.class.getSimpleName(),
DOCUMENT_ERROR,
"DOCUMENT_ERROR: no pdf file found!");
}
return pdfFileData;
}
/**
* 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;
}
/**
* This method loads a text-block for a specified ref and appends the named
* fileData object of this document.
*
* @param document
* @throws PluginException
*/
public FileData loadXMLTemplate(ItemCollection workitem, ItemCollection config)
throws PluginException {
String textblock = config.getItemValueString("textblock");
String template = config.getItemValueString("template");
String sourceName = config.getItemValueString("source");
String targetName = "factur-x.xml";
// adapt text....
sourceName = workflowService.adaptText(sourceName, workitem);
if ((template == null || template.isEmpty()) || (textblock == null || textblock.isEmpty())) {
throw new PluginException(KSeFAPIService.class.getSimpleName(),
KSeFAPIService.CONFIG_ERROR,
"invalid e-invoice configuration in model event - textblock/template reference not defined!");
}
// load the text block
FileData fileData = this.loadTextBlockFileData(textblock, template);
// do we found the document?
if (fileData == null) {
throw new PluginException(KSeFAPIService.class.getSimpleName(),
KSeFAPIService.CONFIG_ERROR,
"invalid e-invoice configuration in model event - textblock/template: " + textblock + "/" + template
+ " not found!");
}
fileData.setName(targetName);
return fileData;
}
}