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

org.kapott.hbci.swift.DTAUS Maven / Gradle / Ivy

Go to download

HBCI4j - Home Banking Computer Interface for Java - Clone from https://github.com/hbci4j/hbci4java

There is a newer version: 3.5.46
Show newest version
/*  $Id: DTAUS.java,v 1.1 2011/05/04 22:38:03 willuhn Exp $

    This file is part of HBCI4Java
    Copyright (C) 2001-2008  Stefan Palme

    HBCI4Java 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.

    HBCI4Java 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 should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package org.kapott.hbci.swift;

import lombok.extern.slf4j.Slf4j;
import org.kapott.hbci.datatypes.SyntaxDTAUS;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.exceptions.InvalidArgumentException;
import org.kapott.hbci.exceptions.InvalidUserDataException;
import org.kapott.hbci.structures.Konto;
import org.kapott.hbci.structures.Value;

import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 

Hilfsklasse zum Erzeugen von DTAUS-Datensätzen für die Verwendung in * Sammelüberweisungen und Sammellastschriften. Diese Klasse kann verwendet * werden, um den DTAUS-Datenstrom zu erzeugen, der für Sammellastschriften * und -überweisungen als Job-Parameter angegeben werden muss.

*

In einem DTAUS-Objekt werden ein oder mehrere Transaktionen gespeichert. * Dabei müssen alle Transaktionen entweder Lastschriften oder Überweisungen sein. * Außerdem wird für alle Transaktionen das gleiche "Auftraggeberkonto" * angenommen (bei Überweisungen also das Belastungskonto, bei Lastschriften * das Konto, auf das der Betrag gutgeschrieben wird).

*

In der Regel wird zunächst ein DTAUS-Objekt erzeugt. Dazu * wird der Konstruktor {@link #DTAUS(Konto, int)} * verwendet, womit gleichzeit das zu verwendende Auftraggeberkonto und der * Typ des Sammelauftrages (TYPE_CREDIT für Sammelüberweisungen, * TYPE_DEBIT für Sammellastschriften) festgelegt wird. * Anschließend können beliebig viele {@link DTAUS.Transaction}-Objekte * erzeugt werden, welche jeweils eine Transaktion darstellen. Jedes so erzeugte * Objekt kann mit {@link #addEntry(DTAUS.Transaction)} * zum Sammelauftrag hinzugefügt werden. Die Methode {@link #toString()} * liefert schließlich den so erzeugten Sammelauftrag im DTAUS-Format.

*/ // TODO: API ändern (Setter/Getter), damit wir sauber die LogFilter für // kritische Daten setzen können @Slf4j public class DTAUS { /** * Typ des Sammelauftrages: Sammelüberweisung */ public static final int TYPE_CREDIT = 1; /** * Typ des Sammelauftrages: Sammellastschrift */ public static final int TYPE_DEBIT = 2; /** * TODO: doku fehlt */ public static final byte CURR_DM = 0x20; /** * TODO: doku fehlt */ public static final byte CURR_EUR = 0x31; private static final byte ALIGN_LEFT = 1; private static final byte ALIGN_RIGHT = 2; private Konto myAccount; private int type; private Date execdate; private byte curr; private String referenceId; private ArrayList entries; private long sumDM; private long sumEUR; private long sumBLZ; private long sumNumber; /** * Entspricht {@link #DTAUS(Konto, int, Date) DTAUS(myAccount,type,null)} */ public DTAUS(Konto myAccount, int type) { this(myAccount, type, null); } /** * Erzeugen eines neuen Objektes für die Aufnahme von * Sammelaufträgen. myAccount ist dabei das "eigene" Konto, * welches bei Sammelüberweisungen als Belastungskonto und bei * Sammellastschriften als Gutschriftkonto verwendet wird. Von dem * {@link Konto}-Objekt müssen mindestens die Felder blz, * number, curr und name richtig * gesetzt sein.
* execdate gibt das Datum an, wann dieser Sammelauftrag * ausgeführt werden soll. ACHTUNG: execdate wird zur Zeit noch * nicht ausgewertet! * * @param myAccount Gegenkonto für die enthaltenen Aufträge * @param type
  • TYPE_CREDIT für Sammelüberweisungen,
  • *
  • TYPE_DEBIT für Sammellastschriften
* @param execdate Ausführungsdatum für diesen Sammelauftrag; null, * wenn kein Ausführungsdatum gesetzt werden soll (sofortige Ausführung) */ public DTAUS(Konto myAccount, int type, Date execdate) { this.myAccount = myAccount; this.type = type; this.execdate = execdate; entries = new ArrayList<>(); if (myAccount.curr.equals("EUR")) this.curr = CURR_EUR; else if (myAccount.curr.equals("DEM")) this.curr = CURR_DM; else throw new InvalidUserDataException("*** invalid currency of this account: " + myAccount.curr); } /** * TODO: doku fehlt */ public DTAUS(String dtaus) { entries = new ArrayList(); parseDTAUS(dtaus); } /** * Hinzufügen eines einzelnen Auftrages zu diesem Sammelauftrag. Das * {@link DTAUS.Transaction}-Objekt, welches hier als Argument benötigt wird, * muss mit 'dtaus.new Transaction()' erzeugt werden * ('dtaus' ist dabei das aktuelle DTAUS-Objekt). * * @param entry Hinzuzufügender Einzelauftrag */ public void addEntry(Transaction entry) { entries.add(entry); } /** * TODO: doku fehlt */ public byte getCurr() { return curr; } /** * TODO: doku fehlt */ public ArrayList getEntries() { return entries; } /** * TODO: doku fehlt */ public Date getExecdate() { return execdate; } /** * TODO: doku fehlt */ public Konto getMyAccount() { return myAccount; } /** * TODO: doku fehlt */ public int getType() { return type; } /** * Gibt den Wert von Feld Nr 10 ("Referenznummer des Einreichers") zurück */ public String getReferenceId() { return (this.referenceId != null) ? this.referenceId : ""; } /** * Setzt das Feld Nr 10 ("Referennummer des Einreichers") */ public void setReferenceId(String referenceId) { this.referenceId = referenceId; } /** * Rückgabe des Sammelauftrages im DTAUS-Format. Der Rückgabewert dieser * Methode kann direkt als Parameterwert für den Parameter 'data' * bei Sammelaufträgen verwendet werden (für eine Parameterbeschreibung * siehe Paketbeschreibung des Paketes org.kapott.hbci.GV). * * @return DTAUS-Datenstrom für diesen Sammelauftrag */ public String toString() { StringBuffer ret = new StringBuffer(); sumBLZ = 0; sumNumber = 0; sumDM = 0; sumEUR = 0; // A-set ret.append("0128A"); switch (type) { case TYPE_CREDIT: ret.append("GK"); break; case TYPE_DEBIT: ret.append("LK"); break; default: throw new InvalidUserDataException("*** type of DTAUS order not set (DEBIT/CREDIT)"); } ret.append(expand(myAccount.blz, 8, (byte) 0x20, ALIGN_RIGHT)); ret.append(expand("", 8, (byte) 0x30, ALIGN_LEFT)); ret.append(expand(SyntaxDTAUS.check(myAccount.name), 27, (byte) 0x20, ALIGN_LEFT)); SimpleDateFormat form = new SimpleDateFormat("ddMMyy"); ret.append(form.format(new Date())); ret.append(expand("", 4, (byte) 0x20, ALIGN_LEFT)); ret.append(expand(myAccount.number, 10, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(getReferenceId(), 10, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand("", 15, (byte) 0x20, ALIGN_LEFT)); if (execdate == null) { ret.append(expand("", 8, (byte) 0x20, ALIGN_LEFT)); } else { form = new SimpleDateFormat("ddMMyyyy"); ret.append(form.format(execdate)); } ret.append(expand("", 24, (byte) 0x20, ALIGN_LEFT)); ret.append((char) curr); // C-sets for (Iterator i = entries.iterator(); i.hasNext(); ) { Transaction entry = i.next(); ret.append(entry.toString()); } // E-set ret.append("0128E"); ret.append(expand("", 5, (byte) 0x20, ALIGN_LEFT)); ret.append(expand(Integer.toString(entries.size()), 7, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(Long.toString(curr == CURR_DM ? sumDM : 0), 13, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(Long.toString(sumNumber), 17, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(Long.toString(sumBLZ), 17, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(Long.toString(curr == CURR_EUR ? sumEUR : 0), 13, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand("", 51, (byte) 0x20, ALIGN_LEFT)); return ret.toString(); } private String expand(String st, int len, byte filler, int align) { if (st.length() < len) { try { byte[] fill = new byte[len - st.length()]; Arrays.fill(fill, filler); String fillst = new String(fill, StandardCharsets.ISO_8859_1); if (align == ALIGN_LEFT) st = st + fillst; else if (align == ALIGN_RIGHT) st = fillst + st; else throw new HBCI_Exception("*** invalid align type: " + align); } catch (Exception e) { throw new HBCI_Exception(e); } } else if (st.length() > len) { throw new InvalidArgumentException("*** string too long: \"" + st + "\" has " + st.length() + " chars, " + "but max is " + len); } return st; } private void parseDTAUS(String dtaus) { log.debug("parsing DTAUS data"); // satz A String header = dtaus.substring(0, 5); if (!header.equals("0128A")) { throw new HBCI_Exception("*** DTAUS stream does not start with '0128A'"); } char typ = dtaus.charAt(5); if (typ == 'G') { this.type = TYPE_CREDIT; } else if (typ == 'L') { this.type = TYPE_DEBIT; } else { throw new HBCI_Exception("*** Invalid type: " + typ); } setReferenceId(dtaus.substring(70, 80).trim()); String myBLZ = dtaus.substring(7, 15).trim(); String myName = dtaus.substring(23, 50).trim(); String myNumber = dtaus.substring(60, 70).trim(); try { SimpleDateFormat format = new SimpleDateFormat("ddMMyyyy"); this.execdate = format.parse(dtaus.substring(95, 103).trim()); } catch (ParseException e) { this.execdate = null; } this.curr = (byte) dtaus.charAt(127); if (this.curr != CURR_DM && this.curr != CURR_EUR) { throw new HBCI_Exception("*** Invalid currency: " + this.curr); } this.myAccount = new Konto("DE", myBLZ, myNumber); this.myAccount.curr = (this.curr == CURR_EUR) ? "EUR" : "DEM"; this.myAccount.name = myName; // satz C beginn int posi = 128; // schleife für einzelne aufträge (c-sets) while (true) { Transaction entry = new Transaction(); if (dtaus.charAt(posi + 4) != 'C') { // gefundener abschnitt ist kein c-set break; } int setCLen = Integer.parseInt(dtaus.substring(posi, posi + 4)); posi += 4; log.debug("SetCLen = " + setCLen + " data bytes (--> " + ((setCLen - 187) / 29.0) + " extensions)"); // "C" überspringen posi++; // skip myBLZ posi += 8; String otherBLZ = dtaus.substring(posi, posi + 8).trim(); posi += 8; String otherNumber = dtaus.substring(posi, posi + 10).trim(); posi += 10; entry.internalCustomerId = dtaus.substring(posi + 1, posi + 1 + 11).trim(); posi += 13; entry.key = dtaus.substring(posi, posi + 2).trim(); posi += 2; entry.addkey = dtaus.substring(posi, posi + 3).trim(); posi += 3; // skip bankintern posi++; String value_st = null; if (this.curr == CURR_EUR) { value_st = dtaus.substring(posi + 29, posi + 29 + 11).trim(); } else { value_st = dtaus.substring(posi, posi + 11).trim(); } posi += 40; // skip reserve posi += 3; String otherName = dtaus.substring(posi, posi + 27).trim(); posi += 27; // skip fillbytes posi += 8; // skip myName posi += 27; entry.addUsage(dtaus.substring(posi, posi + 27).trim()); posi += 27; // skip währung // TODO: hier konsistenz überprüfen posi++; // skip reserve posi += 2; int nofExtensions = Integer.parseInt(dtaus.substring(posi, posi + 2)); posi += 2; log.debug("field 'nofExtensions' = " + nofExtensions); String otherName2 = null; for (int i = 0; i < nofExtensions; i++) { if ((posi % 128) + 29 > 128) { posi = ((posi / 128) + 1) * 128; } String code = dtaus.substring(posi, posi + 2).trim(); posi += 2; String data = dtaus.substring(posi, posi + 27).trim(); posi += 27; if (code.equals("01")) { otherName2 = data; } else if (code.equals("02")) { entry.addUsage(data); } else if (code.equals("03")) { this.myAccount.name2 = data; } } posi = ((posi / 128) + 1) * 128; entry.otherAccount = new Konto("DE", otherBLZ, otherNumber); entry.otherAccount.curr = (this.curr == CURR_EUR) ? "EUR" : "DEM"; entry.otherAccount.name = otherName; entry.otherAccount.name2 = otherName2; entry.value = new Value(Long.parseLong(value_st), (this.curr == CURR_EUR) ? "EUR" : "DEM"); addEntry(entry); } // e-satz if (!dtaus.substring(posi, posi + 5).equals("0128E")) { throw new HBCI_Exception("*** e-set does not start with 0128E"); } posi += 5; // skip reserve posi += 5; int x = Integer.parseInt(dtaus.substring(posi, posi + 7)); if (x != entries.size()) { throw new HBCI_Exception("*** there were " + entries.size() + " c-sets, but e-set says " + x); } // TODO: restliche konsistenzchecks machen log.debug("parsinng of DTAUS data finished"); } /** * Daten einer einzelnen Transaktion, die in einen Sammelauftrag * übernommen werden soll. Vor dem Hinzufügen dieser Transaktion zum * Sammelauftrag müssen alle Felder dieses Transaktions-Objektes mit den * jeweiligen Auftragsdaten gefüllt werden. */ public class Transaction { /** *

Konto des Zahlungsempfängers bzw. des Zahlungspflichtigen. Soll * dieser Einzelauftrag in eine Sammelüberweisung eingestellt werden, * so muss in diesem Feld die Kontoverbindung des Zahlungsempfängers * eingestellt werden. Bei Sammellastschriften ist hier die * Kontoverbindung des Zahlungspflichtigen einzustellen.

*

Von dem verwendeten {@link Konto}-Objekt müssen mindestens die * Felder blz, number und name * richtig belegt sein.

*/ public Konto otherAccount; /** * interne Kunden-ID. Wie die verwendet wird weiß ich leider nicht * genau, kann im Prinzip leer gelassen werden (ansonsten Maximallänge * 11 Zeichen). */ public String internalCustomerId; /** * Textschlüssel für den Auftrag. Bei Sammelüberweisungen ist dieses * Feld mit '51' vorbelegt, bei Sammellastschriften mit '05'. Dieser * Wert kann überschrieben werden, gültige Werte finden sich in den * Job-Restrictions * (siehe {@link org.kapott.hbci.GV.AbstractHBCIJob#getJobRestrictions()}). */ public String key; /** * Zusätzlicher Textschlüssel (wird i.d.R. bankintern verwendet). * Dieser Wert muss aus drei Ziffern bestehen und ist mit '000' * vorbelegt. Das manuelle Setzen dieses Wertes ist in den meisten * Fällen nicht nötig (außer für Leute, die wissen was sie tun ;-) ). */ public String addkey; /** * Geldbetrag, der bei diesem Einzelauftrag überwiesen (Sammelüberweisungen) * bzw. eingezogen (Sammellastschriften) werden soll */ public Value value; private ArrayList usage; /** * Erzeugen eine neuen Objektes für die Aufnahme von Daten für eine * Transaktion */ public Transaction() { addkey = "000"; key = (type == TYPE_CREDIT ? "51" : "05"); usage = new ArrayList(); } /** * Hinzufügen einer Verwendungszweckzeile zu diesem Auftrag. */ public void addUsage(String st) { usage.add(st); } /** * Gibt eine Liste der Verwendungszweckzeilen (String) zurück. */ public List getUsage() { return usage; } public String toString() { StringBuffer ret = new StringBuffer(); try { ret.append("0000C"); ret.append(expand(myAccount.blz, 8, (byte) 0x20, ALIGN_RIGHT)); ret.append(expand(otherAccount.blz, 8, (byte) 0x20, ALIGN_RIGHT)); ret.append(expand(otherAccount.number, 10, (byte) 0x30, ALIGN_RIGHT)); sumBLZ += Long.parseLong(otherAccount.blz); sumNumber += Long.parseLong(otherAccount.number); if (internalCustomerId == null) { ret.append(expand("", 13, (byte) 0x30, ALIGN_LEFT)); } else { ret.append((char) 0); ret.append(expand(SyntaxDTAUS.check(internalCustomerId), 11, (byte) 0x30, ALIGN_LEFT)); ret.append((char) 0); } ret.append(expand(key, 2, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(addkey, 3, (byte) 0x30, ALIGN_RIGHT)); ret.append((char) 0x20); ret.append(expand(Long.toString(value.getCurr().equals("DEM") ? value.getLongValue() : 0), 11, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(myAccount.blz, 8, (byte) 0x20, ALIGN_RIGHT)); ret.append(expand(myAccount.number, 10, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand(Long.toString(value.getCurr().equals("EUR") ? value.getLongValue() : 0), 11, (byte) 0x30, ALIGN_RIGHT)); ret.append(expand("", 3, (byte) 0x20, ALIGN_LEFT)); ret.append(expand(SyntaxDTAUS.check(otherAccount.name), 27, (byte) 0x20, ALIGN_LEFT)); ret.append(expand("", 8, (byte) 0x20, ALIGN_LEFT)); if (value.getCurr().equals("EUR")) sumEUR += value.getLongValue(); else if (value.getCurr().equals("DEM")) sumDM += value.getLongValue(); ret.append(expand(SyntaxDTAUS.check(myAccount.name), 27, (byte) 0x20, ALIGN_LEFT)); String st = ""; if (usage.size() != 0) st = SyntaxDTAUS.check(usage.get(0)); ret.append(expand(st, 27, (byte) 0x20, ALIGN_LEFT)); ret.append((char) curr); ret.append(expand("", 2, (byte) 0x20, ALIGN_LEFT)); int posForNumOfExt = ret.length(); ret.append("00"); int basicLenOfCSet = 128 + 27 + 27 + 5; int realLenOfCSet = basicLenOfCSet; int numOfExt = 0; // erweiterungsteile // TODO: name2 für myAccount und otherAccount vorerst weggelassen for (int i = 1; i < usage.size(); i++) { st = SyntaxDTAUS.check(usage.get(i)); if (((realLenOfCSet % 128) + 29) > 128) { int diff = 128 - (realLenOfCSet % 128); ret.append(expand("", diff, (byte) 0x20, ALIGN_LEFT)); realLenOfCSet += diff; } ret.append("02"); ret.append(expand(st, 27, (byte) 0x20, ALIGN_LEFT)); realLenOfCSet += 29; numOfExt++; } if ((realLenOfCSet % 128) != 0) { int diff = 128 - (realLenOfCSet % 128); ret.append(expand("", diff, (byte) 0x20, ALIGN_LEFT)); realLenOfCSet += diff; } ret.replace(posForNumOfExt, posForNumOfExt + 2, expand(Integer.toString(numOfExt), 2, (byte) 0x30, ALIGN_RIGHT)); ret.replace(0, 4, expand(Integer.toString(basicLenOfCSet + 29 * numOfExt), 4, (byte) 0x30, ALIGN_RIGHT)); } catch (NullPointerException e) { throw new HBCI_Exception("probably one or more DTAUS values which MUST be set are null - please refer" + " the API doc", e); } return ret.toString(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy