Skip to content

Commit c567c7c

Browse files
committed
Saldo-Prognose auch basierend auf vergangenen Umsätzen (per Default
deaktiviert)
1 parent ae99174 commit c567c7c

8 files changed

+203
-18
lines changed

build/ChangeLog

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
HEAD 2.11 (nightly)
22

3+
* NEW: 1076 Saldo-Prognose auch basierend auf vergangenen Ums�tzen (per Default deaktiviert)
34
* NEW: 1075 Kontextmen�-Eintrag "Nach SEPA konvertieren..." im Adressbuch nur anzeigen, wenn Adressen ohne IBAN markiert sind
45
* NEW: 1074 Saldo-Limits als Unread-Counter auf der Startseite markieren
56
* NEW: 1073 Beim Zusammenfassen zu Sammelauftr�gen die Einzelauftr�ge nicht l�schen, wenn sie Wiederholungsvorlagen sind

src/de/willuhn/jameica/hbci/forecast/AbstractForecastProvider.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import de.willuhn.jameica.hbci.schedule.ScheduleProvider;
2323
import de.willuhn.jameica.hbci.schedule.ScheduleProviderFactory;
2424
import de.willuhn.jameica.hbci.server.Value;
25+
import de.willuhn.jameica.util.DateUtil;
2526
import de.willuhn.logging.Logger;
2627

2728
/**
@@ -39,8 +40,11 @@ public String getName()
3940
return provider != null ? provider.getName() : "<unknown provider>";
4041
}
4142

43+
/**
44+
* @see de.willuhn.jameica.hbci.forecast.ForecastProvider#getData(de.willuhn.jameica.hbci.rmi.Konto, java.util.Date)
45+
*/
4246
@Override
43-
public List<Value> getData(Konto k, Date from, Date to) throws Exception
47+
public List<Value> getData(Konto k, Date to) throws Exception
4448
{
4549
List<Value> result = new LinkedList<Value>();
4650

@@ -51,7 +55,7 @@ public List<Value> getData(Konto k, Date from, Date to) throws Exception
5155
return result;
5256
}
5357

54-
List<Schedule<T>> list = provider.getSchedules(k,from,to);
58+
List<Schedule<T>> list = provider.getSchedules(k,DateUtil.startOfDay(new Date()),to);
5559

5660
// In Values kopieren
5761
for (Schedule<T> schedule:list)

src/de/willuhn/jameica/hbci/forecast/ForecastCreator.java

+9-10
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ private static SaldoLimit checkLimit(Konto k, SaldoLimit.Type type)
181181
try
182182
{
183183
final Date today = DateUtil.startOfDay(new Date());
184-
final List<Value> values = create(k,today,DateUtil.endOfDay(cal.getTime()));
184+
final List<Value> values = create(k,DateUtil.endOfDay(cal.getTime()));
185185

186186
// Wir haben keine einzige Buchung. Dann entscheiden wir basierend auf dem aktuellen Saldo
187187
if (values == null || values.isEmpty())
@@ -257,25 +257,22 @@ public static synchronized void updateLimits()
257257
}
258258

259259
/**
260-
* Erzeugt eine Liste von Salden fuer das angegebene Konto im angegebenen Zeitraum.
260+
* Erzeugt eine Liste von Salden fuer das angegebene Konto von heute bis zum angegebenen Zieldatum.
261261
* Die Liste enthaelt hierbei fuer jeden Tag einen Wert (auch wenn an diesem Tag
262262
* keine Zahlungsvorgaenge stattfanden - in dem Fall besitzt der Wert den Saldo des Vortages),
263263
* kann daher also 1:1 auf eine Chart-Grafik gemappt werden.
264264
* @param k das Konto. Optional. Ist keines angegeben, wird eine Prognose ueber
265265
* alle Konten erstellt.
266-
* @param from Beginn des Zeitraumes. Ist keiner angegeben, beginnt die
267-
* Auswertung beim heutigen Tag.
268266
* @param to Ende des Zeitraumes. Ist keines angegeben, endet die Auswertung 1 Jahr nach Beginn
269267
* des Zeitraumes.
270268
* @return die Liste der Salden.
271269
* @throws RemoteException
272270
*/
273-
public static List<Value> create(Konto k, Date from, Date to) throws RemoteException
271+
public static List<Value> create(Konto k, Date to) throws RemoteException
274272
{
275273
////////////////////////////////////////////////////////////////////////////
276274
// Start- und End-Datum vorbereiten
277-
if (from == null)
278-
from = new Date();
275+
Date from = DateUtil.startOfDay(new Date());
279276

280277
if (to == null)
281278
{
@@ -285,8 +282,7 @@ public static List<Value> create(Konto k, Date from, Date to) throws RemoteExcep
285282
to = cal.getTime();
286283
}
287284

288-
from = DateUtil.startOfDay(from);
289-
to = DateUtil.endOfDay(to);
285+
to = DateUtil.endOfDay(to);
290286
//
291287
////////////////////////////////////////////////////////////////////////////
292288

@@ -302,7 +298,10 @@ public static List<Value> create(Konto k, Date from, Date to) throws RemoteExcep
302298

303299
try
304300
{
305-
List<Value> values = p.getData(k,from,to);
301+
List<Value> values = p.getData(k,to);
302+
if (values == null || values.isEmpty())
303+
continue;
304+
306305
for (Value v:values)
307306
{
308307
// Haben wir den Tag schon?

src/de/willuhn/jameica/hbci/forecast/ForecastProvider.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,15 @@ public interface ForecastProvider
2929
public String getName();
3030

3131
/**
32-
* Liefert die voraussichtlichen Zahlungen fuer den angegebenen Zeitraum.
32+
* Liefert die voraussichtlichen Zahlungen beginnend mit heute und endend mit dem angegeben Datum.
3333
* @param k das Konto. Wenn es fehlt, sollte der Provider die Zahlungen
3434
* aller Konten liefern.
35-
* @param from Beginn des Zeitraumes (inclusive). Das Datum ist
36-
* immer angegeben. Die Implementierung muss hier also nicht auf NULL pruefen.
3735
* @param to Ende des Zeitraumes (inclusive). Das Datum ist
3836
* immer angegeben. Die Implementierung muss hier also nicht auf NULL pruefen.
3937
* @return Liste der voraussichtlichen Zahlungen.
4038
* @throws Exception
4139
*/
42-
public List<Value> getData(Konto k, Date from, Date to) throws Exception;
40+
public List<Value> getData(Konto k, Date to) throws Exception;
4341
}
4442

4543

src/de/willuhn/jameica/hbci/forecast/ForecastProviderSepaDauerauftrag.java

+17
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
package de.willuhn.jameica.hbci.forecast;
1212

1313
import java.rmi.RemoteException;
14+
import java.util.Date;
15+
import java.util.List;
1416

17+
import de.willuhn.jameica.hbci.rmi.Konto;
1518
import de.willuhn.jameica.hbci.rmi.SepaDauerauftrag;
1619
import de.willuhn.jameica.hbci.schedule.Schedule;
1720
import de.willuhn.jameica.hbci.server.Value;
@@ -21,6 +24,20 @@
2124
*/
2225
public class ForecastProviderSepaDauerauftrag extends AbstractForecastProvider<SepaDauerauftrag>
2326
{
27+
private final static de.willuhn.jameica.system.Settings settings = new de.willuhn.jameica.system.Settings(ForecastProvider.class);
28+
29+
/**
30+
* @see de.willuhn.jameica.hbci.forecast.AbstractForecastProvider#getData(de.willuhn.jameica.hbci.rmi.Konto, java.util.Date)
31+
*/
32+
@Override
33+
public List<Value> getData(Konto k, Date to) throws Exception
34+
{
35+
if (!settings.getBoolean("forecast.dauerauftrag",true))
36+
return null;
37+
38+
return super.getData(k, to);
39+
}
40+
2441
@Override
2542
Value createValue(Schedule<SepaDauerauftrag> schedule) throws RemoteException
2643
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/**********************************************************************
2+
*
3+
* Copyright (c) 2024 Olaf Willuhn
4+
* All rights reserved.
5+
*
6+
* This software is copyrighted work licensed under the terms of the
7+
* Jameica License. Please consult the file "LICENSE" for details.
8+
*
9+
**********************************************************************/
10+
11+
package de.willuhn.jameica.hbci.forecast;
12+
13+
import java.util.ArrayList;
14+
import java.util.Calendar;
15+
import java.util.Date;
16+
import java.util.HashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
import de.willuhn.datasource.rmi.DBIterator;
21+
import de.willuhn.jameica.hbci.HBCI;
22+
import de.willuhn.jameica.hbci.Settings;
23+
import de.willuhn.jameica.hbci.rmi.HBCIDBService;
24+
import de.willuhn.jameica.hbci.rmi.Konto;
25+
import de.willuhn.jameica.hbci.rmi.Umsatz;
26+
import de.willuhn.jameica.hbci.server.UmsatzUtil;
27+
import de.willuhn.jameica.hbci.server.Value;
28+
import de.willuhn.jameica.system.Application;
29+
import de.willuhn.jameica.util.DateUtil;
30+
import de.willuhn.util.I18N;
31+
32+
/**
33+
* Forecast-Provider für eine Saldo-Prognose anhand der Umsätze der letzten 3 Monate.
34+
*/
35+
public class ForecastProviderUmsatz implements ForecastProvider
36+
{
37+
private final static I18N i18n = Application.getPluginLoader().getPlugin(HBCI.class).getResources().getI18N();
38+
private final static de.willuhn.jameica.system.Settings settings = new de.willuhn.jameica.system.Settings(ForecastProvider.class);
39+
40+
/**
41+
* @see de.willuhn.jameica.hbci.forecast.ForecastProvider#getName()
42+
*/
43+
@Override
44+
public String getName()
45+
{
46+
return i18n.tr("Umsätze");
47+
}
48+
49+
/**
50+
* @see de.willuhn.jameica.hbci.forecast.ForecastProvider#getData(de.willuhn.jameica.hbci.rmi.Konto, java.util.Date)
51+
*/
52+
@Override
53+
public List<Value> getData(Konto k, Date to) throws Exception
54+
{
55+
if (!settings.getBoolean("forecast.umsatz",false))
56+
return null;
57+
58+
// Wir holen uns erstmal eine Liste der Umsätze aus den letzten 6 Monaten
59+
final Date end = DateUtil.endOfDay(new Date());
60+
final Calendar cal = Calendar.getInstance();
61+
cal.add(Calendar.MONTH,-6);
62+
final Date start = DateUtil.startOfDay(cal.getTime());
63+
64+
final Map<String,SumEntry> map = new HashMap<>();
65+
66+
final DBIterator<Umsatz> it = UmsatzUtil.find(k,null,start,end,null);
67+
HBCIDBService service = (HBCIDBService) Settings.getDBService();
68+
it.setOrder("ORDER BY " + service.getSQLTimestamp("datum") + ", id");
69+
70+
while (it.hasNext())
71+
{
72+
final Umsatz u = it.next();
73+
final String iban = u.getGegenkontoNummer();
74+
final double d = u.getBetrag();
75+
final Date date = u.getDatum();
76+
77+
// Zahlungen unter 10,- EUR ignorieren wir aus Performance-Gründen
78+
if (Double.isNaN(d) || date == null || Math.abs(d) <= 10d)
79+
continue;
80+
81+
final SumEntry entry = map.computeIfAbsent(iban,i -> new SumEntry());
82+
cal.setTime(date);
83+
entry.add(cal.get(Calendar.DATE),d);
84+
}
85+
86+
// OK, jetzt haben wir eine Map mit Zahlungen pro Gegenkonto.
87+
// Daraus können wir eine Prognose ableiten
88+
final List<Value> result = new ArrayList<Value>();
89+
90+
// Wir iterieren tagesweise von heute bis um Ende-Zeitraum und
91+
// schauen, ob wir Zahlungen an diesen Tagen haben
92+
int limit = 0;
93+
cal.setTime(DateUtil.startOfDay(new Date()));
94+
while (!cal.getTime().after(to))
95+
{
96+
// Maximal ~3 Jahre
97+
if (limit++ >= 1000)
98+
break;
99+
100+
int day = cal.get(Calendar.DATE);
101+
for (SumEntry e:map.values())
102+
{
103+
// Zahlungen, die in dem ganzen Zeitraum nur einmal vorgekommen sind,
104+
// ignorieren wir. Hier kann nicht mit einer Wiederholung gerechnet werden
105+
if (e.count < 2)
106+
continue;
107+
108+
if (e.getDay() == day)
109+
{
110+
// An dem Tag findet typischerweise eine Zahlung statt
111+
final Value v = new Value(cal.getTime(),e.getValue());
112+
result.add(v);
113+
}
114+
}
115+
116+
cal.add(Calendar.DATE,1);
117+
}
118+
119+
return result;
120+
}
121+
122+
private class SumEntry
123+
{
124+
private int count = 0;
125+
private int days = 0;
126+
private double sum = 0.0d;
127+
128+
/**
129+
* Liefert den mittleren Tag der Zahlungen.
130+
* @return der mittlere Tag der Zahlungen.
131+
*/
132+
private int getDay()
133+
{
134+
return this.days / this.count;
135+
}
136+
137+
/**
138+
* Liefert den Durchschnittsbetrag.
139+
* @return der Durchschnittsbetrag.
140+
*/
141+
private double getValue()
142+
{
143+
return this.sum / this.count;
144+
}
145+
146+
/**
147+
* Fügt den Wert an einem Tag hinzu.
148+
* @param day der Tag.
149+
* @param value der Wert.
150+
*/
151+
private void add(int day, double value)
152+
{
153+
this.count++;
154+
this.days += day;
155+
this.sum += value;
156+
}
157+
}
158+
}
159+
160+

src/de/willuhn/jameica/hbci/gui/chart/ChartDataSaldoForecast.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import de.willuhn.jameica.hbci.forecast.ForecastCreator;
1818
import de.willuhn.jameica.hbci.rmi.Konto;
1919
import de.willuhn.jameica.hbci.server.Value;
20-
import de.willuhn.jameica.util.DateUtil;
2120

2221
/**
2322
* Implementierung eines Datensatzes fuer die Darstellung der Saldo-Prognose.
@@ -47,7 +46,7 @@ public List getData() throws RemoteException
4746
if (this.data != null)
4847
return this.data;
4948

50-
this.data = ForecastCreator.create(this.konto,DateUtil.endOfDay(new Date()),this.end);
49+
this.data = ForecastCreator.create(this.konto,this.end);
5150
return this.data;
5251
}
5352

src/help/de_de/de.willuhn.jameica.hbci.gui.views.SaldoChart.txt

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66
<p>
77
Diese Auswertung stellt den Saldo im zeitlichen Verlauf dar.
88
</p>
9+
10+
<p>
11+
Klicken Sie auf <b>Limits konfigurieren...</b>, um f�r ein Konto ein
12+
oberes und/oder unteres Saldo-Limit zu definieren. Wenn der
13+
prognostizierte Saldo den Wert innerhalb der angegebenen Anzahl von
14+
Tagen erreicht, wird auf der Startseite ein Hinweis-Text angezeigt.
15+
</p>
916

1017
<p>
1118
<b>Tipp:</b> Durch Doppelklick auf einen Eintrag in der Legende kann

0 commit comments

Comments
 (0)