#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""归属修正分析（只读）：产出 15 家「有归属但错」+ 46 家「无归属」的完整明细 JSON。

主下单人判定规则（必须与用户口径一致，不得改变）：
  对每个客户，在其 2026 年【非赠品·标准销售订单·已审核】里，
  按「归并后的销售员」（应用 脚本/sp_merge.py 的 SP_MERGE + MGR_MERGE）汇总金额，
  取金额最大者为归属人。单值归属，不拆分。

部门归属（用于「放权后谁会看见」的部门列）：数据/pricing/_personnel.json 的 dept。
输出：.q3scratch/owner_fix_targets.json
"""
import os, sys, json
SD = '/Users/liuxinyuan/Desktop/Hermes输出-工作类/脚本'
sys.path.insert(0, SD)
import pandas as pd
import erp_sales_core as core
import sp_merge as _spm

W = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
MONTHS_ACT = [f'2026-{m:02d}' for m in range(1, 10)]

fp = core.find_latest_erp()
df = pd.read_excel(fp, dtype=str)
df['_amt'] = pd.to_numeric(df['价税合计'], errors='coerce').fillna(0)
df['_sp'] = df['销售员'].fillna('').astype(str)
pt_col = '客户采购类型#' if '客户采购类型#' in df.columns else ('产品类型#' if '产品类型#' in df.columns else None)
df['_date'] = df['合同日期'].apply(core.ser2date)
df['_month'] = df['_date'].str[:7]

std = df[(df['单据类型'] == '标准销售订单') & (df['单据状态'] == '已审核') & (df['是否赠品'] != '是')]
std = std[~std['客户'].astype(str).str.contains(core.BAORUI_PATTERN, na=False)].copy()
std['_amt'] = std['_amt'].astype(float)
person_dept, lzy = core.load_mappings()

cust_sp, cust_dept = {}, {}
for _, r in std.iterrows():
    m = str(r['_month'])
    if m not in MONTHS_ACT:
        continue
    sp = str(r['_sp']).strip()
    cust = str(r['客户']).strip()
    amt = float(r['_amt'])
    pt = str(r[pt_col]) if pt_col else ''
    kpi_person, dept = core.map_person(sp, cust, person_dept, lzy, pt)
    eff_sp = _spm.merge_sp(kpi_person or sp)
    cust_sp.setdefault(cust, {}).setdefault(eff_sp, 0.0)
    cust_sp[cust][eff_sp] += amt
    if dept:
        cust_dept.setdefault(cust, {}).setdefault(dept, 0.0)
        cust_dept[cust][dept] += amt

spm = (json.load(open(f'{W}/数据/customer_sp_map.json', encoding='utf-8')) or {}).get('map') or {}

rows = []
for cust, d in cust_sp.items():
    tot = sum(d.values())
    dominant = max(d.items(), key=lambda kv: kv[1])[0]
    raw_owner = (spm.get(cust) or '').strip() or None
    owner = _spm.merge_sp(raw_owner) if raw_owner else None
    if owner != dominant:
        rows.append({
            'cust': cust,
            'owner': owner or '(无归属)',
            'owner_raw': raw_owner,
            'dominant': dominant,
            'amt_total': round(tot / 1e4, 2),
            'sp_breakdown': {k: round(v / 1e4, 2) for k, v in sorted(d.items(), key=lambda kv: -kv[1])},
            'depts': {k: round(v / 1e4, 2) for k, v in sorted(cust_dept.get(cust, {}).items(), key=lambda kv: -kv[1])},
            'dominant_dept': person_dept.get(dominant) or '',
        })

rows.sort(key=lambda x: -x['amt_total'])
owned = [r for r in rows if r['owner'] != '(无归属)']
unowned = [r for r in rows if r['owner'] == '(无归属)']

# 边界标注
for r in owned:
    sb = r['sp_breakdown']
    vals = list(sb.values())
    r['low_confidence'] = (len(vals) >= 2 and vals[1] > 0 and (vals[0] - vals[1]) / vals[0] < 0.10)
    r['owner_is_manager'] = (r['dominant'] not in core.KPI_PEOPLE)

out = {
    'erp': os.path.basename(fp),
    'rule': '对每个客户，在其 2026 年非赠品、标准销售订单里，按「归并后的销售员」汇总金额，取金额最大者为归属人；单值归属，不拆分。',
    'total_mismatch': len(rows),
    'owned_count': len(owned), 'owned_amt': round(sum(r['amt_total'] for r in owned), 2),
    'unowned_count': len(unowned), 'unowned_amt': round(sum(r['amt_total'] for r in unowned), 2),
    'owned': owned, 'unowned': unowned,
}
json.dump(out, open(f'{W}/.q3scratch/owner_fix_targets.json', 'w', encoding='utf-8'), ensure_ascii=False, indent=1)

print(f"ERP={os.path.basename(fp)}  不一致={len(rows)}  有归属但错={len(owned)}({out['owned_amt']}万)  无归属={len(unowned)}({out['unowned_amt']}万)")
print("\n=== 有归属但错（本次全部改）===")
for i, r in enumerate(owned, 1):
    fl = []
    if r['low_confidence']: fl.append('低置信度')
    if r['owner_is_manager']: fl.append('主下单人为管理者')
    print(f"{i:2d}. {r['cust']} | {r['owner']} -> {r['dominant']} | {r['amt_total']}万 | dept={r['dominant_dept']} | {'/'.join(fl) or '-'}")
print(f"\n=== 无归属（不改，出清单）共 {len(unowned)} 家，{out['unowned_amt']}万 ===")
