From d7c9682bfd6e4f33daa9cc946161397f4aa6d665 Mon Sep 17 00:00:00 2001 From: Ralph Soika Date: Tue, 24 Feb 2026 16:29:50 +0100 Subject: [PATCH] korrektur der Steuerberechnung --- .../einvoice/KSeFAdapter.java | 21 +-- .../xml/CargosoftXMLInvoiceImportService.java | 11 +- .../ksef/api/KSeFAdapterTest.java | 156 +++++++++++++++-- .../src/test/resources/ksef/output/6602.xml | 164 ++++++++++++++++++ .../{ => ksef}/output/ksef-output.xml | 13 +- .../ksef/output/test-korrekturrechnung.xml | 114 ++++++++++++ 6 files changed, 448 insertions(+), 31 deletions(-) create mode 100644 office-alexander-logistics-app/src/test/resources/ksef/output/6602.xml rename office-alexander-logistics-app/src/test/resources/{ => ksef}/output/ksef-output.xml (89%) create mode 100644 office-alexander-logistics-app/src/test/resources/ksef/output/test-korrekturrechnung.xml diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/einvoice/KSeFAdapter.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/einvoice/KSeFAdapter.java index 09e903b..cb4bd8d 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/einvoice/KSeFAdapter.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/einvoice/KSeFAdapter.java @@ -224,14 +224,10 @@ public class KSeFAdapter implements SignalAdapter { // Netto model.setNetTotalAmount(workitem.getItemValueDouble("invoice.total.net")); - // Tax - if (workitem.getItemValueDouble("invoice.total.tax") > 0) { - // wir haben eine Steuer! - model.setTaxTotalAmount(InvoiceUtil.round(workitem.getItemValueDouble("invoice.total") - - workitem.getItemValueDouble("invoice.total.net"))); - model.setTaxRate(workitem.getItemValueDouble("invoice.total.tax")); - } + model.setTaxTotalAmount(InvoiceUtil.round(workitem.getItemValueDouble("invoice.total") + - workitem.getItemValueDouble("invoice.total.net"))); + model.setTaxRate(workitem.getItemValueDouble("invoice.total.tax")); // Brutto model.setGrandTotalAmount(workitem.getItemValueDouble("invoice.total")); @@ -353,9 +349,14 @@ public class KSeFAdapter implements SignalAdapter { tradeLineItem.setName(orderItem.getItemValueString("datev.text")); tradeLineItem.setQuantity(1); - tradeLineItem.setNetPrice(orderItem.getItemValueDouble("datev.umsatz")); - tradeLineItem.setTotal(orderItem.getItemValueDouble("datev.umsatz")); - // tradeLineItem.setTaxRate(orderItem.getItemValueDouble("vat")); + + double vat = orderItem.getItemValueDouble("datev.vatrate"); // 23.00 + double netto = orderItem.getItemValueDouble("datev.umsatz"); // 970.00 + double brutto = netto * (1 + (vat / 100)); + double steuer = brutto - netto; + tradeLineItem.setTaxRate(vat); + tradeLineItem.setNetPrice(netto); + tradeLineItem.setTotal(brutto); return tradeLineItem; } diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java index cfb8297..a0e128f 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/xml/CargosoftXMLInvoiceImportService.java @@ -612,7 +612,8 @@ public class CargosoftXMLInvoiceImportService { XPathExpression netAmountValueExpr = xPath.compile("InvoiceAmount/NetAmount/Amount/Value/text()"); XPathExpression netAmountExchangeRateExpr = xPath .compile("InvoiceAmount/NetAmount/Amount/ExchangeRate/text()"); - + XPathExpression vatInformationExpr = xPath + .compile("InvoiceAmount/VATInformation/VAT/VATRate/text()"); XPathExpression netActivityTypeExpr = xPath.compile("ActivityType/Codes/Code[@Type='cs']/text()"); NodeList rowList = doc.getElementsByTagName("InvoiceRow"); @@ -634,6 +635,14 @@ public class CargosoftXMLInvoiceImportService { String fileNumber = (String) fileNumberExpr.evaluate(rowNode, XPathConstants.STRING); childItemCol.setItemValue("datev.text", fileNumber); + // get VAT Rate + try { + String vatRateText = (String) vatInformationExpr.evaluate(rowNode, XPathConstants.STRING); + childItemCol.setItemValue("datev.vatrate", Double.valueOf(vatRateText)); + } catch (Exception e) { + // no op + } + // speichere die Position in invoice.positions zur suche nach dem // Positionskennzeichen workitem.appendItemValue("invoice.positions", fileNumber); diff --git a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/ksef/api/KSeFAdapterTest.java b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/ksef/api/KSeFAdapterTest.java index ac004ca..cfc7f09 100644 --- a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/ksef/api/KSeFAdapterTest.java +++ b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/ksef/api/KSeFAdapterTest.java @@ -48,9 +48,7 @@ public class KSeFAdapterTest { private static Logger logger = Logger.getLogger(KSeFAdapterTest.class.getName()); private static final String TEMPLATE_FILE = "ksef/ksef.xml"; - private static final String OUTPUT_FILE = "ksef-output.xml"; - ItemCollection workitem; ItemCollection businessPartner; @Mock @@ -69,8 +67,28 @@ public class KSeFAdapterTest { void setup() throws Exception { TestLoggerConfig.setupTestLogger(); + + // Prepare mock business partner + businessPartner = new ItemCollection(); + businessPartner.setItemValue("partner.name", "Test Sp. z o.o."); + businessPartner.setItemValue("partner.country", "PL"); + businessPartner.setItemValue("partner.city", "Warszawa"); + businessPartner.setItemValue("partner.zip", "00-001"); + businessPartner.setItemValue("partner.address", "ul. Testowa 1"); + businessPartner.setItemValue("partner.vat", "PL1234567890"); + businessPartner.setItemValue("dbtr.number", "D-12345"); + } + + /** + * Erzeugt ein lokales XML File zum testen + */ + @Test + @DisplayName("Test Simple Invoice") + public void testSimpleInvoice() throws Exception { + logger.info("==> Test: Upload Invoice XML"); + // Prepare a workitem with typical invoice data - workitem = new ItemCollection(); + ItemCollection workitem = new ItemCollection(); workitem.setItemValue("invoice.number", "FV/2025/001"); workitem.setItemValue("invoice.date", LocalDate.of(2025, 2, 10)); workitem.setItemValue("invoice.duedate", LocalDate.of(2025, 3, 10)); @@ -99,25 +117,131 @@ public class KSeFAdapterTest { workitem.setItemValue("_childitems", childItems); - // Prepare mock business partner - businessPartner = new ItemCollection(); - businessPartner.setItemValue("partner.name", "Test Sp. z o.o."); - businessPartner.setItemValue("partner.country", "PL"); - businessPartner.setItemValue("partner.city", "Warszawa"); - businessPartner.setItemValue("partner.zip", "00-001"); - businessPartner.setItemValue("partner.address", "ul. Testowa 1"); - businessPartner.setItemValue("partner.vat", "PL1234567890"); - businessPartner.setItemValue("dbtr.number", "D-12345"); + // Arrange + when(businessPartnerService.getBusinessPartnerByID("BP-001")) + .thenReturn(businessPartner); + + FileData xmlTemplate = loadTemplateFromResources(TEMPLATE_FILE); + + // Act + adapter.updateEInvoice(xmlTemplate, workitem); + + // Assert - basic checks + assertNotNull(xmlTemplate.getContent(), "XML content should not be null after update"); + assertTrue(xmlTemplate.getContent().length > 0, "XML content should not be empty"); + + // Write output for manual inspection + writeOutputToResources(xmlTemplate, "invoice-simple.xml"); + } /** * Erzeugt ein lokales XML File zum testen */ @Test - @DisplayName("Test Transform") - public void testTransform() throws Exception { + @DisplayName("Test Invoice Korrektur") + public void testInvoiceKorektur() throws Exception { logger.info("==> Test: Upload Invoice XML"); + // Prepare a workitem with typical invoice data + ItemCollection workitem = new ItemCollection(); + workitem.setItemValue("invoice.number", "FV/2025/001"); + workitem.setItemValue("invoice.date", LocalDate.of(2025, 2, 10)); + workitem.setItemValue("invoice.duedate", LocalDate.of(2025, 3, 10)); + workitem.setItemValue("invoice.currency", "EUR"); + workitem.setItemValue("invoice.total.net", 0.00); + workitem.setItemValue("invoice.total.tax", 0.0); + workitem.setItemValue("invoice.total", 0.00); + + workitem.setItemValue("partner.id", "BP-001"); + workitem.setItemValue("partner.vat", "PL1234567890"); + + // simulation Korrekturrechnung + workitem.setItemValue("invoice.correction", true); + workitem.setItemValue("invoice.CorrectionInvoiceNumber", "6551"); + + // Prepare child items (invoice line items) + List childItems = new ArrayList<>(); + + ItemCollection lineItem1 = new ItemCollection() + .setItemValue("numpos", "1") + .setItemValue("datev.shzeichen", "H") + .setItemValue("datev.kurs", 0.236485) + .setItemValue("datev.basisumsatz", -3805.74) + .setItemValue("datev.text", "Transport Berlin - Warsaw") + .setItemValue("billingtext", "usługa spedycyjna / transport w relacji, PL63 - CZ43") + .setItemValue("datev.umsatz", -900.00) + .setItemValue("datev.wkz", "EUR") + .setItemValue("billingcode", "TRANSLKW"); + + childItems.add(lineItem1.getAllItems()); + + /** + * 1 + * 7f846436-7c29-48b3-8f5a-fed996ea30a3 + * IM-POL-2512-008 + * szt. + * 1 + * 0.00 + * 0.00 + * + * + * 2 + * f3077e37-9198-4431-a82b-68d9439b587e + * IM-POL-2512-008 + * szt. + * 1 + * -900.00 + * -900.00 + * + * + * 3 + * 31fdfe9e-671e-42f6-9f7e-ceb227a3a42c + * IM-POL-2512-008 + * szt. + * 1 + * 0.00 + * 0.00 + * + * + * 4 + * 79ffd1e8-be87-478b-97b5-d37aa302d090 + * IM-POL-2512-008 + * szt. + * 1 + * 0.00 + * 0.00 + * + * + * 5 + * 38e8cbd3-e558-4b0e-875c-c4f2d96d1659 + * IM-POL-2512-008 + * szt. + * 1 + * 900.00 + * 900.00 + * + * + * 6 + * 3774dab3-b6c4-433e-8298-60ecf6cbab74 + * IM-POL-2512-008 + * szt. + * 1 + * 0.00 + * 0.00 + * + * + * 7 + * f19846ab-3567-4e5d-823b-807d474af062 + * IM-POL-2512-008 + * szt. + * 1 + * 0.00 + * 0.00 + */ + + workitem.setItemValue("_childitems", childItems); + // Arrange when(businessPartnerService.getBusinessPartnerByID("BP-001")) .thenReturn(businessPartner); @@ -132,7 +256,7 @@ public class KSeFAdapterTest { assertTrue(xmlTemplate.getContent().length > 0, "XML content should not be empty"); // Write output for manual inspection - writeOutputToResources(xmlTemplate, OUTPUT_FILE); + writeOutputToResources(xmlTemplate, "test-korrekturrechnung.xml"); } @@ -159,7 +283,7 @@ public class KSeFAdapterTest { * Write the resulting XML to src/test/resources/output/ for manual inspection. */ private void writeOutputToResources(FileData fileData, String filename) throws IOException { - Path outputDir = Paths.get("src", "test", "resources", "output"); + Path outputDir = Paths.get("src", "test", "resources", "ksef/output"); Files.createDirectories(outputDir); Path outputPath = outputDir.resolve(filename); Files.write(outputPath, fileData.getContent()); diff --git a/office-alexander-logistics-app/src/test/resources/ksef/output/6602.xml b/office-alexander-logistics-app/src/test/resources/ksef/output/6602.xml new file mode 100644 index 0000000..84beb06 --- /dev/null +++ b/office-alexander-logistics-app/src/test/resources/ksef/output/6602.xml @@ -0,0 +1,164 @@ + + + + FA + 3 + 2026-02-09T16:46:47.217821373Z + Imixs eInvoice + + + + + 9552521552 + Alexander Global Logistics + + + PL + Gdanska 36 + 70-660 Szczecin + + + MBudas@alexander-logistics.com + + + + + + + + 7851801689 + DWORCZAK LOGISTICS Sp. z o.o. + + + PL + ul. Szkolna 10 + 63-100 Niesłabin + + + D21839 + 2 + + 2 + + + + + EUR + 2025-12-12 + + 6602 + + 2026-01-11 + + + + 0.00 + 0.00 + + + 2 + + 2 + + 2 + + 2 + + + 1 + + + + 1 + + + 2 + + + 1 + + + + KOR + + + 2025-12-05 + 6551 + 1 + + + 1 + 7f846436-7c29-48b3-8f5a-fed996ea30a3 + IM-POL-2512-008 + szt. + 1 + 0.00 + 0.00 + + + 2 + f3077e37-9198-4431-a82b-68d9439b587e + IM-POL-2512-008 + szt. + 1 + -900.00 + -900.00 + + + 3 + 31fdfe9e-671e-42f6-9f7e-ceb227a3a42c + IM-POL-2512-008 + szt. + 1 + 0.00 + 0.00 + + + 4 + 79ffd1e8-be87-478b-97b5-d37aa302d090 + IM-POL-2512-008 + szt. + 1 + 0.00 + 0.00 + + + 5 + 38e8cbd3-e558-4b0e-875c-c4f2d96d1659 + IM-POL-2512-008 + szt. + 1 + 900.00 + 900.00 + + + 6 + 3774dab3-b6c4-433e-8298-60ecf6cbab74 + IM-POL-2512-008 + szt. + 1 + 0.00 + 0.00 + + + 7 + f19846ab-3567-4e5d-823b-807d474af062 + IM-POL-2512-008 + szt. + 1 + 0.00 + 0.00 + + + \ No newline at end of file diff --git a/office-alexander-logistics-app/src/test/resources/output/ksef-output.xml b/office-alexander-logistics-app/src/test/resources/ksef/output/ksef-output.xml similarity index 89% rename from office-alexander-logistics-app/src/test/resources/output/ksef-output.xml rename to office-alexander-logistics-app/src/test/resources/ksef/output/ksef-output.xml index c45f200..fce425c 100644 --- a/office-alexander-logistics-app/src/test/resources/output/ksef-output.xml +++ b/office-alexander-logistics-app/src/test/resources/ksef/output/ksef-output.xml @@ -6,7 +6,7 @@ FA 3 - 2026-02-10T12:46:08.366684Z + 2026-02-24T15:23:18.952460Z Imixs eInvoice @@ -94,11 +94,16 @@ - VAT + KOR + + 2025-02-10 + 6551 + 1 + 1 - 5a2dd34c-6592-40aa-aafc-80bac9c9b9c4 + f8deaaf2-dfe0-4a7e-801a-c977a4e400ba Transport Berlin - Warsaw szt. 1 @@ -107,7 +112,7 @@ 2 - d44bf6a0-758b-415b-b45a-d83052a2f2aa + 29636625-ac8a-47a6-a795-8954d1d106f2 Customs handling szt. 1 diff --git a/office-alexander-logistics-app/src/test/resources/ksef/output/test-korrekturrechnung.xml b/office-alexander-logistics-app/src/test/resources/ksef/output/test-korrekturrechnung.xml new file mode 100644 index 0000000..675ab1f --- /dev/null +++ b/office-alexander-logistics-app/src/test/resources/ksef/output/test-korrekturrechnung.xml @@ -0,0 +1,114 @@ + + + + FA + 3 + 2026-02-24T16:11:02.707702Z + Imixs eInvoice + + + + + 9552521552 + Alexander Global Logistics + + + PL + Gdanska 36 + 70-660 Szczecin + + + MBudas@alexander-logistics.com + + + + + + + + 1234567890 + Test Sp. z o.o. + + + PL + ul. Testowa 1 + 00-001 Warszawa + + + D-12345 + 2 + + 2 + + + + + EUR + 2025-02-10 + + FV/2025/001 + + 2025-03-10 + + + + 0.00 + 0.00 + 0.00 + + + 2 + + 2 + + 2 + + 2 + + + 1 + + + + 1 + + + 2 + + + 1 + + + + KOR + + + 2025-02-10 + 6551 + 1 + + + 1 + 781e1f16-a86e-452d-b959-01c76743a792 + Transport Berlin - Warsaw + szt. + 1 + -900.00 + -900.00 + + +