提议留痕:保留原消费来源,单列采纳时的最新检查(桥台账077)

一、无关版本变化允许快速采纳,但不能将新计划身份和旧消费凭据拼在一起。保留建议原计划与消费记录,当前检查版本只存入version_check。

二、专项覆盖旧消费来源不变且最新检查可追溯,46批隔离禁网回归通过。交易行为、仓位、阈值和调度保持。
This commit is contained in:
baobao 2026-10-20 11:32:54 +08:00
parent 0acf7b8fdb
commit 1df17e6777
3 changed files with 7 additions and 4 deletions

View File

@ -158,9 +158,9 @@ def before_accept(p, expected_revision):
if reason: if reason:
return _pending_response(p, reason, 'execution') return _pending_response(p, reason, 'execution')
# 保留生成时的已落库消费凭据。采纳核对结果随动作账本写入,不写另一份消费快照。 # 保留生成时的已落库消费凭据。采纳核对结果随动作账本写入,不写另一份消费快照。
provenance = dict(check['provenance']) checked = check['provenance']
provenance['consumption_id'] = hard.get('consumption_id') version_check = dict(checked.get('version_check') or {}, checked_decision=checked.get('decision'))
return {'ok': True, 'proposal': dict(p, hard_numbers=dict(hard, **provenance))} return {'ok': True, 'proposal': dict(p, hard_numbers=dict(hard, version_check=version_check))}
except Exception: except Exception:
logger.exception('采纳快速检查失败 proposal=%s', p.get('proposal_id')) logger.exception('采纳快速检查失败 proposal=%s', p.get('proposal_id'))
reason = '当前资料暂不可用,建议保留,后台将自动检查' reason = '当前资料暂不可用,建议保留,后台将自动检查'

View File

@ -23,6 +23,7 @@
采纳时检查确认内容、当日有效期、当前研究是否仍适用,以及资金、仓位、暂停与买卖冲突。 采纳时检查确认内容、当日有效期、当前研究是否仍适用,以及资金、仓位、暂停与买卖冲突。
最新计划只读取完整发布结果,不新装配,不新增消费快照。必要交易动作审计仍必须落账。 最新计划只读取完整发布结果,不新装配,不新增消费快照。必要交易动作审计仍必须落账。
生成时的计划与消费编号成对保留。最新核验的计划另记入检查记录,不拼接成虚假消费。
依据发生变化时快速返回等待后台更新,不在HTTP请求里重评,也不暗中改数量。 依据发生变化时快速返回等待后台更新,不在HTTP请求里重评,也不暗中改数量。
已准备的数量仍在当前额度内时,不因其他持仓或资金读数变化强制重新确认。 已准备的数量仍在当前额度内时,不因其他持仓或资金读数变化强制重新确认。
正常下发继续执行既有择时及交易前终检。 正常下发继续执行既有择时及交易前终检。

View File

@ -15,7 +15,7 @@ CODE='600183.SH'
def proposal(**kw): def proposal(**kw):
h={'preparation':{'status':'ready'},'proposal_revision':'shown','consumption_id':'saved', h={'preparation':{'status':'ready'},'proposal_revision':'shown','consumption_id':'saved',
'plan_basis':{'risk':[]},'price':10,'sector':'电子','prepared_judgement':{'verdict':'PASS','reason':'原研究','degraded':False}} 'decision':{'id':'prepared'},'plan_basis':{'risk':[]},'price':10,'sector':'电子','prepared_judgement':{'verdict':'PASS','reason':'原研究','degraded':False}}
p={'proposal_id':'p1','ts_code':CODE,'action':'OPEN','qty':100,'hard_numbers':h, p={'proposal_id':'p1','ts_code':CODE,'action':'OPEN','qty':100,'hard_numbers':h,
'hard_numbers_json':pms_repo._dumps(h),'expire_at':datetime.now()+timedelta(hours=1)} 'hard_numbers_json':pms_repo._dumps(h),'expire_at':datetime.now()+timedelta(hours=1)}
p.update(kw) p.update(kw)
@ -41,6 +41,8 @@ class PreparedProposalTest(unittest.TestCase):
self.assertTrue(out['ok']) self.assertTrue(out['ok'])
self.assertFalse(basis.call_args.kwargs['record']) self.assertFalse(basis.call_args.kwargs['record'])
self.assertEqual(out['proposal']['hard_numbers']['consumption_id'],'saved') self.assertEqual(out['proposal']['hard_numbers']['consumption_id'],'saved')
self.assertEqual(out['proposal']['hard_numbers']['decision']['id'],'prepared')
self.assertEqual(out['proposal']['hard_numbers']['version_check']['checked_decision']['id'],'new')
def test_cash_or_other_position_change_can_accept_existing_quantity(self): def test_cash_or_other_position_change_can_accept_existing_quantity(self):
with patch.object(rc,'current_basis',return_value=current(ok=False,material=True,portfolio_changed=True)), \ with patch.object(rc,'current_basis',return_value=current(ok=False,material=True,portfolio_changed=True)), \