mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-08-25 06:55:17 +02:00
Remember the last-used GnuCash account per file
AppConfig now keeps a gnucash_last_accounts map (file path -> account guid). When the import dialog opens a file it already knows, it auto-selects whichever account was picked last time for that specific file instead of always defaulting to the first one alphabetically; picking a different account updates and persists the mapping right away. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
745e634a8b
commit
42cde2a0c8
+10
-1
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -18,6 +18,7 @@ if TYPE_CHECKING:
|
||||
class AppConfig:
|
||||
store_path: str = ""
|
||||
gnucash_path: str = ""
|
||||
gnucash_last_accounts: dict[str, str] = field(default_factory=dict)
|
||||
theme_mode: str = "dark"
|
||||
run_housekeeper_on_startup: bool = True
|
||||
splash_minimum_seconds: float = 5.0
|
||||
@@ -43,6 +44,7 @@ class AppConfig:
|
||||
"schema_version": 1,
|
||||
"store_path": self.store_path,
|
||||
"gnucash_path": self.gnucash_path,
|
||||
"gnucash_last_accounts": self.gnucash_last_accounts,
|
||||
"theme_mode": self.theme_mode,
|
||||
"run_housekeeper_on_startup": self.run_housekeeper_on_startup,
|
||||
"splash_minimum_seconds": _non_negative_float(self.splash_minimum_seconds, 5.0),
|
||||
@@ -97,9 +99,16 @@ def load_config() -> AppConfig:
|
||||
monitor_bounds = None
|
||||
if isinstance(monitor_raw, list) and len(monitor_raw) == 4:
|
||||
monitor_bounds = tuple(int(value) for value in monitor_raw)
|
||||
last_accounts_raw = data.get("gnucash_last_accounts")
|
||||
gnucash_last_accounts = (
|
||||
{str(key): str(value) for key, value in last_accounts_raw.items()}
|
||||
if isinstance(last_accounts_raw, dict)
|
||||
else {}
|
||||
)
|
||||
return AppConfig(
|
||||
store_path=store_override or str(data.get("store_path", "")),
|
||||
gnucash_path=str(data.get("gnucash_path", "")),
|
||||
gnucash_last_accounts=gnucash_last_accounts,
|
||||
theme_mode=str(data.get("theme_mode", "dark")),
|
||||
run_housekeeper_on_startup=bool(data.get("run_housekeeper_on_startup", True)),
|
||||
splash_minimum_seconds=_non_negative_float(data.get("splash_minimum_seconds", 5.0), 5.0),
|
||||
|
||||
@@ -210,7 +210,7 @@ class GnuCashImportDialog(tk.Toplevel):
|
||||
}
|
||||
self.account_combo.configure(values=list(self.account_by_label))
|
||||
if self.account_by_label and self.account_var.get() not in self.account_by_label:
|
||||
self.account_var.set(next(iter(self.account_by_label)))
|
||||
self.account_var.set(self._preferred_account_label() or next(iter(self.account_by_label)))
|
||||
self.selected_guids.clear()
|
||||
if self.account_var.get():
|
||||
self._account_selected()
|
||||
@@ -221,6 +221,27 @@ class GnuCashImportDialog(tk.Toplevel):
|
||||
self.config.gnucash_path = path_text
|
||||
self.config.save()
|
||||
|
||||
def _current_file_key(self) -> str | None:
|
||||
path_text = self.file_var.get().strip()
|
||||
if not path_text:
|
||||
return None
|
||||
path = Path(path_text).expanduser()
|
||||
if not path.is_file():
|
||||
return None
|
||||
return str(path.resolve())
|
||||
|
||||
def _preferred_account_label(self) -> str | None:
|
||||
file_key = self._current_file_key()
|
||||
if file_key is None:
|
||||
return None
|
||||
last_guid = self.config.gnucash_last_accounts.get(file_key)
|
||||
if not last_guid:
|
||||
return None
|
||||
return next(
|
||||
(label for label, account in self.account_by_label.items() if account.guid == last_guid),
|
||||
None,
|
||||
)
|
||||
|
||||
def _account_selected(self) -> None:
|
||||
account = self.account_by_label.get(self.account_var.get())
|
||||
if account is None:
|
||||
@@ -236,6 +257,10 @@ class GnuCashImportDialog(tk.Toplevel):
|
||||
self.transactions = [item for item in all_transactions if item.amount > 0]
|
||||
self.selected_guids.clear()
|
||||
self._render_transactions()
|
||||
file_key = self._current_file_key()
|
||||
if file_key is not None and self.config.gnucash_last_accounts.get(file_key) != account.guid:
|
||||
self.config.gnucash_last_accounts[file_key] = account.guid
|
||||
self.config.save()
|
||||
|
||||
def _filtered_transactions(self) -> list[GnuCashTransaction]:
|
||||
needle = self.description_filter_var.get().strip().casefold()
|
||||
|
||||
@@ -48,3 +48,27 @@ def test_store_path_can_be_overridden_from_ccma_environment(tmp_path, monkeypatc
|
||||
monkeypatch.setenv("CCMA_STORE", str(tmp_path / "store"))
|
||||
|
||||
assert load_config().store_path == str(tmp_path / "store")
|
||||
|
||||
|
||||
def test_gnucash_last_account_per_file_round_trips(tmp_path, monkeypatch) -> None:
|
||||
monkeypatch.setenv("CCMA_CONFIG_DIR", str(tmp_path / "config"))
|
||||
first_file = str(tmp_path / "verein.gnucash")
|
||||
second_file = str(tmp_path / "spenden.gnucash")
|
||||
config = AppConfig(
|
||||
gnucash_last_accounts={first_file: "bank-guid", second_file: "cash-guid"}
|
||||
)
|
||||
config.save()
|
||||
|
||||
loaded = load_config()
|
||||
assert loaded.gnucash_last_accounts == {first_file: "bank-guid", second_file: "cash-guid"}
|
||||
|
||||
|
||||
def test_gnucash_last_accounts_defaults_to_empty_dict_for_malformed_value(tmp_path, monkeypatch) -> None:
|
||||
monkeypatch.setenv("CCMA_CONFIG_DIR", str(tmp_path / "config"))
|
||||
config_path = tmp_path / "config" / "config.json"
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
config_path.write_text(
|
||||
json.dumps({"schema_version": 1, "gnucash_last_accounts": "not-a-dict"}), encoding="utf-8"
|
||||
)
|
||||
|
||||
assert load_config().gnucash_last_accounts == {}
|
||||
|
||||
Reference in New Issue
Block a user