#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""ERP 订单级「发货日期」索引 —— 供订单管理页显示「预计发货日期」。

为什么要做这个：
  ERP 导出（销售订单_*.xlsx）的第 20 列 `发货日期` 是**订单级**字段（同一单据多行值完全一致，
  6171 单实测 0 单分歧），且**未出库订单也有值**（2455 行/601 单）→ 就是「预计发货日期」。
  它是滚动计划：正常情况下落单后固定不变（5295 单对比 99.9% 未变），改期时会往后推
  （实测 4 单变更，全部是当时未出库的单）→ 发货后即等于实际发货日。

输出: 数据/erp_ship_dates.json
  { "updated_at": ..., "source": ..., "count": N,
    "orders": { "ZHBR260831034": {"d": "2026-09-06", "out": 305.6, "notify": 300.0, "st": "已审核"} } }
  d=发货日期(YYYY-MM-DD) ｜ out=累计出库数量(0=未发货) ｜ notify=累计发货通知数量 ｜ st=单据状态
"""
import io, json, math, os, sys, datetime

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(ROOT, '脚本'))
OUT = os.path.join(ROOT, '数据', 'erp_ship_dates.json')


def num(v):
    """⚠️ 空单元格在 dtype=str 读出的是字符串 'nan' —— float('nan') 不会抛异常，
    会让「未发货」(out==0) 统计永远为 0。必须显式判有限性。"""
    try:
        f = float(str(v).replace(',', ''))
    except Exception:
        return 0.0
    return f if math.isfinite(f) else 0.0


def main():
    import pandas as pd
    import erp_sales_core as E

    fp = E.find_latest_erp()
    if not fp:
        print('❌ 未找到 ERP 导出文件')
        return 1
    df = pd.read_excel(fp, dtype=str)
    print('源文件: %s ｜ %d 行' % (os.path.basename(fp), len(df)))

    orders = {}
    for _, r in df.iterrows():
        no = str(r.get('单据编号') or '').strip()
        if not no:
            continue
        o = orders.get(no)
        if o is None:
            o = orders[no] = {'d': str(r.get('发货日期') or '')[:10], 'out': 0.0, 'notify': 0.0,
                              'st': str(r.get('单据状态') or ''), 'ty': str(r.get('单据类型') or '')}
        o['out'] = round(o['out'] + num(r.get('累计出库数量')), 4)
        o['notify'] = round(o['notify'] + num(r.get('累计发货通知数量')), 4)

    n_future = sum(1 for o in orders.values() if o['d'] > datetime.date.today().isoformat())
    n_unshipped = sum(1 for o in orders.values() if o['out'] == 0)
    n_overdue = sum(1 for o in orders.values() if o['out'] == 0 and o['d'] and o['d'] < datetime.date.today().isoformat())
    payload = {
        'updated_at': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'source': os.path.basename(fp),
        'count': len(orders),
        'orders': orders,
    }
    with io.open(OUT, 'w', encoding='utf-8') as f:
        json.dump(payload, f, ensure_ascii=False, separators=(',', ':'))
    print('✅ 写入 %s（%d 单 ｜ %.1f KB）' % (OUT, len(orders), os.path.getsize(OUT) / 1024))
    print('   发货日期在未来的 %d 单 ｜ 未发货 %d 单 ｜ 其中已超期 %d 单' % (n_future, n_unshipped, n_overdue))
    return 0


if __name__ == '__main__':
    sys.exit(main())
