fixed correct summarization in writeSummaryFields - with multipel 0% rules
This commit is contained in:
parent
ba40d05c9d
commit
111527b407
9 changed files with 248 additions and 29 deletions
|
|
@ -286,34 +286,49 @@ public class KSeFInvoiceLineBuilder {
|
|||
Map<TaxCode, NetVatPair> aggregates,
|
||||
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()) {
|
||||
TaxCode taxCode = entry.getKey();
|
||||
NetVatPair pair = entry.getValue();
|
||||
|
||||
// Net summary field (always present)
|
||||
String netField = taxCode.getNetSummaryField();
|
||||
Element netElement = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, netField);
|
||||
netElement.setTextContent(format(pair.net));
|
||||
logger.info("│ ├── set " + netField + " = " + format(pair.net));
|
||||
netByField.merge(taxCode.getNetSummaryField(), pair.net, BigDecimal::add);
|
||||
|
||||
// VAT summary field (only for taxable codes)
|
||||
if (taxCode.hasVat()) {
|
||||
String vatField = taxCode.getVatSummaryField();
|
||||
Element vatElement = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, vatField);
|
||||
vatElement.setTextContent(format(pair.vat));
|
||||
logger.info("│ ├── set " + vatField + " = " + format(pair.vat));
|
||||
vatByField.merge(taxCode.getVatSummaryField(), pair.vat, BigDecimal::add);
|
||||
}
|
||||
|
||||
// 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");
|
||||
p18Element.setTextContent(taxCode.getP18Value());
|
||||
logger.info("│ ├── set P_18 = " + taxCode.getP18Value());
|
||||
p18Element.setTextContent(reverseCharge ? "1" : "2");
|
||||
logger.info("│ ├── set P_18 = " + (reverseCharge ? "1" : "2"));
|
||||
|
||||
}
|
||||
|
||||
// P_15 - gross total of the entire invoice (always present)
|
||||
// P_15 - gross total
|
||||
Element p15 = model.findOrCreateChildNode(elementFa, EInvoiceNS.KSEF, "P_15");
|
||||
p15.setTextContent(format(grossTotal));
|
||||
logger.info("│ ├── set P_15 = " + format(grossTotal));
|
||||
|
|
|
|||
|
|
@ -491,6 +491,86 @@ public class KSeFAdapterTest {
|
|||
"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 ──────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-14T09:50:45.122365080Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-05-28T19:15:59.290135Z</DataWytworzeniaFa>
|
||||
<SystemInfo>Imixs eInvoice</SystemInfo>
|
||||
</Naglowek>
|
||||
<Podmiot1>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<P_1>2025-02-10</P_1>
|
||||
<P_1M>Szczecin</P_1M>
|
||||
<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_15>4620.00</P_15>
|
||||
<KursWalutyZ>0.2326</KursWalutyZ>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-14T09:50:45.516800880Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-05-28T19:15:59.433548Z</DataWytworzeniaFa>
|
||||
<SystemInfo>Imixs eInvoice</SystemInfo>
|
||||
</Naglowek>
|
||||
<Podmiot1>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<P_1>2025-02-10</P_1>
|
||||
<P_1M>Szczecin</P_1M>
|
||||
<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_14_1>910.80</P_14_1>
|
||||
<P_13_6_1>14040.00</P_13_6_1>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-14T09:50:45.478749958Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-05-28T19:15:59.394284Z</DataWytworzeniaFa>
|
||||
<SystemInfo>Imixs eInvoice</SystemInfo>
|
||||
</Naglowek>
|
||||
<Podmiot1>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<P_1>2025-02-10</P_1>
|
||||
<P_1M>Szczecin</P_1M>
|
||||
<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_15>10000.00</P_15>
|
||||
<Adnotacje>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-14T09:50:45.408813197Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-05-28T19:15:59.342086Z</DataWytworzeniaFa>
|
||||
<SystemInfo>Imixs eInvoice</SystemInfo>
|
||||
</Naglowek>
|
||||
<Podmiot1>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<P_1>2025-02-10</P_1>
|
||||
<P_1M>Szczecin</P_1M>
|
||||
<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_15>10000.00</P_15>
|
||||
<Adnotacje>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-14T09:50:45.613224263Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-05-28T19:15:59.512152Z</DataWytworzeniaFa>
|
||||
<SystemInfo>Imixs eInvoice</SystemInfo>
|
||||
</Naglowek>
|
||||
<Podmiot1>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<P_1>2025-02-10</P_1>
|
||||
<P_1M>Szczecin</P_1M>
|
||||
<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_14_1>2300.00</P_14_1>
|
||||
<P_15>12300.00</P_15>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-14T09:50:45.565082350Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-05-28T19:15:59.464195Z</DataWytworzeniaFa>
|
||||
<SystemInfo>Imixs eInvoice</SystemInfo>
|
||||
</Naglowek>
|
||||
<Podmiot1>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<P_1>2025-02-10</P_1>
|
||||
<P_1M>Szczecin</P_1M>
|
||||
<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_14_1>-207.00</P_14_1>
|
||||
<P_14_1W>-48.15</P_14_1W>
|
||||
|
|
|
|||
Loading…
Reference in a new issue