feat: add persistent monthly settlement drafts and approved valuation selection
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
"""Operator feedback distinguishes read failures and partially committed saves."""
|
||||
import pytest
|
||||
from streamlit.testing.v1 import AppTest
|
||||
|
||||
from jarca_ledger_mcp import service as s
|
||||
from jarca_ledger_mcp.adapters.streamlit import settlement_gateway
|
||||
from jarca_ledger_mcp.db import init_db
|
||||
|
||||
|
||||
def panel(monkeypatch, path):
|
||||
monkeypatch.setenv('JARCA_LEDGER_DB_PATH', str(path))
|
||||
app = AppTest.from_string('from dashboard.page_views.settlement_drafts import render_settlement_drafts\nrender_settlement_drafts()\n').run(timeout=20)
|
||||
assert not app.exception
|
||||
return app
|
||||
|
||||
|
||||
def control(elements, label):
|
||||
return next(element for element in elements if element.label == label)
|
||||
|
||||
|
||||
def test_panel_shows_safe_error_when_draft_listing_fails(tmp_path, monkeypatch):
|
||||
path = tmp_path / 'missing.sqlite3'
|
||||
monkeypatch.setattr(settlement_gateway, 'list_settlement_drafts', lambda *args, **kwargs: {
|
||||
'success': False, 'error_code': 'storage_error', 'message': 'SYNTHETIC_PRIVATE_DIAGNOSTIC',
|
||||
})
|
||||
app = panel(monkeypatch, path)
|
||||
assert app.error and 'storage_error' in ' '.join(element.value for element in app.error)
|
||||
assert not any('초안이 없습니다' in element.value for element in app.info)
|
||||
visible = ' '.join(element.value for elements in (app.error, app.info, app.caption) for element in elements)
|
||||
assert 'SYNTHETIC_PRIVATE_DIAGNOSTIC' not in visible
|
||||
assert not path.exists()
|
||||
|
||||
|
||||
def test_panel_reports_partial_save_when_item_update_fails(tmp_path, monkeypatch):
|
||||
path = str(tmp_path / 'partial.sqlite3')
|
||||
init_db(path)
|
||||
account = s.create_ledger_account('Synthetic cash', db_path=path)['account']['id']
|
||||
assert s.register_account_valuation(account, '2026-09-30', 10, verification_status='verified',
|
||||
idempotency_key='synthetic-value', db_path=path)['success']
|
||||
app = panel(monkeypatch, path)
|
||||
control(app.button, '초안 생성 / 정정 초안').click().run(timeout=20)
|
||||
control(app.button, '검토 / 새로고침 대상').click().run(timeout=20)
|
||||
draft = s.list_settlement_drafts('2026-09', db_path=path)['drafts'][0]
|
||||
review_key = f"review_result_{draft['id']}"
|
||||
assert app.session_state[review_key]['success']
|
||||
control(app.text_input, '초안 메모 저장').set_value('Synthetic persisted memo')
|
||||
control(app.text_input, '대상 ID').set_value('synthetic-nonexistent-target')
|
||||
control(app.button, '저장 / 지정 / 포함·제외').click().run(timeout=20)
|
||||
assert not app.exception
|
||||
current = s.get_settlement_draft(draft['id'], db_path=path)
|
||||
assert current['draft']['memo'] == 'Synthetic persisted memo'
|
||||
assert current['draft']['version'] == draft['version'] + 1
|
||||
assert len(current['items']) == 1 and current['items'][0]['source_id'] == account
|
||||
assert app.error
|
||||
assert any('메모는 저장되었지만 항목 변경은 실패했습니다' in element.value for element in app.warning)
|
||||
with pytest.raises(KeyError):
|
||||
app.session_state[review_key]
|
||||
assert not any(element.label in {'검토 결과 승인', '최종 마감'} for element in app.button)
|
||||
Reference in New Issue
Block a user