Modernes Design (Standard, Win95 als Legacy), Zeitraum abrechnen, Abrechnung erledigt, Linux-Build

- Design: „modern“ (hell, flach, wie Windows 11, normaler Windows-Rahmen) ist Standard;
  „win95“ bleibt unter Datei > Einstellungen wählbar (Einstellung „design“).
- Export: Zeitraum von–bis (nach Aktivierungsdatum oder Abrechnungszeitraum des Anbieters),
  exportierte Positionen werden als abgerechnet gekennzeichnet (Betrag/Händler eingefroren) und
  per Fingerabdruck auch in späteren Dateien/Abrechnungen nicht noch einmal abgerechnet.
- Datei > Abrechnung erledigt / wieder öffnen: erledigte Abrechnungen sind gegen Änderungen gesperrt.
- DB-Schema v4 (Migration inkl. Fingerabdrücke für alte Positionen).
- Linux-Build (python:3.12-bookworm) als zweiter Pipeline-Job mit Tests und Selbsttest;
  Release-Upload für beide Jobs über build/release_hochladen.sh.
- Behoben: normaler Windows-Rahmen stürzte beim Start ab (Hauptrahmen.nativ fehlte).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kerim AtilganandClaude Opus 5.5 committed 2026-11-02 20:47:00 +01:00
1 parent 97c73b82c7
commit 851fd6600a
17 files changed
+829 -80

No files matched your search

+69 -5
View File
@@ -203,9 +203,7 @@ def home(tmp_path, monkeypatch):
return tmp_path
@pytest.fixture
def lauf_mit_daten(home):
"""App mit einem Händler und einer Abrechnung (erfundene Daten)."""
def _profil_mit_daten(home):
from tests.test_kern import FREENET_KOPF, freenet_zeile
csv = home / "freenet.csv"
csv.write_bytes(("\r\n".join([
@@ -219,6 +217,21 @@ def lauf_mit_daten(home):
from provtool.importer import lies_datei
db.importieren(db.abrechnung_neu("Oktober 2026"), lies_datei(csv))
db.close()
@pytest.fixture
def lauf_mit_daten(home):
"""App mit einem Händler und einer Abrechnung (erfundene Daten), klassisches Win95-Design."""
_profil_mit_daten(home)
lauf = Lauf(home, {"assistent_erledigt": True, "tipps_beim_start": False, "design": "win95"})
yield lauf
lauf.ende()
@pytest.fixture
def lauf_modern(home):
"""Wie lauf_mit_daten, aber im modernen Design (Standard)."""
_profil_mit_daten(home)
lauf = Lauf(home, {"assistent_erledigt": True, "tipps_beim_start": False})
yield lauf
lauf.ende()
@@ -324,8 +337,10 @@ def _dialog_oeffner():
@pytest.mark.parametrize("name", ["haendler", "abrechnungen", "export", "einstellungen", "neu", "info", "tipp",
"dateien", "hilfe", "assistent", "prozent", "neu_berechnen", "provisionsarten",
"staffel"])
def test_schliessen_waehrend_dialog_offen(lauf_mit_daten, name):
lauf = lauf_mit_daten
@pytest.mark.parametrize("design", ["win95", "modern"])
def test_schliessen_waehrend_dialog_offen(home, name, design):
_profil_mit_daten(home)
lauf = Lauf(home, {"assistent_erledigt": True, "tipps_beim_start": False, "design": design})
oeffnen = _dialog_oeffner()[name]
lauf.ablauf([(IMMER, lambda: oeffnen(lauf.app), f"{name} öffnen"),
(lambda: bool(lauf.dialoge()), lauf.schliessen_ueber_fenster, "Programm schließen")])
@@ -1052,3 +1067,52 @@ def test_rand_druecken_startet_natives_ziehen(lauf_mit_daten, monkeypatch):
r._resize_start(ev)
assert gezogen == ["w", "se"]
lauf.pruefen()
def test_modern_ist_standard(lauf_modern):
from provtool.gui import win95 as w
lauf = lauf_modern
assert w.DESIGN == "modern" and not lauf.app.rahmen.klassisch and lauf.app.rahmen.titelleiste is None
lauf.ablauf([(IMMER, lambda: lauf.app.menueleiste._klick(lauf.app.menueleiste.knoepfe["Datei"]), "Menü"),
(lambda: lauf.app.menueleiste.offener_knopf is not None,
lambda: lauf.app.menueleiste.schliessen(), "zu")])
assert not lauf.uebrig, lauf.diagnose()
lauf.pruefen()
def test_export_zeitraum_kennzeichnen_und_erledigt(lauf_modern, tmp_path, monkeypatch):
"""Zeitraum abrechnen, exportierte Positionen nicht erneut exportieren, Abrechnung erledigt sperrt."""
from provtool.gui import win95 as w
from provtool.gui.dialogs import ExportDialog
lauf = lauf_modern
app = lauf.app
app.settings["export_ordner"] = str(tmp_path / "x")
meldungen = []
monkeypatch.setattr(w, "info", lambda m, t, text: meldungen.append(text))
monkeypatch.setattr(w, "frage", lambda *a, **k: True)
def ok(von="", bis=""):
d = lauf.dialog(ExportDialog)
d.v_von.set(von)
d.v_bis.set(bis)
d.v_auf.set(False)
d._ok()
lauf.ablauf([
(IMMER, app.exportieren, "Export Oktober 6."),
(lambda: lauf.dialog(ExportDialog) is not None, lambda: ok("01.10.2026", "05.10.2026"), "nur bis 5.10."),
(lambda: lauf.dialog(ExportDialog) is None, app.exportieren, "Export Rest"),
(lambda: lauf.dialog(ExportDialog) is not None, ok, "alles Offene"),
(lambda: lauf.dialog(ExportDialog) is None, app.exportieren, "nochmal"),
])
assert not lauf.uebrig, lauf.diagnose()
assert sum(1 for p in app.positionen if p["abgerechnet"]) == 2
assert "1 Position(en) als abgerechnet" in meldungen[0] and "1 Position(en) als abgerechnet" in meldungen[1]
assert "bereits abgerechnet" in meldungen[2], meldungen
# erledigt: Änderungen gesperrt
app.erledigt_umschalten()
assert app.db.erledigt(app.aid)
app.ptree.selection_set(app.ptree.get_children()[0])
app.prozent()
assert "erledigt" in meldungen[-1]
lauf.pruefen()