from __future__ import annotations # ruff: noqa: F405 import pandas as pd import streamlit as st from jarca_ledger_mcp.adapters.streamlit import categorization_gateway from dashboard.common import * # noqa: F403, F405 def page_categories(db_path: str) -> None: st.caption("카테고리 삭제는 기본적으로 비활성화 처리합니다. 기존 거래의 과거 category 값은 보존됩니다.") c1, c2 = st.columns(2) if c1.button("기본 카테고리 seed/update"): res = categorization_gateway.seed_default_ledger_categories(db_path=db_path) clear_cache() st.success(f"{res.get('created_or_updated', 0)}개 카테고리를 생성/갱신했습니다.") st.rerun() show_inactive = c2.checkbox("비활성 카테고리도 보기", value=False) render_section_label("➕", "카테고리 추가") with st.form("create_ledger_category"): cols = st.columns([2, 2, 2, 1, 3]) category = cols[0].text_input("대분류", placeholder="예: 반려동물") subcategory = cols[1].text_input("소분류", placeholder="예: 사료") cashflow_kind_label = cols[2].selectbox("현금흐름 성격", [CASHFLOW_KIND_LABELS[k] for k in CASHFLOW_KIND_OPTIONS], index=1) sort_order = cols[3].number_input("정렬", value=100, step=10) memo = cols[4].text_input("메모", value="dashboard: user category") submitted = st.form_submit_button("추가/재활성화", type="primary") if submitted: cashflow_kind = next(k for k, v in CASHFLOW_KIND_LABELS.items() if v == cashflow_kind_label) res = categorization_gateway.create_ledger_category(category, subcategory, int(sort_order), memo, cashflow_kind, db_path=db_path) clear_cache() if res.get("success"): st.success("카테고리를 저장했습니다.") st.rerun() else: st.error(res.get("error", res)) result = categorization_gateway.list_ledger_categories(active_only=not show_inactive, include_usage=True, db_path=db_path) rows = result.get("categories", []) render_section_label("🗂️", "카테고리 목록") if rows: df = pd.DataFrame(rows) if "cashflow_kind" in df: df["cashflow_kind_label"] = df["cashflow_kind"].map(CASHFLOW_KIND_LABELS).fillna(df["cashflow_kind"]) if "total_amount" in df: df["total_amount_display"] = df["total_amount"].map(format_krw) st.dataframe(df, width="stretch", height=360) else: st.info("등록된 카테고리가 없습니다. 기본 카테고리를 seed하거나 새 카테고리를 추가하세요.") return render_section_label("🛡️", "카테고리 삭제/비활성화") options = { f"{r['category']} / {r['subcategory'] or '-'} · 사용 {r.get('transaction_count', 0)}건 · {'활성' if r.get('active') else '비활성'}": r for r in rows } selected = st.selectbox("대상", list(options.keys())) target = options[selected] hard_delete = st.checkbox("DB에서 완전 삭제", value=False, help="보통은 끄고 비활성화만 하세요. 거래 기록은 별도 보존됩니다.") force = st.checkbox("사용 중이어도 강제", value=False, help="거래/예산/규칙에서 사용 중인 카테고리도 삭제/비활성화합니다. 거래 category 값은 변경하지 않습니다.") if st.button("삭제/비활성화 실행", type="secondary"): res = categorization_gateway.delete_ledger_category(target["category"], target.get("subcategory", ""), hard_delete=hard_delete, force=force, db_path=db_path) clear_cache() if res.get("success"): st.warning(f"처리했습니다. 사용 거래 {res.get('transaction_count', 0)}건") st.rerun() else: st.error(res.get("error", res))