fix: address account valuation review findings
This commit is contained in:
@@ -13,6 +13,8 @@ from .shared import (
|
||||
Path,
|
||||
csv,
|
||||
db,
|
||||
read_db,
|
||||
read_operation,
|
||||
fail,
|
||||
json,
|
||||
make_dedupe_key,
|
||||
@@ -38,6 +40,24 @@ def _record_import_valuation_candidate(conn: Any, account_id: str, balance: Any,
|
||||
from .account_valuation_service import record_account_valuation_candidate
|
||||
record_account_valuation_candidate(conn, account_id, basis_date, balance, "KRW", "import", source_hash, f"import-balance:{account_id}:{basis_date}:{source_hash}")
|
||||
|
||||
def _update_current_balance_if_newer(conn: Any, account_id: str, balance: Any, basis_date: str, synced_at: str) -> None:
|
||||
if balance is None or not basis_date:
|
||||
return
|
||||
current = conn.execute("SELECT last_synced_at FROM accounts WHERE id=?", (account_id,)).fetchone()
|
||||
latest_evidence = conn.execute(
|
||||
"""SELECT basis_date FROM account_valuations
|
||||
WHERE account_id=? AND verification_status IN ('verified', 'unverified')
|
||||
ORDER BY basis_date DESC, recorded_at DESC, id DESC LIMIT 1""",
|
||||
(account_id,),
|
||||
).fetchone()
|
||||
current_date = max(
|
||||
str(current["last_synced_at"] or "")[:10] if current else "",
|
||||
str(latest_evidence["basis_date"] or "")[:10] if latest_evidence else "",
|
||||
)
|
||||
if not current_date or basis_date[:10] >= current_date:
|
||||
conn.execute("UPDATE accounts SET last_balance=?, last_synced_at=?, updated_at=? WHERE id=?", (balance, synced_at, synced_at, account_id))
|
||||
|
||||
@read_operation
|
||||
def preview_ledger_csv_import(file_path: str, source: str = "generic", db_path: str | None = None) -> dict[str, Any]:
|
||||
path=Path(file_path).expanduser()
|
||||
if not path.exists():
|
||||
@@ -49,6 +69,7 @@ def preview_ledger_csv_import(file_path: str, source: str = "generic", db_path:
|
||||
return ok(source=source, filename=redacted_source_file_label(str(path), source_hash), source_hash=source_hash, row_count=len(rows), preview=preview, required_columns=["transaction_date/date", "amount", "type optional", "category optional", "merchant/description optional"])
|
||||
|
||||
|
||||
@read_operation
|
||||
def preview_kb_bank_pdf_import(file_path: str, password: str, preview_limit: int = 20, db_path: str | None = None) -> dict[str, Any]:
|
||||
try:
|
||||
parsed = parse_kb_bank_pdf(file_path, password)
|
||||
@@ -62,7 +83,7 @@ def preview_kb_bank_pdf_import(file_path: str, password: str, preview_limit: int
|
||||
validation = parsed["validation"]
|
||||
source_hash = parsed["source_hash"]
|
||||
duplicate_count = 0
|
||||
with db(db_path) as conn:
|
||||
with read_db(db_path) as conn:
|
||||
for tx in transactions:
|
||||
dedupe_key = make_dedupe_key(tx.transaction_date, tx.amount, tx.counterparty, "", tx.external_id(source_hash))
|
||||
found = conn.execute("SELECT 1 FROM transactions WHERE dedupe_key=?", (dedupe_key,)).fetchone()
|
||||
@@ -218,7 +239,7 @@ def import_kb_bank_pdf(file_path: str, password: str, account_id: str = "", skip
|
||||
raise
|
||||
conn.execute("UPDATE import_batches SET row_count=? WHERE id=?", (inserted, batch_id))
|
||||
if transactions:
|
||||
conn.execute("UPDATE accounts SET last_balance=?, last_synced_at=?, updated_at=? WHERE id=?", (transactions[-1].balance_after, ts, ts, linked_account_id))
|
||||
_update_current_balance_if_newer(conn, linked_account_id, transactions[-1].balance_after, transactions[-1].transaction_date, ts)
|
||||
if transactions and transactions[-1].balance_after is not None:
|
||||
_record_import_valuation_candidate(conn, linked_account_id, transactions[-1].balance_after, transactions[-1].transaction_date, source_hash)
|
||||
except ValueError as e:
|
||||
@@ -362,6 +383,7 @@ def _classify_toss_bank_transaction(tx: Any, owner_name: str = "") -> tuple[str,
|
||||
return "수입", "캐시백", counterparty, False
|
||||
return "이체", "확인필요", counterparty, False
|
||||
|
||||
@read_operation
|
||||
def preview_seoulpay_xlsx_import(file_path: str, password: str = "", preview_limit: int = 20, db_path: str | None = None) -> dict[str, Any]:
|
||||
try:
|
||||
parsed = parse_seoulpay_xlsx(file_path, password=password)
|
||||
@@ -376,7 +398,7 @@ def preview_seoulpay_xlsx_import(file_path: str, password: str = "", preview_lim
|
||||
source_hash = parsed["source_hash"]
|
||||
duplicate_count = 0
|
||||
by_category: dict[str, dict[str, int]] = {}
|
||||
with db(db_path) as conn:
|
||||
with read_db(db_path) as conn:
|
||||
linked_account_id = ""
|
||||
metadata = parsed["metadata"]
|
||||
holder_name = metadata.get("holder_name") or ""
|
||||
@@ -529,6 +551,7 @@ def import_seoulpay_xlsx(file_path: str, password: str = "", account_id: str = "
|
||||
)
|
||||
|
||||
|
||||
@read_operation
|
||||
def preview_toss_bank_pdf_import(file_path: str, preview_limit: int = 20, db_path: str | None = None) -> dict[str, Any]:
|
||||
try:
|
||||
parsed = parse_toss_bank_pdf(file_path)
|
||||
@@ -542,7 +565,7 @@ def preview_toss_bank_pdf_import(file_path: str, preview_limit: int = 20, db_pat
|
||||
transactions = parsed["transactions"]
|
||||
source_hash = parsed["source_hash"]
|
||||
duplicate_count = 0
|
||||
with db(db_path) as conn:
|
||||
with read_db(db_path) as conn:
|
||||
metadata = parsed["metadata"]
|
||||
account_number_masked = metadata.get("account_number_masked") or ""
|
||||
linked_account_id = ""
|
||||
@@ -683,7 +706,7 @@ def import_toss_bank_pdf(file_path: str, account_id: str = "", skip_duplicates:
|
||||
raise
|
||||
conn.execute("UPDATE import_batches SET row_count=? WHERE id=?", (inserted, batch_id))
|
||||
if transactions:
|
||||
conn.execute("UPDATE accounts SET last_balance=?, last_synced_at=?, updated_at=? WHERE id=?", (transactions[-1].balance_after, ts, ts, linked_account_id))
|
||||
_update_current_balance_if_newer(conn, linked_account_id, transactions[-1].balance_after, transactions[-1].transaction_date, ts)
|
||||
if transactions and transactions[-1].balance_after is not None:
|
||||
_record_import_valuation_candidate(conn, linked_account_id, transactions[-1].balance_after, transactions[-1].transaction_date, source_hash)
|
||||
except ValueError as e:
|
||||
@@ -763,6 +786,7 @@ def _classify_toss_transaction(tx: Any, owner_name: str = "") -> tuple[str, str,
|
||||
return "이체", "투자이동", counterparty, False
|
||||
|
||||
|
||||
@read_operation
|
||||
def preview_toss_securities_pdf_import(file_path: str, preview_limit: int = 20, db_path: str | None = None) -> dict[str, Any]:
|
||||
try:
|
||||
parsed = parse_toss_securities_pdf(file_path)
|
||||
@@ -775,7 +799,7 @@ def preview_toss_securities_pdf_import(file_path: str, preview_limit: int = 20,
|
||||
transactions = parsed["transactions"]
|
||||
source_hash = parsed["source_hash"]
|
||||
duplicate_count = 0
|
||||
with db(db_path) as conn:
|
||||
with read_db(db_path) as conn:
|
||||
metadata = parsed["metadata"]
|
||||
account_number_masked = metadata.get("account_number_masked") or ""
|
||||
linked_account_id = ""
|
||||
@@ -907,7 +931,7 @@ def import_toss_securities_pdf(file_path: str, account_id: str = "", skip_duplic
|
||||
raise
|
||||
conn.execute("UPDATE import_batches SET row_count=? WHERE id=?", (inserted, batch_id))
|
||||
if transactions:
|
||||
conn.execute("UPDATE accounts SET last_balance=?, last_synced_at=?, updated_at=? WHERE id=?", (transactions[-1].balance_after, ts, ts, linked_account_id))
|
||||
_update_current_balance_if_newer(conn, linked_account_id, transactions[-1].balance_after, transactions[-1].transaction_date, ts)
|
||||
if transactions and transactions[-1].balance_after is not None:
|
||||
_record_import_valuation_candidate(conn, linked_account_id, transactions[-1].balance_after, transactions[-1].transaction_date, source_hash)
|
||||
except ValueError as e:
|
||||
@@ -927,6 +951,7 @@ def import_toss_securities_pdf(file_path: str, account_id: str = "", skip_duplic
|
||||
)
|
||||
|
||||
|
||||
@read_operation
|
||||
def list_ledger_import_batches(
|
||||
source: str = "",
|
||||
include_rolled_back: bool = True,
|
||||
@@ -972,6 +997,7 @@ def _batch_provenance(row: dict[str, Any]) -> dict[str, Any]:
|
||||
return provenance
|
||||
|
||||
|
||||
@read_operation
|
||||
def list_ledger_import_batches_with_provenance(
|
||||
source: str = "",
|
||||
include_rolled_back: bool = True,
|
||||
@@ -992,7 +1018,7 @@ def list_ledger_import_batches_with_provenance(
|
||||
clauses.append("status='active'")
|
||||
where = " WHERE " + " AND ".join(clauses) if clauses else ""
|
||||
params.append(max(1, min(int(limit), 500)))
|
||||
with db(db_path) as conn:
|
||||
with read_db(db_path) as conn:
|
||||
rows=conn.execute(f"SELECT * FROM import_batches{where} ORDER BY imported_at DESC LIMIT ?", params).fetchall()
|
||||
try:
|
||||
items = []
|
||||
|
||||
Reference in New Issue
Block a user