"""Source-bounded sales review from archived project evidence; no live-state claims."""
import csv,hashlib
from pathlib import Path
ROOT=Path(__file__).resolve().parents[2]
MATRIX=ROOT/'modules/product/products/smart-canteen/product-solutions/2026-08-28-software-sku-sales-demo/data/project-product-function-matrix.csv'
BASE=ROOT/'modules/product/products/smart-canteen/product-solutions/2026-08-06-28-project-3d-case-atlas/data/project-case-base.csv'
PACKAGES=[
 dict(id='employee',name='职工食堂规则与结算',short='人员、补贴、消费统一管理',groups=['多策略职工食堂版','多档口高峰结算版'],priority='优先验证',buyer='行政后勤牵头，财务与信息化共同评审',trigger='多班次、多身份、补贴规则增多；现有结算或对账需要升级',promise='把员工、访客、班次和补贴规则讲清、配好、对上账。',scope=['组织与账户','已验证消费规则','结算与退款','对账与运营报表'],demo='导入一名员工 → 配置一条已验证补贴规则 → 完成消费与退款 → 对上账户和报表',why='10条历史案例被映射到多策略或高峰结算方向，具有重复场景线索；先验证启用规则和交付成本，再锁定标准范围。',proof='同一版本的消费规则启用表、正常与退款交易回放、账户对账结果、客户验收范围。',gaps='有订单不证明高并发；有项目登记不证明所有策略已启用。',counter='既有一卡通可能已满足结算；若客户没有新增规则或对账痛点，不宜推动全套替换。',question='现在每月最难对清的是哪一类人的哪笔钱？',next='选2个有交易证据的项目，整理一套消费—退款—对账演示，由财务确认口径。',roles='产品负责人 + 交付负责人 + 财务接口人',quote='平台许可 / 组织与消费规则配置 / 已验证终端接入 / 实施培训 / 运维；新接口单独列项。',accept='在约定身份和餐次矩阵内，消费、退款和账户汇总一致；性能另按实际负载测试。',opponent='一卡通延伸、支付终端厂商、客户现有系统。'),
 dict(id='selfservice',name='称重与自选结算',short='按量选餐，计价过程可核对',groups=['智能称重自选版','AI视觉结算版'],priority='条件化报价',buyer='食堂运营方与后勤负责人；采购、硬件和IT参与',trigger='新建自选餐线、改造按量计价或视觉结算点位',promise='让自选餐的计价、身份和结算过程能够现场演示、逐笔核对。',scope=['餐线与点位设计','称重或视觉计价','身份/餐盘规则','交易与异常复核'],demo='选定一种已验证餐线 → 完成取餐计价 → 模拟移盘或识别异常 → 人工复核 → 查交易',why='5条历史案例涉及称重/视觉方向；现场布局与硬件证据可构成演示资产，但不同设备路线不可混作统一规格。',proof='同项目点位照片、准确型号/SN与数量、固件/软件版本、身份与计价异常测试、签收及验收记录。',gaps='多条源记录存在型号或数量冲突；视觉准确率、离线补传和节约比例没有统一验证。',counter='设备密集会放大联调与售后成本；若单点适配未冻结，复制越快返工越多。',question='贵方最需要解决的是按量公平计价，还是结算效率？餐线可以怎么改？',next='优先把1条实际餐线冻结为样板，跑通异常矩阵后才承诺跨点位复制。',roles='硬件负责人 + 交付负责人 + 测试',quote='按冻结点位BOM报价；称重与视觉分路线；施工/布线、定制接口、备件、维保单列。',accept='型号数量与签收一致；约定取餐和异常场景逐笔对账通过；不采用通用节约率承诺。',opponent='称重设备商、视觉结算商、传统窗口/按份结算。'),
 dict(id='ordering',name='移动订餐与取餐协同',short='订单从手机走到厨房与取餐点',groups=['移动订餐取餐版'],priority='优先验证',buyer='后勤/食堂运营牵头，使用部门与IT共同验收',trigger='分时供餐、多取餐点、预订餐或厨房分单需求',promise='把预订、厨房分单、取餐和退款串成一条能追查的订单流程。',scope=['已验证订餐入口','订单分单','核销取餐','退款与异常补单'],demo='提交订单 → 厨房接单/打印 → 取餐核销 → 取消退款 → 核对订单与账单',why='当前仅1条案例映射到此主产品方向；适合先做窄范围复制实验，不支持普遍成熟度结论。',proof='选定项目真实端到端订单证据、打印/分单配置、取餐异常与退款回读、业务验收。',gaps='订单量不能直接证明错单率降低；各终端和网络条件仍需兼容性确认。',counter='如果仍以即来即买为主，预订流程可能增加用户操作成本。',question='现在最常出错的是厨房分单、取餐找单，还是取消退款？',next='对现有样板完成一次正常和一次异常演示，再找同类供餐单位确认需求与预算。',roles='产品负责人 + 项目经理 + 运营接口人',quote='订餐入口 / 厨房分单配置 / 取餐接入 / 支付接口 / 试运行支持；新增柜机协议另评估。',accept='一笔订单全链路可追溯，重复核销和退款异常按确认规则处理。',opponent='团餐订餐SaaS、现有小程序加功能、线下报餐。'),
 dict(id='foodsafety',name='后厨记录与食安检查',short='把检查材料串成可追溯记录',groups=['食安后厨监管版'],priority='增购验证',buyer='食安负责人、后厨管理者；行政后勤与采购共同决策',trigger='收货、晨检、留样、巡检等记录分散，检查准备成本高',promise='让约定的食安记录能查到来源、责任人和处理结果。',scope=['已验证收货/留样入口','人员与设备记录','检查台账','告警处理与留痕'],demo='完成一次收货或留样 → 查记录 → 处理一条异常 → 导出对应检查材料',why='3条案例映射到此方向；多种硬件已被记录，但硬件出现不等于整条整改流程已使用。',proof='同项目已启用功能、记录样张、责任与整改回读、设备型号及故障处置记录。',gaps='AI识别准确性、误报处理、系统责任边界需要单独验证。',counter='纸面检查表电子化可能已足够；未被使用的AI告警会增加管理负担。',question='每次检查最费时间补的是哪些记录，出了异常谁来确认闭环？',next='在现有客户选一种高频检查记录验证闭环，再决定是否追加AI与其他设备。',roles='食安产品负责人 + 客户食安负责人 + 交付',quote='记录模块 / 设备点位 / 告警服务与存储 / 实施培训 / 维保，按启用范围分项。',accept='约定记录可追溯，告警可复核，处理结果有凭据；不承诺消除食品安全责任。',opponent='后厨ERP、食安平台、纸质/电子表单和视频方案。'),
 dict(id='menu',name='菜单与营养信息公示',short='菜单、价格与营养信息统一发布',groups=['校园菜单营养公示版'],priority='轻量切入',buyer='学校/机构后勤、食堂管理员；采购与网络管理参与',trigger='菜单改动频繁、多屏不一致、需要清晰展示价格与营养信息',promise='让管理员从一个入口维护菜单、价格和经审核的营养信息。',scope=['菜单内容管理','已验证屏幕适配','审核与发布','设备与内容检查'],demo='编辑次日菜单 → 审核 → 发布指定屏组 → 修改一个价格 → 检查显示',why='3条案例被映射到菜单公示方向；部分源记录只有系统或设备观察，需补实际发布路径。',proof='真实屏幕照片、终端版本、可运行发布链路、营养数据来源与审核规则。',gaps='不能把电子菜牌案例包装为整套智慧食堂；未核实的营养数值不得作为正式公示。',counter='若只有单屏、低频修改，普通信息发布系统可能更经济。',question='一次菜单改动要在多少块屏、由多少人重复修改？',next='选1个有屏幕证据的项目录制发布流程，明确屏数、内容范围及部署条件。',roles='产品负责人 + 客户菜单管理员',quote='内容管理 / 屏幕与播放终端 / 屏组配置 / 培训；营养内容审核服务独立核价。',accept='指定屏组内容一致、修改可追溯；按确认终端检查断网与恢复表现。',opponent='通用数字标牌、普通电视播放、客户既有发布工具。'),
 dict(id='deployment',name='私有化与受控部署服务',short='先通过环境评审，再承诺交付',groups=['政企安全运营版','内网保障供餐版'],priority='专项评审',buyer='信息化与安全负责人；后勤业务和采购联合评审',trigger='私有化、内网分区、平台适配或安全验收条件明确',promise='在客户确认的网络和平台边界内，交付可核验的软件运行与运维方案。',scope=['环境与接口评审','指定平台部署','监控备份与回滚','交接及专项验收'],demo='展示已验证部署拓扑 → 核对版本与端口 → 执行业务冒烟 → 演示确认过的故障恢复',why='4条案例被映射到此类场景；证据包含部署方案，也包含仅项目登记，成熟度差异显著。',proof='精确OS/CPU/数据库/软件版本、配置范围、测试记录、安全要求响应及最终验收。',gaps='方案存在不等于通过安全/国产化认证；高可用必须有故障切换测试。',counter='非标平台和环境改动会拖累毛利与交付周期，不能打包承诺无限适配。',question='客户必须通过的环境清单和验收条款分别是什么，谁签字？',next='把已做过的平台组合与未验证组合分开，报价前形成一页兼容性矩阵。',roles='架构/运维 + 交付 + 客户IT',quote='基础部署 / 指定平台适配 / 高可用与容灾专项 / 安全整改 / 驻场服务分开核价。',accept='只对确认的版本组合与测试场景验收；合规/认证结论由相应机构确定。',opponent='本地集成商、客户IT自建、既有平台扩展。'),
 dict(id='nutrition',name='营养展示与持续服务试点',short='把营养能力变成可执行的服务',groups=['营养健康服务版'],priority='小规模试点',buyer='后勤/工会/健康服务管理者；营养专业人员参与',trigger='有明确服务对象、执行人员和持续运营预算的营养服务需求',promise='围绕菜单与营养教育，交付有内容、有服务记录、有复盘的试点。',scope=['菜单营养内容','营养教育','经确认的服务流程','参与与服务记录'],demo='展示审核后的菜单 → 演示一次教育/解读服务 → 查看服务记录 → 复盘参与情况',why='2条案例被映射为营养服务方向，其中有规划能力记录；不能据此证明持续服务收入或健康效果。',proof='真实服务对象、专业人员产能、服务样张、内容审核、授权和付费试点结果。',gaps='持续付费、服务成本、专业产能和效果尚未闭环；不把软件字段等同于服务能力。',counter='没有客户侧组织者和运营预算，服务容易停留在一次展示活动。',question='由谁组织服务、每月做什么、经费来自哪里，客户愿意为哪项持续动作付费？',next='先锁定一个明确服务对象的小范围付费验证，记录服务工时和续费意愿。',roles='营养服务负责人 + 销售 + 客户服务组织者',quote='内容/平台 / 专业服务场次与人天 / 运营复盘，试点与持续服务分别报价。',accept='验收服务交付与参与记录；不承诺疾病治疗或未经验证的健康改善比例。',opponent='营养服务机构、客户内部人员、一次性健康宣教活动。')]

def load_sales():
    with MATRIX.open(encoding='utf-8-sig') as f:rows=list(csv.DictReader(f))
    with BASE.open(encoding='utf-8-sig') as f:base={r['项目ID']:r for r in csv.DictReader(f)}
    cases=[]
    for i,r in enumerate(rows,1):
        groups=[p for p in PACKAGES if r['主SKU名称'] in p['groups']]
        if len(groups)!=1:raise ValueError('Unmapped/ambiguous package')
        b=base.get(r['项目ID'],{})
        cases.append(dict(key=r['项目ID'],name=r['项目名称'],package=groups[0]['id'],scene=r['场景类型'],observed=r['实际软件观察'],observationState=r['实际软件状态'],facts=b.get('验证能力/证据边界',r['证据边界/缺口']),gaps=r['证据边界/缺口'],proposed=r['场景建议软件'],sourceGrade=r['项目证据等级'],grade='B · 历史材料' if '当前为规划' not in r['证据边界/缺口'] and '只有项目' not in r['证据边界/缺口'] else 'D · 规划/登记',sourceRow=i,uniqueProject=False))
    packs=[]
    for p in PACKAGES:
        v=dict(p);v['caseKeys']=[c['key'] for c in cases if c['package']==p['id']];v['count']=len(v['caseKeys']);packs.append(v)
    return dict(sourceDate='2026-08-28',sourceLabel='8月28日历史案例与产品映射',caseCount=len(cases),cases=cases,packages=packs,notice='销售机会来自历史案例材料，属于待验证的产品化建议；不表示当前商机、已验收能力、已发布SKU或可直接对外承诺。28条为案例记录，城市副中心与C08等可能属于同一项目不同点位。',sourcePaths=[str(MATRIX.relative_to(ROOT)),str(BASE.relative_to(ROOT))],hashes={str(p.relative_to(ROOT)):hashlib.sha256(p.read_bytes()).hexdigest() for p in [MATRIX,BASE]},competitorSources=[dict(title='优信无限官方方案：前厅与后厨能力范围',url='https://www.iyouxin.com/',fact='官方同时介绍称重、视觉、订餐、进销存与食安能力；功能覆盖本身不足以证明独有优势。',grade='C · 厂商自述'),dict(title='帆软经营分析官方方案',url='https://www.fanruan.com/solutions/consumer-business/',fact='官方介绍数据整合与经营分析平台；图表呈现本身不足以证明行业交付优势。',grade='C · 厂商自述')])
