package de.open4me.depot.tools;
import java.math.BigDecimal;
import java.rmi.RemoteException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import de.open4me.depot.abruf.utils.Utils;
import de.open4me.depot.datenobj.DepotAktion;
import de.open4me.depot.sql.GenericObjectSQL;
import de.open4me.depot.sql.SQLUtils;
import de.willuhn.jameica.hbci.rmi.Konto;
import de.willuhn.logging.Logger;
import de.willuhn.util.ApplicationException;
public class Bestandspruefung {
/**
* Liefert das gespeicherte Ergebnisse der Bestandsprüfung zurück.
* Falls noch keine Bestandsprüfung durchgeführt wurde bzw. neu durchgeführt werden muss,
* wird vorher durchgeführt
*
* @return true= wenn die Bestandprüfung ok war
* false: wenn die Bestandprüfung fehlerhaft war
* null: im Fehlerfall
*
*/
public static Boolean isOK() {
Boolean ret = Utils.getUmsatzBestandTest();
if (ret != null) {
return ret;
}
try {
checkAndRecalcOfflineDepots();
} catch (RemoteException | ApplicationException e) {
e.printStackTrace();
}
return Utils.getUmsatzBestandTest();
}
public static String exec() throws RemoteException, ApplicationException {
String output = checkAndRecalcOfflineDepots();
if (output.isEmpty()) {
output = "Keine Abweichungen gefunden.<br/>Der Bestand passt zu den Umsätzen im Orderbuch.";
} else {
output = "Folgende Abweichungen wurden gefunden: <p/>" + output;
}
return output;
}
/**
*
* @return
* @throws RemoteException
* @throws ApplicationException
*/
private static String checkAndRecalcOfflineDepots() throws RemoteException, ApplicationException {
String output = "";
// Überprüfe alle Konten für die es Umsätze bzw. Bestände gibt
List<GenericObjectSQL> konten = SQLUtils.getResultSet("select * from konto where id in (select distinct kontoid from depotviewer_bestand union select distinct kontoid from depotviewer_umsaetze)", null, "id");
for (GenericObjectSQL konto : konten) {
String outputKonto = pruefe(konto);
if (konto.getAttribute("flags") != null
&& (((Integer) konto.getAttribute("flags")) & Konto.FLAG_OFFLINE) == Konto.FLAG_OFFLINE) {
createOfflineBestand(konto);
outputKonto = pruefe(konto);
}
output += outputKonto;
}
try {
Utils.setUmsatzBetsandTest(output.isEmpty());
} catch (ApplicationException e) {
e.printStackTrace();
Logger.error("Fehler beim Setzen des Umsatz/Bestand-Flags", e);
}
return output;
}
/**
* Bestimmt den Bestand von Offline Konten aus den Umsätzen und
* bewertet ihn falls Kursdaten vorhanden sind
* @param konto Konto
* @throws RemoteException
* @throws ApplicationException
*/
private static void createOfflineBestand(GenericObjectSQL konto) throws RemoteException, ApplicationException {
Konto k = Utils.getKontoByID(konto.getAttribute("id").toString());
HashMap<Integer, BigDecimal> bestand = getBestandLautOrder(konto);
Utils.clearBestand(k);
BigDecimal saldo = BigDecimal.ZERO;
for (Entry<Integer, BigDecimal> position : bestand.entrySet()) {
BigDecimal wert = BigDecimal.ZERO;
String wertW = "EUR";
BigDecimal kurs = BigDecimal.ZERO;
String kursW = "EUR";
Date bewertung = null;
String id = position.getKey().toString();
// Falls Kursdaten vorhanden sind, bitte diese nutzen
List<GenericObjectSQL> res = SQLUtils.getResultSet(SQLUtils.addTop(1, "select * from depotviewer_kurse where wpid = " + id +" order by kursdatum desc"), "depotviewer_kurse", id, id);
if (res.size() == 1) {
GenericObjectSQL data = res.get(0);
kurs = new BigDecimal(data.getAttribute("kurs").toString());
kursW = data.getAttribute("kursw").toString();
wertW = kursW;
wert = kurs.multiply(position.getValue());
bewertung = (Date) data.getAttribute("kursdatum");
saldo = saldo.add(wert); // Währung beachten!
}
// Bestand hinzufügen
Utils.addBestand(position.getKey().toString(), k, position.getValue().doubleValue(), kurs.doubleValue(), kursW, wert.doubleValue(), wertW, new Date(), bewertung);
}
k.setSaldo(saldo.doubleValue());
k.store();
}
private static String pruefe(GenericObjectSQL konto) throws RemoteException {
String output = "";
HashMap<Integer, BigDecimal> bestandLautOrder = getBestandLautOrder(konto);
// Abgleich tatsächlicher Bestand vs. errechneter Bestand
List<GenericObjectSQL> bestaende = SQLUtils.getResultSet("select * from depotviewer_bestand where kontoid = " + konto.getID() , null, null);
for (GenericObjectSQL bestand : bestaende) {
BigDecimal depotAnzahl = (BigDecimal) bestand.getAttribute("anzahl");
BigDecimal x = bestandLautOrder.get(bestand.getAttribute("wpid"));
if (x == null) {
x = BigDecimal.ZERO;
}
if (x.compareTo(depotAnzahl) != 0) {
output = addDifferenz(konto, (Integer) bestand.getAttribute("wpid"), x, depotAnzahl, output);
}
bestandLautOrder.remove(bestand.getAttribute("wpid"));
}
// Und jetzt noch alles prüfen, was wir jetzt noch in den Umsätzen haben
for (Entry<Integer, BigDecimal> set : bestandLautOrder.entrySet()) {
if (set.getValue().compareTo(BigDecimal.ZERO) != 0) {
output = addDifferenz(konto, set.getKey(), set.getValue(), BigDecimal.ZERO, output);
}
}
return output;
}
private static HashMap<Integer, BigDecimal> getBestandLautOrder(GenericObjectSQL konto) throws RemoteException {
HashMap<Integer, BigDecimal> bestandLautOrder = new HashMap<Integer, BigDecimal>();
// Alle Umsätze nehmen und daraus einen Bestand berechnen.
List<GenericObjectSQL> buchungen = SQLUtils.getResultSet("select * from depotviewer_umsaetze where kontoid = " + konto.getID() + " order by buchungsdatum asc", null, null);
for (GenericObjectSQL x : buchungen) {
Integer wpid = (Integer) x.getAttribute("wpid");
BigDecimal transactionanzahl = (BigDecimal) x.getAttribute("anzahl");
BigDecimal aktuellerBestand = (bestandLautOrder.containsKey(wpid)) ? bestandLautOrder.get(wpid) : new BigDecimal(0);
DepotAktion aktion = DepotAktion.getByString((String) x.getAttribute("aktion"));
if (aktion.equals(DepotAktion.KAUF) || aktion.equals(DepotAktion.EINBUCHUNG)) {
aktuellerBestand = aktuellerBestand.add(transactionanzahl);
} else if (aktion.equals(DepotAktion.VERKAUF) || aktion.equals(DepotAktion.AUSBUCHUNG)) {
aktuellerBestand = aktuellerBestand.subtract(transactionanzahl);
}
bestandLautOrder.put(wpid, aktuellerBestand);
}
return bestandLautOrder;
}
private static String addDifferenz(GenericObjectSQL konto, Integer wpid, BigDecimal lautUmsaetze,
BigDecimal lautBestand, String output) throws RemoteException {
GenericObjectSQL wp = SQLUtils.getResultSet("select * from depotviewer_wertpapier where id = " + wpid,
null, null).get(0);
output += "Konto: "
+ konto.getAttribute("bezeichnung").toString()
+ "<br/>"
+ "Wertpapier: " + ((wp.getAttribute("wertpapiername") == null) ? "" :wp.getAttribute("wertpapiername")) + "<br/>"
+ "Wertpapier: " + ((wp.getAttribute("wkn") == null) ? "" :wp.getAttribute("wkn")) + "<br/>"
+ "Wertpapier: " + ((wp.getAttribute("isin") == null) ? "" :wp.getAttribute("isin")) + "<br/>"
+ "Anzahl laut Bestand : " + lautBestand.toPlainString() + "<br/>"
+ "Anzahl laut Orderbuch: " + lautUmsaetze.toPlainString() + "<br/>"
+ "Differenz: " + lautBestand.subtract(lautUmsaetze) + "<br/>"
+ "<p/>";
return output;
}
}