update ksef workflow

This commit is contained in:
Ralph Soika 2026-04-16 17:46:32 +02:00
parent 9884a3cd00
commit ae11393c8c
5 changed files with 228 additions and 11 deletions

View file

@ -2,6 +2,10 @@ package com.alexanderlogistics.einvoice;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Collection; import java.util.Collection;
@ -10,6 +14,9 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import org.imixs.archive.core.SnapshotService; import org.imixs.archive.core.SnapshotService;
@ -29,11 +36,15 @@ import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException; import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException; import org.imixs.workflow.exceptions.QueryException;
import org.imixs.workflow.util.XMLParser; import org.imixs.workflow.util.XMLParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.alexanderlogistics.BusinessPartnerService; import com.alexanderlogistics.BusinessPartnerService;
import com.alexanderlogistics.InvoiceService; import com.alexanderlogistics.InvoiceService;
import com.alexanderlogistics.InvoiceUtil; import com.alexanderlogistics.InvoiceUtil;
import com.alexanderlogistics.xml.CargosoftXMLInvoiceImportService;
import jakarta.inject.Inject; import jakarta.inject.Inject;
@ -155,13 +166,20 @@ public class KSeFAdapter implements SignalAdapter {
// date // date
model.setIssueDateTime(workitem.getItemValueLocalDate("invoice.date")); model.setIssueDateTime(workitem.getItemValueLocalDate("invoice.date"));
model.setDueDateTime(workitem.getItemValueLocalDate("invoice.duedate"));
// Set Performance Date
if (workitem.getItemValueDate("invoice.performancedate") == null) {
// hilfs code um das invoice.performancedate nachträglich zu parsen
syncPerformanceDate(workitem);
}
((EInvoiceModelKSeF) model)
.setPerformanceDateTime(workitem.getItemValueLocalDate("invoice.performancedate"));
// Update Addresses // Update Addresses
TradeParty billingAddress = buildAddress(workitem, "buyer", model); TradeParty billingAddress = buildAddress(workitem, "buyer", model);
model.setTradeParty(billingAddress); model.setTradeParty(billingAddress);
// set Tax Type based on vatID // set Tax Type based on vatID - as a result taxType is 1=Poland 2=EU 3=Other
((EInvoiceModelKSeF) model).setTaxType(workitem.getItemValueString("partner.vat")); ((EInvoiceModelKSeF) model).setTaxType(workitem.getItemValueString("partner.vat"));
workitem.setItemValue("invoice.tax.type", ((EInvoiceModelKSeF) model).getTaxType()); workitem.setItemValue("invoice.tax.type", ((EInvoiceModelKSeF) model).getTaxType());
@ -227,16 +245,56 @@ public class KSeFAdapter implements SignalAdapter {
} }
// Summenbildung // Summenbildung
/*
// Netto * Field mapping:
* <ul>
* <li>taxType "1" (Poland): P_13_1 (domestic VAT)</li>
* <li>taxType "2" (EU): P_13_6_2 (intra-community delivery, 0%)</li>
* <li>taxType "3" (Non-EU): P_13_6_3 (export, 0%)</li>
* </ul>
*/
model.setNetTotalAmount(workitem.getItemValueDouble("invoice.total.net")); model.setNetTotalAmount(workitem.getItemValueDouble("invoice.total.net"));
// ?? has no function
model.setTaxRate(workitem.getItemValueDouble("invoice.total.tax"));
// Tax // Tax
/*
* P_14_1
*
* This call also generate P_14_1W bei fremdwährung
*/
model.setTaxTotalAmount(InvoiceUtil.round(workitem.getItemValueDouble("invoice.total") model.setTaxTotalAmount(InvoiceUtil.round(workitem.getItemValueDouble("invoice.total")
- workitem.getItemValueDouble("invoice.total.net"))); - workitem.getItemValueDouble("invoice.total.net")));
model.setTaxRate(workitem.getItemValueDouble("invoice.total.tax")); /*
* If we have Foreign Currency we need to set P_14_1W in case we are tax type 1
*/
if (!"PLN".equals(workitem.getItemValueString("invoice.currency"))) {
if ("1".equals(((EInvoiceModelKSeF) model).getTaxType())) {
// compute rate
double rate = workitem.getItemValueDouble("invoice.rate");
logger.info("│ ├── rate=" + rate);
double totalTax = InvoiceUtil.round(workitem.getItemValueDouble("invoice.total.tax"));
logger.info("│ ├── total.tax=" + totalTax);
BigDecimal value = BigDecimal.valueOf(totalTax)
.divide(BigDecimal.valueOf(rate), 10, RoundingMode.HALF_UP);
// P_14_1W must come directly after P_14_1
logger.info("│ ├── P_14_1W=" + value);
Element element = model.findOrCreateChildNodeAfter(elementFa, EInvoiceNS.KSEF, "P_14_1W", "P_14_1");
element.setTextContent(value.setScale(2, RoundingMode.HALF_UP).toPlainString());
}
}
// Brutto // Brutto
/*
* P_15
*/
model.setGrandTotalAmount(workitem.getItemValueDouble("invoice.total")); model.setGrandTotalAmount(workitem.getItemValueDouble("invoice.total"));
// finally set the due date at the end of the XML tree
model.setDueDateTime(workitem.getItemValueLocalDate("invoice.duedate"));
// finally update the template file // finally update the template file
fileDataXMLTemplate.setContent(model.getContent()); fileDataXMLTemplate.setContent(model.getContent());
@ -246,6 +304,42 @@ public class KSeFAdapter implements SignalAdapter {
} }
/**
* Dies ist eine Hilfsmethode die nachträglich das invoice.performancedate aus
* dem Cargosoft XML ausliest
*
* @param workitem
* @throws PluginException
*/
private void syncPerformanceDate(ItemCollection workitem) throws PluginException {
try {
logger.info("----Resync cargosoft performancedate....");
DocumentBuilder documentBuilder;
// hole die XML Datei
FileData cargoXML = snapshotService.getWorkItemFile(workitem.getUniqueID(),
workitem.getItemValueString("cargosoft.import.filename"));
if (cargoXML != null) {
InputStream inputStream = new ByteArrayInputStream(cargoXML.getContent());
InputSource inputSource = new InputSource(inputStream);
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = documentBuilder.parse(inputSource);
// Performance Date
CargosoftXMLInvoiceImportService.readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PerformanceDate",
workitem, "invoice.performancedate",
Date.class);
// falls keines gefunden wurde nehmen wir das invoice date
if (workitem.getItemValueDate("invoice.performancedate") == null) {
workitem.setItemValue("invoice.performancedate", workitem.getItemValueDate("invoice.date"));
}
}
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new PluginException(CargosoftXMLInvoiceImportService.class.getName(), "XML_ERROR", e.getMessage());
}
}
/** /**
* Gibt True zurück wenn es eine korrektur rechnung ist * Gibt True zurück wenn es eine korrektur rechnung ist
* *

View file

@ -445,6 +445,10 @@ public class CargosoftXMLInvoiceImportService {
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PaymentConditions/DueDate", workitem, "invoice.reminder", readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PaymentConditions/DueDate", workitem, "invoice.reminder",
Date.class); Date.class);
// Performance Date
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/PerformanceDate", workitem, "invoice.performancedate",
Date.class);
readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAddress/Codes/Code", workitem, "dbtr.number", readXMLValue(doc, "/Invoices/Invoice/InvoiceHeader/InvoiceAddress/Codes/Code", workitem, "dbtr.number",
String.class); String.class);
String dbtrNumber = workitem.getItemValueString("dbtr.number"); String dbtrNumber = workitem.getItemValueString("dbtr.number");
@ -522,7 +526,7 @@ public class CargosoftXMLInvoiceImportService {
* @param itemName * @param itemName
* @param itemType * @param itemType
*/ */
private <T> void readXMLValue(Document doc, String expression, ItemCollection workitem, String itemName, public static <T> void readXMLValue(Document doc, String expression, ItemCollection workitem, String itemName,
Class<T> itemType) { Class<T> itemType) {
// create XPath... // create XPath...
XPathFactory xpathFactory = XPathFactory.newInstance(); XPathFactory xpathFactory = XPathFactory.newInstance();

View file

@ -0,0 +1,118 @@
<?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-04-16T06:22:32.455873037Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek>
<!-- Seller (Your Polish Company - Pre-filled) -->
<Podmiot1>
<DaneIdentyfikacyjne>
<NIP>9552521552</NIP>
<Nazwa>Alexander Global Logistics</Nazwa>
</DaneIdentyfikacyjne>
<Adres>
<KodKraju>PL</KodKraju>
<AdresL1>Gdanska 36</AdresL1>
<AdresL2>70-660 Szczecin</AdresL2>
</Adres>
<DaneKontaktowe>
<Email>MBudas@alexander-logistics.com</Email>
</DaneKontaktowe>
</Podmiot1>
<!-- Buyer (Customer - Empty, to be filled) -->
<Podmiot2>
<DaneIdentyfikacyjne>
<!-- NIP falls eine PL Ust Vorliegt
ansonsten NrID - geht immer -->
<!-- <Nazwa>#Customer Name#</Nazwa> -->
<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>
<!---
Contact information from buyer can be left
<DaneKontaktowe>
<Email></Email>
<Telefon></Telefon>
</DaneKontaktowe>
-->
<NrKlienta>D-12345</NrKlienta>
<JST>2</JST>
<!-- fixed -->
<GV>2</GV>
<!-- fixed -->
</Podmiot2>
<!-- Invoice Data -->
<Fa>
<KodWaluty>PLN</KodWaluty>
<P_1>2025-02-10</P_1>
<!-- Invoice Date -->
<P_2>FV/2025/001</P_2>
<!-- Invoice Number -->
<P_6>2025-03-10</P_6>
<!-- Due Date -->
<!-- Totals will only be computed by the EInvoiceModelKSeF Class-->
<!--
<P_13_1>0.00</P_13_1>
<P_14_1>0.00</P_14_1>
<P_15>0.00</P_15>
-->
<P_13_1>10000.00</P_13_1>
<P_14_1>2300.00</P_14_1>
<P_15>12300.00</P_15>
<Adnotacje>
<!-- 1 yes - 2 no -->
<P_16>2</P_16>
<!-- Keine Selbstfakturierung -->
<P_17>2</P_17>
<!-- Kein Reverse Charge -->
<P_18>2</P_18>
<!-- Kein Split Payment (Rechnung unter 15.000 PLN/EUR) -->
<P_18A>2</P_18A>
<!-- Keine Steuerbefreiung -->
<Zwolnienie>
<P_19N>1</P_19N>
</Zwolnienie>
<!-- Keine neuen Verkehrsmittel -->
<NoweSrodkiTransportu>
<P_22N>1</P_22N>
</NoweSrodkiTransportu>
<!-- Kein vereinfachtes Verfahren nach Art. 135 -->
<P_23>2</P_23>
<!-- Keine Margenregelung -->
<PMarzy>
<P_PMarzyN>1</P_PMarzyN>
</PMarzy>
</Adnotacje>
<!-- Invoice Type (VAT) -->
<RodzajFaktury>VAT</RodzajFaktury>
<!-- Invoice Positions: FaWiersz -->
<FaWiersz>
<NrWierszaFa>1</NrWierszaFa>
<UU_ID>a743f373-b75c-44c5-a077-ee628295b5d3</UU_ID>
<P_8A>szt.</P_8A>
<P_8B>1</P_8B>
<P_9A>6000.00</P_9A>
<P_11>6000.00</P_11>
<P_12>0</P_12>
</FaWiersz>
<FaWiersz>
<NrWierszaFa>2</NrWierszaFa>
<UU_ID>9eb2d946-a3cb-4adb-8ed1-069e2f48d67d</UU_ID>
<P_8A>szt.</P_8A>
<P_8B>1</P_8B>
<P_9A>4000.00</P_9A>
<P_11>4000.00</P_11>
<P_12>0</P_12>
</FaWiersz>
</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-02-24T16:11:02.707702Z</DataWytworzeniaFa> <DataWytworzeniaFa>2026-04-16T06:22:32.198172335Z</DataWytworzeniaFa>
<SystemInfo>Imixs eInvoice</SystemInfo> <SystemInfo>Imixs eInvoice</SystemInfo>
</Naglowek> </Naglowek>
<!-- Seller (Your Polish Company - Pre-filled) --> <!-- Seller (Your Polish Company - Pre-filled) -->
@ -103,12 +103,13 @@
</DaneFaKorygowanej> </DaneFaKorygowanej>
<FaWiersz> <FaWiersz>
<NrWierszaFa>1</NrWierszaFa> <NrWierszaFa>1</NrWierszaFa>
<UU_ID>781e1f16-a86e-452d-b959-01c76743a792</UU_ID> <UU_ID>d437ac36-9439-4bd6-96fb-0fe0b91fd32d</UU_ID>
<P_7>Transport Berlin - Warsaw</P_7> <P_7>usługa spedycyjna / transport w relacji, PL63 - CZ43</P_7>
<P_8A>szt.</P_8A> <P_8A>szt.</P_8A>
<P_8B>1</P_8B> <P_8B>1</P_8B>
<P_9A>-900.00</P_9A> <P_9A>-900.00</P_9A>
<P_11>-900.00</P_11> <P_11>-900.00</P_11>
<P_12>0</P_12>
</FaWiersz> </FaWiersz>
</Fa> </Fa>
</Faktura> </Faktura>

View file

@ -1569,7 +1569,7 @@ Wiedervorlage wird um 7 bzw. 5 Tage erhöht</bpmn2:text>
<imixs:value><![CDATA[0]]></imixs:value> <imixs:value><![CDATA[0]]></imixs:value>
</imixs:item> </imixs:item>
<imixs:item name="rtfresultlog" type="xs:string"> <imixs:item name="rtfresultlog" type="xs:string">
<imixs:value/> <imixs:value><![CDATA[-> ksef.xml created]]></imixs:value>
</imixs:item> </imixs:item>
<imixs:item name="keyupdateacl" type="xs:boolean"> <imixs:item name="keyupdateacl" type="xs:boolean">
<imixs:value>false</imixs:value> <imixs:value>false</imixs:value>
@ -2301,7 +2301,7 @@ AGL Poland Team
<imixs:value><![CDATA[0]]></imixs:value> <imixs:value><![CDATA[0]]></imixs:value>
</imixs:item> </imixs:item>
<imixs:item name="rtfresultlog" type="xs:string"> <imixs:item name="rtfresultlog" type="xs:string">
<imixs:value/> <imixs:value><![CDATA[-> ksef.xml tranfered successful. ]]></imixs:value>
</imixs:item> </imixs:item>
<imixs:item name="keyupdateacl" type="xs:boolean"> <imixs:item name="keyupdateacl" type="xs:boolean">
<imixs:value>false</imixs:value> <imixs:value>false</imixs:value>