Neuer Cargosoft Import , neue API für Korrektur falsch importierter Eingangsrechnungen

This commit is contained in:
Ralph Soika 2024-02-02 12:36:05 +01:00
parent 0f1ad9e4c8
commit 3a3843fd04
4 changed files with 6472 additions and 40 deletions

View file

@ -1,6 +1,14 @@
# Versionen
### 1.2.14 (Development)
### 1.2.15 (Development)
- Fix Cargosoft DATEV Import - Korektur des Rechnungsdatums / Jahr
- Neuer Rest Service für Korrektur von Cargsoft Ausgangsrechnungen
http://localhost:8080/api/cargosoft/fix/5
### 1.2.14
- Internationalisierung

View file

@ -0,0 +1,152 @@
/*******************************************************************************
* Imixs Workflow
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* http://www.imixs.org
* http://java.net/projects/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
*******************************************************************************/
package com.alexanderlogistics.api;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.exceptions.QueryException;
/**
** Dieser Service korrigiert falsch importierte Cargosoft daten.
* Ausgangsrechnungen die ein falsches Jahr haben.
*
* @author rsoika
* @version 1.1
*/
@Stateless
@Produces({ MediaType.TEXT_HTML, MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON,
MediaType.TEXT_XML })
@Path("/cargosoft")
public class CargosoftMigrationRestService implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
DocumentService documentService;
private static Logger logger = Logger.getLogger(CargosoftMigrationRestService.class.getName());
public CargosoftMigrationRestService() {
super();
}
/**
* This method loads taxonomy data for a workflow group within a given process
* and builds a ChartJS data structure in JSON format
*
* @param workflowgroup
* @param task
* @return
* @throws QueryException
*/
@GET
@Path("/test")
@Produces({ MediaType.TEXT_PLAIN })
public String testeFehlerhafteCargosoftDaten() throws QueryException {
String log;
String query = "($modelversion:rechnungsausgang-de-1.0)\n" + //
"AND $created:[20240101 TO 20240501]\n" + //
"AND invoice.date:[20230101 TO 20230501]";
logger.info("query=" + query);
log = "Query\n" + query;
List<ItemCollection> result = documentService.find(query, 100, 0);
log = log + "\n\nCount=" + result.size();
return log;
}
/**
* This method loads taxonomy data for a workflow group within a given process
* and builds a ChartJS data structure in JSON format
*
* @param workflowgroup
* @param task
* @return
* @throws QueryException
*/
@GET
@Path("/fix/{count}")
@Produces({ MediaType.TEXT_PLAIN })
public String fixFehlerhafteCargosoftDaten(@PathParam("count") int count) throws QueryException {
String log;
String query = "($modelversion:rechnungsausgang-de-1.0)\n" + //
"AND $created:[20240101 TO 20240501]\n" + //
"AND invoice.date:[20230101 TO 20230501]";
logger.info("query=" + query);
log = "Query\n\n" + query;
log = log + "\n\nMax Count=" + count;
List<ItemCollection> result = documentService.find(query, count, 0);
log = log + "\n\nSelection Count=" + result.size();
log = log + "\n\nFixes\n\n";
for (ItemCollection doc : result) {
Date invoiceDate = doc.getItemValueDate("invoice.date");
// Convert to Calendar
Calendar calendar = Calendar.getInstance();
calendar.setTime(invoiceDate);
// Add one year
calendar.add(Calendar.YEAR, 1);
// Convert back to Date
doc.setItemValue("invoice.date", calendar.getTime());
documentService.save(doc);
log = log + doc.getUniqueID() + "\n";
// break!
}
log = log + "\n\n=== Completed! ===\n\n";
return log;
}
}

View file

@ -50,6 +50,43 @@ import com.alexanderlogistics.KreditorDebitorService;
* ausgelesen, welche Regular Expressions enthalten können. Gibt es einen match,
* wird der Space der Rechnung zugeordnet.
*
* Changes 2.Feb. 2024
* =====================
*
* Es wurde festgestellt (und von Cargosoft bestätigt), dass eine DATEV Datei
* aus Cargosoft (Ausgangsrechnungen) falsche Belegdaten bezüglch des
* Belegdatums bereitstellt.
*
* Es können in einer Datei Rechnungen aus unterschiedlichen Buchungsperioden
* enthalten sein. So können in der Periode Dezember auch Belege aus Januar
* enthalten sein. In diesem Fall wird bisher davon ausgegangen dass diese zum
* angegebenen Wirtschafsjahr gehören. Das ist aber bei Cargosoft nicht der
* Fall. Vielmehr müssen die Belegdaten für das Folgejahr angelegt weden.
*
* Beispiel:
*
* Wirtschafts Jahr = 20230101
*
* Buchunsbeginn = 20231201
*
* Buchungsende = 20231231
*
* Als Belegdatum wird nun der 1601 angegeben. Da der Beleg-Monat vor dem
* angegebenen Buchungszeitraum liegt (Monat-Beleg < Monat-Stapel) muss künftig
* das Beleg Jahr um 1 erhöht werden. Diese Regel gilt nicht wenn in der Datei
* Belege liegen deren Beleg-Monat größer als der Stapel-Monat sind. Also in
* einer Datei für August liegen Beleg-Monate aus September. Dann bleibt das
* Beleg-Jahr wie bisher.
*
* Der Fall tritt scheinbar also nur im Januar mit Belegstapeln aus Dezember des
* Vorjahres auf .
*
* Als Lösung wird daher hier die Kopfzeile nochnmal ausgelesen und der Monat
* aus dem Buchungstapel beginn genommen (z.b. 12). Liegt nun der Monat aus dem
* Belegdatum vor diesem Datum (z.b. 01) wir das Jahr um 1 erhöht. Das
* Wirtschaftsjahr wird ignoriert.
*
*
* @version 1.0
* @author rsoika
*/
@ -128,8 +165,7 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd");
// load spaces Pos Expressions
Map<String, List<String>> spacePosMappings = loadSpacePosMappings();
Map<String, List<String>> spacePosMappings = loadSpacePosMappings();
ItemCollection invoiceWorkitem = null;
List<ItemCollection> splitBuchungen = new ArrayList<ItemCollection>();
@ -141,8 +177,20 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(imputStream, ENCODING));
// skip header
in.readLine();
// Wir lesen hier nochmal das Datum des Buchunsstpels aus und berechnen den
// Monat des Buchungsstapels.
// dieser Monat wird benötigt um ggf. das Buchungsjahr zu ändern (Das ist eine
// Besonderheit von cargosoft)
String header1;
header1 = in.readLine();
String[] header1List = header1.split(";(?=([^\"]*\"[^\"]*\")*[^\"]*$)", 99);
workitem.setItemValue("datev.Datum-von", DatevImportAdapter.csvVal(header1List[14]));
workitem.setItemValue("datev.Datum-bis", DatevImportAdapter.csvVal(header1List[15]));
// Monat des Buchungsstapels berechnen
String stapelDatumBeginn = workitem.getItemValueString("datev.Datum-von");
String stapelMonat = stapelDatumBeginn.substring(4, 6);
// skip second header line
in.readLine();
// read content....
@ -156,16 +204,16 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
}
// alle werte parsen
String[] header1List = dataLine.split(";(?=([^\"]*\"[^\"]*\")*[^\"]*$)", 99);
if (header1List.length < 6) {
String[] dataList = dataLine.split(";(?=([^\"]*\"[^\"]*\")*[^\"]*$)", 99);
if (dataList.length < 6) {
throw new PluginException(DatevCargosoftImportAdapter.class.getName(),
DatevImportAdapter.DATEV_IMPORT_ERROR, "Invalid data in line " + line);
}
String belegNummer = DatevImportAdapter.csvVal(header1List[10]);
String gegenKonto = DatevImportAdapter.csvVal(header1List[7]);
String text = DatevImportAdapter.csvVal(header1List[13]);
String buchungsTag = DatevImportAdapter.csvVal(header1List[9]);
String belegNummer = DatevImportAdapter.csvVal(dataList[10]);
String gegenKonto = DatevImportAdapter.csvVal(dataList[7]);
String text = DatevImportAdapter.csvVal(dataList[13]);
String buchungsTag = DatevImportAdapter.csvVal(dataList[9]);
// cargosoft laesst gerne die führende 0 weg....
if (buchungsTag.length() == 3) {
buchungsTag = "0" + buchungsTag;
@ -173,26 +221,31 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
// berechne Buchungsdatum DDMM
String tag = buchungsTag.substring(0, 2);
String monat = buchungsTag.substring(2, 4);
String jahr = wjBeginn.substring(0, 4);
// compute next year if start of WJ is not January
if (Integer.parseInt(wjBeginnMonat) > Integer.parseInt(monat)) {
jahr = Integer.parseInt(jahr + 1) + "";
String jahr = stapelDatumBeginn.substring(0, 4);
// Cargosoft Spezial Lösung.
// Liegt der Beleg-Monat vor dem stapelMonat (z.b. Rechnung aus Januar in einer
// Dezember Datei), dann erhöhen wir das Beleg-datum-Jahr. Hier wird also nicht
// wie normalerweise das Wirtschafsjahr betrchtet.
if (Integer.parseInt(stapelMonat) > Integer.parseInt(monat)) {
int _year = Integer.parseInt(jahr) + 1;
jahr = _year + "";
}
Date dateBuchung = dateFormatter.parse(jahr + monat + tag);
// Fälligkeit
Date dueDate = new Date();
try {
dueDate=dateFormatter.parse(DatevImportAdapter.csvVal(header1List[23]));
dueDate = dateFormatter.parse(DatevImportAdapter.csvVal(dataList[23]));
} catch (Exception e) {
dueDate = new Date();
}
String paymentTerm = DatevImportAdapter.csvVal(header1List[31]);
String waehrung = DatevImportAdapter.csvVal(header1List[2]);
String paymentTerm = DatevImportAdapter.csvVal(dataList[31]);
String waehrung = DatevImportAdapter.csvVal(dataList[2]);
// kurse
double kurs = parseBetrag(DatevImportAdapter.csvVal(header1List[3]));
double basisumsatz = parseBetrag(DatevImportAdapter.csvVal(header1List[4]));
double kurs = parseBetrag(DatevImportAdapter.csvVal(dataList[3]));
double basisumsatz = parseBetrag(DatevImportAdapter.csvVal(dataList[4]));
// Skip Eingangsrechnungen
if (!gegenKonto.startsWith("1")) {
@ -216,12 +269,12 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
// Erzeuge einen Buchungssatz
ItemCollection dataItemCol = new ItemCollection();
dataItemCol.setItemValue("datev.text", text);
dataItemCol.setItemValue("datev.umsatz", parseBetrag(DatevImportAdapter.csvVal(header1List[0])));
dataItemCol.setItemValue("datev.shzeichen", DatevImportAdapter.csvVal(header1List[1]));
dataItemCol.setItemValue("datev.umsatz", parseBetrag(DatevImportAdapter.csvVal(dataList[0])));
dataItemCol.setItemValue("datev.shzeichen", DatevImportAdapter.csvVal(dataList[1]));
dataItemCol.setItemValue("datev.wkz", waehrung);
dataItemCol.setItemValue("datev.kurs", parseBetrag(DatevImportAdapter.csvVal(header1List[3])));
dataItemCol.setItemValue("datev.basisumsatz", parseBetrag(DatevImportAdapter.csvVal(header1List[4])));
dataItemCol.setItemValue("datev.konto", DatevImportAdapter.csvVal(header1List[6]));
dataItemCol.setItemValue("datev.kurs", parseBetrag(DatevImportAdapter.csvVal(dataList[3])));
dataItemCol.setItemValue("datev.basisumsatz", parseBetrag(DatevImportAdapter.csvVal(dataList[4])));
dataItemCol.setItemValue("datev.konto", DatevImportAdapter.csvVal(dataList[6]));
// Haben wir schon eine Invoice Workitem angelegt?
if (invoiceWorkitem == null) {
@ -246,7 +299,7 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
logger.info("...close workitem....");
// nein - also invoice schließen
closeInvoiceWorkitem(invoiceWorkitem, splitBuchungen,spacePosMappings);
closeInvoiceWorkitem(invoiceWorkitem, splitBuchungen, spacePosMappings);
invoiceWorkitem = null;
// neue Splitbuchungstabelle anlegen
splitBuchungen = new ArrayList<ItemCollection>();
@ -264,7 +317,7 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
}
} // wile end
closeInvoiceWorkitem(invoiceWorkitem, splitBuchungen,spacePosMappings);
closeInvoiceWorkitem(invoiceWorkitem, splitBuchungen, spacePosMappings);
} catch (IOException | ParseException e) {
throw new PluginException(DatevCargosoftImportAdapter.class.getName(),
@ -296,19 +349,19 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
*
* @return List of list of expressions
*/
private Map<String,List<String>> loadSpacePosMappings() {
Map<String,List<String>> result =new HashMap<>();
private Map<String, List<String>> loadSpacePosMappings() {
Map<String, List<String>> result = new HashMap<>();
// als erstes lesen wir die pos.mappings aus den Spaces ein, auf die dann eine
// Rechnung emapped werden kann.
List<ItemCollection> spaces_subs = teamService.getSpaces();
for (ItemCollection stub: spaces_subs) {
for (ItemCollection stub : spaces_subs) {
// load full workitem
ItemCollection space = documentService.load(stub.getUniqueID());
if (space!=null) {
result.put(space.getUniqueID(),space.getItemValueList("pos.mapping", String.class));
if (space != null) {
result.put(space.getUniqueID(), space.getItemValueList("pos.mapping", String.class));
}
}
return result;
}
@ -407,7 +460,7 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
}
}
total=InvoiceUtil.round(total);
total = InvoiceUtil.round(total);
invoiceWorkitem.setItemValue("invoice.total", total);
invoiceWorkitem.setItemValue("invoice.saldo", total);
// implode die Splitbuchungen
@ -433,17 +486,17 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
// dazu kucken wir in alle spaces den config wert 'pos.mapping'
String text = invoiceWorkitem.getItemValueString("invoice.text");
if (!text.isEmpty()) {
boolean found=false;
for (Map.Entry<String, List<String> > entry : spacePosMappings.entrySet()) {
List<String> expressionsList=entry.getValue();
boolean found = false;
for (Map.Entry<String, List<String>> entry : spacePosMappings.entrySet()) {
List<String> expressionsList = entry.getValue();
for (String expr : expressionsList) {
Pattern p = Pattern.compile(expr);
Matcher m = p.matcher(text);
if (m.find()) {
// we have a match
invoiceWorkitem.setItemValue("space.ref", entry.getKey());
found=true;
found = true;
break;
}
}
@ -457,7 +510,6 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
workflowService.processWorkItem(invoiceWorkitem);
}
/**
* Convert the List of ItemCollections back into a List of Map elements

File diff suppressed because it is too large Load diff