"""W38 evidence-backed illustrated workbook. Raw sources and artifacts stay local."""
from pathlib import Path
from copy import copy
import json,hashlib,shutil,math
from openpyxl import Workbook,load_workbook
from openpyxl.styles import Font,PatternFill,Alignment,Border,Side
from openpyxl.comments import Comment
from openpyxl.drawing.image import Image as XImage
from openpyxl.drawing.spreadsheet_drawing import OneCellAnchor,AnchorMarker
from openpyxl.drawing.xdr import XDRPositiveSize2D
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.pagebreak import Break
from PIL import Image,ImageOps

HERE=Path(__file__).resolve().parent; ROOT=HERE.parents[3]; OUT=HERE/'output'; A=OUT/'assets'; DEL=OUT/'交付'; DEL.mkdir(exist_ok=True)
NAVY='193A4D';BLUE='216F92';TEAL='277D73';ORANGE='AC6224';GRAY='566875';LIGHT='EDF4F7';LINE='DCE5EA';WHITE='FFFFFF'
MEETING='https://zhctpmt.yyangpt.cn/work/2026-09-18-weekly-meeting/weekly-meeting-content.html'
SPACE='https://doc.weixin.qq.com/smartsheet/s3_AHkAH3hlAHwCNUzm1hPTKQQGwNBft_a'
COLLECT='https://doc.weixin.qq.com/sheet/e3_Ac0AJgaVAEYCN2YUa9YSsQKC6Sx37'
PACK='https://doc.weixin.qq.com/sheet/e3_AdYAzAZnACUCNCp19nO7KSR6LnvvB'
# Preserve the latest illustrated template's navy/blue 12-column card layout.
wb=Workbook();wb.remove(wb.active)
images=json.loads((OUT/'image-manifest.json').read_text());image_map={m['key']:Path(m['local']) for m in images}
for key,source in [('harbin-health','work/weekly-reports/2026-W36/weekly-0907-project-photos/assets/harbin-health.jpg'),('offline','work_android/CusumptionMachine/announcements/assets/offline-order-release/02-offline-order-list.png'),('school','work/weekly-reports/2026-W37/project-cockpit/output/项目驾驶舱周报包/assets/proto-school-analysis.jpg')]:
 src=ROOT/source; dst=A/(key+src.suffix);shutil.copy2(src,dst);image_map[key]=dst
 images.append(dict(key=key,source=source,local=str(dst),sha256=hashlib.sha256(src.read_bytes()).hexdigest()))
for i in range(3):image_map[f'certificate-{i}']=A/f'certificate-{i}.png'

def box(s,r1,c1,r2,c2,text='',bg=None,color=GRAY,bold=False,link=None,source=None):
 s.merge_cells(start_row=r1,start_column=c1,end_row=r2,end_column=c2)
 c=s.cell(r1,c1,text);c.font=Font(name='微软雅黑',size=12,bold=bold,color=color)
 c.alignment=Alignment(vertical='center',wrap_text=True,indent=1)
 if bg:
  for row in s.iter_rows(min_row=r1,max_row=r2,min_col=c1,max_col=c2):
   for q in row:q.fill=PatternFill('solid',fgColor=bg)
 if link:c.hyperlink=link
 if source:c.comment=Comment(source,'证据来源')
 return c

def sheet(name):
 s=wb.create_sheet(name);s.sheet_view.showGridLines=False;s.sheet_view.zoomScale=85
 for c in range(1,13):s.column_dimensions[get_column_letter(c)].width=13
 s.sheet_properties.pageSetUpPr.fitToPage=True
 s.page_setup.orientation='landscape';s.page_setup.paperSize=s.PAPERSIZE_A4;s.page_setup.fitToWidth=1;s.page_setup.fitToHeight=0
 s.page_margins.left=s.page_margins.right=.28;s.page_margins.top=s.page_margins.bottom=.28
 s.freeze_panes='A5';s.oddFooter.center.text='康比特数字技术中心  |  内部周报  |  &P'
 s.oddFooter.center.size=9
 return s

def page(s,title,subtitle):
 n=getattr(s,'_pages',0);r=n*28+1;s._pages=n+1
 for i in range(r,r+28):s.row_dimensions[i].height=20
 if n:s.row_breaks.append(Break(id=r-1))
 box(s,r,1,r+1,12,title,NAVY,WHITE,True)
 box(s,r+2,1,r+3,12,subtitle,LIGHT,GRAY)
 box(s,r+27,1,r+27,12,'W38 · 9月14—20日  |  资料截止9月19日  |  照片日期、原型和验收范围分别标注',color=GRAY)
 s.print_area=f'A1:L{r+27}'
 return r

def picture(s,key,r,c,maxw,maxh):
 src=image_map[key]
 im=ImageOps.exif_transpose(Image.open(src)).convert('RGB');im.thumbnail((1900,1900))
 dest=A/(key+'-display.jpg');im.save(dest,quality=93)
 x=XImage(dest);f=min(maxw/x.width,maxh/x.height);x.width*=f;x.height*=f
 # Center inside its reserved box, without stretching or cropping evidence.
 x.anchor=OneCellAnchor(_from=AnchorMarker(col=c-1,row=r-1,colOff=int((maxw-x.width)/2*9525),rowOff=int((maxh-x.height)/2*9525)),ext=XDRPositiveSize2D(int(x.width*9525),int(x.height*9525)))
 s.add_image(x)

def para(s,r,c1,c2,title,body,height=3,color=BLUE):
 box(s,r,c1,r,c2,title,LIGHT,color,True)
 box(s,r+1,c1,r+height,c2,body)

s=sheet('图文总览');r=page(s,'本周周报｜交易可靠性补齐，学校营养进入开发','数字技术中心与交付实施 · 2026.09.14—09.20 · 参考事业部模板及W37图文版')
for a,b,label,value,note in [(1,4,'产品变化','交易与营养两条主线','已上线功能与开发中能力分别报告'),(5,8,'本周新增软著','2项｜9月16日登记','营养点餐、消费终端营养结算'),(9,12,'管理重点','交付测试与研发结果对齐','哈尔滨、三全、四方达需关口验证')]:
 box(s,r+5,a,r+5,b,label,color=BLUE,bold=True);box(s,r+6,a,r+7,b,value,LIGHT,TEAL,True);box(s,r+8,a,r+9,b,note)
para(s,r+11,1,6,'01 产品差异性｜学校营养进入集中开发','9/11学校线仍待评审；9/18需求、接口、数据及测试设计齐备。推荐食谱确定采用服务端确定性算法，9月底为开发目标；尚不能按已上线能力销售。',3)
para(s,r+11,7,12,'02 产品标准化｜交易可靠性形成增量','央美一卡通补传与同步、消费机离线订单、PC补打小票及订单详情、金斯瑞地址查看均有完成自报。价值在于减少异常处理盲区，尚缺跨项目复用和故障率数据。',3)
para(s,r+16,1,6,'03 项目交付｜优先关闭现场主流程','哈尔滨现场全流程自报80%、机器人数据对接50%；四方达端口替代方案测试50%；三全支付权限与食安点位仍需现场验证。研发完成不直接推导整体验收。',3,color=ORANGE)
para(s,r+16,7,12,'AI赋能｜沉淀可检查的工作资产','需求—接口—测试成套设计、原型追踪、售前调研模板及任务台账已形成资料。自动测试、SQL部署和真实群催办尚缺完整运行验证，本周不写节省工时或全自动落地。',3)
box(s,r+21,1,r+23,12,'下周验收重点：学校营养形成可运行主流程；哈尔滨对齐9/22交付范围；三全冻结必须交付链路；四方达确认试运行条件；重庆扫码认证完成真机验证。具体责任人与下一关口见“项目、产品”。',LIGHT,BLUE,True)
box(s,r+24,1,r+26,12,'经营口径：现有来源不能支持当周合同收入、回款额、毛利或真实使用成效，不沿用旧模板金额。交付表本周已读取赵野11条、张帅5条；其余三人未检索到同周期记录，不解释为零工作。',source='来源：9/18周会；9/19实时企业微信周报；软著PDF原件。')

projects=[
 dict(name='哈尔滨膳质舍｜联调有进展，现场仍需收口',image='harbin-health',fact='体检、称重与绑盘设备已安装测试；研发侧食物成分/调味品接口联调完成。现场侧机器人数据对接自报50%、业务全流程80%，两者范围不同。',next='赵野与兰海军、郭东伟、李潇对齐9/22原交付节点；完成菜品清理同步、全流程复测和操作视频。',value='把体检建档、营养服务和餐厅设备接入连起来；复制条件是接口、数据、培训与交接同时闭环。',caption='9/6用户提供的项目设备照片，拍摄日待核；设备外观不证明本周联调结果。',boundary='状态：现场验证中；50%/80%为交付自报，非审计进度。',source='9/18周会 + 赵野9.14—9.20周报；9/4与9/11节点连续核对。'),
 dict(name='三全集团｜支付与食安先收敛交付主链路',image='sanquan-weigh',fact='研发记录支付宝配置完成；现场本周记录访问权限协调及食安摄像头点位确认。钉钉、魔点、商米及PC定制仍未形成整链路通过证据。',next='赵野、赖清涛、尹旭亮及田亚辉按主链路排序；先完成小餐台支付宝测试、食安摄像头部署，再确认后续范围与日期。',value='形成企业多设备、多系统集成的标准检查单；控制范围和验证顺序，减少现场反复联调。',caption='微盘项目现场照片，8/26归档；称重终端现场形态，不是本周验收照片。',boundary='状态：集成/现场验证；不将配置完成写成可正式开餐。',source='9/18周会 + 赵野本周记录；微盘三全现场图片IMG_0104。'),
 dict(name='中央美院｜一卡通异常恢复能力补齐',image='cafa-line',fact='研发自报消费失败补传、消费前卡同步、消费记录同步和日志闭环完成；张帅本周现场联调晨检仪和留样秤。',next='尹旭亮与交付团队收齐离线、失败重试、对账及食安设备复测记录；由客户确认问题清单与验收范围。',value='校园场景验证一卡通与消费机协同；将失败补偿、日志和恢复步骤纳入标准交付包。',caption='9/6用户提供的央美餐线照片，拍摄日待核；本周增量来自研发及交付周报。',boundary='状态：功能完成自报 + 现场联调；未取得整体合同验收。',source='9/18周会；张帅本周周报；W36用户供图。'),
 dict(name='滨州健康科技职业学院｜从餐线交付转向价值验证',image='binzhou-line',fact='在线项目核心信息表填写410单秤80台、绑盘机8台、消费机30台等设备。定位为教职工、学生和访客用餐及产教融合；核销方案尚待完成。',next='兰海军完成核销测试上线；王金洋配合现场复测，李潇组织客户访谈，补实际教学使用和营养数据证据。',value='校园标准包需同时证明就餐稳定和教学使用。新食堂没有旧运营基线，不编造节省人力或成本比例。',caption='微盘现场餐线照片，7/16归档；数量来自在线填写表，未与签收单复核。',boundary='状态：运营问题与产品增量收口；产教融合效果待验证。',source='交付物料准备包/项目核心信息表；9/18周会；微盘滨州现场照片。'),
 dict(name='金斯瑞｜订单售后处理补齐可见信息',image='jsr-line',fact='研发自报小票补打、送餐地址查看及相关异常修复完成。现场图片用于说明餐厅场景，不承担本周发布与验收证明。',next='赖清涛与交付团队核对现场版本，覆盖补打、地址查看、权限和异常订单复测；旧退款问题单独取回归证据。',value='提高外卖/配送订单的可追溯性；把补打和送餐信息抽成标准能力，避免项目重复开发。',caption='微盘金斯瑞项目现场照片；拍摄日待核，作为场景说明。',boundary='状态：功能完成自报；不据此关闭其他历史退款问题。',source='9/18周会；微盘金斯瑞现场照片。'),
 dict(name='国康医院｜设备联调向简化取餐流程推进',image='guokang-line',fact='研发本周记录售卖柜联调完成，后续仍安排称重流程简化。既有餐线已具备现场图，尚无本周漏餐率或健康改善的量化结果。',next='赖清涛、尹旭亮完成称重流程验证，孙海琴组织客户访谈；补用户路径、异常提示与使用效果记录。',value='医院场景验证营养反馈和取餐管控；以实际启用、使用及客户反馈判断复制价值。',caption='微盘国康餐线照片，8/7归档；不把历史照片当本周运行效果。',boundary='状态：设备联调与流程优化；经营和健康效果未量化。',source='9/18周会；微盘国康现场照片。')]
s=sheet('项目')
for i in range(0,len(projects),2):
 r=page(s,f'重点项目｜{i//2+1}/4 · 本周变化与下一验收关口','延续上一期图文卡片；本周事实来自周会/在线周报，历史照片仅用于项目场景说明。')
 for j,p in enumerate(projects[i:i+2]):
  q=r+4+j*11
  box(s,q,1,q,12,p['name'],BLUE,WHITE,True)
  picture(s,p['image'],q+1,1,455,200)
  box(s,q+1,6,q+3,12,'本周事实｜'+p['fact'],source=p['source'])
  box(s,q+4,6,q+5,12,'下一关口｜'+p['next'],LIGHT,ORANGE)
  box(s,q+6,6,q+7,12,'复用价值｜'+p['value'])
  box(s,q+8,6,q+9,12,p['boundary'],color=TEAL)
  box(s,q+9,1,q+10,5,p['caption'])
r=page(s,'重点项目｜4/4 · 交付关口与支持事项','先核实本周变化，再安排下一节点。项目总表的“已完成”字段不替代验收单。')
heads=[(1,2,'项目'),(3,6,'本周可确认变化'),(7,10,'下一关口与负责人'),(11,12,'状态')]
for a,b,h in heads:box(s,r+4,a,r+4,b,h,BLUE,WHITE,True)
rows=[('重庆环卫','450推荐量、跨端推荐能量和重量限制已上线；扫码身份认证约70%。','尹旭亮完成扫码认证真机验证；李潇确认验收问题。','终端待验证'),('四方达','组织/人员初始化完成；端口替代方案测试自报50%，试运行仍受网络条件影响。','赵野与研发确认443端口替代方案；完成端到端测试后开启试运行。','外部依赖'),('保康中学','进销存已部署；食安进场、一楼摄像头调试完成。','张帅完成一楼、二楼及职工餐厅设备联调；孙倩倩提供现场支持。','现场联调'),('机场项目','新配13台壁挂消费机已安装软件并联调，用于运动会临时摊位。','姜阳、赖清涛推进账户流水查询VWCG-1381；李潇确认上线排期。','部分联调'),('张家港','结算接口与部署包完成；现场部署尚待实施。','赖清涛完成现场部署，收齐实际环境验收和业务冒烟。','待现场部署'),('江西体科所','体重管理、InBody对接、体能模块已开发；正式测试上线待补。','兰海军输出InBody操作文档，完成模块测试上线。','开发待验证')]
for i,row in enumerate(rows):
 q=r+5+i*3
 for (a,b,_),v in zip(heads,row):box(s,q,a,q+2,b,v,LIGHT if i%2==0 else None,color=BLUE if a==1 else GRAY,bold=a==1,source='9/18周会；赵野/张帅9.14—9.20周报。')
box(s,r+24,1,r+26,12,'客户价值补证：重庆在线核心信息表已填写14台450等设备，甲方仍在体验，效果未确认；滨州定位产教融合，尚无效果反馈。两项目均不填降本比例。',LIGHT,ORANGE)

s=sheet('产品');r=page(s,'产品增量｜交易可靠性与移动管理','产品差异性 / 产品标准化 / AI赋能 · 完成自报、演示界面、原型与实际验收分开标注。')
box(s,r+4,1,r+4,8,'产品标准化｜消费机离线订单 + PC订单详情',BLUE,WHITE,True)
picture(s,'offline',r+5,1,720,205)
box(s,r+13,1,r+15,8,'本周：离线订单记录、人工上传、扫码支付超时配置，以及PC补打小票、订单详情和多菜品展示已有完成自报。补齐消费异常后的可见与恢复步骤。',source='9/18周会；9/17功能公告中的离线订单演示界面。')
box(s,r+16,1,r+18,8,'下一步：尹旭亮、孙倩倩核对跨设备版本，验证断网—恢复—上传—查询全流程；用失败订单闭环率、重复处理次数验证实际价值。暂无同口径成效数据。',LIGHT,ORANGE)
box(s,r+19,1,r+20,8,'图示边界：9/17功能公告演示界面，订单、金额和用户均为展示数据；不代表真实营业流水。',color=TEAL)
box(s,r+4,9,r+4,12,'产品差异性｜商户移动管理',BLUE,WHITE,True)
picture(s,'merchant',r+5,9,360,335)
box(s,r+18,9,r+21,12,'孙海琴完成经营、订单、补打等原型和技术评审资料。下一步完成产品评审，冻结权限与接口范围。',source='商户移动管理端README；9/18周会。')
box(s,r+22,9,r+24,12,'图示为本周静态原型；非生产发布。截图中的经营数字不能作为业务收入。',LIGHT,ORANGE)
box(s,r+22,1,r+24,8,'竞争力变化：订单追溯、异常恢复、手机端经营处理更完整；对降低交付成本有潜在价值。实际毛利、复用率和人效尚待持续测量。',LIGHT,BLUE)
box(s,r+25,1,r+26,8,'查看订单技术设计 ↗',link='https://zhctpmt.yyangpt.cn/work_store/VWCG-1334-pc-consume-order-detail-multi-dish/technical-development-design.html',color=BLUE)
box(s,r+25,9,r+26,12,'查看商户移动原型 ↗',link='https://zhctpmt.yyangpt.cn/work_store/20260915-merchant-mobile-management-prototype/merchant-mobile-management.html',color=BLUE)
r=page(s,'产品路线图｜营养能力、交付标准与AI资产','按本周状态变化组织；Build=开发，Validate=验证，Standardize=标准化，Scale=规模复制。阶段为本报告判断。')
box(s,r+4,1,r+4,6,'学校膳食营养｜Build',BLUE,WHITE,True)
picture(s,'school',r+5,1,550,220)
box(s,r+14,1,r+17,6,'9/11：学校线设计偏慢、评审待完成。\n9/18：需求、接口、数据库、测试和推荐算法设计齐；进入集中开发。\n下一门槛：供餐模板—食谱—营养分析—审核发布主流程可运行并通过测试。',source='9/11、9/18周会；学校营养生产开发方案。')
box(s,r+18,1,r+20,6,'孙倩倩调整方案，李潇、王朔确认产品口径，赖清涛复核技术方案；9月底是目标，非已实现承诺。',LIGHT,ORANGE)
box(s,r+21,1,r+23,6,'图为已有学校营养原型，延用说明功能范围；不计为本周新上线。确定性推荐算法不采用Coze或大模型工作流。',color=TEAL)
box(s,r+24,1,r+26,6,'学校营养资料导航 ↗',link='https://zhctpmt.yyangpt.cn/work/2026-09-17-school-nutrition-requirement-analysis/index.html',color=BLUE)
para(s,r+4,7,12,'政企营养｜Validate（评审/验证）','政企带量食谱完成评审，现阶段优先食谱解读。李潇继续扩充哈尔滨菜品库并评审退款业务；用真实菜单与数据校验解释能力。',3)
para(s,r+9,7,12,'交付标准｜形成资产，复用待验证','项目采集表覆盖营养、食安、采购的网络/部署/接口前提；410准备包明确标识、手册及备件；新增素材规范和核心信息表。下一步按项目核对填写与签收。',3)
para(s,r+14,7,12,'AI赋能｜成套资料 → 实际执行验证','本周沉淀售前调研模板、需求测试资料、原型追踪及任务台账。自动测试、SQL部署、部署Agent及真实群催办仍需运行证据，不作全自动上线宣称。',3)
para(s,r+19,7,12,'合规与知识产权｜分别管理','两项软著9/16登记，称重软著8/20已登记；三级等保仍待网安审核和测评进场。王朔补充密评采集材料，孙海琴核对其他申请项；不可将软著当等保通过。',3,color=ORANGE)
box(s,r+24,7,r+26,9,'项目采集模板 ↗',link=COLLECT,color=BLUE)
box(s,r+24,10,r+26,12,'交付准备包 ↗',link=PACK,color=BLUE)

s=sheet('软著证书');r=page(s,'本周新增软著｜2项，登记日期均为9月16日','著作权人：北京康比特体育科技股份有限公司 · 以企业微盘PDF原件为准。')
for i,(key,title,num) in enumerate([('certificate-0','智慧食堂营养点餐系统 V1.0','2026SR0946678'),('certificate-1','智慧食堂消费终端营养结算系统 V1.0','2026SR0946737')]):
 a=1+i*6;b=a+5;box(s,r+4,a,r+5,b,title,BLUE,WHITE,True)
 picture(s,key,r+6,a,550,475)
 box(s,r+24,a,r+26,b,f'登记号：{num}  |  2026-09-16\n本周新增。纳入产品资质与投标材料；不代表功能测试或客户验收。',LIGHT,TEAL)
r=page(s,'已取得资质｜称重结算系统，8月20日登记','本页为既有证书；不计入本周新增2项。软著取得与等保、密评、部署验收分别管理。')
box(s,r+4,1,r+5,6,'智慧食堂称重结算系统 V1.0',BLUE,WHITE,True)
picture(s,'certificate-2',r+6,1,550,475)
para(s,r+5,7,12,'原件核对结果','登记号：2026SR0851059\n登记日期：2026-08-20\n权利取得方式：原始取得\n权利范围：全部权利',4)
para(s,r+11,7,12,'三项能力与资质覆盖','营养点餐 → 消费终端营养结算 → 称重结算。\n三份证书可用于整理产品资质包；其中仅前两份于本周登记。',3)
para(s,r+16,7,12,'与周会记录对齐','9/18周会仍写“推进3个软著”；本报告依据证书原件更新这三份材料的登记状态。其他申请是否属于同一批次，仍由孙海琴核对。',3,color=ORANGE)
box(s,r+22,7,r+25,12,'来源：企业微盘“2026数科事业部资料库 / 业务资料 / 数科产品证书 / 软件著作权 / 膳食系统-11个”。原件扫描与登记文字均已核对。',LIGHT,BLUE)
box(s,r+24,1,r+26,6,'历史资质  |  2026SR0851059  |  2026-08-20',LIGHT,TEAL,True)

for s in wb:
 for row in s:
  for c in row:
   f=copy(c.font);f.name='微软雅黑';f.sz=12;c.font=f
wb.active=0
out=DEL/'数字技术中心与交付实施部周报_20260914-0920_图文版.xlsx';wb.save(out)
w=load_workbook(out)
assert w.sheetnames==['图文总览','项目','产品','软著证书']
assert all(c.font.name=='微软雅黑' and c.font.sz==12 for s in w for row in s for c in row if c.value is not None)
assert not [(s.title,c.coordinate,c.value) for s in w for row in s for c in row if c.data_type=='e']
receipt={'workbook':out.name,'sheets':w.sheetnames,'images':{s.title:len(s._images) for s in w},'planned_pages':{s.title:getattr(wb[s.title],'_pages') for s in w},'new_certificates':2,'historical_certificates':1,'font':'微软雅黑12','sha256':hashlib.sha256(out.read_bytes()).hexdigest(),'bytes':out.stat().st_size,'raw_inputs_public':False}
(HERE/'validation.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n')
(OUT/'image-manifest.json').write_text(json.dumps(images,ensure_ascii=False,indent=2)+'\n')
print(json.dumps(receipt,ensure_ascii=False,indent=2))
