from __future__ import annotations # ruff: noqa: F405 import sqlite3 import pandas as pd import streamlit as st from jarca_ledger_mcp.adapters.streamlit import transfers_gateway from dashboard.common import * # noqa: F403, F405 def page_cross_transfer_review(db_path: str) -> None: c1, c2 = st.columns(2) with c1: if st.button("미리보기(드라이런)"): st.session_state["cross_transfer_preview"] = transfers_gateway.preview_cross_account_transfers(db_path=db_path) with c2: if st.button("자동 매칭 실행"): res = transfers_gateway.run_cross_account_transfer_match(db_path=db_path) clear_cache() st.session_state["cross_transfer_last_run"] = res st.success(f"매칭 {res.get('matched_count', 0)}건 적용, 확인필요 {res.get('review_count', 0)}건") st.rerun() if "cross_transfer_preview" in st.session_state: prev = st.session_state["cross_transfer_preview"] render_section_label("🧪", "미리보기 결과") st.info(f"예상 매칭 {prev.get('matched_count', 0)}건 / 확인필요 {prev.get('review_count', 0)}건") if prev.get("matched_pairs"): st.dataframe(pd.DataFrame(prev.get("matched_pairs")), width="stretch", height=250) if prev.get("review_items"): st.dataframe(pd.DataFrame(prev.get("review_items")), width="stretch", height=250) st.divider() render_section_label("📌", "확인필요 큐") list_queue_fn = getattr(transfers_gateway, "list_cross_transfer_review_queue", None) if callable(list_queue_fn): queue = list_queue_fn(db_path=db_path) rows = queue.get("transactions", []) else: # 호환성 보호: 구버전 서비스에서 메서드가 없을 때 직접 조회 st.info("확인필요 큐 조회 함수가 현재 서비스 모듈에 없어 직접 DB 조회로 표시합니다.") with sqlite3.connect(db_path) as _conn: _conn.row_factory = lambda cursor, row: {description[0]: row[idx] for idx, description in enumerate(cursor.description)} _rows = _conn.execute( """ SELECT * FROM transactions WHERE status='active' AND source IN ('kb_bank_pdf','toss_bank_pdf') AND memo LIKE '%cross_transfer_review:%' ORDER BY transaction_date DESC, created_at DESC LIMIT 300 """ ).fetchall() rows = [dict(r) for r in _rows] if not rows: st.success("현재 확인필요 큐가 비어 있습니다.") return df = pd.DataFrame(rows) if "cashflow_kind" in df.columns: df["cashflow_kind"] = df["cashflow_kind"].fillna("") st.dataframe(df[["transaction_date", "source", "type", "amount", "counterparty", "category", "subcategory", "memo", "id"]].rename(columns={"amount": "금액"}), width="stretch", height=320) options = { f"{r.get('transaction_date')} · {r.get('source')} · {r.get('type')} · {int(r.get('amount', 0)):,}원 · {r.get('counterparty', '')}": r for r in rows } selected = st.selectbox("수동 수정할 거래", list(options.keys())) selected_row = options[selected] st.caption(f"현재 review_status: {selected_row.get('review_status', 'pending')}") with st.expander("Review decision 저장/보류/재검토/해제", expanded=False): render_review_decision_actions(transfers_gateway, "cross_transfer", selected_row["id"], f"transfer_review_decision_{selected_row['id']}", db_path, target_payload=selected_row) update_transaction_form(selected_row, "transfer_review", db_path)