All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gdv.xport.Datenpaket Maven / Gradle / Ivy

Go to download

gdv-xport-lib ist die Java-Bibliothek fuer den Umgang mit dem GDV-Format. Sie erleichtert den Export und Export dieses Datenformats.

The newest version!
/*
 * Copyright (c) 2009 - 2012 by Oli B. Licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express orimplied. See the License for the specific language
 * governing permissions and limitations under the License. (c)reated 23.10.2009
 * by Oli B. ([email protected])
 */

package gdv.xport;

import com.fasterxml.jackson.annotation.JsonIgnore;
import gdv.xport.config.Config;
import gdv.xport.event.ImportListener;
import gdv.xport.event.SatzValidator;
import gdv.xport.feld.*;
import gdv.xport.io.*;
import gdv.xport.satz.Datensatz;
import gdv.xport.satz.Nachsatz;
import gdv.xport.satz.Satz;
import gdv.xport.satz.Vorsatz;
import gdv.xport.util.*;
import net.sf.oval.ConstraintViolation;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.*;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;

/**
 * Ein Datenpaket besteht aus {@link Vorsatz}, mehrere {@link Datensatz}-Elementen
 * und einem {@link Nachsatz}.
 *
 * @author oliver
 * @since 23.10.2009
 */
public class Datenpaket implements ImportListener {

    private static final Logger LOG = LogManager.getLogger(Datenpaket.class);
    private Vorsatz vorsatz;
    private final List datensaetze = new ArrayList<>();
    private final Config config;
    private Nachsatz nachsatz;

    /**
     * Wenn man den Default-Konstruktor verwendet, sollte man vorher die
     * VU-Nummer konfiguriert haben.
     *
     * @see Config#getVUNr()
     */
    public Datenpaket() {
        this(Config.getInstance());
    }

    /**
     * Hierueber kann eine eigene Config mit uebergeben werden.
     *
     * @param config eigene Config
     * @since 5.3
     */
    public Datenpaket(Config config) {
        this.config = config;
        this.vorsatz = new Vorsatz(SatzRegistry.getInstance(config));
        this.nachsatz = new Nachsatz(SatzRegistry.getInstance(config));
        this.vorsatz.setVersion(this.nachsatz);
        Datum heute = Datum.heute();
        this.setErstellungsDatumVon(heute);
        this.setVuNummer(config.getVUNr().getInhalt());
        LOG.debug("{} created.", this);
    }

    /**
     * Falls die VU-Nummer noch nicht konfiguriert ist, kann man zu diesem
     * Konstruktor greifen.
     * 

* Absender wird jetzt nicht mehr vorbelegt, da der Absender der Klarname * des VUs ist (und nicht bekannt ist). Auch das ErstellungsDatumBis wird * nicht mehr vorbelegt. *

* * @param vuNummer die Nummer des Versicherungsunternehmens (VU) * @since 0.3 */ public Datenpaket(final String vuNummer) { this(Config.getInstance().withProperty("gdv.VU-Nummer", vuNummer)); } /** * Legt ein Datenpaket mit den angegebenen Datensaetze an. * * @param datensaetze fuers Datenpaket * @return ein neues Datenpaket * @since 5.2 */ public static Datenpaket of(Collection datensaetze) { Config cfg = datensaetze.isEmpty() ? Config.DEFAULT : datensaetze.iterator().next().getConfig(); return of(datensaetze, cfg); } /** * Legt ein Datenpaket anhand der uebergebenen Datei an. * * @param file Datei mit Datenpaket * @return Datenpaket * @throws IOException bei Lesefehlern * @since 6.3 */ public static Datenpaket of(File file) throws IOException { Datenpaket datenpaket = new Datenpaket(); datenpaket.importFrom(file); return datenpaket; } /** * Legt ein Datenpaket mit den angegebenen Datensaetze an. * * @param datensaetze fuers Datenpaket * @param cfg gemeinsame Config fuer alle Datensaetze * @return ein neues Datenpaket * @since 6.2 */ public static Datenpaket of(Collection datensaetze, Config cfg) { Datenpaket datenpaket = new Datenpaket(cfg); List dsList = new ArrayList<>(); for (Satz satz : datensaetze) { if (satz instanceof Vorsatz) { datenpaket.vorsatz = (Vorsatz) satz; } else if (satz instanceof Nachsatz) { datenpaket.nachsatz = (Nachsatz) satz; datenpaket.vorsatz.setVersion(datenpaket.nachsatz); } else { dsList.add((Datensatz) satz); } } for (Datensatz satz : dsList) { datenpaket.add(satz); } return datenpaket; } /** * Liefert die eingestelle Konfiguration des Datenpakets zurueck. * * @return Konfiguration * @since 6.2 */ public Config getConfig() { return config; } /** * Um die VU-Nummer setzen zu koennen. * * @param vuNummer VU-Nummer (max. 5-stellig) */ public void setVuNummer(final String vuNummer) { this.vorsatz.setVuNummer(vuNummer); for (Datensatz datensatz : this.datensaetze) { if (datensatz.hasFeld(Bezeichner.VU_NUMMER)) { datensatz.setVuNummer(vuNummer); } } } /** * Dazu verwenden wir den Vorsatz, um die VU-Nummer zu bestimmen. * * @return VU-Nummer aus dem Vorsatz * @since 0.3 */ public String getVuNummer() { return this.vorsatz.getVuNummer(); } /** * Gets the datensaetze. * * @return the datensaetze */ public List getDatensaetze() { return Collections.unmodifiableList(datensaetze); } /** * Liefert die Liste der Datensaetze zurueck, die mit dem uebergebenen * {@link SatzTyp} uebereinstimmen. * * @param typ gewuenschter {@link SatzTyp} * @return Liste von Datensaetzen * @since 5.2 */ public List getDatensaetze(SatzTyp typ) { List saetze = new ArrayList<>(); for (Datensatz ds : datensaetze) { if (typ.equals(ds.getSatzTyp())) { saetze.add(ds); } } return saetze; } /** * Gets the saetze. * * @return the saetze * @since 5.0 */ public List getAllSaetze() { List satzListe = new ArrayList<>(); satzListe.add(this.vorsatz); satzListe.addAll(datensaetze); satzListe.add(this.nachsatz); return Collections.unmodifiableList(satzListe); } /** * Sets the datensaetze. * * @param datensaetze the datensaetze to set */ public void setDatensaetze(final List datensaetze) { this.datensaetze.clear(); this.datensaetze.addAll(datensaetze); } /** * Liefert den internen Vorsatz. *

* Achtung:Der Vorsatz wird intern durch das Datenpaket verwaltet. * Er kann aber veraendert werden, wenn dies notwendig ist (z.B. zum * Setzen der Satzart-Versionen). *

* * @return Vorsatz */ public Vorsatz getVorsatz() { return this.vorsatz; } /** * Liefert den internen Nachsatz. *

* Achtung:Der Nachsatz wird intern durch das Datenpaket verwaltet. * Aus Symmetriegruenden zum Vorsatz kann auch der Nachsatz veraendert * werden. Normalerweise sollte das aber nicht notwendig sein. *

* * @return Nachsatz */ public Nachsatz getNachsatz() { return this.nachsatz; } /** * Fuegt den uebergebenen Datensatz hinzu. *

* Achtung: Satzart 001 (Vorsatz) bzw. Satzart 9999 (Nachsatz) kann * nicht hinzugefuegt werden! *

* * @param datensatz Datensatz, der hinzugefuegt werden soll */ public void add(final Datensatz datensatz) { if (("0001").equalsIgnoreCase(datensatz.getGdvSatzartName()) || ("9999") .equalsIgnoreCase(datensatz.getGdvSatzartName())) throw new IllegalArgumentException(("0001").equalsIgnoreCase(datensatz .getGdvSatzartName()) ? "Einen Vorsatz gibt es bereits!" : "Einen Nachsatz gibt es bereits!"); preset(datensatz); datensaetze.add(datensatz); vorsatz.setVersion(datensatz); if (datensatz.getSatzTyp().equals(SatzTyp.of(200))) { setNachsatzSummenAus0200(datensatz); } else if (datensatz.getSatzTyp().equals(SatzTyp.of(400))) { setNachsatzSummenAus0400(datensatz); } else if (datensatz.getSatzTyp().equals(SatzTyp.of(500))) { setNachsatzSummenAus0500(datensatz); } nachsatz.setAnzahlSaetze(nachsatz.getAnzahlSaetze() + datensatz.getNumberOfTeildatensaetze()); } private void preset(Datensatz datensatz) { if (StringUtils.isNotEmpty(getVuNummer()) && datensatz.hasVuNummer() && StringUtils.isEmpty(datensatz.getVuNummer())) { datensatz.setVuNummer(getVuNummer()); } if (StringUtils.isEmpty(datensatz.getVermittler())) { datensatz.setVermittler(getVermittler()); } } /** * Export. * * @param file Datei, in die exportiert werden soll * @throws IOException falls was schiefgelaufen ist (z.B. Platte voll) */ public void export(final File file) throws IOException { export(file, Config.DEFAULT_ENCODING); } /** * Export. * * @param file Datei, in die exportiert werden soll * @param encoding z.B. "ISO-8859-1" * @throws IOException falls was schiefgelaufen ist (z.B. Platte voll) * @since 1.0 */ public void export(final File file, final String encoding) throws IOException { export(file, Charset.forName(encoding)); } /** * Export. * * @param file Datei, in die exportiert werden soll * @param encoding z.B. "ISO-8859-1" * @throws IOException falls was schiefgelaufen ist (z.B. Platte voll) * @since 1.0 */ public void export(final File file, final Charset encoding) throws IOException { try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), encoding)) { export(writer); } } /** * Falls wir einen Stream haben, koennen wir diese Methode benutzen. * * @param ostream z.B. System.out * @throws IOException falls was schiefgelaufen ist * @since 0.3 */ public void export(final OutputStream ostream) throws IOException { Writer writer = new OutputStreamWriter(ostream, Config.DEFAULT_ENCODING); export(writer); writer.flush(); ostream.flush(); } /** * Export. * * @param writer wird zum Export verwendet * @throws IOException falls was schiefgelaufen ist */ public void export(final Writer writer) throws IOException { vorsatz.export(writer); for (Datensatz datensatz : datensaetze) { datensatz.export(writer); } nachsatz.export(writer); writer.flush(); LOG.info("{} Saetze exportiert.", nachsatz.getAnzahlSaetze()); } /** * Damit kann direkt ueber das Netz importiert werden. Gibt man eine * File-URL (oder File) an, kann man damit auch direkt aus einer Datei importieren. * * @param uri z.B. * http://www.gdv-online.de/vuvm/musterdatei_bestand/musterdatei_041222.txt * @return das Datenpaket zur Weiterverabeitung (seit 5.2) * @throws IOException wenn z.B. das Netz weg ist * @since 3.0 */ public Datenpaket importFrom(final URI uri) throws IOException { return importFrom(uri.toURL()); } /** * Damit kann direkt ueber das Netz importiert werden. Gibt man eine * File-URL (oder File) an, kann man damit auch direkt aus einer Datei importieren. * * @param url z.B. * http://www.gdv-online.de/vuvm/musterdatei_bestand/musterdatei_041222.txt * @return das Datenpaket zur Weiterverabeitung (seit 5.2) * @throws IOException wenn z.B. das Netz weg ist * @since 0.3 */ public Datenpaket importFrom(final URL url) throws IOException { URLReader urlReader = new URLReader(url); String content = urlReader.read(); return importFrom(content); } /** * Importiert direkt aus einem String. * * @param content Inhalt der eingelesen wird * @return das Datenpaket zur Weiterverabeitung (seit 5.2) * @throws IOException sollte eigentlich nicht vorkommen * @since 0.3 */ public Datenpaket importFrom(final String content) throws IOException { try (Reader reader = new StringReader(content)) { importFrom(reader); } return this; } /** * Importiert von einem {@link InputStream}. * * @param istream z.B. Sytem.in * @return das Datenpaket zur Weiterverabeitung (seit 5.2) * @throws IOException falls es Fehler beim Lesen gibt */ public Datenpaket importFrom(final InputStream istream) throws IOException { Reader reader = new RecyclingInputStreamReader(istream, Config.DEFAULT_ENCODING); return importFrom(reader); } /** * Import von einem {@link Reader}. * * @param reader hiervon wird importiert * @return das Datenpaket zur Weiterverabeitung (seit 5.2) * @throws IOException falls was schiefgelaufen ist */ public Datenpaket importFrom(final Reader reader) throws IOException { PushbackLineNumberReader lnr = new PushbackLineNumberReader(new RecordReader(reader), 256); try { return importFrom(lnr); } catch (EOFException eofe) { throw new ExtendedEOFException("line " + lnr.getLineNumber() + ": " + eofe.getMessage(), eofe); } catch (IOException ioe) { throw new ImportException(lnr, "read error", ioe); } catch (NumberFormatException nfe) { throw new ImportException(lnr, "number expected, but found: \"" + lnr.readLine() + '"', nfe); } } /** * Der hier verwendete PushbackReader wird benoetigt, damit die gelesene * Satzart und Sparte wieder zurueckgestellt werden kann. *

* Im Gegensatz zu {@link Datenpaket#importSatz(PushbackLineNumberReader, Map)} * werden die Versionen (aus dem Vorsatz) nicht beruecksichtigt. *

* * @param reader PushbackReader mit einem Puffer von mind. 14 Zeichen * @return das Datenpaket zur Weiterverabeitung (seit 5.2) * @throws IOException falls was schief gelaufen ist */ public Datenpaket importFrom(final PushbackLineNumberReader reader) throws IOException { this.vorsatz.importFrom(reader); Map satzartVersionen = this.vorsatz.getSatzartVersionen(); while (true) { Satz satz = importSatz(reader, satzartVersionen); if (satz.getSatzart() == 9999) { this.nachsatz = (Nachsatz) satz; break; } datensaetze.add((Datensatz) satz); } return this; } /** * Der hier verwendete PushbackReader wird benoetigt, damit die gelesene * Satzart und Sparte wieder zurueckgestellt werden kann. * * @param reader PushbackReader mit einem Puffer von mind. 14 Zeichen * @param satzartVersionen Satz-Versionen aus dem Vorsatz * @return das Datenpaket zur Weiterverabeitung * @throws IOException falls was schief gelaufen ist */ protected static Satz importSatz(PushbackLineNumberReader reader, Map satzartVersionen) throws IOException { int satzart = Importer.of(reader).readSatzart(); LOG.debug("Satzart {} wird importiert...", satzart); if (satzart == 9999) { return importNachsatzFrom(reader); } else { return importSatzFrom(reader, satzart, satzartVersionen); } } private static Satz importSatzFrom(PushbackLineNumberReader reader, int satzart, Map satzartVersionen) throws IOException { SatzTyp satzTyp = Importer.of(reader).readSatzTyp(satzart); Version wanted = satzartVersionen.get(satzTyp); if (wanted == null) { return importDatensatz(reader, satzart); } else { Satz satz = SatzRegistry.getSatz(satzTyp, satzartVersionen.get(satzTyp).getInhalt()); satz.importFrom(reader); return satz; } } /** * Importiert einen einzelnen Satz. Dies kann entweder ein Datensatz, oder * aber der Nachsatz sein. * * @param reader the reader * @return the satz * @throws IOException Signals that an I/O exception has occurred. */ public static Satz importSatz(final PushbackLineNumberReader reader) throws IOException { int satzart = Importer.of(reader).readSatzart(); LOG.debug("reading Satzart " + satzart + "..."); if (satzart == 9999) { return importNachsatzFrom(reader); } else { return importDatensatz(reader, satzart); } } private static Nachsatz importNachsatzFrom(PushbackLineNumberReader reader) throws IOException { Nachsatz nachsatz = new Nachsatz(); nachsatz.importFrom(reader); return nachsatz; } private static Satz importDatensatz(final PushbackLineNumberReader reader, final int satzart) throws IOException { SatzTyp satzTyp = Importer.of(reader).readSatzTyp(satzart); Satz satz = getSatz(satzTyp); satz.importFrom(reader); return satz; } private static Satz getSatz(SatzTyp satzTyp) { try { return SatzRegistry.getInstance().getSatz(satzTyp); } catch (NotRegisteredException ex) { LOG.warn("Satzart '{}' ist nicht registriert und wird generiert.", satzTyp); LOG.debug("Details:", ex); Datensatz satz = new Datensatz(SatzTyp.of(satzTyp.getSatzart(), satzTyp.getSparte())); satz.addFiller(); return satz; } } /** * Importieren einer Datei. * * @param file Import-Datei * @throws IOException falls was schiefgelaufen ist * @since 0.2 */ public void importFrom(final File file) throws IOException { importFrom(file, Config.DEFAULT_ENCODING); } /** * Importieren einer Datei. * * @param file Import-Datei * @param encoding z.B. "ISO-8859-1" * @throws IOException falls was schiefgelaufen ist * @since 1.0 */ public void importFrom(final File file, final String encoding) throws IOException { importFrom(file, Charset.forName(encoding)); } /** * Importieren einer Datei. * * @param file Import-Datei * @param encoding z.B. "ISO-8859-1" * @throws IOException falls was schiefgelaufen ist * @since 1.0 */ public void importFrom(final File file, final Charset encoding) throws IOException { try (Reader reader = new InputStreamReader(new FileInputStream(file), encoding)) { this.importFrom(reader); } } /** * Fasst benachbarte Saetze mit Luecken zusammen, sofern es sinnvoll ist. * So kann z.B. folgende Reihenfolge in den Datensaetzen vorkommen: *
     *     0220.010.13.1 Teildatensatz 1
     *     0221.010.13.1 Teildatensatz 1
     *     0220.010.13.1 Teildatensatz 2
     * 
* Logisch gehoeren Teildatensatz 1 und 2 von Satzart 0220.010.13.1 * zusammen. Gemaess den FAQ des GDVs ist es wohl zulaessig, dass * Teildatensatz 1 von Satzart 0221.xxx dazwischen stehen darf. Daher * fasst die pack-Methode dieses getrennten Teildatensaetze wieder * zusammen. *

* Diese Version wurde mit Issue #62 eingefuehrt. Naehere Infos siehe * https://github.com/oboehm/gdv.xport/issues/62. *

* * @return das Datenpaket selbst zur Weiterverarbeitung * @since 5.2 */ public Datenpaket pack() { for (int i = 0; i < datensaetze.size(); i++) { Datensatz ds = datensaetze.get(i); if (ds.getTeildatensaetze().size() == 0) { // keine Teildatensaetze, evtl. bereits gemergt, uebergehe den Datensatz continue; } boolean nextVsnrReached = false; for (int j = i+1; j < datensaetze.size() && !ds.isComplete() && !nextVsnrReached; j++) { Optional next = findNextDatensatzWithinVsnr(ds.getVersicherungsscheinNummer(), ds.getSatzTyp(), j); next.ifPresent(ds::mergeWith); if (!next.isPresent()) { nextVsnrReached = true; } } } removeEmptyDatensaetze(); return this; } private void removeEmptyDatensaetze() { List cleaned = new ArrayList<>(); for (Datensatz ds : datensaetze) { if (ds.getNumberOfTeildatensaetze() > 0) { cleaned.add(ds); } } datensaetze.clear(); datensaetze.addAll(cleaned); } private Optional findNextDatensatzWithinVsnr(String vsNr, SatzTyp satzTyp, int position) { for (int i = position; i < datensaetze.size(); i++) { Datensatz ds = datensaetze.get(i); if (ds.getTeildatensaetze().size() == 0) { // keine Teildatensätze, evtl. bereits gemergt, übergehe den Datensatz continue; } if (!ds.getVersicherungsscheinNummer().equals(vsNr)) { // Versicherungsscheinnummer hat geändert, fertig break; } if (satzTyp.equals(ds.getSatzTyp())) { // Potentieller Datensatz gefunden, fertig return Optional.of(ds); } } return Optional.empty(); } /** * Sets the erstellungsDatumVon im Vorsatz (Byte 70 - 77) (alle * Teildatensätze) * * @param d Erstellungsdatum von */ public void setErstellungsDatumVon(final Datum d) { this.vorsatz.setErstellungsZeitraumVon(d); } /** * Gets the erstellungs datum von. * * @return Erstellungsdatum bis */ public Datum getErstellungsDatumVon() { return this.vorsatz.getErstellungsZeitraumVon(); } /** * Sets the erstellungs datum bis. * * @param d Erstellungsdatum bis */ public void setErstellungsDatumBis(final Datum d) { this.vorsatz.setErstellungsZeitraumBis(d); } /** * Gets the erstellungs datum bis. * * @return Erstellungdatum bis */ public Datum getErstellungsDatumBis() { return this.vorsatz.getErstellungsZeitraumBis(); } /** * Sets the absender im Vorsatz (Byte 10 - 39) (alle Teildatensätze) * * @param absender neuer Absender */ public void setAbsender(final String absender) { this.vorsatz.setAbsender(absender); } /** * Gets the absender im Vorsatz (Byte 10 - 39) (alle Teildatensätze) * * @return Absender */ public String getAbsender() { return this.vorsatz.getAbsender(); } /** * Sets the adressat. * * @param s Adressat */ public void setAdressat(final String s) { this.vorsatz.setAdressat(s); } /** * Gets the adressat. * * @return Adressat */ public String getAdressat() { return this.vorsatz.getAdressat(); } /** * Sets the vermittler Um Geschaeftsstelle/Vermittler in Vorsatz (alle * Teildatensaetze) und Nachsatz setzen zu koennen. * * @param s Vermittler */ public void setVermittler(final String s) { for (Satz satz : getAllSaetze()) { satz.setVermittler(s); } } /** * Gets the vermittler. * * @return Vermittler */ public String getVermittler() { String vermittler = this.vorsatz.getVermittler(); assert vermittler.equals(this.nachsatz.getVermittler()) : vorsatz + " or " + nachsatz + " is corrupt"; return vermittler; } /** * Aus Performance-Gruenden wird nicht auf die validate-Methode * zurueckgegriffen (die dauert zu lang). * * @return true/false */ @JsonIgnore public boolean isValid() { if (!this.vorsatz.isValid()) { LOG.info(this.vorsatz + " is not valid"); return false; } if (!this.nachsatz.isValid()) { LOG.info(this.nachsatz + " is not valid"); return false; } for (Satz satz : this.datensaetze) { if (!satz.isValid()) { LOG.info(satz + " is not valid"); return false; } } if (!this.validateFolgenummern().isEmpty()) { LOG.info("Folgenummern stimmen nicht"); return false; } if (!this.validateVUNummer().isEmpty()) { LOG.info("VU-Nummer is not set / not valid"); return false; } return true; } /** * Validiert die einzelnen Saetze (inkl. Vorsatz und Nachsatz). * * @return Liste der ConstraintViolations */ public List validate() { return validate(config); } public List validate(Config validationConfig) { SatzValidator satzValidator = new SatzValidator(validationConfig); satzValidator.notice(this.vorsatz); for (Satz datensatz : this.datensaetze) { satzValidator.notice(datensatz); } satzValidator.notice(this.nachsatz); List violations = satzValidator.getViolations(); violations.addAll(validateVUNummer()); violations.addAll(this.nachsatz.validate(validationConfig)); return violations; } private List validateVUNummer() { List violations = new ArrayList<>(); if (Config.DUMMY_VU_NUMMER.equals(this.getVuNummer())) { ConstraintViolation cv = new SimpleConstraintViolation("VU-Nummer is not set", this, Config.DUMMY_VU_NUMMER); violations.add(cv); } return violations; } /** * Fuer eine Versicherungsscheinnummer muss die Folgenummer immer mit 1 * anfangen. Taucht dieser Versicherungsscheinnummer fuer den gleichen Satz * ein zweites Mal auf, muss die Folgenummer entsprechend erhoeht werden. Es * sei denn, es handelt sich doch noch um den gleichen Vertrag. Aber die * Nummern duerfen keine Spruenge machen - dies wird hier kontrolliert. * * @return eine Liste, die die verletzten Folgenummern enthaelt * @since 0.3 */ private List validateFolgenummern() { List violations = new ArrayList<>(); Map folgenummern = new HashMap<>(); for (Datensatz datensatz : this.datensaetze) { String nr = datensatz.getVersicherungsscheinNummer().trim(); String key = nr + datensatz.getSatzartFeld().getInhalt() + datensatz.getSparteFeld().getInhalt(); Integer expected = folgenummern.computeIfAbsent(key, k -> 1); int folgenr = datensatz.getFolgenummer(); if (folgenr == expected) { continue; } expected++; folgenummern.put(key, expected); if (folgenr != expected) { ConstraintViolation cv = new SimpleConstraintViolation("falsche Folgenummer (erwartet: " + expected + ")", datensatz, folgenr); violations.add(cv); } } return violations; } /* * (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return this.getClass().getSimpleName() + " for " + this.getVuNummer() + " with " + this.datensaetze.size() + "+2 (Daten-)Saetze"; } private void setNachsatzSummenAus0200(Datensatz datensatz) { Betrag beitrag = datensatz.getFeld(Bezeichner.GESAMTBEITRAG_IN_WAEHRUNGSEINHEITEN, Betrag.class); nachsatz.addGesamtBeitrag(beitrag.toBigDecimal()); } private void setNachsatzSummenAus0400(Datensatz datensatz) { BetragMitVorzeichen betrag = datensatz.getFeld(Bezeichner.GESAMTBEITRAG_BRUTTO_IN_WAEHRUNGSEINHEITEN, BetragMitVorzeichen.class); nachsatz.addGesamtBeitragBrutto(betrag.toBigDecimal()); betrag = datensatz.getFeld(Bezeichner.GESAMTPROVISIONSBETRAG_IN_WAEHRUNGSEINHEITEN, BetragMitVorzeichen.class); nachsatz.addGesamtProvisionsBetrag(betrag.toBigDecimal()); } private void setNachsatzSummenAus0500(Datensatz datensatz) { BetragMitVorzeichen betrag = datensatz.getFeld(Bezeichner.BETRAG_IN_WAEHRUNGSEINHEITEN_GEMAESS_ZAHLUNGSART, BetragMitVorzeichen.class); nachsatz.addVersicherungsLeistungen(betrag.toBigDecimal()); betrag = datensatz.getFeld(Bezeichner.SCHADENBEARBEITUNGSKOSTEN_IN_WAEHRUNGSEINHEITEN, BetragMitVorzeichen.class); nachsatz.addSchadenbearbeitungskosten(betrag.toBigDecimal()); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Datenpaket other = (Datenpaket) obj; return Objects.equals(vorsatz, other.vorsatz) && isEquals(datensaetze, other.datensaetze) && Objects.equals(nachsatz, other.nachsatz); } private static boolean isEquals(List d1, List d2) { if (d1.size() != d2.size()) { return false; } for (int i = 0; i < d1.size(); i++) { if (!d1.get(i).equals(d2.get(i))) { return false; } } return true; } @Override public int hashCode() { return datensaetze.size(); } /** * Damit kann das Datenpaket selbst als Listener beim * {@link DatenpaketStreamer} registriert werden. * * @param satz der importierte Satz * @since 5.3 */ @Override public void notice(Satz satz) { try { if (satz.getSatzart() == 1) { LOG.info("Vorsatz {} wurde erkannt - {} wird zurueckgesetzt.", satz,this); this.datensaetze.clear(); this.vorsatz.importFrom(satz.toLongString()); } else if (satz.getSatzart() == 9999) { this.nachsatz.importFrom(satz.toLongString()); } else { add((Datensatz) satz); } } catch (IOException ex) { throw new IllegalStateException("Import-Fehler in " + satz, ex); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy