anapssungen der einvoice
This commit is contained in:
parent
f758c4a6ac
commit
3f15b3a11b
12 changed files with 281 additions and 622 deletions
|
|
@ -38,6 +38,12 @@ public class InvoiceUtil {
|
|||
return bd.doubleValue();
|
||||
}
|
||||
|
||||
public static BigDecimal roundBigDecimal(double value) {
|
||||
BigDecimal bd = BigDecimal.valueOf(value);
|
||||
bd = bd.setScale(2, RoundingMode.HALF_UP);
|
||||
return bd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds a Flat Value
|
||||
*
|
||||
|
|
|
|||
|
|
@ -224,9 +224,9 @@ public class EInvoiceAdapter implements SignalAdapter {
|
|||
// Update Rechnungssummen...
|
||||
if (workitem.getItemValueDouble("invoice.total.tax") > 0) {
|
||||
// wir haben eine Steuer!
|
||||
model.setTaxTotalAmount(InvoiceUtil.round(workitem.getItemValueDouble("invoice.total")
|
||||
model.setTaxTotalAmount(InvoiceUtil.roundBigDecimal(workitem.getItemValueDouble("invoice.total")
|
||||
- workitem.getItemValueDouble("invoice.total.net")));
|
||||
model.setTaxRate(workitem.getItemValueDouble("invoice.total.tax"));
|
||||
model.setTaxRate(InvoiceUtil.roundBigDecimal(workitem.getItemValueDouble("invoice.total.tax")));
|
||||
}
|
||||
|
||||
// Update Invoice Items
|
||||
|
|
@ -234,13 +234,13 @@ public class EInvoiceAdapter implements SignalAdapter {
|
|||
double lineTotalAmount = 0.00;
|
||||
for (ItemCollection invoiceItem : invoiceItems) {
|
||||
TradeLineItem tradeLineItem = buildTradeLineItem(invoiceItem);
|
||||
model.setTradeLineItem(tradeLineItem);
|
||||
model.addTradeLineItem(tradeLineItem);
|
||||
lineTotalAmount = lineTotalAmount + tradeLineItem.getTotal();
|
||||
}
|
||||
|
||||
// // Summenbildung
|
||||
model.setNetTotalAmount(workitem.getItemValueDouble("invoice.total.net"));
|
||||
model.setGrandTotalAmount(workitem.getItemValueDouble("invoice.total"));
|
||||
model.setNetTotalAmount(InvoiceUtil.roundBigDecimal(workitem.getItemValueDouble("invoice.total.net")));
|
||||
model.setGrandTotalAmount(InvoiceUtil.roundBigDecimal(workitem.getItemValueDouble("invoice.total")));
|
||||
|
||||
// date
|
||||
model.setIssueDateTime(workitem.getItemValueLocalDate("invoice.date"));
|
||||
|
|
|
|||
|
|
@ -1,600 +0,0 @@
|
|||
package com.alexanderlogistics.einvoice;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
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.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
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 org.imixs.archive.core.SnapshotService;
|
||||
import org.imixs.einvoice.EInvoiceFormatException;
|
||||
import org.imixs.einvoice.EInvoiceModel;
|
||||
import org.imixs.einvoice.EInvoiceModelFactory;
|
||||
import org.imixs.einvoice.EInvoiceModelKSeF;
|
||||
import org.imixs.einvoice.EInvoiceNS;
|
||||
import org.imixs.einvoice.TradeLineItem;
|
||||
import org.imixs.einvoice.TradeParty;
|
||||
import org.imixs.workflow.FileData;
|
||||
import org.imixs.workflow.ItemCollection;
|
||||
import org.imixs.workflow.SignalAdapter;
|
||||
import org.imixs.workflow.engine.DocumentService;
|
||||
import org.imixs.workflow.engine.WorkflowService;
|
||||
import org.imixs.workflow.exceptions.AdapterException;
|
||||
import org.imixs.workflow.exceptions.PluginException;
|
||||
import org.imixs.workflow.exceptions.QueryException;
|
||||
import org.imixs.workflow.util.XMLParser;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.alexanderlogistics.BusinessPartnerService;
|
||||
import com.alexanderlogistics.InvoiceService;
|
||||
import com.alexanderlogistics.InvoiceUtil;
|
||||
import com.alexanderlogistics.xml.CargosoftXMLInvoiceImportService;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* The KSeFAdapter converts a Cargsoft outbound invoice into an KSeF XML
|
||||
* e-invoice and sends the xml file to the polish KSeF API
|
||||
*
|
||||
* The adapter can be configured by the model:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
<ksef name="create">
|
||||
<textblock>textblock-ref</textblock>
|
||||
<template>filename</template>
|
||||
<debug>true</debug>
|
||||
</ksef>
|
||||
|
||||
}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* NIP: The adapter needs the NIP (vat-id). If we do not find the partner.vat in
|
||||
* the business object, we do a lookup on the D-Cargosoft object and try the vat
|
||||
* id from there. This is because the partner.vat is a field which was not
|
||||
* defined before.
|
||||
*
|
||||
* <p>
|
||||
* Wenn Debug = true gibt der Adapter alle einzelschritte auf der console aus
|
||||
* und erzeugt zusätzlich die factur-x xml und txt dateien.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @version 1.0
|
||||
* @author rsoika
|
||||
*/
|
||||
public class KSeFAdapterDeprecated implements SignalAdapter {
|
||||
|
||||
final String TYPE_TEXTBLOCK = "textblock";
|
||||
public static final String DOCUMENT_ERROR = "DOCUMENT_ERROR";
|
||||
public static final String CONFIG_ERROR = "CONFIG_ERROR";
|
||||
public static final String API_ERROR = "API_ERROR";
|
||||
public static final String BUSINESSPARTNER_ERROR = "BUSINESSPARTNER_ERROR";
|
||||
public static final String LINE_ITEMS_PROPERTY = "invoice.items";
|
||||
private static Logger logger = Logger.getLogger(EInvoiceAdapter.class.getName());
|
||||
|
||||
public static SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN);
|
||||
public static NumberFormat numberFormat = NumberFormat.getInstance(Locale.GERMANY);
|
||||
boolean debug = false;
|
||||
|
||||
@Inject
|
||||
WorkflowService workflowService;
|
||||
|
||||
@Inject
|
||||
DocumentService documentService;
|
||||
|
||||
@Inject
|
||||
SnapshotService snapshotService;
|
||||
|
||||
@Inject
|
||||
BusinessPartnerService businessPartnerService;
|
||||
|
||||
@Inject
|
||||
InvoiceService invoiceService;
|
||||
|
||||
/**
|
||||
* This method
|
||||
*
|
||||
* @throws PluginException
|
||||
*/
|
||||
@Override
|
||||
public ItemCollection execute(ItemCollection workitem, ItemCollection event)
|
||||
throws AdapterException, PluginException {
|
||||
|
||||
logger.info("├── 🔜 Convert Invoice to KSeF...");
|
||||
// read configuration....
|
||||
ItemCollection eInvoiceConfig = workflowService.evalWorkflowResult(event, "ksef",
|
||||
workitem,
|
||||
false);
|
||||
if (eInvoiceConfig == null || !eInvoiceConfig.hasItem("CREATE")) {
|
||||
throw new PluginException(EInvoiceAdapter.class.getSimpleName(), CONFIG_ERROR,
|
||||
"missing e-invoice/ksef configuration in model event - please check model configuration");
|
||||
}
|
||||
ItemCollection ksefCreateDefinition = XMLParser.parseItemStructure(eInvoiceConfig.getItemValueString("CREATE"));
|
||||
try {
|
||||
|
||||
// Load the e-invoice template....
|
||||
FileData xmlFileData = loadXMLTemplate(workitem, ksefCreateDefinition);
|
||||
|
||||
updateEInvoice(xmlFileData, workitem);
|
||||
|
||||
// append XML document
|
||||
logger.info("│ ├── attach KSeF e-invoice...");
|
||||
workitem.addFileData(xmlFileData);
|
||||
|
||||
} catch (PluginException e) {
|
||||
throw new AdapterException(e);
|
||||
}
|
||||
|
||||
return workitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method updates an e-invoice template with the data stored in the
|
||||
* workitem.
|
||||
*
|
||||
* First the method loads an EInvoiceModel based on the provided XML Template
|
||||
* and than updates the e-invoice data based on the items stored in the given
|
||||
* workitem.
|
||||
*
|
||||
* @param workitem
|
||||
* @throws PluginException
|
||||
*/
|
||||
public void updateEInvoice(FileData fileDataXMLTemplate, ItemCollection workitem) throws PluginException {
|
||||
|
||||
try {
|
||||
EInvoiceModel model = EInvoiceModelFactory.read(new ByteArrayInputStream(fileDataXMLTemplate.getContent()));
|
||||
|
||||
model.setId(workitem.getItemValueString("invoice.number"));
|
||||
|
||||
// date
|
||||
model.setIssueDateTime(workitem.getItemValueLocalDate("invoice.date"));
|
||||
|
||||
// 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
|
||||
TradeParty billingAddress = buildAddress(workitem, "buyer", model);
|
||||
model.setTradeParty(billingAddress);
|
||||
|
||||
// set Tax Type based on vatID - as a result taxType is 1=Poland 2=EU 3=Other
|
||||
((EInvoiceModelKSeF) model).setTaxType(workitem.getItemValueString("partner.vat"));
|
||||
workitem.setItemValue("invoice.tax.type", ((EInvoiceModelKSeF) model).getTaxType());
|
||||
|
||||
// Update Invoice Type (RodzajFaktury) -> VAT | KOR
|
||||
Element elementFa = model.findOrCreateChildNode(model.getRoot(), EInvoiceNS.KSEF, "Fa");
|
||||
|
||||
if (isKorrekturRechnung(workitem)) {
|
||||
((EInvoiceModelKSeF) model).setRodzajFaktury("KOR");
|
||||
logger.info("│ ├── invoice type=KOR");
|
||||
|
||||
// Set correction data (DaneFaKorygowanej) - required for KOR invoices
|
||||
Element daneFaKorygowanej = model.findOrCreateChildNodeAfter(
|
||||
elementFa, EInvoiceNS.KSEF, "DaneFaKorygowanej", "RodzajFaktury");
|
||||
|
||||
Date correctionInvoiceDate = workitem.getItemValueDate("invoice.date");
|
||||
// try to lookup original invoice by invoice.CorrectionInvoiceNumber
|
||||
ItemCollection correctionInvoice = invoiceService
|
||||
.findOutboundInvoiceByNumber(workitem.getItemValueString("invoice.CorrectionInvoiceNumber"));
|
||||
if (correctionInvoice != null) {
|
||||
correctionInvoiceDate = correctionInvoice.getItemValueDate("invoice.date");
|
||||
logger.info("│ ├── found original invoice, date: " + correctionInvoiceDate);
|
||||
} else {
|
||||
logger.info("│ ├── ⚠️ original invoice not found, using current date as fallback");
|
||||
}
|
||||
// Original invoice date (DataWystFaKorygowanej) - required
|
||||
if (correctionInvoiceDate != null) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String sCorrectionDate = formatter.format(correctionInvoiceDate);
|
||||
model.updateElementValue(daneFaKorygowanej, EInvoiceNS.KSEF,
|
||||
"DataWystFaKorygowanej", sCorrectionDate);
|
||||
}
|
||||
|
||||
// Original invoice number (NrFaKorygowanej) - required
|
||||
model.updateElementValue(daneFaKorygowanej, EInvoiceNS.KSEF,
|
||||
"NrFaKorygowanej", workitem.getItemValueString("invoice.CorrectionInvoiceNumber"));
|
||||
|
||||
// NrKSeFN = 1 means the original invoice was issued outside KSeF
|
||||
model.updateElementValue(daneFaKorygowanej, EInvoiceNS.KSEF, "NrKSeFN", "1");
|
||||
|
||||
} else {
|
||||
// normale rechnung
|
||||
((EInvoiceModelKSeF) model).setRodzajFaktury("VAT");
|
||||
logger.info("│ ├── invoice type=VAT");
|
||||
}
|
||||
|
||||
// set currency
|
||||
model.updateElementValue(elementFa, EInvoiceNS.KSEF, "KodWaluty",
|
||||
workitem.getItemValueString("invoice.currency"));
|
||||
|
||||
// Update Invoice Items
|
||||
// Here we compute the pos number independent if the _childitems hold a posnum.
|
||||
// This is because a new imported cargosoft invoice does not provide numPos
|
||||
// items in the child list. So it is important to generate the pos numbers here
|
||||
// one by one
|
||||
List<ItemCollection> invoiceItems = InvoiceUtil.explodeChildList(workitem, "_childitems");
|
||||
double lineTotalAmount = 0.00;
|
||||
int pos = 1;
|
||||
for (ItemCollection invoiceItem : invoiceItems) {
|
||||
TradeLineItem tradeLineItem = buildTradeLineItem(invoiceItem, pos);
|
||||
model.setTradeLineItem(tradeLineItem);
|
||||
lineTotalAmount = lineTotalAmount + tradeLineItem.getTotal();
|
||||
pos++;
|
||||
}
|
||||
|
||||
// Summenbildung
|
||||
/*
|
||||
* 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"));
|
||||
|
||||
// ?? has no function
|
||||
model.setTaxRate(workitem.getItemValueDouble("invoice.total.tax"));
|
||||
|
||||
// Tax
|
||||
/*
|
||||
* P_14_1
|
||||
*
|
||||
* This call also generate P_14_1W bei fremdwährung
|
||||
*/
|
||||
model.setTaxTotalAmount(InvoiceUtil.round(workitem.getItemValueDouble("invoice.total")
|
||||
- workitem.getItemValueDouble("invoice.total.net")));
|
||||
/*
|
||||
* 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
|
||||
/*
|
||||
* P_15
|
||||
*/
|
||||
model.setGrandTotalAmount(workitem.getItemValueDouble("invoice.total"));
|
||||
|
||||
/*
|
||||
* KursWalutyZ
|
||||
*
|
||||
* Für Rechnungen in Fremdwährung obligatorisch. Anzuwenden ist der NBP-
|
||||
* Durchschnittskurs des Tages vor Entstehen der Steuerpflicht (Art. 31a
|
||||
* UStG-PL).
|
||||
* Dezimalformat mit Punkt.
|
||||
*/
|
||||
String currency = workitem.getItemValueString("invoice.currency");
|
||||
if (!currency.isBlank() && !"PLN".equals(currency)) {
|
||||
Element p15 = model.findChildNode(elementFa, EInvoiceNS.KSEF, "P_15");
|
||||
if (p15 != null) {
|
||||
Double rate = workitem.getItemValueDouble("invoice.rate");
|
||||
logger.info("│ ├── set KursWalutyZ = " + rate);
|
||||
Element element = model.findOrCreateChildNodeAfter(elementFa, EInvoiceNS.KSEF, "KursWalutyZ",
|
||||
"P_15");
|
||||
element.setTextContent(rate.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// finally set the due date at the end of the XML tree
|
||||
model.setDueDateTime(workitem.getItemValueLocalDate("invoice.duedate"));
|
||||
|
||||
/*
|
||||
* finally update the template file
|
||||
*/
|
||||
fileDataXMLTemplate.setContent(model.getContent());
|
||||
|
||||
} catch (FileNotFoundException | EInvoiceFormatException | TransformerException e) {
|
||||
throw new PluginException(this.getClass().getName(), DOCUMENT_ERROR, e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
if (!workitem.hasItem("invoice.performancedate")) {
|
||||
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
|
||||
*
|
||||
* InvoiceHeader/Correction=true
|
||||
* InvoiceHeader/CorrectionInvoiceNumber !empty
|
||||
*
|
||||
*
|
||||
* @param workitem
|
||||
* @return
|
||||
*/
|
||||
private boolean isKorrekturRechnung(ItemCollection workitem) {
|
||||
return ("true".equals(workitem.getItemValueString("invoice.correction"))
|
||||
&& !workitem.getItemValueString("invoice.CorrectionInvoiceNumber").isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein TradeParty Objekt aus einer Liste von Adresszeilen.
|
||||
*
|
||||
* @param addressLines Liste der Adresszeilen
|
||||
* @param type Der Typ der TradeParty
|
||||
* @return TradeParty
|
||||
*/
|
||||
public TradeParty buildAddress(ItemCollection workitem, String type, EInvoiceModel model) throws PluginException {
|
||||
|
||||
String partnerID = workitem.getItemValueString("partner.id");
|
||||
if (partnerID == null || partnerID.isEmpty()) {
|
||||
throw new PluginException(this.getClass().getName(), DOCUMENT_ERROR, "Missing partnerID");
|
||||
}
|
||||
|
||||
ItemCollection businessPartner = businessPartnerService.getBusinessPartnerByID(partnerID);
|
||||
if (businessPartner == null) {
|
||||
throw new PluginException(this.getClass().getName(), DOCUMENT_ERROR,
|
||||
"Business Partner ID '" + partnerID + "' does not exist");
|
||||
}
|
||||
|
||||
/**
|
||||
* Migration:
|
||||
* If the business partner does not yet have the item "partner.vat" we try here
|
||||
* to resync this information from the cargosoftkreditor object. This is needed
|
||||
* because the partner.vat was not initially defined by the synch processor and
|
||||
* so many partner objects do not yet provide this information.
|
||||
*/
|
||||
if (businessPartner.getItemValueString("partner.vat").isEmpty()) {
|
||||
logger.info("│ ├── BusinessPartner " + partnerID + " does not provide vat-id - try to migrate....");
|
||||
String dNumber = businessPartner.getItemValueString("dbtr.number");
|
||||
if (!dNumber.isEmpty()) {
|
||||
try {
|
||||
String query = "(type:cargosoftkreditor) AND (name:" + dNumber + ")";
|
||||
List<ItemCollection> result;
|
||||
result = documentService.find(query, 1, 0);
|
||||
if (result != null && result.size() > 0) {
|
||||
ItemCollection creditorData = result.get(0);
|
||||
String vatID = creditorData.getItemValueString("_vendor_vat_registration_id");
|
||||
logger.info("│ ├── synchronize VAT Registrytion ID: " + vatID);
|
||||
// update business partner
|
||||
businessPartner.setItemValue("partner.vat", vatID);
|
||||
documentService.saveByNewTransaction(businessPartner);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// should not happen!
|
||||
logger.info("│ ├── ⚠️ Failed to sync BusinessPartner : " + e.getMessage());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TradeParty tradeParty = new TradeParty(type);
|
||||
|
||||
// Name ist immer die erste Zeile
|
||||
tradeParty.setName(businessPartner.getItemValueString("partner.name"));
|
||||
tradeParty.setCountryId(businessPartner.getItemValueString("partner.country"));
|
||||
tradeParty.setCityName(businessPartner.getItemValueString("partner.city"));
|
||||
tradeParty.setPostcodeCode(businessPartner.getItemValueString("partner.zip"));
|
||||
tradeParty.setStreetAddress(businessPartner.getItemValueString("partner.address"));
|
||||
|
||||
if ("buyer".equals(type)) {
|
||||
// if we do NOT have a partner.vat we can not upload the invoice!
|
||||
String partnerVAT = businessPartner.getItemValueString("partner.vat");
|
||||
if (partnerVAT.isBlank()) {
|
||||
// Just a warning
|
||||
logger.warning("│ ├── ⚠️ Business Partner ID '" + partnerID + "' does not contain a VAT ID !");
|
||||
// throw new PluginException(this.getClass().getName(), BUSINESSPARTNER_ERROR,
|
||||
// "Business Partner ID '" + partnerID + "' does not contain a VAT ID !");
|
||||
}
|
||||
workitem.setItemValue("partner.vat", partnerVAT);
|
||||
tradeParty.setVatNumber(partnerVAT);
|
||||
// Update or create NrKlienta element directly under Podmiot2
|
||||
Element podmiot2 = model.findOrCreateChildNode(model.getRoot(), EInvoiceNS.KSEF, "Podmiot2");
|
||||
model.updateElementValue(podmiot2, EInvoiceNS.KSEF, "NrKlienta",
|
||||
businessPartner.getItemValueString("dbtr.number"));
|
||||
|
||||
}
|
||||
|
||||
return tradeParty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the data list of an invoice line and returns a TradeLineItem object.
|
||||
* The order of the list items must be exactly!
|
||||
*
|
||||
* # 16.04.2026
|
||||
* Laut Herrn Grzegorz Grzelczyk dürfen in den Rechnungspositionen nur netto
|
||||
* werte eingetragen sein. Siehe buildTradeLineItem()
|
||||
*
|
||||
* Des weiteren soll anstatt datev.text (pos nummer) der original billing text
|
||||
* ausgewiesen werden
|
||||
*/
|
||||
private TradeLineItem buildTradeLineItem(ItemCollection orderItem, int pos) {
|
||||
if (orderItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TradeLineItem tradeLineItem = new
|
||||
// TradeLineItem(orderItem.getItemValueString("numpos"));
|
||||
// We do not trust the item 'numPos' here because it can be empty for new
|
||||
// invoices!
|
||||
TradeLineItem tradeLineItem = new TradeLineItem(pos + "");
|
||||
|
||||
// Herrn Grzegorz Grzelczyk möchte hier BillingText
|
||||
// tradeLineItem.setName(orderItem.getItemValueString("datev.text"));
|
||||
// tradeLineItem.setName(orderItem.getItemValueString("billingtext"));
|
||||
// Herr Grzelczyk will das alle billing texte aus der liste, verkettet
|
||||
// ausgegeben werden.
|
||||
List<String> billingTexts = orderItem.getItemValue("billingtext");
|
||||
String billingTextName = billingTexts == null
|
||||
? ""
|
||||
: String.join(", ", billingTexts);
|
||||
final int MAX_LENGTH = 512;
|
||||
if (billingTextName.length() > MAX_LENGTH) {
|
||||
billingTextName = billingTextName.substring(0, MAX_LENGTH);
|
||||
}
|
||||
tradeLineItem.setName(billingTextName);
|
||||
|
||||
tradeLineItem.setQuantity(1);
|
||||
|
||||
double vat = orderItem.getItemValueDouble("datev.vatrate"); // 23.00
|
||||
double netto = orderItem.getItemValueDouble("datev.umsatz"); // 970.00
|
||||
|
||||
// # 16.04.2026
|
||||
// Der total bezieht sich laut Herrn Grzegorz Grzelczyk ausschließlich auf den
|
||||
// Nettowert x Menge.
|
||||
// Der Brutto Wert ist hier falsch! Da die Menge immer 1 ist ist das beide male
|
||||
// der selbe wert
|
||||
// WRONG: tradeLineItem.setTotal(brutto);
|
||||
|
||||
// double brutto = netto * (1 + (vat / 100));
|
||||
// double steuer = brutto - netto;
|
||||
tradeLineItem.setTaxRate(vat);
|
||||
tradeLineItem.setNetPrice(netto);
|
||||
tradeLineItem.setTotal(netto); // menge x netto
|
||||
|
||||
return tradeLineItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads a text-block for a specified ref and appends the named
|
||||
* fileData object of this document.
|
||||
*
|
||||
* @param document
|
||||
* @throws PluginException
|
||||
*/
|
||||
|
||||
private FileData loadXMLTemplate(ItemCollection workitem, ItemCollection config)
|
||||
throws PluginException {
|
||||
|
||||
String textblock = config.getItemValueString("textblock");
|
||||
String template = config.getItemValueString("template");
|
||||
String sourceName = config.getItemValueString("source");
|
||||
|
||||
try {
|
||||
debug = Boolean.parseBoolean(config.getItemValueString("debug"));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
String targetName = "ksef.xml";
|
||||
|
||||
// adapt text....
|
||||
sourceName = workflowService.adaptText(sourceName, workitem);
|
||||
|
||||
if ((template == null || template.isEmpty()) || (textblock == null || textblock.isEmpty())) {
|
||||
throw new PluginException(EInvoiceAdapter.class.getSimpleName(),
|
||||
CONFIG_ERROR,
|
||||
"invalid e-invoice configuration in model event - textblock/template reference not defined!");
|
||||
}
|
||||
|
||||
// load the text block
|
||||
FileData fileData = loadTextBlockFileData(textblock, template);
|
||||
|
||||
// do we found the document?
|
||||
if (fileData == null) {
|
||||
throw new PluginException(EInvoiceAdapter.class.getSimpleName(),
|
||||
CONFIG_ERROR,
|
||||
"invalid e-invoice configuration in model event - textblock/template: " + textblock + "/" + template
|
||||
+ " not found!");
|
||||
}
|
||||
fileData.setName(targetName);
|
||||
|
||||
return fileData;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a text-block ItemCollection for a specified name.
|
||||
*
|
||||
* @param name in attribute txtname
|
||||
*
|
||||
*
|
||||
*/
|
||||
public FileData loadTextBlockFileData(String name, String fileName) {
|
||||
ItemCollection textBlockItemCollection = null;
|
||||
|
||||
// load text-block by name....
|
||||
String sQuery = "(type:\"" + TYPE_TEXTBLOCK + "\" AND txtname:\"" + name + "\")";
|
||||
Collection<ItemCollection> col;
|
||||
try {
|
||||
// find the textblock...
|
||||
col = documentService.find(sQuery, 1, 0);
|
||||
if (col.size() > 0) {
|
||||
textBlockItemCollection = col.iterator().next();
|
||||
// fetch the fileData...
|
||||
return snapshotService.getWorkItemFile(textBlockItemCollection.getUniqueID(), fileName);
|
||||
|
||||
} else {
|
||||
logger.warning("Missing text-block : '" + name + "'");
|
||||
}
|
||||
} catch (QueryException e) {
|
||||
logger.warning("getTextBlock - invalid query: " + e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -139,6 +139,71 @@ public class AGLEInvoiceAdapterTest {
|
|||
writeOutputToResources(xmlTemplate, "einvoice-simple.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixed tax rates: 0% (Art. 83) + 23% on the same invoice in PLN.
|
||||
* <p>
|
||||
* This is the case from the tax advisor mapping document (invoice 7471)
|
||||
* where the previous implementation incorrectly aggregated all amounts
|
||||
* into a single field. Expected output: P_13_1+P_14_1 (for the 23%
|
||||
* position) AND P_13_6_1 (for the 0% position) populated separately.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("Test Mixed Tax Rates (PLN, 0% KR + 23%)")
|
||||
public void testMixedTaxRates() throws Exception {
|
||||
logger.info("==> Test: Mixed Tax Rates");
|
||||
|
||||
ItemCollection workitem = new ItemCollection();
|
||||
workitem.setItemValue("invoice.number", "FV/2025/7471");
|
||||
workitem.setItemValue("invoice.date", LocalDate.of(2025, 2, 10));
|
||||
workitem.setItemValue("invoice.duedate", LocalDate.of(2025, 3, 10));
|
||||
workitem.setItemValue("invoice.currency", "PLN");
|
||||
// workitem.setItemValue("invoice.total.net", 18000.00);
|
||||
// workitem.setItemValue("invoice.total.tax", 23.0);
|
||||
workitem.setItemValue("invoice.total", 18000.00);
|
||||
|
||||
workitem.setItemValue("invoice.correction", "false");
|
||||
workitem.setItemValue("invoice.CorrectionInvoiceNumber", "");
|
||||
workitem.setItemValue("partner.id", "BP-001");
|
||||
workitem.setItemValue("partner.vat", "PL1234567890");
|
||||
workitem.setItemValue("invoice.performancedate", new Date());
|
||||
|
||||
List<Object> childItems = new ArrayList<>();
|
||||
|
||||
// Position 1: 0% domestic (Art. 83 sec. 1 no. 19 - forwarding for export)
|
||||
ItemCollection lineItem1 = new ItemCollection()
|
||||
.setItemValue("numpos", "1")
|
||||
.setItemValue("datev.text", "EX-GDY-2602-001")
|
||||
.setItemValue("billingtext", "Forwarding service for export shipment")
|
||||
.setItemValue("datev.umsatz", 14040.00)
|
||||
.setItemValue("datev.vatrate", 0.0)
|
||||
.setItemValue("cargosoft.vat.code", "0%E");
|
||||
childItems.add(lineItem1.getAllItems());
|
||||
|
||||
// Position 2: 23% domestic taxable
|
||||
ItemCollection lineItem2 = new ItemCollection()
|
||||
.setItemValue("numpos", "2")
|
||||
.setItemValue("datev.text", "Domestic transport handling")
|
||||
.setItemValue("billingtext", "Krajowa obsługa transportu")
|
||||
.setItemValue("datev.umsatz", 3960.00)
|
||||
.setItemValue("datev.vatrate", 23.0)
|
||||
.setItemValue("cargosoft.vat.code", "23");
|
||||
childItems.add(lineItem2.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");
|
||||
|
||||
writeOutputToResources(xmlTemplate, "invoice-mixed-rates.xml");
|
||||
}
|
||||
|
||||
// ── Helper methods ──────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,188 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
|
||||
xmlns:a="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
|
||||
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:10"
|
||||
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument>
|
||||
<ram:ID>FV/2025/7471</ram:ID>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20250210</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Payment Instructions:</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Please ensure that the payment reference includes the invoice number, BL or
|
||||
AWB number, container or shipment number and place of loading and discharge.
|
||||
The full invoice amount must be transferred without any deductions and all bank charges
|
||||
must be covered by the sender.
|
||||
Otherwise, the beneficiary’s bank will be unable to process the incoming payment.</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Alexander Global Logistics</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
<ram:IncludedNote>
|
||||
<ram:Content>Numer NIP: PL9552521552</ram:Content>
|
||||
</ram:IncludedNote>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>EX-GDY-2602-001</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>14040.0</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>14040.0</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="C62">1.0</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>Z</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>0.0</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>14040.0</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>2</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Domestic transport handling</ram:Name>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount>3960.0</ram:ChargeAmount>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount>3960.0</ram:ChargeAmount>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="C62">1.0</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>23.0</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount>3960.0</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:BuyerReference>n/a</ram:BuyerReference>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:Name>Alexander Global Logistics</ram:Name>
|
||||
<ram:DefinedTradeContact>
|
||||
<ram:PersonName>n/a</ram:PersonName>
|
||||
<ram:TelephoneUniversalCommunication>
|
||||
<ram:CompleteNumber>+49 421 566 46 0</ram:CompleteNumber>
|
||||
</ram:TelephoneUniversalCommunication>
|
||||
<ram:EmailURIUniversalCommunication>
|
||||
<ram:URIID>info@alexander-logistics.com</ram:URIID>
|
||||
</ram:EmailURIUniversalCommunication>
|
||||
</ram:DefinedTradeContact>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>70-660</ram:PostcodeCode>
|
||||
<ram:LineOne>Gdanska 36</ram:LineOne>
|
||||
<ram:CityName>Szczecin</ram:CityName>
|
||||
<ram:CountryID>PL</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:URIUniversalCommunication>
|
||||
<ram:URIID schemeID="EM">info@alexander-logistics.com</ram:URIID>
|
||||
</ram:URIUniversalCommunication>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">PL9552521552</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:Name>Test Sp. z o.o.</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>00-001</ram:PostcodeCode>
|
||||
<ram:LineOne>ul. Testowa 1</ram:LineOne>
|
||||
<ram:CityName>Warszawa</ram:CityName>
|
||||
<ram:CountryID>PL</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">PL1234567890</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:BuyerTradeParty>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ShipToTradeParty>
|
||||
<ram:Name>Test Sp. z o.o.</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>00-001</ram:PostcodeCode>
|
||||
<ram:LineOne>ul. Testowa 1</ram:LineOne>
|
||||
<ram:CityName>Warszawa</ram:CityName>
|
||||
<ram:CountryID>PL</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
</ram:ShipToTradeParty>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:InvoiceCurrencyCode>PLN</ram:InvoiceCurrencyCode>
|
||||
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:TypeCode>30</ram:TypeCode>
|
||||
<ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:IBANID>PL79116022020000000654306674</ram:IBANID>
|
||||
</ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||
<ram:BICID>BIGBPLPWXXX</ram:BICID>
|
||||
</ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>0.00</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>14040.0</ram:BasisAmount>
|
||||
<ram:CategoryCode>Z</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>0.0</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount>910.80</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount>3960.0</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>23.0</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Payment due by 10.03.2025</ram:Description>
|
||||
<ram:DueDateDateTime>
|
||||
<udt:DateTimeString format="102">20250310</udt:DateTimeString>
|
||||
</ram:DueDateDateTime>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount>18000.00</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount>18000.00</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="PLN">910.80</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount>18910.80</ram:GrandTotalAmount>
|
||||
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
|
||||
<ram:DuePayableAmount>18910.80</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-28T19:18:53.815720274Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-07-24T10:11:51.410517Z</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-28</P_6>
|
||||
<P_6>2026-07-24</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-28T19:18:53.906736962Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-07-24T10:11:51.547969Z</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-28</P_6>
|
||||
<P_6>2026-07-24</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>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-28T19:18:53.629147269Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-07-24T10:11:51.000225Z</DataWytworzeniaFa>
|
||||
<SystemInfo>Imixs eInvoice</SystemInfo>
|
||||
</Naglowek>
|
||||
<Podmiot1>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<Naglowek>
|
||||
<KodFormularza kodSystemowy="FA (3)" wersjaSchemy="1-0E">FA</KodFormularza>
|
||||
<WariantFormularza>3</WariantFormularza>
|
||||
<DataWytworzeniaFa>2026-05-28T19:18:53.885083580Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-07-24T10:11:51.517086Z</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-28</P_6>
|
||||
<P_6>2026-07-24</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-07-23T14:06:32.328007Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-07-24T10:11:51.468487Z</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-07-23</P_6>
|
||||
<P_6>2026-07-24</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-07-23T15:09:14.896034Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-07-24T10:11:51.644379Z</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-07-23</P_6>
|
||||
<P_6>2026-07-24</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-28T19:18:53.925385306Z</DataWytworzeniaFa>
|
||||
<DataWytworzeniaFa>2026-07-24T10:11:51.591043Z</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-28</P_6>
|
||||
<P_6>2026-07-24</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>
|
||||
|
|
@ -75,10 +75,10 @@
|
|||
<P_7>usługa spedycyjna / transport w relacji, PL63 - CZ43</P_7>
|
||||
<P_8A>szt.</P_8A>
|
||||
<P_8B>1.00</P_8B>
|
||||
<P_9A>-900.00</P_9A>
|
||||
<P_11>-900.00</P_11>
|
||||
<P_11A>-1107.00</P_11A>
|
||||
<P_11Vat>-207.00</P_11Vat>
|
||||
<P_9A>900.00</P_9A>
|
||||
<P_11>900.00</P_11>
|
||||
<P_11A>1107.00</P_11A>
|
||||
<P_11Vat>207.00</P_11Vat>
|
||||
<P_12>23</P_12>
|
||||
</FaWiersz>
|
||||
<Platnosc>
|
||||
|
|
|
|||
Loading…
Reference in a new issue