#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""佰奥莱博集团近三年经营简报（2024–2026.10）— Word 生成器

数据源：
  数据/baiaolab_3y.json（2025/2026 ERP 实算 + 2024 引自 客户分析报告_2024-2026）
  数据/2026年10月应收账龄_大客户部.json（应收账款）
运行：env -u PYTHONPATH /usr/bin/python3 脚本/build_baiaolab_brief.py
"""
import json
import os
import sys

from docx import Document
from docx.enum.section import WD_SECTION
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Cm, Pt, RGBColor

BASE = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
OUT = BASE + '/销售分析/佰奥莱博集团_近三年经营简报_2026-10-21.docx'
LOGO = os.path.expanduser('~/work/公司资料/logo_transparent.png')
SLOGAN = '守护生命健康，缔造美好生活'
BLUE = RGBColor(0x1F, 0x4E, 0x79)
GREY = RGBColor(0x60, 0x60, 0x60)
RED = RGBColor(0xB0, 0x1F, 0x1F)

P = json.load(open(BASE + '/数据/baiaolab_3y.json', encoding='utf-8'))
Y24 = P['2024']['total']
Y25, Y26 = P['2025'], P['2026']
T25, T26 = Y25['total'], Y26['total']
M25, M26 = Y25['by_month'], Y26['by_month']
MONTHS = ['%02d' % i for i in range(1, 11)]
JAN_OCT_25 = sum(M25.get('2025-' + m, 0) for m in MONTHS)
JAN_OCT_26 = sum(M26.get('2026-' + m, 0) for m in MONTHS)
YOY = (JAN_OCT_26 / JAN_OCT_25 - 1) * 100 if JAN_OCT_25 else 0
G2425 = (T25 / Y24 - 1) * 100 if Y24 else 0

AR = json.load(open(BASE + '/数据/2026年10月应收账龄_大客户部.json', encoding='utf-8'))['detail']
ar = [r for r in AR if '佰奥' in str(r.get('cust', ''))]
AR_TOT = sum(float(r['amt']) for r in ar)
AR_OD = sum(float(r.get('od_amt') or 0) for r in ar)
AR_MAXD = max([int(r['od_days']) for r in ar if r.get('od_days')] or [0])

COMPS = P['complaints']
OPEN = [c for c in COMPS if c.get('status') not in ('结束',)]
ACTS = P['activities']


def w(x):
    return '%.1f' % (x / 1e4)


def pct(a, b):
    return '%.1f%%' % (a / b * 100) if b else '—'


# ── 图表：月度对比 ─────────────────────────────────────────────
def make_chart():
    bars = []
    for i, m in enumerate(MONTHS):
        v25 = M25.get('2025-' + m, 0) / 1e4
        v26 = M26.get('2026-' + m, 0) / 1e4
        bars.append((m, v25, v26))
    rows = ''.join(
        '<div class="g"><div class="b25" style="height:%.1f%%"><span>%s</span></div>'
        '<div class="b26" style="height:%.1f%%"><span>%s</span></div>'
        '<div class="lb">%d月</div></div>' % (
            v / 36 * 100, ('%.0f' % v) if v >= 3 else '', u / 36 * 100, ('%.0f' % u) if u >= 3 else '', int(m))
        for m, v, u in bars)
    html = """<!doctype html><html><head><meta charset="utf-8"><style>
    body{margin:0;background:#fff;font-family:"PingFang SC","Microsoft YaHei",sans-serif}
    .wrap{width:1500px;padding:18px 26px 8px}
    .ttl{font-size:26px;font-weight:700;color:#1F4E79;margin-bottom:2px}
    .sub{font-size:15px;color:#777;margin-bottom:14px}
    .plot{display:flex;align-items:flex-end;gap:14px;height:420px;border-bottom:2px solid #d7dee8;
          border-left:2px solid #d7dee8;padding:0 8px 0 10px;position:relative}
    .g{flex:1;display:flex;align-items:flex-end;justify-content:center;gap:5px;position:relative;height:100%}
    .b25,.b26{width:34px;border-radius:3px 3px 0 0;position:relative;min-height:1px}
    .b25{background:#9db7d4}.b26{background:#1F4E79}
    .b25 span,.b26 span{position:absolute;top:-19px;left:50%;transform:translateX(-50%);
      font-size:12px;color:#456;white-space:nowrap}
    .lb{position:absolute;bottom:-28px;left:50%;transform:translateX(-50%);font-size:13px;color:#666}
    .leg{display:flex;gap:26px;justify-content:flex-end;font-size:14px;color:#444;margin:34px 6px 0}
    .k{display:inline-block;width:14px;height:14px;border-radius:2px;margin-right:6px;vertical-align:-2px}
    </style></head><body><div class="wrap">
    <div class="ttl">月度销售走势（万元）</div>
    <div class="sub">__SUB__</div>
    <div class="plot">__ROWS__</div>
    <div class="leg"><span><i class="k" style="background:#9db7d4"></i>2025</span>
    <span><i class="k" style="background:#1F4E79"></i>2026</span></div>
    </div></body></html>"""
    html = html.replace('__SUB__', '2025 全年 %s 万元 ｜ 2026 截至 10-20 合计 %s 万元，1–10 月同比 %.1f%%' % (w(T25), w(T26), YOY))
    html = html.replace('__ROWS__', rows)
    hp = BASE + '/销售分析/_chart_baiaolab.html'
    open(hp, 'w', encoding='utf-8').write(html)
    from playwright.sync_api import sync_playwright
    png = BASE + '/销售分析/_chart_baiaolab.png'
    with sync_playwright() as p:
        b = p.chromium.launch(channel='chrome')
        pg = b.new_page(viewport={'width': 1560, 'height': 640}, device_scale_factor=2)
        pg.goto('file://' + hp)
        pg.wait_for_timeout(400)
        pg.locator('.wrap').screenshot(path=png)
        b.close()
    return png


# ── docx 工具 ────────────────────────────────────────────────
def set_font(run, size=10.5, bold=False, color=None, name='微软雅黑'):
    run.font.size = Pt(size)
    run.font.bold = bold
    run.font.name = name
    run._element.rPr.rFonts.set(qn('w:eastAsia'), name)
    if color is not None:
        run.font.color.rgb = color


def shade(cell, hexcolor):
    tcPr = cell._tc.get_or_add_tcPr()
    el = OxmlElement('w:shd')
    el.set(qn('w:val'), 'clear')
    el.set(qn('w:color'), 'auto')
    el.set(qn('w:fill'), hexcolor)
    tcPr.append(el)


def cell_text(cell, text, size=9.5, bold=False, color=None, align=WD_ALIGN_PARAGRAPH.LEFT):
    cell.text = ''
    p = cell.paragraphs[0]
    p.alignment = align
    p.paragraph_format.space_before = Pt(2)
    p.paragraph_format.space_after = Pt(2)
    set_font(p.add_run(str(text)), size, bold, color)


def style_table(t, widths=None, head_fill='1F4E79', zebra='F2F6FB'):
    t.alignment = WD_TABLE_ALIGNMENT.CENTER
    t.autofit = False
    for i, row in enumerate(t.rows):
        for j, cell in enumerate(row.cells):
            if i == 0:
                shade(cell, head_fill)
                for p in cell.paragraphs:
                    for r in p.runs:
                        r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
                        r.font.bold = True
            elif i % 2 == 0:
                shade(cell, zebra)
            if widths:
                cell.width = Cm(widths[j])
    tbl = t._tbl
    borders = OxmlElement('w:tblBorders')
    for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'):
        e = OxmlElement('w:%s' % edge)
        e.set(qn('w:val'), 'single')
        e.set(qn('w:sz'), '4')
        e.set(qn('w:color'), 'D0D7E2')
        borders.append(e)
    tbl.tblPr.append(borders)


def h1(doc, text):
    p = doc.add_paragraph()
    p.paragraph_format.space_before = Pt(14)
    p.paragraph_format.space_after = Pt(6)
    set_font(p.add_run(text), 13.5, True, BLUE)
    pPr = p._p.get_or_add_pPr()
    bd = OxmlElement('w:pBdr')
    bt = OxmlElement('w:bottom')
    bt.set(qn('w:val'), 'single'); bt.set(qn('w:sz'), '10')
    bt.set(qn('w:space'), '3'); bt.set(qn('w:color'), '1F4E79')
    bd.append(bt); pPr.append(bd)
    return p


def body(doc, text, size=10.5, bold=False, color=None, indent=0, space=4):
    p = doc.add_paragraph()
    p.paragraph_format.space_before = Pt(1)
    p.paragraph_format.space_after = Pt(space)
    p.paragraph_format.line_spacing = 1.32
    if indent:
        p.paragraph_format.left_indent = Cm(indent)
    set_font(p.add_run(text), size, bold, color)
    return p


def bullet(doc, text, size=10.5, color=None):
    p = doc.add_paragraph()
    p.paragraph_format.left_indent = Cm(0.55)
    p.paragraph_format.first_line_indent = Cm(-0.35)
    p.paragraph_format.space_after = Pt(3)
    p.paragraph_format.line_spacing = 1.3
    set_font(p.add_run('· ' + text), size, False, color)
    return p


def caption(doc, text):
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.space_after = Pt(8)
    set_font(p.add_run(text), 8.5, False, GREY)


chart_png = make_chart()

doc = Document()
sec = doc.sections[0]
sec.page_width, sec.page_height = Cm(21.0), Cm(29.7)
sec.top_margin, sec.bottom_margin = Cm(1.9), Cm(1.7)
sec.left_margin, sec.right_margin = Cm(2.1), Cm(2.1)

# 页眉
hp = sec.header.paragraphs[0]
hp.alignment = WD_ALIGN_PARAGRAPH.LEFT
if os.path.exists(LOGO):
    hp.add_run().add_picture(LOGO, height=Cm(0.56))
r = hp.add_run('    佰奥莱博集团 · 近三年经营简报')
set_font(r, 8.5, False, GREY)
tabs = hp.paragraph_format.tab_stops
tabs.add_tab_stop(Cm(16.6), 2)  # right align
r2 = hp.add_run('\t内部资料 · 2026-10-21')
set_font(r2, 8.5, False, GREY)

# 页脚
fp = sec.footer.paragraphs[0]
fp.alignment = WD_ALIGN_PARAGRAPH.CENTER
set_font(fp.add_run(SLOGAN + '　｜　BIORI BIOTECH · 宝锐生物　｜　0756-8699969　｜　www.biori.com'), 7.5, False, GREY)

# 标题区
p = doc.add_paragraph()
p.paragraph_format.space_before = Pt(2)
p.paragraph_format.space_after = Pt(2)
set_font(p.add_run('佰奥莱博集团 近三年经营简报'), 20, True, BLUE)
p = doc.add_paragraph()
p.paragraph_format.space_after = Pt(6)
set_font(p.add_run('2024 – 2026.10　｜　诊断原料 · 大客户销售部'), 10.5, False, GREY)

meta = doc.add_table(rows=1, cols=3)
meta.autofit = False
vals = [('编制', '营销中心·销售管理 刘新元'), ('呈报', '总经理'), ('数据截止', '2026-10-20（ERP）')]
for j, (k, v) in enumerate(vals):
    c = meta.rows[0].cells[j]
    c.text = ''
    pp = c.paragraphs[0]
    set_font(pp.add_run(k + '　'), 8.5, True, GREY)
    set_font(pp.add_run(v), 8.5, False, RGBColor(0x33, 0x33, 0x33))
    c.width = Cm(5.6)
style_table(meta, head_fill='FFFFFF', zebra='FFFFFF')

# 一页结论
h1(doc, '一、一页结论')
concl = [
    ('规模走势：一年冲高，今年失速。', '2024 年 %s 万元 → 2025 年 %s 万元（+%.1f%%）；2026 年 1–10 月仅 %s 万元，同比 %s，其中 8、9 月零采购。' % (
        w(Y24), w(T25), G2425, w(JAN_OCT_26), '%.1f%%' % YOY)),
    ('失速不是需求消失，而是客户内部变动叠加项目未达标。', '研发对接人离职、厂房搬迁（预计 10 月底完工）造成 3 个月断档；宠物真菌、马 ACTB 两个在测项目均未拿到稳定结果；磺胺项目被竞品替代。'),
    ('财务与质量敞口同时存在。', '应收 %s 万元未收，其中逾期 %s 万元（占 %.0f%%，最长 %d 天）；10 条客诉中 4 条未闭环，最早一条已挂 %.0f 天。' % (
        w(AR_TOT), w(AR_OD), AR_OD / AR_TOT * 100 if AR_TOT else 0, AR_MAXD,
        max([int(c.get('days') or 0) for c in OPEN] or [0]))),
    ('建议：先控风险，再谈恢复。', '四季度以「回款 + 客诉闭环 + 恢复供货」为三条硬线，2027 年再谈增量；同时把佰奥长生（深圳）目前 %.0f%% 的占比往上拉，降低对西安主体 %.0f%% 的单点依赖。' % (
        list(Y26['by_cust'].values())[1] / T26 * 100 if T26 else 0,
        list(Y26['by_cust'].values())[0] / T26 * 100 if T26 else 0)),
]
for i, (head, txt) in enumerate(concl, 1):
    p = doc.add_paragraph()
    p.paragraph_format.space_before = Pt(2)
    p.paragraph_format.space_after = Pt(4)
    p.paragraph_format.line_spacing = 1.3
    set_font(p.add_run('%d. %s' % (i, head)), 10.5, True, BLUE)
    set_font(p.add_run(txt), 10, False, RGBColor(0x22, 0x22, 0x22))

# 二、三年经营
h1(doc, '二、三年经营数据')
t = doc.add_table(rows=1, cols=6)
hdr = ['年度', '销售额（万元）', '同比', '有效单据', '单均金额（元）', '在采货号数']
for i, h in enumerate(hdr):
    cell_text(t.rows[0].cells[i], h, 9.5, True, align=WD_ALIGN_PARAGRAPH.CENTER)

sku25 = {s['sku'] for s in Y25['top_sku']}
rows = [
    ['2024', w(Y24), '—', '—', '—', '—'],
    ['2025', w(T25), '+%.1f%%' % G2425, Y25['orders'], '%.0f' % (T25 / Y25['orders']), len(Y25['top_sku'])],
    ['2026（1–10 月）', w(T26), '%.1f%%' % YOY, Y26['orders'], '%.0f' % (T26 / Y26['orders']), len(Y26['top_sku'])],
]
for r_ in rows:
    cells = t.add_row().cells
    for i, v in enumerate(r_):
        cell_text(cells[i], v, 9.5, False, align=WD_ALIGN_PARAGRAPH.CENTER)
style_table(t, widths=[3.0, 3.2, 2.2, 2.2, 3.0, 3.0])
caption(doc, '注：2026 同比为 1–10 月同口径（2025 同期 %s 万元）；2024 数据引自《客户分析报告 2024–2026》。' % w(JAN_OCT_25))

doc.add_picture(chart_png, width=Cm(16.8))
doc.paragraphs[-1].alignment = WD_ALIGN_PARAGRAPH.CENTER
caption(doc, '图 1　月度销售走势（万元）｜数据来源：ERP 订单，截至 2026-10-20')

# 三、产品结构
h1(doc, '三、产品结构：主力集中在 5 个冻干预混液')
t = doc.add_table(rows=1, cols=5)
for i, h in enumerate(['货号', '产品', '2026 销售额（万元）', '占比', '2025 销售额（万元）']):
    cell_text(t.rows[0].cells[i], h, 9, True, align=WD_ALIGN_PARAGRAPH.CENTER)
sku25map = {s['sku']: s['amt'] for s in Y25['top_sku']}
for s in Y26['top_sku'][:6]:
    cells = t.add_row().cells
    nm = s['name'].replace('(Probe qPCR)', '').replace('(Probe qRT-PCR)', '').replace('(DG)', '').strip()
    cell_text(cells[0], s['sku'], 9)
    cell_text(cells[1], nm[:34], 9)
    cell_text(cells[2], '%.1f' % (s['amt'] / 1e4), 9, align=WD_ALIGN_PARAGRAPH.RIGHT)
    cell_text(cells[3], pct(s['amt'], T26), 9, align=WD_ALIGN_PARAGRAPH.RIGHT)
    cell_text(cells[4], '%.1f' % (sku25map.get(s['sku'], 0) / 1e4), 9, align=WD_ALIGN_PARAGRAPH.RIGHT)
style_table(t, widths=[3.8, 6.4, 2.8, 1.6, 2.0])
caption(doc, '注：2026 前 5 个货号合计占 %s；2025 同期第一主力 FM5071-NA 由 %.1f 万元降至 %.1f 万元。' % (
    pct(sum(s['amt'] for s in Y26['top_sku'][:5]), T26),
    sku25map.get('FM5071-NA', 0) / 1e4, next((s['amt'] for s in Y26['top_sku'] if s['sku'] == 'FM5071-NA'), 0) / 1e4))

body(doc, '结构判断：', 10.5, True, BLUE)
bullet(doc, '两个主体、一个集团：西安佰奥莱博 %s 万元（%s）、佰奥长生（深圳）%s 万元（%s）。2025 年两者分别占 %s / %s，2026 年西安占比升至 %s——客户结构进一步集中。' % (
    w(list(Y26['by_cust'].values())[0]), pct(list(Y26['by_cust'].values())[0], T26),
    w(list(Y26['by_cust'].values())[1]), pct(list(Y26['by_cust'].values())[1], T26),
    pct(list(Y25['by_cust'].values())[0], T25), pct(list(Y25['by_cust'].values())[1], T25),
    pct(list(Y26['by_cust'].values())[0], T26)))
bullet(doc, '产品全部走「冻干预混液 + 定制化组分」，2026 年由试剂生产部承接 %s 万元（%s），研发两部仅 %s 万元——生产端已基本承接，转产不是矛盾点。' % (
    w(Y26['by_dept'].get('试剂生产部', 0)), pct(Y26['by_dept'].get('试剂生产部', 0), T26),
    w(sum(v for k, v in Y26['by_dept'].items() if '研究部' in k or '产品部' in k))))

# 四、原因
doc.add_page_break()
h1(doc, '四、2026 年失速的四个原因（按证据强度排序）')
causes = [
    ('客户内部变动导致 3 个月断档（强证据）',
     '研发对接人离职，项目交接给李总，新人未到岗；同时搬厂房，新厂房预计 10 月底完工。8、9 月 ERP 零采购，10 月仅 %s 万元。' % w(M26.get('2026-10', 0))),
    ('在测项目性能未达客户要求（强证据）',
     '宠物真菌粪便直扩（裂解液 pH≈11）：FM507 冻干后比液体滞后 1 个 Ct；新酶系 FM2181-4-020303、FMD5104-014429 滞后 2–3 个 Ct。马 ACTB：FMD5084-000901 个别靶标 Ct 延迟约 3 个，增加探针与镁离子均未解决 Rn 下降。'),
    ('注册与货号变更带来的下单摩擦（中证据）',
     '客户受兽药 GMP 约束，已注册产品的原料品名/货号不得变更，只能改出货文件；本期完成 FMD5084-000901 → FMD5084-007703-DB、FMD2011 由 2× 改 5× 等 3 个货号的切换，期间下单节奏受扰。'),
    ('需求端被替代或收缩（中证据）',
     '磺胺项目客户需求减少，客户反馈诺唯赞去核酸效果更好，且搬家前不再采购；二代 POC 平台客户自评「项目定位错误」，不是其重点项目。'),
]
for i, (head, txt) in enumerate(causes, 1):
    p = doc.add_paragraph()
    p.paragraph_format.space_before = Pt(4)
    p.paragraph_format.space_after = Pt(2)
    set_font(p.add_run('%d. %s' % (i, head)), 10.5, True, BLUE)
    body(doc, txt, 10, indent=0.45, space=3)

# 五、风险
h1(doc, '五、风险敞口：应收与质量')
t = doc.add_table(rows=1, cols=3)
for i, h in enumerate(['指标', '数值', '说明']):
    cell_text(t.rows[0].cells[i], h, 9, True, align=WD_ALIGN_PARAGRAPH.CENTER)
risk = [
    ['应收未收', '%s 万元' % w(AR_TOT), '占 2026 年销售额 %s' % pct(AR_TOT, T26)],
    ['其中逾期', '%s 万元' % w(AR_OD), '占应收 %s，最长逾期 %d 天' % (pct(AR_OD, AR_TOT), AR_MAXD)],
    ['未闭环客诉', '%d 条' % len(OPEN), '批内差、漏发、漏液、冻融失效各 1 条'],
    ['客诉最长挂起', '%d 天' % max([int(c.get('days') or 0) for c in OPEN] or [0]), '2025-02-17 FM5071-NA 批内差，状态仍为「销售审核中」'],
]
for r_ in risk:
    cells = t.add_row().cells
    cell_text(cells[0], r_[0], 9)
    cell_text(cells[1], r_[1], 9, True, RED if '逾期' in r_[0] or '未闭环' in r_[0] else None, WD_ALIGN_PARAGRAPH.RIGHT)
    cell_text(cells[2], r_[2], 9)
style_table(t, widths=[3.4, 3.2, 10.0])

body(doc, '未闭环客诉清单：', 9.5, True, BLUE)
t = doc.add_table(rows=1, cols=4)
for i, h in enumerate(['日期', '客户', '问题', '当前状态']):
    cell_text(t.rows[0].cells[i], h, 8.8, True, align=WD_ALIGN_PARAGRAPH.CENTER)
for c in OPEN:
    cells = t.add_row().cells
    cell_text(cells[0], c.get('created', ''), 8.8)
    cell_text(cells[1], str(c.get('customer', '')), 8.8)
    cell_text(cells[2], str(c.get('name', '')).split('-', 1)[-1][:22], 8.8)
    cell_text(cells[3], str(c.get('status', '')), 8.8, False, RED)
style_table(t, widths=[2.6, 5.4, 5.6, 3.0])

# 六、建议
h1(doc, '六、建议：四季度三条硬线，六项动作')
t = doc.add_table(rows=1, cols=4)
for i, h in enumerate(['动作', '主责', '时限', '验收标准']):
    cell_text(t.rows[0].cells[i], h, 9, True, align=WD_ALIGN_PARAGRAPH.CENTER)
acts_rows = [
    ['逾期应收专项：逐票对账、锁定付款计划', '刘子研（主）· 林潇（协同）', '10 月底', '逾期 %s 万元回收 ≥70%%，剩余签还款计划' % w(AR_OD)],
    ['4 条未闭环客诉清零，两条超 300 天的先定性', '质量部（主）· 刘子研', '11 月中', '全部关闭或出具技术结论书'],
    ['搬厂完成后恢复供货，锁定 Q4 最低采购量', '刘子研 · 林潇', '11 月中', '11、12 月合计 ≥ %s 万元（回到月均 15 万）' % '30.0'],
    ['宠物真菌 + 马 ACTB 两个项目出配方对比结论', '技术支持（主）· 刘子研', '10 月底', '同体系冻干/液体对照数据 + 推荐配方'],
    ['货号变更收尾：FMD2011 2×→5× 取数换算规则落系统', '张立娅', '10 月底', '下单不再人工折算，双人复核通过'],
    ['客户结构：把佰奥长生（深圳）占比从 %s 提到 25%%' % pct(list(Y26['by_cust'].values())[1], T26), '林潇', '2027 Q1', '新增 2 个在测项目、1 个量产项目'],
]
for r_ in acts_rows:
    cells = t.add_row().cells
    for i, v in enumerate(r_):
        cell_text(cells[i], v, 8.8)
style_table(t, widths=[6.6, 3.6, 2.2, 4.2])

# 七、口径
h1(doc, '七、数据口径与三个不确定点')
body(doc, '口径：金额取 ERP「价税合计」，标准销售订单 + 已审核 + 非赠品；测试单与赠品单不计金额；主体为「西安佰奥莱博生物科技有限公司」与「佰奥长生（深圳）科技有限公司」两家；2026 数据截至 10-20。2025 年含一笔 2026-01-02 要货单据，按合同日期归 2025 年。', 9.5, space=5)
unc = [
    '2024 年基数（%s 万元）来自《客户分析报告 2024–2026》，原始 2024 订单导出已不在库；该表当时可能只归集了西安主体、未含佰奥长生，2024 真实基数可能被低估。' % w(Y24),
    '8、9 月零采购归因于「搬厂 + 研发离职」，依据是销售活动记录与 10-10 拜访；是否存在订单走了经销商或其他主体、ERP 未记录的情况，需销售确认。',
    '4 条未闭环客诉的「销售审核中 / 大区确认中 / 技术支持信息补充中」，可能是流程未走完，也可能已实质解决未关单，需质量部核对后再对外表述。',
]
for i, u in enumerate(unc, 1):
    p = doc.add_paragraph()
    p.paragraph_format.left_indent = Cm(0.55)
    p.paragraph_format.first_line_indent = Cm(-0.35)
    p.paragraph_format.space_after = Pt(3)
    p.paragraph_format.line_spacing = 1.3
    set_font(p.add_run('%d. ' % i), 9.5, True, GREY)
    set_font(p.add_run(u), 9.5, False, RGBColor(0x33, 0x33, 0x33))

p = doc.add_paragraph()
p.paragraph_format.space_before = Pt(10)
set_font(p.add_run('（本简报数据可在 ERP 与活动库逐条回溯；如需明细，营销中心可提供按单、按货号的下钻表。）'), 8.5, False, GREY)

os.makedirs(os.path.dirname(OUT), exist_ok=True)
doc.save(OUT)
print('SAVED', OUT)
print('KEY', {'Y24': Y24, 'T25': T25, 'T26': T26, 'JAN_OCT_25': round(JAN_OCT_25), 'JAN_OCT_26': round(JAN_OCT_26),
              'YOY': round(YOY, 1), 'G2425': round(G2425, 1), 'AR_TOT': AR_TOT, 'AR_OD': AR_OD,
              'OPEN': len(OPEN), 'ACTS': len(ACTS)})
