finalize 1.3.4

This commit is contained in:
Ralph Soika 2025-11-15 20:35:58 +01:00
parent 1b31712ac7
commit 113ddb8a9f
8 changed files with 89 additions and 201 deletions

View file

@ -85,7 +85,7 @@ public class KSeFAPIService {
// First open an interactive Session. The KSeFAuthManager automatically reuses // First open an interactive Session. The KSeFAuthManager automatically reuses
// an existing session // an existing session
// kseFAuthManager.openSession(); kseFAuthManager.openSession();
if (kseFAuthManager.getAccessToken() == null) { if (kseFAuthManager.getAccessToken() == null) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API, throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
@ -219,6 +219,7 @@ public class KSeFAPIService {
textlist.add(referenceNumber); textlist.add(referenceNumber);
fileData.setAttribute("ksef.referenceNumber", textlist); fileData.setAttribute("ksef.referenceNumber", textlist);
kseFAuthManager.closeSession();
return referenceNumber; return referenceNumber;
} }

View file

@ -204,7 +204,7 @@ public class KSeFAuthManager {
this.redeemToken(); this.redeemToken();
this.openInteractiveSession(); this.openInteractiveSession();
} else { } else {
logger.info("│ ├── reuse existing KSeF Session..."); logger.warning("│ ├── ! Session already exists - reuse existing KSeF Session...");
} }
} }
@ -215,43 +215,41 @@ public class KSeFAuthManager {
*/ */
public boolean hasValidSession() { public boolean hasValidSession() {
return false; // Check if session reference number exists
if (sessionRefNumber == null || sessionRefNumber.isEmpty()) {
return false;
}
// // Check if session reference number exists // Check if valid until timestamp exists
// if (sessionRefNumber == null || sessionRefNumber.isEmpty()) { if (sessionValidUntil == null || sessionValidUntil.isEmpty()) {
// return false; return false;
// } }
// // Check if valid until timestamp exists try {
// if (sessionValidUntil == null || sessionValidUntil.isEmpty()) { // Parse the validUntil timestamp (ISO 8601 format with UTC)
// return false; DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
// } Instant validUntilInstant = Instant.from(formatter.parse(sessionValidUntil));
// try { // Get current time in UTC
// // Parse the validUntil timestamp (ISO 8601 format with UTC) Instant now = Instant.now();
// DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
// Instant validUntilInstant = Instant.from(formatter.parse(sessionValidUntil));
// // Get current time in UTC // Check if session is still valid
// Instant now = Instant.now(); boolean isValid = now.isBefore(validUntilInstant);
// // Check if session is still valid if (debug && isValid) {
// boolean isValid = now.isBefore(validUntilInstant); logger.info("├── Session is still valid until: " + sessionValidUntil);
} else if (debug) {
logger.info("├── Session expired at: " + sessionValidUntil);
}
// if (debug && isValid) { return isValid;
// logger.info("├── Session is still valid until: " + sessionValidUntil);
// } else if (debug) {
// logger.info("├── Session expired at: " + sessionValidUntil);
// }
// return isValid; } catch (Exception e) {
// If parsing fails, assume session is invalid
// } catch (Exception e) { logger.warning("├── ⚠️ Error parsing sessionValidUntil timestamp: " +
// // If parsing fails, assume session is invalid e.getMessage());
// logger.warning("├── ⚠️ Error parsing sessionValidUntil timestamp: " + return false;
// e.getMessage()); }
// return false;
// }
} }
/** /**
@ -771,4 +769,51 @@ public class KSeFAuthManager {
} }
} }
/**
* This method closes the current session
*
* https://ksef-test.mf.gov.pl/docs/v2/index.html#tag/Wysylka-interaktywna/paths/~1api~1v2~1sessions~1online~1%7BreferenceNumber%7D~1invoices/post
*
*
* NOTE: Seems to be not possible to close a session in test - response is
* usually 400
*
* @throws PluginException
*/
public void closeSession() throws PluginException {
logger.info("├── 📦 KSeF API close session...");
// https://ksef-test.mf.gov.pl/api/v2/sessions/online/{referenceNumber}/close
String uri = baseURI + "/sessions/online/" + sessionRefNumber + "/close";
if (debug) {
logger.info("│ ├── Endpoint: " + uri);
}
if (sessionRefNumber == null || sessionRefNumber.isEmpty()) {
throw new PluginException(KSeFAuthManager.class.getSimpleName(), ERROR_API,
"API Error: Unable to close session - session does not exist!");
}
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 " + accessToken)
.POST(HttpRequest.BodyPublishers.noBody()) //
.build();
response = httpClient.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());
}
if (true) {
logger.info("│ ├── Response Code = " + response.statusCode());
logger.info("Response: " + response.body());
}
sessionRefNumber = null;
}
} }

View file

@ -13,6 +13,7 @@ import java.util.logging.Logger;
import org.imixs.workflow.FileData; import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection; import org.imixs.workflow.ItemCollection;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
@ -23,6 +24,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import com.alexanderlogistics.TestLoggerConfig; import com.alexanderlogistics.TestLoggerConfig;
@Disabled
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class KSeFAPIServiceTest { public class KSeFAPIServiceTest {
@ -49,9 +51,9 @@ public class KSeFAPIServiceTest {
manager.init(); manager.init();
// Open Session // Open Session
manager.openSession(); // manager.openSession();
manager.checkTokenStatus(); // manager.checkTokenStatus();
// manager.loadPublicKeyCertificates(); // manager.loadPublicKeyCertificates();
// manager.authChallenge(); // manager.authChallenge();
// manager.authKSeFToken(); // manager.authKSeFToken();

View file

@ -18,6 +18,7 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
@ -26,6 +27,7 @@ import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
@Disabled
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class KSeFAuthManagerTest { public class KSeFAuthManagerTest {

View file

@ -1,165 +0,0 @@
package com.alexanderlogistics.ksef;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.logging.Logger;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Test cases KSeF Interface
*
*
* @author rsoika
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestKSeF {
final static String ENCODING = "UTF-8";
private static Logger logger = Logger.getLogger(TestKSeF.class.getName());
// Configuration - replace with your actual values
private static final String KSEF_TEST_URL = "https://ksef-test.mf.gov.pl/api/v2";
// https://ksef-test.mf.gov.pl/api/v2/auth/challenge
private static HttpClient httpClient;
private static String challenge; // Static variable to share between tests
private final ObjectMapper objectMapper = new ObjectMapper();
private String refNumber = null;
private String authToken = null;
@BeforeAll
public static void setupClass() {
logger.info("=== KSeF 2.0 Client Test ===");
logger.info("KSeF URL: " + KSEF_TEST_URL);
logger.info("NIP: " + Params.NIP);
httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.build();
}
@BeforeEach
public void setup() throws PluginException, ModelException {
logger.info("setup test environment ...");
}
@Test
@Order(1)
@DisplayName("Einfacher Challenge test 2.0 API")
public void testChallenge() throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(KSEF_TEST_URL + "/auth/challenge")) // nur Endpoint checken
.header("Accept", "application/json")
.POST(HttpRequest.BodyPublishers.noBody()) //
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Response: " + response.body());
// Prüfen, dass wir eine API-Antwort bekommen, kein HTML
assertTrue(response.statusCode() < 500, "API sollte antworten, Status < 500");
assertFalse(response.body().contains("<html>"), "Response sollte keine HTML-Seite sein");
// Challenge aus Response extrahieren und speichern
if (response.statusCode() == 200) {
JsonNode jsonNode = objectMapper.readTree(response.body());
challenge = jsonNode.get("challenge").asText();
logger.info("Extracted challenge: " + challenge);
}
}
@Test
@Order(2)
@DisplayName("KSeF Token Request")
public void testKsefToken() throws Exception {
// JSON Payload erstellen
String jsonPayload = String.format(
"{" +
"\"challenge\": \"%s\"," +
"\"contextIdentifier\": {" +
" \"type\": \"Nip\"," +
" \"value\": \"%s\"" +
"}," +
"\"encryptedToken\": \"%s\"" +
"}",
challenge, Params.NIP, Params.getEncodedToken());
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(KSEF_TEST_URL + "/auth/ksef-token"))
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Response: " + response.body());
// Prüfen, dass wir eine API-Antwort bekommen
assertTrue(response.statusCode() < 500, "API sollte antworten, Status < 500");
assertFalse(response.body().contains("<html>"), "Response sollte keine HTML-Seite sein");
// JSON parsen und Werte speichern
if (response.statusCode() == 200 || response.statusCode() == 202) {
JsonNode jsonNode = objectMapper.readTree(response.body());
// Reference Number speichern
refNumber = jsonNode.get("referenceNumber").asText();
logger.info("Extracted referenceNumber: " + refNumber);
// Authentication Token speichern
authToken = jsonNode.get("authenticationToken").get("token").asText();
logger.info("Extracted authenticationToken: " + authToken);
}
}
@Test
@Order(3)
@DisplayName("KSeF Public Key Zertifikate abrufen")
public void testFetchKsefPublicKeys() throws Exception {
assertNotNull(Params.TOKEN, "KSEF_TOKEN environment variable nicht gesetzt");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(KSEF_TEST_URL + "/security/public-key-certificates"))
.header("Accept", "application/json")
.header("Authorization", "Bearer " + Params.TOKEN) // Access Token nutzen
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Response: " + response.body());
// Assertions
assertEquals(200, response.statusCode(), "Request sollte 200 OK zurückgeben");
assertTrue(response.body().contains("certificate"), "Response sollte ein Feld 'certificate' enthalten");
}
}

View file

@ -8,6 +8,7 @@ import java.util.logging.Logger;
import org.imixs.workflow.exceptions.ModelException; import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException; import org.imixs.workflow.exceptions.PluginException;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
@ -16,6 +17,7 @@ import org.junit.jupiter.api.Test;
* *
* @author rsoika * @author rsoika
*/ */
@Disabled
public class TestSEPATransform { public class TestSEPATransform {
final static String ENCODING = "UTF-8"; final static String ENCODING = "UTF-8";

View file

@ -17,7 +17,7 @@ import org.junit.jupiter.api.Test;
* A test to explore a corgosoft invoice event * A test to explore a corgosoft invoice event
* *
*/ */
// @Disabled @Disabled
public class TestCargosoftEvents { public class TestCargosoftEvents {
private static Logger logger = Logger.getLogger(TestCargosoftEvents.class.getName()); private static Logger logger = Logger.getLogger(TestCargosoftEvents.class.getName());

View file

@ -14,6 +14,7 @@ import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.exceptions.PluginException; import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.xml.XMLDataCollectionAdapter; import org.imixs.workflow.xml.XMLDataCollectionAdapter;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.JAXBException;
@ -22,7 +23,7 @@ import jakarta.xml.bind.JAXBException;
* A simple example how to send an invoice document remote. * A simple example how to send an invoice document remote.
* *
*/ */
// @Disabled @Disabled
public class TestSendInvoice { public class TestSendInvoice {
private static Logger logger = Logger.getLogger(TestSendInvoice.class.getName()); private static Logger logger = Logger.getLogger(TestSendInvoice.class.getName());