fix: align settlement draft valuation and approval policies (PR16 review73)

This commit is contained in:
2026-10-10 15:55:18 +00:00
parent bae137dce7
commit fa51b4dbb5
2 changed files with 296 additions and 6 deletions
@@ -61,6 +61,7 @@ def _freeze(conn, source_type, source_id, valuation_id=''):
def _review(conn, draft):
from .assets_service import _summarize_valuation_items
stored = _items(conn, draft['id'])
items, included, excluded, missing, warnings, states = [], [], [], [], [], []
for item in stored:
@@ -75,7 +76,7 @@ def _review(conn, draft):
row['item_version'] = item['version']
row.update(source_type='account' if item['source_type'] == 'account' else 'manual_asset',
included=bool(item['included']), basis_date=draft['basis_date'],
name=source.get('name', ''), currency=source.get('currency', 'KRW'),
name=source.get('name', ''), currency=(source.get('currency') or 'KRW').upper(),
liquidity_bucket='loan' if source.get('type') == 'loan' else source.get('liquidity_bucket', 'other'),
authority_source='account_valuations' if item['source_type'] == 'account' else 'manual_assets')
row['is_liability'] = row['liquidity_bucket'] == 'loan'
@@ -126,11 +127,10 @@ def _review(conn, draft):
# All candidate changes and source/selected evidence are bound privately; never exposed as raw JSON.
candidates = [dict(v) for v in conn.execute('SELECT * FROM account_valuations WHERE account_id=? ORDER BY id', (item['source_id'],))] if item['source_type'] == 'account' else []
states.append({'stored': item, 'current': current, 'candidates': candidates})
assets = sum(x['amount'] for x in included if not x['is_liability'])
liabilities = sum(x['amount'] for x in included if x['is_liability'])
latest = _latest_close(conn, draft['basis_date'])
serial = json.dumps({'draft_id': draft['id'], 'version': draft['version'], 'basis_date': draft['basis_date'], 'states': states, 'warnings': warnings, 'latest_run': latest, 'correction_parent': draft['correction_of_run_id']}, sort_keys=True, ensure_ascii=False)
totals = {'total_assets': assets, 'total_liabilities': liabilities, 'net_worth': assets - liabilities}
summary = _summarize_valuation_items(included)
totals = {key: summary[key] for key in ('total_assets', 'total_liabilities', 'net_worth')}
serial = json.dumps({'draft_id': draft['id'], 'version': draft['version'], 'basis_date': draft['basis_date'], 'states': states, 'warnings': warnings, 'latest_run': latest, 'correction_parent': draft['correction_of_run_id'], 'totals': totals}, sort_keys=True, ensure_ascii=False)
return {'draft_id': draft['id'], 'version': draft['version'], 'review_fingerprint': hashlib.sha256(serial.encode()).hexdigest(),
'items': items, 'included_items': included, 'excluded_items': excluded, 'missing_items': missing, 'warnings': warnings,
'approval_required': True, 'totals': totals, **totals, 'complete': bool(items) and not missing,
@@ -282,7 +282,7 @@ def set_settlement_draft_item(draft_id: str,source_type: str,source_id: str,expe
if not v or v['account_id'] != source_id: return _err('validation_error', 'valuation does not belong to account')
if v['currency'] != source['currency']: return _err('validation_error', 'valuation currency mismatch')
kind, loan = v['valuation_kind'], source['type'] == 'loan'
valid_kind = kind in ('loan', 'loan_balance', 'balance') if loan else kind in ('total_value', 'cash_balance', 'balance') if source['type'] == 'investment' else kind == 'balance'
valid_kind = kind in ('loan', 'loan_balance', 'balance') if loan else kind in ('total_value', 'cash_balance', 'balance') if source['type'] == 'investment' else kind in ('balance', 'cash_balance')
if not valid_kind or (loan and v['representative_liability_definition'] not in ('principal_only', 'principal_interest_fees')) or (not loan and v['representative_liability_definition']):
return _err('validation_error', 'valuation purpose or representative liability is invalid')
status = v['verification_status']