fixed correct summarization in writeSummaryFields - with multipel 0% rules

This commit is contained in:
Ralph Soika 2026-05-28 19:17:47 +02:00
parent ba40d05c9d
commit 111527b407
9 changed files with 248 additions and 29 deletions

View file

@ -286,34 +286,49 @@ public class KSeFInvoiceLineBuilder {
Map<TaxCode, NetVatPair> aggregates, Map<TaxCode, NetVatPair> aggregates,
BigDecimal grossTotal) { BigDecimal grossTotal) {
Element elementAdnotacje = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, "Adnotacje"); // Aggregate by target XML field name, because multiple TaxCodes
// can map to the same summary field (e.g. CARGO_0, CARGO_0MR,
// CARGO_023 all target P_13_6_1).
Map<String, BigDecimal> netByField = new java.util.LinkedHashMap<>();
Map<String, BigDecimal> vatByField = new java.util.LinkedHashMap<>();
boolean reverseCharge = false;
for (Map.Entry<TaxCode, NetVatPair> entry : aggregates.entrySet()) { for (Map.Entry<TaxCode, NetVatPair> entry : aggregates.entrySet()) {
TaxCode taxCode = entry.getKey(); TaxCode taxCode = entry.getKey();
NetVatPair pair = entry.getValue(); NetVatPair pair = entry.getValue();
// Net summary field (always present) netByField.merge(taxCode.getNetSummaryField(), pair.net, BigDecimal::add);
String netField = taxCode.getNetSummaryField();
Element netElement = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, netField);
netElement.setTextContent(format(pair.net));
logger.info("│ ├── set " + netField + " = " + format(pair.net));
// VAT summary field (only for taxable codes)
if (taxCode.hasVat()) { if (taxCode.hasVat()) {
String vatField = taxCode.getVatSummaryField(); vatByField.merge(taxCode.getVatSummaryField(), pair.vat, BigDecimal::add);
Element vatElement = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, vatField);
vatElement.setTextContent(format(pair.vat));
logger.info("│ ├── set " + vatField + " = " + format(pair.vat));
} }
// Set P_18 if ("1".equals(taxCode.getP18Value())) {
reverseCharge = true;
}
}
// Write net summary fields (P_13_x)
for (Map.Entry<String, BigDecimal> entry : netByField.entrySet()) {
Element netElement = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, entry.getKey());
netElement.setTextContent(format(entry.getValue()));
logger.info("│ ├── set " + entry.getKey() + " = " + format(entry.getValue()));
}
// Write VAT summary fields (P_14_x)
for (Map.Entry<String, BigDecimal> entry : vatByField.entrySet()) {
Element vatElement = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, entry.getKey());
vatElement.setTextContent(format(entry.getValue()));
logger.info("│ ├── set " + entry.getKey() + " = " + format(entry.getValue()));
}
// P_18 - reverse charge flag
Element elementAdnotacje = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, "Adnotacje");
Element p18Element = model.findOrCreateChildNode(elementAdnotacje, EInvoiceNS.KSEF, "P_18"); Element p18Element = model.findOrCreateChildNode(elementAdnotacje, EInvoiceNS.KSEF, "P_18");
p18Element.setTextContent(taxCode.getP18Value()); p18Element.setTextContent(reverseCharge ? "1" : "2");
logger.info("│ ├── set P_18 = " + taxCode.getP18Value()); logger.info("│ ├── set P_18 = " + (reverseCharge ? "1" : "2"));
} // P_15 - gross total
// P_15 - gross total of the entire invoice (always present)
Element p15 = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, "P_15"); Element p15 = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, "P_15");
p15.setTextContent(format(grossTotal)); p15.setTextContent(format(grossTotal));
logger.info("│ ├── set P_15 = " + format(grossTotal)); logger.info("│ ├── set P_15 = " + format(grossTotal));

View file

@ -491,6 +491,86 @@ public class KSeFAdapterTest {
"Unknown CargoSoft VAT code must raise a PluginException"); "Unknown CargoSoft VAT code must raise a PluginException");
} }
/**
* Multiple 0% KR codes (023, 0, 0MR) on the same invoice in USD.
* <p>
* Regression test for the summary aggregation bug: all three CargoSoft
* codes map to {@code P_13_6_1}. Before the fix, only the last code's
* amount survived because {@code setTextContent} overwrote the previous
* value instead of summing. Expected: {@code P_13_6_1 = 2640.00}
* (1515 + 340 + 785).
*/
@Test
@DisplayName("Test Multiple 0% KR Codes aggregate into P_13_6_1 (USD)")
public void testMultipleZeroRateCodes() throws Exception {
logger.info("==> Test: Multiple 0% KR Codes");
ItemCollection workitem = new ItemCollection();
workitem.setItemValue("invoice.number", "FV/2026/7795");
workitem.setItemValue("invoice.date", LocalDate.of(2026, 5, 22));
workitem.setItemValue("invoice.duedate", LocalDate.of(2026, 6, 21));
workitem.setItemValue("invoice.performancedate", LocalDate.of(2026, 5, 21));
workitem.setItemValue("invoice.currency", "USD");
workitem.setItemValue("invoice.rate", 0.2724); // CargoSoft format
workitem.setItemValue("invoice.correction", "false");
workitem.setItemValue("invoice.CorrectionInvoiceNumber", "");
workitem.setItemValue("partner.id", "BP-001");
workitem.setItemValue("partner.vat", "PL1234567890");
List<Object> childItems = new ArrayList<>();
// Position 1: code "023" -> 0 KR -> P_13_6_1
ItemCollection lineItem1 = new ItemCollection()
.setItemValue("numpos", "1")
.setItemValue("datev.text", "Fracht morski")
.setItemValue("billingtext", "Usługa spedycyjna: Fracht morski, + ubezpieczenie")
.setItemValue("datev.umsatz", 1515.00)
.setItemValue("datev.vatrate", 0.0)
.setItemValue("cargosoft.vat.code", "023");
childItems.add(lineItem1.getAllItems());
// Position 2: code "0" -> 0 KR -> P_13_6_1
ItemCollection lineItem2 = new ItemCollection()
.setItemValue("numpos", "2")
.setItemValue("datev.text", "THC")
.setItemValue("billingtext", "Usługa spedycyjna: THC")
.setItemValue("datev.umsatz", 340.00)
.setItemValue("datev.vatrate", 0.0)
.setItemValue("cargosoft.vat.code", "0");
childItems.add(lineItem2.getAllItems());
// Position 3: code "0MR" -> 0 KR -> P_13_6_1
ItemCollection lineItem3 = new ItemCollection()
.setItemValue("numpos", "3")
.setItemValue("datev.text", "Transport intermodalny")
.setItemValue("billingtext", "Usługa spedycyjna:, transport intermodalny")
.setItemValue("datev.umsatz", 785.00)
.setItemValue("datev.vatrate", 0.0)
.setItemValue("cargosoft.vat.code", "0MR");
childItems.add(lineItem3.getAllItems());
workitem.setItemValue("_childitems", childItems);
when(businessPartnerService.getBusinessPartnerByID("BP-001"))
.thenReturn(businessPartner);
FileData xmlTemplate = loadTemplateFromResources(TEMPLATE_FILE);
adapter.updateEInvoice(xmlTemplate, workitem);
assertNotNull(xmlTemplate.getContent(), "XML content should not be null after update");
assertTrue(xmlTemplate.getContent().length > 0, "XML content should not be empty");
// Verify that P_13_6_1 contains the SUM of all three positions
String xml = new String(xmlTemplate.getContent(), "UTF-8");
assertTrue(xml.contains("<P_13_6_1>2640.00</P_13_6_1>"),
"P_13_6_1 must be the sum of all 0%KR positions (1515 + 340 + 785 = 2640.00) but was not");
assertTrue(xml.contains("<P_15>2640.00</P_15>"),
"P_15 must equal the gross total (2640.00) but was not");
writeOutputToResources(xmlTemplate, "invoice-multiple-zero-rate-codes.xml");
}
// Helper methods // Helper methods
/** /**

View file

@ -6,7 +6,7 @@
<Naglowek> <Naglowek>
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza> <KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
<WariantFormularza>3</WariantFormularza> <WariantFormularza>3</WariantFormularza>
<DataWytworzeniaFa>2026-05-14T09:50:45.122365080Z</DataWytworzeniaFa> <DataWytworzeniaFa>2026-05-28T19:15:59.290135Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo> <SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek> </Naglowek>
<Podmiot1> <Podmiot1>
@ -42,7 +42,7 @@
<P_1>2025-02-10</P_1> <P_1>2025-02-10</P_1>
<P_1M>Szczecin</P_1M> <P_1M>Szczecin</P_1M>
<P_2>FV/2025/7470</P_2> <P_2>FV/2025/7470</P_2>
<P_6>2026-05-14</P_6> <P_6>2026-05-28</P_6>
<P_13_9>4620.00</P_13_9> <P_13_9>4620.00</P_13_9>
<P_15>4620.00</P_15> <P_15>4620.00</P_15>
<KursWalutyZ>0.2326</KursWalutyZ> <KursWalutyZ>0.2326</KursWalutyZ>

View file

@ -6,7 +6,7 @@
<Naglowek> <Naglowek>
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza> <KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
<WariantFormularza>3</WariantFormularza> <WariantFormularza>3</WariantFormularza>
<DataWytworzeniaFa>2026-05-14T09:50:45.516800880Z</DataWytworzeniaFa> <DataWytworzeniaFa>2026-05-28T19:15:59.433548Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo> <SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek> </Naglowek>
<Podmiot1> <Podmiot1>
@ -42,7 +42,7 @@
<P_1>2025-02-10</P_1> <P_1>2025-02-10</P_1>
<P_1M>Szczecin</P_1M> <P_1M>Szczecin</P_1M>
<P_2>FV/2025/7471</P_2> <P_2>FV/2025/7471</P_2>
<P_6>2026-05-14</P_6> <P_6>2026-05-28</P_6>
<P_13_1>3960.00</P_13_1> <P_13_1>3960.00</P_13_1>
<P_14_1>910.80</P_14_1> <P_14_1>910.80</P_14_1>
<P_13_6_1>14040.00</P_13_6_1> <P_13_6_1>14040.00</P_13_6_1>

View file

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<Faktura xmlns="http://crd.gov.pl/wzor/2025/06/25/13775/"
xmlns:etd="http://crd.gov.pl/xml/schematy/dziedzinowe/mf/2022/01/05/eD/DefinicjeTypy/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Naglowek>
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
<WariantFormularza>3</WariantFormularza>
<DataWytworzeniaFa>2026-05-28T19:15:59.040792Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek>
<Podmiot1>
<PrefiksPodatnika>PL</PrefiksPodatnika>
<DaneIdentyfikacyjne>
<NIP>9552521552</NIP>
<Nazwa>ALEXANDER GLOBAL LOGISTICS POLAND sp. z o.o.</Nazwa>
</DaneIdentyfikacyjne>
<Adres>
<KodKraju>PL</KodKraju>
<AdresL1>ul. Gdańska 36, 70-660 Szczecin</AdresL1>
</Adres>
<DaneKontaktowe>
<Email>MBudas@alexander-logistics.com</Email>
</DaneKontaktowe>
</Podmiot1>
<Podmiot2>
<DaneIdentyfikacyjne>
<NIP>1234567890</NIP>
<Nazwa>Test Sp. z o.o.</Nazwa>
</DaneIdentyfikacyjne>
<Adres>
<KodKraju>PL</KodKraju>
<AdresL1>ul. Testowa 1</AdresL1>
<AdresL2>00-001 Warszawa</AdresL2>
</Adres>
<NrKlienta>D-12345</NrKlienta>
<JST>2</JST>
<GV>2</GV>
</Podmiot2>
<Fa>
<KodWaluty>USD</KodWaluty>
<P_1>2026-05-22</P_1>
<P_1M>Szczecin</P_1M>
<P_2>FV/2026/7795</P_2>
<P_6>2026-05-21</P_6>
<P_13_6_1>2640.00</P_13_6_1>
<P_15>2640.00</P_15>
<KursWalutyZ>3.6711</KursWalutyZ>
<Adnotacje>
<P_16>2</P_16>
<P_17>2</P_17>
<P_18>2</P_18>
<P_18A>2</P_18A>
<Zwolnienie>
<P_19N>1</P_19N>
</Zwolnienie>
<NoweSrodkiTransportu>
<P_22N>1</P_22N>
</NoweSrodkiTransportu>
<P_23>2</P_23>
<PMarzy>
<P_PMarzyN>1</P_PMarzyN>
</PMarzy>
</Adnotacje>
<RodzajFaktury>VAT</RodzajFaktury>
<FaWiersz>
<NrWierszaFa>1</NrWierszaFa>
<P_7>Usługa spedycyjna: Fracht morski, + ubezpieczenie</P_7>
<P_8A>szt.</P_8A>
<P_8B>1.00</P_8B>
<P_9A>1515.00</P_9A>
<P_11>1515.00</P_11>
<P_11A>1515.00</P_11A>
<P_11Vat>0.00</P_11Vat>
<P_12>0 KR</P_12>
</FaWiersz>
<FaWiersz>
<NrWierszaFa>2</NrWierszaFa>
<P_7>Usługa spedycyjna: THC</P_7>
<P_8A>szt.</P_8A>
<P_8B>1.00</P_8B>
<P_9A>340.00</P_9A>
<P_11>340.00</P_11>
<P_11A>340.00</P_11A>
<P_11Vat>0.00</P_11Vat>
<P_12>0 KR</P_12>
</FaWiersz>
<FaWiersz>
<NrWierszaFa>3</NrWierszaFa>
<P_7>Usługa spedycyjna:, transport intermodalny</P_7>
<P_8A>szt.</P_8A>
<P_8B>1.00</P_8B>
<P_9A>785.00</P_9A>
<P_11>785.00</P_11>
<P_11A>785.00</P_11A>
<P_11Vat>0.00</P_11Vat>
<P_12>0 KR</P_12>
</FaWiersz>
<Platnosc>
<TerminPlatnosci>
<Termin>2026-06-21</Termin>
</TerminPlatnosci>
<FormaPlatnosci>6</FormaPlatnosci>
<RachunekBankowy>
<NrRB>PL79116022020000000654306674</NrRB>
<SWIFT>BIGBPLPWXXX</SWIFT>
<NazwaBanku>Bank Millennium S.A.</NazwaBanku>
<OpisRachunku>Konto PLN</OpisRachunku>
</RachunekBankowy>
<RachunekBankowy>
<NrRB>PL16116022020000000654910469</NrRB>
<SWIFT>BIGBPLPWXXX</SWIFT>
<NazwaBanku>Bank Millennium S.A.</NazwaBanku>
<OpisRachunku>Konto EUR</OpisRachunku>
</RachunekBankowy>
<RachunekBankowy>
<NrRB>PL72116022020000000654911595</NrRB>
<SWIFT>BIGBPLPWXXX</SWIFT>
<NazwaBanku>Bank Millennium S.A.</NazwaBanku>
<OpisRachunku>Konto USD</OpisRachunku>
</RachunekBankowy>
</Platnosc>
</Fa>
</Faktura>

View file

@ -6,7 +6,7 @@
<Naglowek> <Naglowek>
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza> <KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
<WariantFormularza>3</WariantFormularza> <WariantFormularza>3</WariantFormularza>
<DataWytworzeniaFa>2026-05-14T09:50:45.478749958Z</DataWytworzeniaFa> <DataWytworzeniaFa>2026-05-28T19:15:59.394284Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo> <SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek> </Naglowek>
<Podmiot1> <Podmiot1>
@ -42,7 +42,7 @@
<P_1>2025-02-10</P_1> <P_1>2025-02-10</P_1>
<P_1M>Szczecin</P_1M> <P_1M>Szczecin</P_1M>
<P_2>FV/2025/001</P_2> <P_2>FV/2025/001</P_2>
<P_6>2026-05-14</P_6> <P_6>2026-05-28</P_6>
<P_13_9>10000.00</P_13_9> <P_13_9>10000.00</P_13_9>
<P_15>10000.00</P_15> <P_15>10000.00</P_15>
<Adnotacje> <Adnotacje>

View file

@ -6,7 +6,7 @@
<Naglowek> <Naglowek>
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza> <KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
<WariantFormularza>3</WariantFormularza> <WariantFormularza>3</WariantFormularza>
<DataWytworzeniaFa>2026-05-14T09:50:45.408813197Z</DataWytworzeniaFa> <DataWytworzeniaFa>2026-05-28T19:15:59.342086Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo> <SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek> </Naglowek>
<Podmiot1> <Podmiot1>
@ -42,7 +42,7 @@
<P_1>2025-02-10</P_1> <P_1>2025-02-10</P_1>
<P_1M>Szczecin</P_1M> <P_1M>Szczecin</P_1M>
<P_2>FV/2025/001</P_2> <P_2>FV/2025/001</P_2>
<P_6>2026-05-14</P_6> <P_6>2026-05-28</P_6>
<P_13_8>10000.00</P_13_8> <P_13_8>10000.00</P_13_8>
<P_15>10000.00</P_15> <P_15>10000.00</P_15>
<Adnotacje> <Adnotacje>

View file

@ -6,7 +6,7 @@
<Naglowek> <Naglowek>
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza> <KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
<WariantFormularza>3</WariantFormularza> <WariantFormularza>3</WariantFormularza>
<DataWytworzeniaFa>2026-05-14T09:50:45.613224263Z</DataWytworzeniaFa> <DataWytworzeniaFa>2026-05-28T19:15:59.512152Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo> <SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek> </Naglowek>
<Podmiot1> <Podmiot1>
@ -42,7 +42,7 @@
<P_1>2025-02-10</P_1> <P_1>2025-02-10</P_1>
<P_1M>Szczecin</P_1M> <P_1M>Szczecin</P_1M>
<P_2>FV/2025/001</P_2> <P_2>FV/2025/001</P_2>
<P_6>2026-05-14</P_6> <P_6>2026-05-28</P_6>
<P_13_1>10000.00</P_13_1> <P_13_1>10000.00</P_13_1>
<P_14_1>2300.00</P_14_1> <P_14_1>2300.00</P_14_1>
<P_15>12300.00</P_15> <P_15>12300.00</P_15>

View file

@ -6,7 +6,7 @@
<Naglowek> <Naglowek>
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza> <KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
<WariantFormularza>3</WariantFormularza> <WariantFormularza>3</WariantFormularza>
<DataWytworzeniaFa>2026-05-14T09:50:45.565082350Z</DataWytworzeniaFa> <DataWytworzeniaFa>2026-05-28T19:15:59.464195Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo> <SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek> </Naglowek>
<Podmiot1> <Podmiot1>
@ -42,7 +42,7 @@
<P_1>2025-02-10</P_1> <P_1>2025-02-10</P_1>
<P_1M>Szczecin</P_1M> <P_1M>Szczecin</P_1M>
<P_2>FV/2025/001</P_2> <P_2>FV/2025/001</P_2>
<P_6>2026-05-14</P_6> <P_6>2026-05-28</P_6>
<P_13_1>-900.00</P_13_1> <P_13_1>-900.00</P_13_1>
<P_14_1>-207.00</P_14_1> <P_14_1>-207.00</P_14_1>
<P_14_1W>-48.15</P_14_1W> <P_14_1W>-48.15</P_14_1W>