package com.alexanderlogistics.einvoice; import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.logging.Logger; 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.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.Element; import com.alexanderlogistics.BusinessPartnerService; import com.alexanderlogistics.InvoiceUtil; 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: * *
* {@code
textblock-ref
filename
true
}
*
*
* * 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. * *
* 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 KSeFAdapter 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 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;
/**
* 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
*/
private 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"));
model.setDueDateTime(workitem.getItemValueLocalDate("invoice.duedate"));
// Update Addresses
TradeParty billingAddress = buildAddress(workitem.getItemValueString("partner.id"), "buyer", model);
model.setTradeParty(billingAddress);
// Update Invoice Type (RodzajFaktury) -> VAT | KOR
Element elementFa = model.findOrCreateChildNode(model.getRoot(), EInvoiceNS.KSEF, "Fa");
if (isKorrekturRechnung(workitem)) {
model.updateElementValue(elementFa, EInvoiceNS.KSEF, "RodzajFaktury", "KOR");
logger.info("β βββ invoice type=KOR");
} else {
// normale rechnung
model.updateElementValue(elementFa, EInvoiceNS.KSEF, "RodzajFaktury", "VAT");
logger.info("β βββ invoice type=VAT");
}
// Update Rechnungssummen...
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"));
}
// set currency
model.updateElementValue(elementFa, EInvoiceNS.KSEF, "KodWaluty",
workitem.getItemValueString("invoice.currency"));
// Update Invoice Items
List