feat: extend comprehensive monthly settlement snapshots (#18)
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import streamlit as st
|
||||
from jarca_ledger_mcp.adapters.streamlit import settlement_gateway as gateway
|
||||
|
||||
@@ -83,6 +85,14 @@ def render_settlement_drafts(db_path: str | None = None, month: str = "") -> Non
|
||||
if draft.get("status") == "completed":
|
||||
st.success(f"완료 — run {draft.get('final_run_id', '-')}; 변경 불가, 정정은 새 초안으로 생성합니다.")
|
||||
if draft.get("status") in {"completed", "cancelled"}:
|
||||
final = detail.get("final_response") if isinstance(detail.get("final_response"), dict) else {}
|
||||
if final:
|
||||
st.markdown("### 기록된 종합 월정산 결과")
|
||||
st.caption(f"정책 버전: {final.get('aggregation_version', 'legacy')}")
|
||||
for key, label in (("income_total", "수입"), ("expense_total", "지출"), ("net_cashflow", "순현금흐름"), ("total_assets", "자산"), ("total_liabilities", "부채"), ("net_worth", "순자산")):
|
||||
st.write(label, final.get(key) if final.get(key) is not None else "미보존")
|
||||
rows = final.get("cashflow_items", [])
|
||||
if isinstance(rows, list): st.dataframe([{k: row.get(k) for k in ("cashflow_kind", "category", "subcategory", "amount", "transaction_count", "currency")} for row in rows if isinstance(row, dict)])
|
||||
st.markdown("### 불변 이력")
|
||||
st.write("final_run_id", draft.get("final_run_id"))
|
||||
st.write("correction_of_run_id", draft.get("correction_of_run_id"))
|
||||
@@ -102,6 +112,23 @@ def render_settlement_drafts(db_path: str | None = None, month: str = "") -> Non
|
||||
except ValueError:
|
||||
st.caption("날짜 차이를 계산할 수 없습니다.")
|
||||
if item.get("status") == "missing": st.warning("누락 — 값은 0원이 아닙니다.")
|
||||
st.markdown("### 종합 월정산 정책")
|
||||
policy_now = draft.get("cashflow_policy") if isinstance(draft.get("cashflow_policy"), dict) else {"savings_categories": [], "category_decisions": []}
|
||||
with st.form(f"cashflow_policy_{selected_id}"):
|
||||
policy_text = st.text_area("정책 JSON (savings_categories 및 category_decisions)", value=json.dumps(policy_now, ensure_ascii=False, indent=2), height=220)
|
||||
policy_submit = st.form_submit_button("정책 저장")
|
||||
if policy_submit:
|
||||
try:
|
||||
policy = json.loads(policy_text)
|
||||
if not isinstance(policy, dict) or not isinstance(policy.get("savings_categories", []), list) or not isinstance(policy.get("category_decisions", []), list): raise ValueError
|
||||
for decision in policy.get("category_decisions", []):
|
||||
if not isinstance(decision, dict) or decision.get("cashflow_kind") not in {"income", "expense", "excluded"}: raise ValueError
|
||||
result = gateway.set_settlement_cashflow_policy(selected_id, version, actor, policy, db_path=db_path)
|
||||
if result.get("success"): _invalidate_and_rerun(selected_id, result)
|
||||
_safe_result(result)
|
||||
except (ValueError, TypeError):
|
||||
st.error("정책은 유효한 JSON이어야 하며 각 분류는 income, expense 또는 excluded로 지정하세요.")
|
||||
|
||||
with st.form(f"settlement_edit_{selected_id}"):
|
||||
memo_edit = st.text_input("초안 메모 저장", value=draft.get("memo", ""))
|
||||
source_type = st.selectbox("대상 유형", ["account", "manual_asset"])
|
||||
@@ -179,7 +206,11 @@ def render_settlement_drafts(db_path: str | None = None, month: str = "") -> Non
|
||||
review_result = review_result or st.session_state.get(f"review_result_{selected_id}")
|
||||
if isinstance(review_result, dict) and review_result.get("success"):
|
||||
review = review_result.get("review", review_result)
|
||||
st.write("검토 합계 (잠정)", review.get("total_assets"), review.get("total_liabilities"), review.get("net_worth"))
|
||||
st.write("검토 합계 (잠정)", *[review.get(k) for k in ("income_total", "expense_total", "net_cashflow", "total_assets", "total_liabilities", "net_worth")])
|
||||
items_cf = review.get("cashflow_items", [])
|
||||
if isinstance(items_cf, list): st.dataframe([{k: row.get(k) for k in ("cashflow_kind", "category", "subcategory", "amount", "transaction_count", "currency")} for row in items_cf if isinstance(row, dict)])
|
||||
blockers = review.get("cashflow_blockers", [])
|
||||
for blocker in blockers if isinstance(blockers, list) else []: st.warning(str(blocker.get("code", "cashflow_blocked")) if isinstance(blocker, dict) else "현금흐름 블로커")
|
||||
st.write("누락", review.get("missing_items", []))
|
||||
if review.get("contains_substitutions"):
|
||||
st.warning("대체 평가자료를 포함한 월정산")
|
||||
@@ -192,7 +223,8 @@ def render_settlement_drafts(db_path: str | None = None, month: str = "") -> Non
|
||||
allow_missing = st.checkbox("누락 승인", value=False)
|
||||
allow_carried = st.checkbox("이월 승인", value=False)
|
||||
allow_substitute = st.checkbox("대체자료 승인", value=False)
|
||||
approve = st.form_submit_button("검토 결과 승인")
|
||||
approve = st.form_submit_button("검토 결과 승인", disabled=bool(review.get("cashflow_blockers")))
|
||||
if review.get("cashflow_blockers"): st.caption("현금흐름 블로커를 해소해야 승인할 수 있습니다.")
|
||||
if approve:
|
||||
if st.session_state.get(state_key) != (selected_id, review.get("version", version), fingerprint):
|
||||
st.error("선택한 초안/버전/검토 fingerprint가 변경되었습니다. 다시 검토하세요.")
|
||||
|
||||
Reference in New Issue
Block a user