update
This commit is contained in:
parent
f61c7feca5
commit
c232841ed3
8 changed files with 3921 additions and 375 deletions
|
|
@ -120,7 +120,7 @@ public class EInvoiceAdapter implements SignalAdapter {
|
||||||
throw new PluginException(EInvoiceAdapter.class.getSimpleName(), CONFIG_ERROR,
|
throw new PluginException(EInvoiceAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||||
"missing e-invoice configuration in model event - please check model configuration");
|
"missing e-invoice configuration in model event - please check model configuration");
|
||||||
}
|
}
|
||||||
ItemCollection createDefinition = XMLParser.parseItemStructure(eInvoiceConfig.getItemValueString("create"));
|
ItemCollection createDefinition = XMLParser.parseItemStructure(eInvoiceConfig.getItemValueString("CREATE"));
|
||||||
try {
|
try {
|
||||||
// Load the e-invoice template....
|
// Load the e-invoice template....
|
||||||
FileData xmlFileData = loadXMLTemplate(workitem, createDefinition);
|
FileData xmlFileData = loadXMLTemplate(workitem, createDefinition);
|
||||||
|
|
|
||||||
|
|
@ -15,26 +15,33 @@ import com.alexanderlogistics.ksef.api.KSeFAPIService;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This adapter exports the invoice data to KSeF
|
* This adapter exports the invoice data to KSeF and can poll the current status
|
||||||
|
* of an invoice
|
||||||
*
|
*
|
||||||
* To activate debug add the following event definition
|
* To activate debug add the following event definition
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* {@code
|
* {@code
|
||||||
<ksef name="EXPORT">
|
<ksef name="EXPORT">
|
||||||
<debug>true</debug>
|
<debug>true</debug>
|
||||||
</ksef>
|
</ksef>
|
||||||
|
|
||||||
|
|
||||||
|
<ksef name="STATUS">
|
||||||
|
<debug>true</debug>
|
||||||
|
</ksef>
|
||||||
|
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @author rsoika
|
* @author rsoika
|
||||||
*/
|
*/
|
||||||
public class KSeFExportAdapter implements SignalAdapter {
|
public class KSeFAPIAdapter implements SignalAdapter {
|
||||||
|
|
||||||
public static final String CONFIG_ERROR = "CONFIG_ERROR";
|
public static final String CONFIG_ERROR = "CONFIG_ERROR";
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(KSeFExportAdapter.class.getName());
|
private static Logger logger = Logger.getLogger(KSeFAPIAdapter.class.getName());
|
||||||
private boolean debug = false;
|
private boolean debug = false;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|
@ -56,25 +63,33 @@ public class KSeFExportAdapter implements SignalAdapter {
|
||||||
throws AdapterException {
|
throws AdapterException {
|
||||||
// read debug flag
|
// read debug flag
|
||||||
try {
|
try {
|
||||||
List<ItemCollection> ksefDefinitions = workflowService.evalWorkflowResultXML(event, "ksef",
|
List<ItemCollection> ksefExportDefinitions = workflowService.evalWorkflowResultXML(event, "ksef",
|
||||||
"EXPORT", workitem, false);
|
"EXPORT", workitem, false);
|
||||||
if (ksefDefinitions != null && ksefDefinitions.size() > 0) {
|
// List<ItemCollection> ksefStatusDefinitions =
|
||||||
ItemCollection ksefDefinition = ksefDefinitions.get(0);
|
// workflowService.evalWorkflowResultXML(event, "ksef",
|
||||||
|
// "STATUS", workitem, false);
|
||||||
|
|
||||||
|
// EXPORT
|
||||||
|
if (ksefExportDefinitions != null && ksefExportDefinitions.size() > 0) {
|
||||||
|
ItemCollection ksefDefinition = ksefExportDefinitions.get(0);
|
||||||
debug = ksefDefinition.getItemValueBoolean("debug");
|
debug = ksefDefinition.getItemValueBoolean("debug");
|
||||||
}
|
|
||||||
} catch (PluginException ee) {
|
|
||||||
// no op
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
|
|
||||||
kSeFAPIService.uploadInvoice(workitem, "ksef.xml");
|
kSeFAPIService.uploadInvoice(workitem, "ksef.xml");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// // STATUS
|
||||||
|
// if (ksefStatusDefinitions != null && ksefStatusDefinitions.size() > 0) {
|
||||||
|
// ItemCollection ksefDefinition = ksefStatusDefinitions.get(0);
|
||||||
|
// debug = ksefDefinition.getItemValueBoolean("debug");
|
||||||
|
|
||||||
|
// kSeFAPIService.getInvoiceStatus(workitem);
|
||||||
|
|
||||||
|
// }
|
||||||
} catch (PluginException e) {
|
} catch (PluginException e) {
|
||||||
// convert PluginException into a AdapterException to handle the error via the
|
|
||||||
// model!
|
|
||||||
logger.warning("Failed to export data to Zoho: " + e.getMessage());
|
|
||||||
throw new AdapterException(e);
|
throw new AdapterException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return workitem;
|
return workitem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,11 +40,12 @@ import jakarta.inject.Inject;
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* {@code
|
* {@code
|
||||||
<e-invoice name="ksef">
|
<ksef name="create">
|
||||||
<textblock>textblock-ref</textblock>
|
<textblock>textblock-ref</textblock>
|
||||||
<template>filename</template>
|
<template>filename</template>
|
||||||
<debug>true</debug>
|
<debug>true</debug>
|
||||||
</e-invoice>
|
</ksef>
|
||||||
|
|
||||||
}
|
}
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
|
@ -92,18 +93,18 @@ public class KSeFAdapter implements SignalAdapter {
|
||||||
|
|
||||||
logger.info("├── 🔜 Convert Invoice to KSeF...");
|
logger.info("├── 🔜 Convert Invoice to KSeF...");
|
||||||
// read configuration....
|
// read configuration....
|
||||||
ItemCollection eInvoiceConfig = workflowService.evalWorkflowResult(event, "e-invoice",
|
ItemCollection eInvoiceConfig = workflowService.evalWorkflowResult(event, "ksef",
|
||||||
workitem,
|
workitem,
|
||||||
false);
|
false);
|
||||||
if (eInvoiceConfig == null || !eInvoiceConfig.hasItem("ksef")) {
|
if (eInvoiceConfig == null || !eInvoiceConfig.hasItem("CREATE")) {
|
||||||
throw new PluginException(EInvoiceAdapter.class.getSimpleName(), CONFIG_ERROR,
|
throw new PluginException(EInvoiceAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||||
"missing e-invoice/ksef configuration in model event - please check model configuration");
|
"missing e-invoice/ksef configuration in model event - please check model configuration");
|
||||||
}
|
}
|
||||||
ItemCollection ksefDefinition = XMLParser.parseItemStructure(eInvoiceConfig.getItemValueString("ksef"));
|
ItemCollection ksefCreateDefinition = XMLParser.parseItemStructure(eInvoiceConfig.getItemValueString("CREATE"));
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Load the e-invoice template....
|
// Load the e-invoice template....
|
||||||
FileData xmlFileData = loadXMLTemplate(workitem, ksefDefinition);
|
FileData xmlFileData = loadXMLTemplate(workitem, ksefCreateDefinition);
|
||||||
|
|
||||||
updateEInvoice(xmlFileData, workitem);
|
updateEInvoice(xmlFileData, workitem);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ public class KSeFAPIService {
|
||||||
* @return referenceNumber from KSeF
|
* @return referenceNumber from KSeF
|
||||||
* @throws PluginException
|
* @throws PluginException
|
||||||
*/
|
*/
|
||||||
public String uploadInvoice(ItemCollection workitem, String fileName) throws PluginException {
|
public void uploadInvoice(ItemCollection workitem, String fileName) throws PluginException {
|
||||||
|
|
||||||
// First open an interactive session (reuses existing if valid)
|
// First open an interactive session (reuses existing if valid)
|
||||||
kseFAuthManager.openSession();
|
kseFAuthManager.openSession();
|
||||||
|
|
@ -182,9 +182,27 @@ public class KSeFAPIService {
|
||||||
textlist.add(referenceNumber);
|
textlist.add(referenceNumber);
|
||||||
fileData.setAttribute("ksef.referenceNumber", textlist);
|
fileData.setAttribute("ksef.referenceNumber", textlist);
|
||||||
|
|
||||||
|
workitem.setItemValue("ksef.referenceNumber", referenceNumber);
|
||||||
logger.info("├── ✅ Upload successful - Reference: " + referenceNumber);
|
logger.info("├── ✅ Upload successful - Reference: " + referenceNumber);
|
||||||
|
|
||||||
return referenceNumber;
|
// Close Session
|
||||||
|
kseFAuthManager.closeInteractiveSession();
|
||||||
|
|
||||||
|
// Status abfragen
|
||||||
|
// Now we need to wait until auth/{AuthRef} will return 200
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long timeout = 20_000; // 20 Sekunden
|
||||||
|
while (System.currentTimeMillis() - start < timeout) {
|
||||||
|
int code = kseFAuthManager.checkSessionStatus();
|
||||||
|
|
||||||
|
if (code >= 200) {
|
||||||
|
break; // ok or borken
|
||||||
|
}
|
||||||
|
|
||||||
|
// kleine Pause, um CPU zu schonen
|
||||||
|
kseFAuthManager.waitSomeTime(500);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.severe("├── ⚠️ Invoice upload failed: " + e.getMessage());
|
logger.severe("├── ⚠️ Invoice upload failed: " + e.getMessage());
|
||||||
|
|
@ -194,11 +212,101 @@ public class KSeFAPIService {
|
||||||
} finally {
|
} finally {
|
||||||
|
|
||||||
// finally we close the session
|
// finally we close the session
|
||||||
kseFAuthManager.closeInteractiveSession();
|
|
||||||
kseFAuthManager.deleteCurrentAuthSession();
|
kseFAuthManager.deleteCurrentAuthSession();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poll Invoice Status
|
||||||
|
*
|
||||||
|
* https://ksef-test.mf.gov.pl/docs/v2/index.html#tag/Status-wysylki-i-UPO/paths/~1api~1v2~1sessions~1%7BreferenceNumber%7D/get
|
||||||
|
*
|
||||||
|
* @param workitem
|
||||||
|
* @return
|
||||||
|
* @throws PluginException
|
||||||
|
*/
|
||||||
|
private int xxxgetInvoiceStatus(ItemCollection workitem) throws PluginException {
|
||||||
|
|
||||||
|
logger.info("├── 🔎 Get Invoice Status...");
|
||||||
|
|
||||||
|
// 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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
String referenceNumber = workitem.getItemValueString("ksef.referenceNumber");
|
||||||
|
if (referenceNumber.isBlank()) {
|
||||||
|
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
|
||||||
|
"API Error - missing invoice referenceNumber!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate hashes
|
||||||
|
|
||||||
|
// Send upload request
|
||||||
|
String uri = kseFAuthManager.getBaseURI() + "/sessions/" + kseFAuthManager.getSessionRefNumber();
|
||||||
|
|
||||||
|
logger.info("│ ├── GET: " + uri);
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(uri))
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", "Bearer " + kseFAuthManager.getAccessToken())
|
||||||
|
.GET()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = kseFAuthManager.getHttpClient().send(
|
||||||
|
request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
|
||||||
|
logger.info("│ ├── HTTP Response: " + response.statusCode());
|
||||||
|
|
||||||
|
logger.info("│ ├── Response Body: " + response.body());
|
||||||
|
|
||||||
|
int statusCode = -1;
|
||||||
|
String statusDescription = "";
|
||||||
|
try (Jsonb jsonb = JsonbBuilder.create()) {
|
||||||
|
JsonObject jsonObject = jsonb.fromJson(response.body(), JsonObject.class);
|
||||||
|
|
||||||
|
// Status Code aus dem status-Objekt extrahieren
|
||||||
|
if (jsonObject.containsKey("status")) {
|
||||||
|
JsonObject statusObject = jsonObject.getJsonObject("status");
|
||||||
|
if (statusObject.containsKey("code")) {
|
||||||
|
statusCode = statusObject.getInt("code");
|
||||||
|
statusDescription = statusObject.getString("description");
|
||||||
|
logger.info("│ ├── Status Code: " + statusCode);
|
||||||
|
logger.info("│ ├── Status Description: " + statusDescription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
workitem.setItemValue("ksef.status.code", statusCode);
|
||||||
|
workitem.setItemValue("ksef.status.description", statusDescription);
|
||||||
|
return statusCode;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.severe("├── ⚠️ Get Invoice status failed: " + e.getMessage());
|
||||||
|
|
||||||
|
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
|
||||||
|
"Invoice upload failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt invoice XML with the session encryption keys
|
* Encrypt invoice XML with the session encryption keys
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -535,7 +535,7 @@ public class KSeFAuthManager {
|
||||||
/**
|
/**
|
||||||
* waits some time..
|
* waits some time..
|
||||||
*/
|
*/
|
||||||
private void waitSomeTime(long millis) {
|
public void waitSomeTime(long millis) {
|
||||||
logger.info("│ ├── waiting " + millis + "ms....");
|
logger.info("│ ├── waiting " + millis + "ms....");
|
||||||
try {
|
try {
|
||||||
Thread.sleep(millis);
|
Thread.sleep(millis);
|
||||||
|
|
@ -1105,7 +1105,7 @@ public class KSeFAuthManager {
|
||||||
logger.info("Response: " + response.body());
|
logger.info("Response: " + response.body());
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionRefNumber = null;
|
// sessionRefNumber = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public class KSeFAPIServiceTest {
|
||||||
workitem = createWorkitem();
|
workitem = createWorkitem();
|
||||||
|
|
||||||
// Execute upload
|
// Execute upload
|
||||||
referenceNumber = apiService.uploadInvoice(workitem, "example-invoice-01.xml");
|
apiService.uploadInvoice(workitem, "example-invoice-01.xml");
|
||||||
} catch (IOException | PluginException e) {
|
} catch (IOException | PluginException e) {
|
||||||
logger.info("⚠️ Upload failed: " + e.getMessage());
|
logger.info("⚠️ Upload failed: " + e.getMessage());
|
||||||
fail(e);
|
fail(e);
|
||||||
|
|
|
||||||
3413
workflow/pl/rechnungsausgang-pl-1.1.0-versuche.bpmn
Normal file
3413
workflow/pl/rechnungsausgang-pl-1.1.0-versuche.bpmn
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue