# -*- coding: utf-8 -*-
"""Create/read back this requirement and its three tasks, idempotently."""
import json
from pathlib import Path
from transport import api,PREFIX,SPACE,compact
HERE=Path(__file__).resolve().parent
ASSIGNEE='635755195dc8531eeb2e33d9'
PARENT_TYPE='9uy29901re573f561d69jn40';TASK_TYPE='ba102e46bc6a8483d9b7f25c'
TITLE='标准产品档口云端小票三开关与打印规则统一'
STATE=HERE/'items.sanitized.json'
state=json.loads(STATE.read_text()) if STATE.exists() else {'tasks':{}}

def save(): STATE.write_text(json.dumps(state,ensure_ascii=False,indent=2))
def find(category,title,parent=None):
    rows=api('POST',PREFIX+'/workitems:search',{'spaceId':SPACE,'category':category,'page':1,'perPage':200,'orderBy':'gmtCreate','sort':'desc'})
    rows=rows if isinstance(rows,list) else rows.get('result',[])
    return next((x for x in rows if x.get('subject')==title and (parent is None or x.get('parentId')==parent)),None)
def create(title,description,type_id,parent=None,start='2026-10-15'):
    body={'spaceId':SPACE,'workitemTypeId':type_id,'subject':title,'description':description,'documentFormat':'MARKDOWN',
          'assignedTo':ASSIGNEE,'status':'100005','participants':[ASSIGNEE],
          'customFieldValues':{'79':start,'80':'2026-10-15'}}
    if parent: body['parentId']=parent
    result=api('POST',PREFIX+'/workitems',body)
    item_id=result.get('id',result.get('identifier')) if isinstance(result,dict) else result
    if not item_id:raise RuntimeError('Create did not return ID; search before retry')
    return str(item_id)
def read(item_id):
    item=api('GET',PREFIX+'/workitems/'+item_id)
    if item.get('assignedTo',{}).get('id')!=ASSIGNEE:raise RuntimeError('Assignee mismatch')
    for marker in ['Use Case','主流程','异常/恢复','验收','测试','DoR']:
        if marker not in item.get('description',''):raise RuntimeError('Body marker missing: '+marker)
    return item

body=(HERE/'parent-requirement.md').read_text()
if 'PUBLIC_PROTOTYPE_URL' in body:raise RuntimeError('Publish prototype and replace URL before cloud writes')
parent=state.get('parent') or find('Req',TITLE)
if parent: pid=parent['id']
else:
    pid=create(TITLE,body,PARENT_TYPE,start='2026-10-14');state['parent']={'id':pid};save()
parent=read(pid);state['parent']=compact(parent);save()
serial=parent['serialNumber']
tasks=[
 ('analysis','分析：档口云打印规则与兼容范围',4,'2026-10-14','UC-RECEIPT-001/002 V0.5全部业务规则与DoR，M1～M7、A/E/R及AC01～08','需求来源核验、分类、页面、默认、生效、非目标、兼容和测试口径；保留独立于五场景日志需求的边界。','方案V0.5与父需求完整UC已由用户确认。'),
 ('development','开发：档口云打印三开关与规则统一（store/ai_api）',8,'2026-10-15','UC-RECEIPT-001 M1/M2；UC-RECEIPT-002 M3～M7，AC01～08','store配置/PC三开关/三列SQL/统一自动资格与状态；ai_api手机选菜按开关、金额付款不自动打印；两仓库真实提交到develop_binzhou远程分支；MR由用户自行创建。','业务代码最小实现，必要PHP/Vue/测试/SQL；控制材料不进业务仓库。'),
 ('validation','测试：三开关云打印软件回归与开发库验收',4,'2026-10-15','UC-RECEIPT-001/002全部AC与主/分支/异常/恢复流程','三类档口×八组合×八来源、明细、设备0/1、补单、补打、失败重试、CAS、支付落库、取餐、跨库读取及原业务回归。','专项7项909断言通过；真实保留8档口213订单217明细2取餐记录。外部支付/打印及锁为替身，不能宣称真实扣款、实际出纸或生产已验收。')]
for key,title,estimate,start,covered,scope,evidence in tasks:
    desc=f'''## Use Case 执行切片\n关联父需求：{serial}\n关联 Use Case：{covered}\nDoR：READY\n\n## 主流程与实现要求\n{scope}\n\n## 异常/恢复\n保持父需求E1～E5/R1～R5：参数失败/越权拒绝，重复与CAS不覆盖状态，打印关闭或失败不改交易，不重放历史跳过订单。\n\n## 验收与测试矩阵\n覆盖父需求AC01～AC08；{evidence}\n详见父需求正文及https://zhctpmt.yyangpt.cn/work_store/20261015-standard-stall-receipt-control/dev-validation.md\n\n## 非目标与兼容边界\n不改计价、扣款、支付状态、取餐核销或退款；不改设备端串口出票。ydy_equipment.print_receipt、手工补打、内容/模板/份数原规则保留。\n\n## 计划与工时\n计划{start}至2026-10-15。预计{estimate}h按无AI完整交付估算；实际按本线程root阶段执行日志登记，剔除用户等待与并行重叠，提交收尾另记录。\n\n## 交付证据\n负责人兰海军；分支/Commit提交后回写；MR由用户自行创建；开发库已验证，正式外部平台及生产验收未执行。\n'''
    (HERE/(key+'-task.md')).write_text(desc)
    existing=state['tasks'].get(key) or find('Task',title,pid)
    if existing:tid=existing['id']
    else:
        tid=create(title,desc,TASK_TYPE,pid,start);state['tasks'][key]={'id':tid};save()
    item=read(tid)
    if item.get('parentId')!=pid:raise RuntimeError('Parent mismatch')
    state['tasks'][key]={**compact(item),'estimate':estimate,'plan_start':start,'plan_end':'2026-10-15'};save()
    estimates=api('GET',PREFIX+'/workitems/'+tid+'/estimatedEfforts') or []
    if not estimates:api('POST',PREFIX+'/workitems/'+tid+'/estimatedEfforts',{'spentTime':estimate,'owner':ASSIGNEE,'description':'按未使用AI的需求理解、实现、验证与交付投入估算；不作为实际工时。'})
    verified=api('GET',PREFIX+'/workitems/'+tid+'/estimatedEfforts');state['tasks'][key]['estimate_readback']=verified;save()
print(json.dumps({'parent':state['parent'],'tasks':{k:{f:v.get(f) for f in ['id','serialNumber','subject','assignedTo','status','estimate']} for k,v in state['tasks'].items()}},ensure_ascii=False))
