/* $Id: MyBackend.java,v 1.4 2005/06/10 18:03:03 kleiner Exp $ This file is part of HBCI4Java Copyright (C) 2001-2005 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.demo.hbci.server.backend; import java.io.File; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.Random; import org.kapott.hbci.GV_Result.GVRKUms; import org.kapott.hbci.manager.HBCIUtils; import org.kapott.hbci.structures.Konto; import org.kapott.hbci.structures.Saldo; import org.kapott.hbci.structures.Value; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /* Diese Klasse simuliert ein Bank-Hintergrundsystem */ public class MyBackend { private String directory; // Verzeichnis fr Daten-Dateien private XMLTools xml; private Random random; public MyBackend(String directory) { this.directory=directory; this.xml=new XMLTools(); this.random=new Random(); } // eingegangene kundennachricht speichern public void storeCustomMsg(Konto acc, String recpt,String subject,String msgtxt) { try { File dataFile=new File(directory+File.separator+acc.customerid+"_messagesIncoming"); Document doc=xml.getFileContent(dataFile,"messages"); Element content=doc.getDocumentElement(); String id=Long.toString(random.nextLong()).substring(1); Element msg=doc.createElement("msg"); content.appendChild(msg); msg.appendChild(xml.createTimestampElement(doc)); msg.appendChild(xml.createElement(doc,"id",id)); msg.appendChild(xml.createElement(doc,"account",acc.number)); msg.appendChild(xml.createElement(doc,"recpt",recpt)); msg.appendChild(xml.createElement(doc,"subject",subject)); msg.appendChild(xml.createElement(doc,"message",msgtxt)); xml.transform(doc,dataFile); } catch (Exception e) { throw new RuntimeException(e.getMessage(),e); } } // kontobewegung speichern // my ist immer eigenes konto; vorzeichen von btg.value gibt an, ob etwas // dazukommt oder abgeht public void addTransfer(Konto my,Konto other,Value btg,String[] usage,String key,String addkey) { try { File dataFile=new File(directory+File.separator+my.customerid+"_transfers_"+my.number); Document doc=xml.getFileContent(dataFile,"transfers"); Element content=doc.getDocumentElement(); GVRKUms.UmsLine entry=new GVRKUms.UmsLine(); double saldoOld=getSaldo(my); entry.bdate=new Date(); entry.valuta=entry.bdate; entry.cd=btg.value<0?"D":"C"; entry.other=other; entry.value=new Value(Math.abs(btg.value),btg.curr); double v=(Math.round(saldoOld*100.0)+Math.round(btg.value*100.0))/100.0; entry.saldo=new Saldo(); entry.saldo.value=new Value(Math.abs(v),btg.curr); entry.saldo.cd=(v<0)?"D":"C"; entry.saldo.timestamp=entry.valuta; entry.usage=usage; entry.gvcode="0"+key; entry.addkey=addkey; String id=Long.toString(random.nextLong()).substring(1); content.appendChild(xml.createUmsLineElement(doc,"transfer",entry,id)); xml.transform(doc,dataFile); } catch (Exception e) { throw new RuntimeException(e.getMessage(),e); } } // saldo fr bestimmtes konto zurckgeben public double getSaldo(Konto acc) { try { File dataFile=new File(directory+File.separator+acc.customerid+"_transfers_"+acc.number); Document doc=xml.getFileContent(dataFile,"transfers"); Element content=doc.getDocumentElement(); double saldo=0; NodeList transfer_entries=content.getElementsByTagName("transfer"); int len; if (transfer_entries!=null && (len=transfer_entries.getLength())!=0) { Element lastEntry=(Element)transfer_entries.item(len-1); saldo=xml.readValueElement(lastEntry,"saldo",null).value; } return saldo; } catch (Exception e) { throw new RuntimeException(e.getMessage(),e); } } // MT940-Kontoauszug erzeugen public String getStatementOfAccount(Konto my,Date from,Date to,boolean onlyNew) { StringBuffer ret=new StringBuffer(); String lastid=null; if (onlyNew) { // datei mit zeiger auf letzten bermittelten eintrag ffnen uns auslesen File dataFile=new File(directory+File.separator+my.customerid+"_transfers_"+my.number+"_lastentry"); Document doc=xml.getFileContent(dataFile,"lastentry"); Element content=doc.getDocumentElement(); lastid=xml.readElement(content,"id",null); } // datendatei ffnen bzw. anlegen File dataFile=new File(directory+File.separator+my.customerid+"_transfers_"+my.number); Document doc=xml.getFileContent(dataFile,"transfers"); Element content=doc.getDocumentElement(); // alle transfer-eintrge herausfischen NodeList transferList=content.getElementsByTagName("transfer"); if (transferList.getLength()!=0) { // aus nodelist ein arraylist erzeugen ArrayList transferArray=new ArrayList(); int len=transferList.getLength(); for (int i=0;i<len;i++) transferArray.add(transferList.item(i)); // arraylist evtl. um schon gesehene eintrge krzen if (lastid!=null) optionallyRemoveSeenEntries(transferArray,lastid); if (transferArray.size()!=0) { SimpleDateFormat dateFormat=new SimpleDateFormat("yyMMdd"); DecimalFormat valueFormat=new DecimalFormat("0.##"); DecimalFormatSymbols symbols=valueFormat.getDecimalFormatSymbols(); symbols.setDecimalSeparator(','); valueFormat.setDecimalFormatSymbols(symbols); valueFormat.setDecimalSeparatorAlwaysShown(true); Iterator transfers=transferArray.iterator(); Element transfer=(Element)transfers.next(); boolean isFirstOfDay=true; while (true) { // schleife ber alle transfer-eintrge // Daten aus Eintrag extrahieren Date valuta=xml.readDateTimeElement(transfer,"valuta",null); String valuta_st=dateFormat.format(valuta); Date bdate=xml.readDateTimeElement(transfer,"bdate",valuta); String bdate_st=dateFormat.format(bdate); String id=xml.readElement(transfer,"id",null); // liegt dieser Eintrag nicht im gewnschten Zeitraum if (from!=null && !from.before(bdate) || to!=null && !bdate.before(to)) { // entweder abbrechen oder nchster schleifendurchlauf if (!transfers.hasNext()) { break; } transfer=(Element)transfers.next(); continue; } // werte aus eintrag extrahieren double saldo=xml.readValueElement(transfer,"saldo",null).value; double value=xml.readValueElement(transfer,"value",null).value; if (isFirstOfDay) { // startsaldo schreiben ret.append("\r\n"); ret.append(":20:0"+"\r\n"); ret.append(":25:"+my.blz+"/"+my.number+my.curr+"\r\n"); ret.append(":28C:0\r\n"); double saldoBefore=(Math.round(saldo*100.0)-Math.round(value*100.0))/100.0; ret.append(":60F:"+ (saldoBefore<0?"D":"C")+bdate_st+my.curr+ valueFormat.format(Math.abs(saldoBefore))+"\r\n"); isFirstOfDay=false; } // daten fr diese berweisung // *** TRF evtl. anpassen String instref; ret.append(":61:"+valuta_st+bdate_st.substring(2)+ // daten (value<0?"D":"C")+my.curr.charAt(2)+ // value valueFormat.format(Math.abs(value))+ "NTRF"+ xml.readElement(transfer,"customerref","NONREF")+ // customerref ((instref=xml.readElement(transfer,"instref",null))!=null?"//"+instref:"")); // instref // wert in originalwhrung Value orig_value=xml.readValueElement(transfer,"orig",null); boolean additionalAppended=false; if (orig_value!=null) { ret.append("\r\n//OCMT/"+orig_value.curr+valueFormat.format(orig_value.value)+"/"); additionalAppended=true; } // gebhren Value charge_value=xml.readValueElement(transfer,"charge",null); if (charge_value!=null) { if (!additionalAppended) ret.append("\r\n/"); ret.append("/CHGS/"+charge_value.curr+valueFormat.format(charge_value.value)+"/"); } ret.append("\r\n"); // start new tag ret.append(":86:"); int posOfTagStart=ret.length(); // gvcode String gvcode=xml.readElement(transfer,"gvcode","000"); ret.append(gvcode); ret.append("?00"+xml.key2Text(gvcode)); // primanota String primanota=xml.readElement(transfer,"primanota",null); if (primanota!=null) appendWithOptionalCRLF(ret,"?10"+primanota,posOfTagStart,65); // verwendungszweck String[] usage=xml.readStringArrayElement(transfer,"usage",new String[0]); int usageIdx=0; for (usageIdx=0;usageIdx<Math.min(10,usage.length);usageIdx++) { appendWithOptionalCRLF(ret,"?"+(20+usageIdx)+usage[usageIdx],posOfTagStart,65); } // gegenkonto Konto other=xml.readAccountElement(transfer,"other",new Konto()); appendWithOptionalCRLF(ret,"?30"+other.blz,posOfTagStart,65); appendWithOptionalCRLF(ret,"?31"+other.number,posOfTagStart,65); if (other.name!=null && other.name.length()!=0) appendWithOptionalCRLF(ret,"?32"+other.name,posOfTagStart,65); if (other.name2!=null && other.name2.length()!=0) appendWithOptionalCRLF(ret,"?33"+other.name2,posOfTagStart,65); // zusatz-schlssel String addkey=xml.readElement(transfer,"addkey",null); if (addkey!=null) appendWithOptionalCRLF(ret,"?34"+addkey,posOfTagStart,65); // zustzliche verwendungszweckzeilen for (;usageIdx<Math.min(14,usage.length);usageIdx++) { appendWithOptionalCRLF(ret,"?"+(50+usageIdx)+usage[usageIdx],posOfTagStart,65); } ret.append("\r\n"); // nchsten eintrag holen String nextDate=null; if (transfers.hasNext()) { // wenn es einen nchsten eintrag gibt transfer=(Element)transfers.next(); // buchungsdatum aus nchstem eintrag extrahieren nextDate=dateFormat.format(xml.readDateTimeElement(transfer,"bdate", xml.readDateTimeElement(transfer,"valuta",null))); } // wenn das nchste buchungsdatum ungleich dem des gerade erzeugten // eintrages ist, if (!bdate_st.equals(nextDate)) { // anschlusssaldo mit den *alten* daten erzeugen ret.append(":62F:"+ (saldo<0?"D":"C")+bdate_st+"EUR"+ valueFormat.format(Math.abs(saldo))+"\r\n"); ret.append("-"); if (nextDate==null) { // wenn es kein nchstes bdate gibt, abbrechen // vorher aber noch last-seen-id schreiben if (onlyNew) { // datei mit zeiger auf letzten bermittelten eintrag neu erzeugen doc=xml.newDoc(); content=xml.createElement(doc,"lastentry",""); doc.appendChild(content); content.appendChild(xml.createElement(doc,"id",id)); dataFile=new File(directory+File.separator+my.customerid+"_transfers_"+my.number+"_lastentry"); xml.transform(doc,dataFile); } // erzeugung des kontoauszugs beenden break; } // sonst erzeugen eines startsaldos erzwingen isFirstOfDay=true; } } } } return ret.toString(); } private void optionallyRemoveSeenEntries(ArrayList transfers,String lastid) { Iterator i=transfers.iterator(); // alle transfer-eintrge durchlaufen int currentIdx=0; while (i.hasNext()) { Element transfer=(Element)i.next(); currentIdx++; String id=xml.readElement(transfer,"id",null); // wenn dessen id mit der last-id bereinstimmt if (lastid.equals(id)) { // alle eintrge bis hierhin aus array lschen HBCIUtils.log("removing all seen entries ("+currentIdx+") before and including id '"+lastid+"'",HBCIUtils.LOG_DEBUG); for (int j=0;j<currentIdx;j++) transfers.remove(0); break; } } } private void appendWithOptionalCRLF(StringBuffer ret,String data,int posOfTagStart,int maxlen) { int lastCRLF=ret.lastIndexOf("\r\n"); if (lastCRLF<posOfTagStart) lastCRLF=posOfTagStart; else lastCRLF+=2; if (ret.length()-lastCRLF+data.length()>(maxlen-2)) ret.append("\r\n"); ret.append(data); } }