diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/ksef/api/KSeFAPIService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/ksef/api/KSeFAPIService.java index a33ff27..2792b43 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/ksef/api/KSeFAPIService.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/ksef/api/KSeFAPIService.java @@ -1,11 +1,10 @@ package com.alexanderlogistics.ksef.api; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URI; -import java.net.URLEncoder; import java.net.http.HttpRequest; import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.MessageDigest; @@ -30,6 +29,12 @@ import org.imixs.workflow.ItemCollection; import org.imixs.workflow.engine.DocumentService; import org.imixs.workflow.exceptions.PluginException; +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; @@ -239,6 +244,9 @@ public class KSeFAPIService { // store verification url generateVerificationUrl(workitem); + + // store QR Code + generateQRCode(workitem); } } catch (IOException | NoSuchAlgorithmException | InterruptedException e) { @@ -374,8 +382,9 @@ public class KSeFAPIService { httpResponse = response.statusCode(); logger.info("│ ├── HTTP Response: " + httpResponse); - logger.info("│ ├── " + response.body()); - + if (kseFAuthManager.isDebug()) { + logger.info("│ ├── " + response.body()); + } FileData fileData = new FileData(ksefRefNumber + ".xml", response.body().getBytes(), "application/xml", null); return fileData; } @@ -387,20 +396,58 @@ public class KSeFAPIService { * @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 invoiceHash = workitem.getItemValueString("ksef.invoiceHash"); - String urlEncodedHash = URLEncoder.encode(invoiceHash, StandardCharsets.UTF_8); - 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); + // https://ksef-test.mf.gov.pl/api/v2 -> https://ksef-test.mf.gov.pl/client-app/ baseURL = baseURL.replace("/api/v2", "/client-app/invoice"); // Build verification URL workitem.setItemValue("ksef.VerificationUrl", baseURL + "/" + kseFAuthManager.getKsefNip() + "/" + invoiceDate + "/" - + urlEncodedHash); + + 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()); + + } } /**