76 lines
3.6 KiB
Python
76 lines
3.6 KiB
Python
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)
|