feat: persist review workbench decisions (#1)

Merge dcy-012 / REQ-020 / BAT-016 implementation after green CI.
This commit is contained in:
2026-07-08 10:22:53 +09:00
committed by GitHub
parent 2fc972a7bf
commit 698dd9e62e
28 changed files with 989 additions and 81 deletions
+45
View File
@@ -166,6 +166,51 @@ def get_balance_reconciliation_report(account_id: str = "", baseline_balance: in
"""Preview balance reconciliation for manual_only/partial_import accounts without mutating the DB."""
return contracts.get_balance_reconciliation_report(account_id, baseline_balance, baseline_at, source_note, memo, tolerance)
@mcp.tool()
def list_review_decisions(target_type: str = "", target_id: str = "", status: str = "", limit: int = 100) -> dict:
"""List persisted review decisions for workbench targets."""
return contracts.list_review_decisions(target_type=target_type, target_id=target_id, status=status, limit=limit)
@mcp.tool()
def upsert_review_decision(target_type: str, target_id: str, status: str = "decided", decision_type: str = "unknown", reason_code: str = "", memo: str = "", operator: str = "operator", review_after: str = "", target_payload: dict | None = None, decision_id: str = "") -> dict:
"""Create or update a non-destructive persisted review decision."""
return contracts.upsert_review_decision(target_type, target_id, status, decision_type, reason_code, memo, operator, review_after, target_payload, decision_id)
@mcp.tool()
def hold_review_decision(target_type: str, target_id: str, reason_code: str = "held", memo: str = "", operator: str = "operator", review_after: str = "") -> dict:
"""Mark a review target as held without deleting evidence."""
return contracts.hold_review_decision(target_type, target_id, reason_code, memo, operator, review_after)
@mcp.tool()
def mark_review_recheck(target_type: str, target_id: str, reason_code: str = "needs_recheck", memo: str = "", operator: str = "operator", review_after: str = "") -> dict:
"""Mark a review target as needing recheck."""
return contracts.mark_review_recheck(target_type, target_id, reason_code, memo, operator, review_after)
@mcp.tool()
def release_review_decision(target_type: str, target_id: str, memo: str = "", operator: str = "operator") -> dict:
"""Release a held/recheck review target back to pending."""
return contracts.release_review_decision(target_type, target_id, memo, operator)
@mcp.tool()
def list_reconciliation_sessions(account_id: str = "", status: str = "", basis_date: str = "", limit: int = 100) -> dict:
"""List persisted reconciliation sessions."""
return contracts.list_reconciliation_sessions(account_id=account_id, status=status, basis_date=basis_date, limit=limit)
@mcp.tool()
def upsert_reconciliation_session(account_id: str, basis_date: str, expected_balance: int | None = None, actual_balance: int | None = None, difference: int | None = None, status: str = "open", source_note: str = "", memo: str = "", operator: str = "operator", session_id: str = "") -> dict:
"""Create or update an account/basis-date reconciliation session."""
return contracts.upsert_reconciliation_session(account_id, basis_date, expected_balance, actual_balance, difference, status, source_note, memo, operator, session_id)
@mcp.tool()
def close_reconciliation_session(session_id: str = "", account_id: str = "", basis_date: str = "", memo: str = "", operator: str = "operator") -> dict:
"""Close an existing reconciliation session without destructive reset/delete."""
return contracts.close_reconciliation_session(session_id=session_id, account_id=account_id, basis_date=basis_date, memo=memo, operator=operator)
@mcp.tool()
def get_review_operating_indicators() -> dict:
"""Return workbench indicators: pending, held/recheck, unreconciled, last close, uncategorized backlog."""
return contracts.get_review_operating_indicators()
@mcp.tool()
def create_ledger_transaction(transaction_date: str = "", type: str = "expense", amount: int = 0, category: str = "", subcategory: str = "", merchant: str = "", description: str = "", account_id: str = "", payment_method: str = "", person: str = "", project: str = "", tags: list[str] | str | None = None, is_fixed: bool = False, currency: str = "KRW", posted_date: str = "", source: str = "manual", external_id: str = "", memo: str = "", dedupe: bool = True) -> dict:
"""Create an income, expense, transfer, refund, or adjustment transaction. Amount is positive KRW minor unit; type determines direction."""
@@ -26,7 +26,16 @@ from ...service import (
get_ledger_db_status as get_ledger_db_status,
get_monthly_cashflow_report as get_monthly_cashflow_report,
get_net_worth_timeseries as get_net_worth_timeseries,
get_review_operating_indicators as get_review_operating_indicators,
get_uncategorized_merchant_summary as get_uncategorized_merchant_summary,
hold_review_decision as hold_review_decision,
list_reconciliation_sessions as list_reconciliation_sessions,
list_review_decisions as list_review_decisions,
mark_review_recheck as mark_review_recheck,
release_review_decision as release_review_decision,
upsert_reconciliation_session as upsert_reconciliation_session,
upsert_review_decision as upsert_review_decision,
close_reconciliation_session as close_reconciliation_session,
health_check as health_check,
import_kb_bank_pdf as import_kb_bank_pdf,
import_seoulpay_xlsx as import_seoulpay_xlsx,
@@ -86,7 +95,16 @@ __all__ = [
"get_ledger_db_status",
"get_monthly_cashflow_report",
"get_net_worth_timeseries",
"get_review_operating_indicators",
"get_uncategorized_merchant_summary",
"hold_review_decision",
"list_reconciliation_sessions",
"list_review_decisions",
"mark_review_recheck",
"release_review_decision",
"upsert_reconciliation_session",
"upsert_review_decision",
"close_reconciliation_session",
"health_check",
"import_kb_bank_pdf",
"import_seoulpay_xlsx",
@@ -10,7 +10,11 @@ from ...service import (
delete_ledger_category as delete_ledger_category,
get_uncategorized_merchant_summary as get_uncategorized_merchant_summary,
get_uncategorized_workbench as get_uncategorized_workbench,
hold_review_decision as hold_review_decision,
list_category_rules as list_category_rules,
mark_review_recheck as mark_review_recheck,
release_review_decision as release_review_decision,
upsert_review_decision as upsert_review_decision,
list_ledger_categories as list_ledger_categories,
list_uncategorized_transactions as list_uncategorized_transactions,
preview_categorization as preview_categorization,
@@ -29,7 +33,11 @@ __all__ = [
"delete_ledger_category",
"get_uncategorized_merchant_summary",
"get_uncategorized_workbench",
"hold_review_decision",
"list_category_rules",
"mark_review_recheck",
"release_review_decision",
"upsert_review_decision",
"list_ledger_categories",
"list_uncategorized_transactions",
"preview_categorization",
@@ -1,7 +1,25 @@
from __future__ import annotations
from ...service import get_balance_reconciliation_report as get_balance_reconciliation_report
from ...service import (
close_reconciliation_session as close_reconciliation_session,
get_balance_reconciliation_report as get_balance_reconciliation_report,
get_review_operating_indicators as get_review_operating_indicators,
hold_review_decision as hold_review_decision,
list_reconciliation_sessions as list_reconciliation_sessions,
mark_review_recheck as mark_review_recheck,
release_review_decision as release_review_decision,
upsert_reconciliation_session as upsert_reconciliation_session,
upsert_review_decision as upsert_review_decision,
)
__all__ = [
"close_reconciliation_session",
"get_balance_reconciliation_report",
"get_review_operating_indicators",
"hold_review_decision",
"list_reconciliation_sessions",
"mark_review_recheck",
"release_review_decision",
"upsert_reconciliation_session",
"upsert_review_decision",
]
@@ -3,9 +3,13 @@ from __future__ import annotations
from ...service import (
find_cancel_original_candidates as find_cancel_original_candidates,
find_self_transfer_candidates as find_self_transfer_candidates,
hold_review_decision as hold_review_decision,
link_cancel_to_original as link_cancel_to_original,
link_self_transfer_pair as link_self_transfer_pair,
list_cross_transfer_review_queue as list_cross_transfer_review_queue,
mark_review_recheck as mark_review_recheck,
release_review_decision as release_review_decision,
upsert_review_decision as upsert_review_decision,
preview_cross_account_transfers as preview_cross_account_transfers,
run_cross_account_transfer_match as run_cross_account_transfer_match,
)
@@ -13,9 +17,13 @@ from ...service import (
__all__ = [
"find_cancel_original_candidates",
"find_self_transfer_candidates",
"hold_review_decision",
"link_cancel_to_original",
"link_self_transfer_pair",
"list_cross_transfer_review_queue",
"mark_review_recheck",
"release_review_decision",
"upsert_review_decision",
"preview_cross_account_transfers",
"run_cross_account_transfer_match",
]