#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""构建宝锐酶产品谱系数据：代际口径由刘新元 2026-10-31 确认。"""
import json, pathlib, re, collections

ROOT=pathlib.Path('/Users/liuxinyuan/Desktop/Hermes输出-工作类')
OUT=ROOT/'数据/baorui_enzyme_lineage_20261031.json'
ORD=ROOT/'数据/orders_detail_2026.json'

# 2026 YTD 销售额，按主货号族归并（含税金额，剔除 FO 预测单）
order=json.loads(ORD.read_text(encoding='utf-8'))
rows=[]
for oid,o in order.get('orders',{}).items():
    if str(oid).startswith('FO'): continue
    for ln in o.get('lines',[]):
        sku=str(ln.get('sku','')).strip()
        if sku: rows.append((sku,float(ln.get('amount') or 0),float(ln.get('qty') or 0)))
def sales(base):
    pat=re.compile(r'^('+re.escape(base)+r'|F'+re.escape(base)+r')(-|$)')
    a=[x for x in rows if pat.match(x[0])]
    return round(sum(x[1] for x in a),2), round(sum(x[2] for x in a),2), len({x[0] for x in a})
def level(base,amt):
    if base=='E19': return 'internal'
    if amt>=300000: return 'core'
    if amt>=100000: return 'main'
    return 'active'

def M(sku,name,level,note=''):
    return {'sku':sku,'name':name,'level':level,'note':note}

products=[]
def add(base,name,family,gen,role,mods,features,mixes=None,mix_note='',variants=None,caveat='',**extra):
    amt,qty,n=sales(base)
    d={'id':base,'primary_sku':base,'variant_skus':variants or [],'name':name,
       'family':family,'generation':gen,'generation_label':f'{gen}代','role':role,
       'mods':mods,'features':features,'mixes':mixes or [],'mix_note':mix_note,
       'sales_amount':amt,'sales_qty':qty,'sales_sku_count':n,'sales_level':level(base,amt),
       'caveat':caveat}
    d.update(extra)
    products.append(d)

# ---------------- Taq ----------------
add('E02','Taq DNA Polymerase','Taq',1,'1代亲本 / 基础酶',['无修饰'],
    ['野生型 Taq：5′→3′聚合酶 + 5′→3′外切活性；无 3′→5′校对','70–75℃ 延伸 1–2 kb/min','产物 3′端带 A，可直接 T 载体克隆'],
    mix_note='目录成品 mix 的 BOM 未写 E02；以单酶/客户自配为主。',
    variants=['E02-10','E02-NA','FE02'],
    caveat='E02-15（Taq DNA Polymerase Ⅶ）官网无独立页，未并入本卡。')
add('E03','HS Taq','Taq',1,'1代衍生 / 热启动',['化学修饰'],
    ['化学修饰，95℃ 5–10 min 热启动','Time release：升温过程逐步释放活性','高灵敏度、高荧光值、高特异性'],
    mix_note='未找到 BOM 明确写 E03 的目录成品 mix；以单酶/客户自配为主。',
    variants=['E03-10','E03-NA','FE03'])
add('E07','Superstart Taq plus','Taq',1,'1代衍生 / 热启动',['复合型','抗体'],
    ['复合型修饰（官方描述为新型抗体修饰）','95℃ 1–5 min 热启动','高灵敏度、多重扩增；低浓度模板稳定'],
    [M('M0071','10×Superstart Premix plus-UNG (Probe qPCR)','bom','BOM 写 Superstart Taq plus/UNG Mix'),
     M('M2071','2×Superstart Premix plus-UNG (Probe qPCR)','bom','BOM 写 Superstart Taq plus/UNG Mix'),
     M('M5071','5×Superstart Premix plus-UNG (Probe qPCR)','bom','BOM 写 Superstart Taq plus/UNG Mix')],
    variants=['E07-20','E07-NA','FE07'])
add('E09','Hyperstart Taq','Taq',1,'1代衍生 / 热启动',['配体/适配体'],
    ['配体/适配体修饰；60℃以上可逆热启动','PCR 过程动态修饰','适合 2–8℃ 液体保存'],
    [M('M0091','10×Hyperstart Premix-UNG (Probe qPCR)','bom','BOM 写 Hyperstart Taq/UNG Mix'),
     M('2FM091','Hyperstart Premix-UNG 预混液 (Probe qPCR)','bom','BOM 写 Hyperstart Taq/UNG 酶')],
    variants=['FE09'],
    caveat='单酶销售额低（约 0.15 万），主要随 Hyperstart mix 出货。')
add('E16','Robustart Taq','Taq',1,'1代衍生 / 热启动',['抗体'],
    ['抗体修饰；95℃ 1–5 min 热启动','特异性强、适合多重 PCR','体系适用性好'],
    [M('M416-3-JY1','4×Robustart Premix Omni Ⅲ (JY1)','exact','BOM 直接写 E16 Robustart Taq'),
     M('M2161','2×Robustart Premix-UNG (Probe qPCR)','series','BOM 写 Robustart Taq/UNG Mix，未落单酶货号'),
     M('FM5161','5×Robustart Premix-UNG (Probe qPCR) (DG)','series','BOM 写 Robustart Taq/UNG Mix，未落单酶货号')],
    variants=['E16-NA','FE16'])
add('E15','Robustart Taq HD','Taq',1,'1代 / 特殊用途',['热启动','3′端高分辨/ARMS'],
    ['3′端高分辨、ARMS 突变位点检测','基因改造筛选 + 热启动修饰','用于特异性要求更高的基因分型'],
    [M('M2281','2×Robustart ARMS Gene-typing Premix-UNG','series','ARMS 系列，BOM 未写单酶货号'),
     M('FM5281','5×Robustart ARMS Gene-typing Premix-UNG (DG)','series','ARMS 系列，BOM 未写单酶货号')],
    mix_note='ARMS 系列可关联，但 BOM 未写 E15，标系列级。',
    caveat='2026 单酶金额 0、数量 1,501（赠样/测试为主），不作为销售额主推。')

add('E19','Robustart Taq QS','Taq',2,'2代 / 内部（不对外）',['QS 早期版本（资料缺）'],
    ['2代 QS 早期版本','不对外体现','官网无独立产品页'],
    mix_note='无对外 mix 映射。',
    external=False,
    caveat='按用户口径列为 2 代，但仅内部使用，不对外展示。')
add('E20','Robustart Taq QS Ⅱ','Taq',2,'2代 / 快速高活性',['抗体','高活性突变'],
    ['抗体修饰 + 高活性突变','95℃ 1–5 min 热启动；≥1 kb/10 s','耐血液、拭子等来源抑制物'],
    mix_note='目录成品 mix 未见明确写 E20；以单酶/客户自配为主。官方页用 MD2084-4 做测试体系，不是成品 mix 主酶声明。',
    variants=['E20-8','E20-NA','FE20','FE20-20','FE20-50'])
add('E31','Superstart Taq QS Ⅱ plus','Taq',2,'2代 / 快速高活性',['复合型','抗体','高活性突变'],
    ['复合修饰（官方描述新型抗体修饰）+ 高活性突变','95℃ 1–5 min 热启动','≥1 kb/10 s，适合快速扩增/POC'],
    mix_note='目录成品 mix 未见明确写 E31。',
    variants=['E31-NA','FE31'])
add('E35','Polluxstart Taq QS Ⅱ','Taq',2,'2代 / 双抗体',['双抗体','高活性突变'],
    ['双抗体修饰：同时封闭聚合酶活性和 5′→3′外切活性','高特异性，适合多重 PCR','高活性突变背景'],
    mix_note='目录成品 mix 未见明确写 E35。',
    variants=['E35-NA'])

add('E40','Robustart Taq QS Ⅲ','Taq',3,'3代 / 快速高活性',['抗体','高活性突变'],
    ['抗体修饰；95℃ 30 s–1 min 热启动','≥1 kb/10 s','耐血液/拭子抑制物及酚类、醇类残留；宽 pH'],
    mix_note='目录成品 mix 未见明确写 E40。',
    variants=['E40-NA','FE40'])
add('E41','Polluxstart Taq QS Ⅲ','Taq',3,'3代 / 双抗体',['双抗体','高活性突变','冻干适配'],
    ['双抗体修饰：封闭聚合酶 + 5′→3′外切活性','≥1 kb/10 s','按冻干试剂要求优化；耐抑制'],
    mix_note='目录成品 mix 未见明确写 E41。',
    caveat='官方描述为“根据冻干试剂特殊要求优化配制”，不是所有包装均为冻干品。')

# ---------------- MMLV ----------------
add('E12','Celerscript RTase','MMLV',1,'1代逆转录 / 长片段分支',['RNase H−','无热启动'],
    ['M-MLV 基因突变筛选，去除 RNase H','逆转录温度 42–50℃','cDNA 合成效率高、底物亲和力强；适合长片段/复杂二级结构'],
    [M('M512','5×Celerscript RT Premix (Probe qRT-PCR)','bom','BOM 写 Celerscript RTase'),
     M('FM512','5×Celerscript RT Premix (Probe qRT-PCR) (DG)','bom','BOM 写 Celerscript RTase')],
    variants=['FE12'],
    caveat='2026 单酶金额 0；主要随 Celerscript mix 出货。')
add('E13','Neoscript RTase','MMLV',1,'1代逆转录 / 基础',['RNase H−','无热启动'],
    ['M-MLV 突变筛选，去除 RNase H','逆转录温度 42–55℃','200 U/µL；高灵敏度、特异性好'],
    [M('PM05','Neoscript RTase 1ST Strand cDNA Synthesis Kit','exact','BOM 直接写 E13 Neoscript RTase'),
     M('HW204/HW206','RT-LAMP 系列 (Bst2.0 / Bst2.0 HS)','exact','BOM 直接写 E13 Neoscript RTase'),
     M('M513/M5134','5×Neoscript RT Premix(-UNG)','series','BOM 写 Neoscript RTase，未落 E13 货号'),
     M('M8254','8×Neoscript RT Premix Multi-UNG','series','官方页写含 Neoscript RTase')],
    variants=['E13-000702','E13-000801','E13-000802','FE13'])
add('E29','Neoscript RTase HS','MMLV',2,'2代逆转录 / 热启动',['适配体封闭','热启动'],
    ['与 1 代主要差异：增加适配体封闭（用户确认）','热启动修饰，50–55℃','稳定性更高、更适合高灵敏 RNA 检测'],
    [M('FMD5084-020301','5×Fast Direct RT Premix-UNG (020301)','exact','BOM 直接写 FE29 50×Fast Direct Part RTase'),
     M('M5244-SX1','5×Neoscript Fast RT Premix-UNG (SX1)','exact','BOM 直接写 E29 400×RTase')],
    variants=['E29-000702','E29-020303','E29-NA','FE29'])

add('E42','Neoscript RTase Ⅱ','MMLV',3,'3代逆转录 / 高活性（非热启动）',['高活性突变','耐抑制','无热启动'],
    ['理性筛选高活性；42–55℃，可兼容 60℃','耐血液/拭子抑制物及酚、醇、异硫氰酸胍等','无热启动修饰'],
    [M('FMD5084-000804','5×Fast Direct RT Premix-UNG (000804)','exact','BOM 写 Neoscript RTase Ⅱ (DG)'),
     M('M524/FM524','5×Neoscript Fast RT Premix (Probe qRT-PCR)','series','BOM 写 Neoscript Fast RTase，未落 E42 货号')],
    variants=['FE42'],
    caveat='2026 单酶金额 0.4 万，处于导入期。')
add('E43','Neoscript RTase HS Ⅱ','MMLV',3,'3代逆转录 / 高活性 + 热启动',['高活性突变','耐抑制','热启动'],
    ['E42 的高活性 + 热启动修饰；50–55℃','适合快速程序；耐抑制性优于 E13','可用于快速直扩/POC'],
    [M('MD2104-003001','2×SensiDirect RT Premix-UNG (003001)','official','E43 官方页明确在该体系中测试'),
     M('MD5104/FMD5104','5×SensiDirect RT Premix-UNG 系列','series','SensiDirect 系列，BOM 未落 E43 货号'),
     M('M2274','2×Neoscript RT Premix OT-UNG','series','OT 系列，BOM 写温启动 RTase，未落 E43 货号')],
    variants=['FE43','FE43-NA'])

# family summary
def fam_summary(f):
    ps=[p for p in products if p['family']==f]
    return {'id':f,'name':'Taq DNA Polymerase' if f=='Taq' else 'M-MLV 逆转录酶',
            'primary_count':len(ps),'generations':sorted({p['generation'] for p in ps}),
            'sales_amount':round(sum(p['sales_amount'] for p in ps),2)}
families=[fam_summary('Taq'),fam_summary('MMLV')]

out={
 'meta':{
   'title':'宝锐酶产品谱系',
   'date':'2026-10-31',
   'version':'V01',
   'authority':'代际口径由刘新元 2026-10-31 确认',
   'rule':'E02 系列=1代；1代 Taq 在 E02 基础上：E03/E07/E09/E16，特殊用途 E15；1代逆转录：E12/E13；2代 Taq：E19（不对外）/E20/E31/E35；2代 MMLV：E29（与1代主要差异=适配体封闭）；3代 Taq：E40/E41；3代 MMLV：E42/E43。',
   'sales_window':'2026-01-01 至 2026-10-31，ERP 含税金额，剔除 FO 预测单',
   'notes':['代际是内部选型口径，不是官网原始字段；对外使用前由产品部确认。',
            'mix 证据分四档：exact=BOM写单酶货号；bom=BOM写系列名；official=官方产品页明示；series=按产品命名关联，BOM未落单酶。',
            '单酶销售额受 mix 内嵌影响，不能只用单酶金额判断产品重要性。']
 },
 'families':families,
 'products':products
}
OUT.write_text(json.dumps(out,ensure_ascii=False,indent=1),encoding='utf-8')
print('WROTE',OUT,'products',len(products))
print('families',families)
for p in products:
    print(p['primary_sku'],p['generation'],p['sales_amount'],p['sales_level'],len(p['mixes']))
