Neuer Cargosoft Import , neue API für Korrektur falsch importierter Eingangsrechnungen
This commit is contained in:
parent
0f1ad9e4c8
commit
3a3843fd04
4 changed files with 6472 additions and 40 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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,16 +349,16 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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,9 +486,9 @@ 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);
|
||||
|
|
@ -443,7 +496,7 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
|
|||
if (m.find()) {
|
||||
// we have a match
|
||||
invoiceWorkitem.setItemValue("space.ref", entry.getKey());
|
||||
found=true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -458,7 +511,6 @@ public class DatevCargosoftImportAdapter implements SignalAdapter {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the List of ItemCollections back into a List of Map elements
|
||||
*
|
||||
|
|
|
|||
6220
workflow/rechnungseingang-pl-1.0.1.bpmn
Normal file
6220
workflow/rechnungseingang-pl-1.0.1.bpmn
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue