Files
mileage-bonus/generate_q1_summary.py
kkfluous 1c85b8f230 V1.1.0 计算过程sheet金额列拆分,支持逐项对账
- 2月/3月计算过程sheet:各类金额独立成列(结转/补发1月/当月/累计补发)
- 金额列填0而非空值,支持Excel直接SUM对账
- 去掉合并的"最终发放类型/金额"列,改为"发放合计"列
- 车辆奖金池总览:从参考文件导入全量492辆车

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:44:35 +08:00

686 lines
32 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
里程考核绩效汇总生成脚本2026年Q1
老模型计算逻辑 + 完整Excel过程展示
"""
import openpyxl
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
from collections import defaultdict
import os
os.chdir('/Users/kkfluous/Downloads')
RULES = {
'交投40辆4.5T普货': {'km': 3000, '': 150},
'交投190辆4.5T冷链车': {'km': 3000, '': 150},
'羚牛136辆4.5T冷链车': {'km': 5000, '': 260},
'恒运50辆4.5T普货': {'km': 5000, '': 260},
'恒运50辆4.5T 普货': {'km': 5000, '': 260},
'羚牛100辆18T': {'km': 6000, '': 1000},
}
DAYS = {1: 31, 2: 28, 3: 31}
# ============================================================
# 读取
# ============================================================
def read_file(fp, month):
wb = openpyxl.load_workbook(fp, data_only=True)
ws = wb['业务考核视图']
h = [c.value for c in next(ws.iter_rows(min_row=1, max_row=1))]
recs = []
for row in ws.iter_rows(min_row=2, values_only=True):
r = dict(zip(h, row))
r['考核天数'] = float(r.get('考核天数') or 0)
r['应考核里程(km)'] = float(r.get('应考核里程(km)') or 0)
r['实际行驶里程(km)'] = float(r.get('实际行驶里程(km)') or 0)
r['月份'] = month
rule = RULES.get(r.get('考核目标', ''), {})
r['月度目标里程'] = rule.get('km', 0)
r['对应月奖励金额'] = rule.get('', 0)
t, a = r['应考核里程(km)'], r['实际行驶里程(km)']
q = a >= t and t > 0
r['是否达标'] = '达标' if q else '未达标'
r['奖金'] = r['对应月奖励金额'] * (r['考核天数'] / DAYS[month]) if q else 0
r['多跑'] = max(0, a - t) if q else 0
r['可结转'] = int(r['多跑'] // r['月度目标里程']) if r['月度目标里程'] > 0 and q else 0
recs.append(r)
wb.close()
return recs
print("读取...")
D = {1: read_file('租赁任务考核_2026年1月.xlsx', 1),
2: read_file('租赁任务考核_2026年2月.xlsx', 2),
3: read_file('租赁任务考核_2026年3月.xlsx', 3)}
for m in [1,2,3]: print(f" {m}月: {len(D[m])}")
# ============================================================
# 分组
# ============================================================
def grp(recs, month):
gs = defaultdict(lambda: {'recs':[], '应考核':0, '实际':0, '奖金':0, '天数':0,
'有达标':False, '目标km':0, '奖励额':0})
for r in recs:
k = (r['车牌号'], r['销售经理'])
g = gs[k]
g['recs'].append(r)
g['应考核'] += r['应考核里程(km)']
g['实际'] += r['实际行驶里程(km)']
g['奖金'] += r['奖金']
g['天数'] += r['考核天数']
if r['是否达标'] == '达标': g['有达标'] = True
g['目标km'] = max(g['目标km'], r['月度目标里程'])
g['奖励额'] = max(g['奖励额'], r['对应月奖励金额'])
g['部门'] = r['部门名称']
g['销售'] = r['销售经理']
g['车牌'] = r['车牌号']
return dict(gs)
G = {m: grp(D[m], m) for m in [1,2,3]}
# 1月结转
for k, g in G[1].items():
tc = 0
for r in g['recs']:
if r['是否达标'] == '达标':
tc += r['可结转']
g['可结转'] = tc
# ============================================================
# 2月计算老模型
# ============================================================
feb_data = {'结转':[], '补发1月':[], '当月':[], '累计补发2月':[]}
for k, g2 in G[2].items():
g1 = G[1].get(k)
bf = g2['奖励额']
j_t = g1['应考核'] if g1 else 0
j_a = g1['实际'] if g1 else 0
j_q = g1['有达标'] if g1 else False
j_c = g1['可结转'] if g1 else 0
cum_t = j_t + g2['应考核']
cum_a = j_a + g2['实际']
cum_q = cum_a >= cum_t and cum_t > 0
# A. 结转1月达标且多跑够整月 → 完整月奖金占2月名额
carry = 0
if g1 and j_q and j_c >= 1:
carry = bf
feb_data['结转'].append({'车牌':k[0], '销售':g1['销售'], '部门':g2['部门'], '':carry})
# B. 补发1月1月未达标累计全部达标后才补发
bp1 = 0
if g1 and not j_q and cum_q:
bp1 = g1['奖励额'] * (g1['天数'] / 31)
feb_data['补发1月'].append({'车牌':k[0], '销售':g1['销售'], '部门':g2['部门'], '':bp1})
# C. 当月2月单独达标且无结转占位
bonus2 = 0
if g2['有达标'] and carry == 0:
bonus2 = g2['奖金']
feb_data['当月'].append({'车牌':k[0], '销售':g2['销售'], '部门':g2['部门'], '':bonus2})
# D. 累计补发2月2月未达标+无结转+累计全部达标)
cbp2 = 0
if not g2['有达标'] and carry == 0 and cum_q:
cbp2 = g2['奖励额'] * (g2['天数'] / 28)
feb_data['累计补发2月'].append({'车牌':k[0], '销售':g2['销售'], '部门':g2['部门'], '':cbp2})
# 存group结果
g2['cum_t'] = cum_t; g2['cum_a'] = cum_a; g2['cum_q'] = cum_q
g2['结转'] = carry; g2['补发1月'] = bp1; g2['补发1月对应'] = g1['销售'] if g1 and bp1 > 0 else ''
g2['当月奖金'] = bonus2; g2['累计补发2月'] = cbp2
g2['结转占位'] = carry > 0
# 2月结转用于3月
fc = sum(r['可结转'] for r in g2['recs'] if r['是否达标'] == '达标')
jr = max(0, j_c - (1 if carry > 0 else 0))
g2['可结转'] = fc + jr
g2['2月已发'] = carry > 0 or bonus2 > 0 or cbp2 > 0
g2['1月已补发'] = bp1 > 0
print("\n2月:")
for cat in ['结转','补发1月','当月','累计补发2月']:
t = sum(d[''] for d in feb_data[cat])
print(f" {cat}: {len(feb_data[cat])}辆, {t:.2f}")
feb_total = sum(sum(d[''] for d in v) for v in feb_data.values())
print(f" 合计: {feb_total:.2f}")
# ============================================================
# 3月计算老模型
# ============================================================
mar_data = {'结转':[], '补发1月':[], '补发2月':[], '当月':[], '累计补发3月':[]}
for k, g3 in G[3].items():
g1 = G[1].get(k); g2 = G[2].get(k)
bf = g3['奖励额']
j_t = g1['应考核'] if g1 else 0; j_a = g1['实际'] if g1 else 0
j_q = g1['有达标'] if g1 else False
j_paid = (g1['奖金'] > 0) if g1 else False
f_t = g2['应考核'] if g2 else 0; f_a = g2['实际'] if g2 else 0
f_q = g2['有达标'] if g2 else False
f_paid = g2['2月已发'] if g2 else False
f_carry = g2['可结转'] if g2 else 0
# 1月是否已发1月自己达标 或 2月补发过
if g1 and j_q: j_paid = True
if g2 and g2.get('1月已补发', False): j_paid = True
cum_t = j_t + f_t + g3['应考核']
cum_a = j_a + f_a + g3['实际']
cum_q = cum_a >= cum_t and cum_t > 0
# A. 结转
carry = 0
if g2 and f_carry >= 1:
carry = bf
mar_data['结转'].append({'车牌':k[0], '销售':g2['销售'], '部门':g3['部门'], '':carry})
# B. 补发1月1月未发 + 累计全部达标)
bj = 0
if g1 and not j_paid and cum_q:
bj = g1['奖励额'] * (g1['天数'] / 31)
mar_data['补发1月'].append({'车牌':k[0], '销售':g1['销售'], '部门':g3['部门'], '':bj})
# C. 补发2月2月未发 + 累计全部达标)
bf2 = 0
if g2 and not f_paid and cum_q:
bf2 = g2['奖励额'] * (g2['天数'] / 28)
mar_data['补发2月'].append({'车牌':k[0], '销售':g2['销售'], '部门':g3['部门'], '':bf2})
# D. 当月3月单独达标且无结转占位
bonus3 = 0
if g3['有达标'] and carry == 0:
bonus3 = g3['奖金']
mar_data['当月'].append({'车牌':k[0], '销售':g3['销售'], '部门':g3['部门'], '':bonus3})
# E. 累计补发3月3月未达标+无结转+累计全部达标)
cbp3 = 0
if not g3['有达标'] and carry == 0 and cum_q:
cbp3 = g3['奖励额'] * (g3['天数'] / 31)
mar_data['累计补发3月'].append({'车牌':k[0], '销售':g3['销售'], '部门':g3['部门'], '':cbp3})
g3['cum_t'] = cum_t; g3['cum_a'] = cum_a; g3['cum_q'] = cum_q
g3['结转'] = carry; g3['补发1月'] = bj; g3['补发1月对应'] = g1['销售'] if g1 and bj>0 else ''
g3['补发2月'] = bf2; g3['补发2月对应'] = g2['销售'] if g2 and bf2>0 else ''
g3['当月奖金'] = bonus3; g3['累计补发3月'] = cbp3
g3['结转占位'] = carry > 0
print("\n3月:")
for cat in ['结转','补发1月','补发2月','当月','累计补发3月']:
t = sum(d[''] for d in mar_data[cat])
print(f" {cat}: {len(mar_data[cat])}辆, {t:.2f}")
mar_total = sum(sum(d[''] for d in v) for v in mar_data.values())
print(f" 合计: {mar_total:.2f}")
jan_total = sum(r['奖金'] for r in D[1])
jan_q = sum(1 for r in D[1] if r['是否达标'] == '达标')
print(f"\n1月: {jan_q}条达标, {jan_total:.2f}")
print(f"Q1总计: {jan_total + feb_total + mar_total:.2f}")
# ============================================================
# 车辆发放追踪12个月奖金池
# ============================================================
# 收集每辆车的所有发放记录: {车牌号: [{'结算月','对应考核月','业务员','金额','类型','期数'}]}
vehicle_payments = defaultdict(list)
vehicle_info = {} # {车牌号: {'考核目标','月度奖励','月度目标里程'}}
# 1月当月达标
for k, g in G[1].items():
plate = k[0]
if not vehicle_info.get(plate):
first = g['recs'][0]
vehicle_info[plate] = {'考核目标': first.get('考核目标',''), '月度奖励': g['奖励额'], '月度目标里程': g['目标km']}
if g['奖金'] > 0:
vehicle_payments[plate].append({
'结算月': 1, '对应考核月': 1, '业务员': g['销售'], '金额': g['奖金'],
'类型': '当月达标', '部门': g['部门']})
# 2月各类
for d in feb_data['结转']:
vehicle_payments[d['车牌']].append({'结算月':2, '对应考核月':2, '业务员':d['销售'], '金额':d[''], '类型':'结转', '部门':d['部门']})
for d in feb_data['补发1月']:
vehicle_payments[d['车牌']].append({'结算月':2, '对应考核月':1, '业务员':d['销售'], '金额':d[''], '类型':'补发', '部门':d['部门']})
for d in feb_data['当月']:
vehicle_payments[d['车牌']].append({'结算月':2, '对应考核月':2, '业务员':d['销售'], '金额':d[''], '类型':'当月达标', '部门':d['部门']})
for d in feb_data['累计补发2月']:
vehicle_payments[d['车牌']].append({'结算月':2, '对应考核月':2, '业务员':d['销售'], '金额':d[''], '类型':'累计补发', '部门':d['部门']})
# 3月各类
for d in mar_data['结转']:
vehicle_payments[d['车牌']].append({'结算月':3, '对应考核月':3, '业务员':d['销售'], '金额':d[''], '类型':'结转', '部门':d['部门']})
for d in mar_data['补发1月']:
vehicle_payments[d['车牌']].append({'结算月':3, '对应考核月':1, '业务员':d['销售'], '金额':d[''], '类型':'补发', '部门':d['部门']})
for d in mar_data['补发2月']:
vehicle_payments[d['车牌']].append({'结算月':3, '对应考核月':2, '业务员':d['销售'], '金额':d[''], '类型':'补发', '部门':d['部门']})
for d in mar_data['当月']:
vehicle_payments[d['车牌']].append({'结算月':3, '对应考核月':3, '业务员':d['销售'], '金额':d[''], '类型':'当月达标', '部门':d['部门']})
for d in mar_data['累计补发3月']:
vehicle_payments[d['车牌']].append({'结算月':3, '对应考核月':3, '业务员':d['销售'], '金额':d[''], '类型':'累计补发', '部门':d['部门']})
# 补充vehicle_info
for m in [2,3]:
for k, g in G[m].items():
plate = k[0]
if not vehicle_info.get(plate):
first = g['recs'][0]
vehicle_info[plate] = {'考核目标': first.get('考核目标',''), '月度奖励': g['奖励额'], '月度目标里程': g['目标km']}
# 为每辆车的发放记录按对应考核月排序并编期数
for plate in vehicle_payments:
records = sorted(vehicle_payments[plate], key=lambda x: (x['对应考核月'], x['结算月']))
for i, r in enumerate(records):
r['期数'] = i + 1
# ============================================================
# Excel输出
# ============================================================
print("\n生成Excel...")
wb = openpyxl.Workbook()
hf = Font(bold=True)
hfl = PatternFill(start_color='D9E1F2', end_color='D9E1F2', fill_type='solid')
bd = Border(left=Side(style='thin'),right=Side(style='thin'),top=Side(style='thin'),bottom=Side(style='thin'))
def WH(ws, headers, row=1):
for c, h in enumerate(headers, 1):
cl = ws.cell(row=row, column=c, value=h)
cl.font = hf; cl.fill = hfl; cl.border = bd; cl.alignment = Alignment(horizontal='center', wrap_text=True)
def WR(ws, rn, vals):
for c, v in enumerate(vals, 1):
cl = ws.cell(row=rn, column=c, value=v); cl.border = bd
def AW(ws):
for col in ws.columns:
ml = max((len(str(c.value or '')) for c in col), default=0)
ws.column_dimensions[col[0].column_letter].width = min(ml+3, 22)
def R(v, n=2): return round(v, n) if isinstance(v, (int,float)) and v else v
def agg(dl):
bp = defaultdict(lambda: {'n':0, 'a':0})
for d in dl: bp[d['销售']]['n'] += 1; bp[d['销售']]['a'] += d['']
return dict(bp)
def write_sec(ws, rn, title, dl):
ws.cell(row=rn, column=1, value=title).font = Font(bold=True, size=11); rn+=1
WH(ws, ['销售人员','车辆数','金额'], rn); rn+=1
bp = agg(dl); tv=ta=0
for p in sorted(bp.keys()):
WR(ws, rn, [p, bp[p]['n'], R(bp[p]['a'])]); tv+=bp[p]['n']; ta+=bp[p]['a']; rn+=1
WR(ws, rn, ['总计', tv, R(ta)]); ws.cell(row=rn,column=1).font=hf; return rn+2
def write_total(ws, rn, month, all_data):
total_bp = defaultdict(lambda: {'部门':'', '':0})
for cat, dl in all_data.items():
for d in dl: total_bp[d['销售']][''] += d['']; total_bp[d['销售']]['部门'] = d['部门']
ws.cell(row=rn, column=1, value=f'{month}月合计应发奖励(按销售人员)').font=Font(bold=True, size=11); rn+=1
WH(ws, ['销售人员','部门名称','合计应发奖励'], rn); rn+=1
gt=0
for p in sorted(total_bp.keys()):
WR(ws, rn, [p, total_bp[p]['部门'], R(total_bp[p][''])]); gt+=total_bp[p]['']; rn+=1
WR(ws, rn, ['合计','', R(gt)]); ws.cell(row=rn,column=1).font=hf; rn+=2
by_dept = defaultdict(float)
for p,d in total_bp.items(): by_dept[d['部门']] += d['']
ws.cell(row=rn, column=1, value=f'{month}月合计应发奖励(按部门)').font=Font(bold=True, size=11); rn+=1
WH(ws, ['部门名称','合计应发奖励'], rn); rn+=1
for dept in sorted(by_dept.keys()): WR(ws, rn, [dept, R(by_dept[dept])]); rn+=1
WR(ws, rn, ['合计', R(gt)]); ws.cell(row=rn,column=1).font=hf
# ---- 考核奖励规则 ----
ws0 = wb.active; ws0.title='考核奖励规则'
WH(ws0, ['考核目标','月度目标里程(km)','奖励金额(元)'])
for i,(n,km,b) in enumerate([('交投40辆4.5T普货',3000,150),('交投190辆4.5T冷链车',3000,150),
('羚牛136辆4.5T冷链车',5000,260),('恒运50辆4.5T普货',5000,260),('羚牛100辆18T',6000,1000)],2):
WR(ws0,i,[n,km,b])
AW(ws0)
# ---- 里程明细1月 ----
ws1 = wb.create_sheet('里程明细1月')
WH(ws1, ['车牌号','部门名称','销售经理','客户名称','合同编号','考核目标','月度目标里程','对应月奖励金额',
'考核天数','1月应考核里程','1月实际行驶里程','完成率','1月是否达标',
'1月奖金(天数折算)','多跑里程','可结转月数','考核状态'])
rn=2
for r in sorted(D[1], key=lambda x: (x['销售经理'],x['车牌号'])):
t,a = r['应考核里程(km)'], r['实际行驶里程(km)']
WR(ws1, rn, [r['车牌号'],r['部门名称'],r['销售经理'],r.get('客户名称',''),r.get('合同编号',''),
r.get('考核目标',''),r['月度目标里程'],r['对应月奖励金额'],r['考核天数'],
R(t),R(a),R(a/t,4) if t>0 else 0,r['是否达标'],R(r['奖金']),R(r['多跑']),r['可结转'],
r.get('考核状态','')]); rn+=1
AW(ws1)
# ---- 1月汇总 ----
ws1s = wb.create_sheet('1月汇总')
jan_dl = [{'车牌':r['车牌号'],'销售':r['销售经理'],'部门':r['部门名称'],'':r['奖金']}
for r in D[1] if r['是否达标']=='达标']
rn = write_sec(ws1s, 1, '1月达标奖励', jan_dl)
write_total(ws1s, rn, 1, {'达标': jan_dl})
AW(ws1s)
# ---- 里程明细2月完整过程----
ws2 = wb.create_sheet('里程明细2月')
WH(ws2, ['车牌号','部门名称','1月销售经理','2月销售经理','是否同一销售',
'客户名称','合同编号','考核目标','月度目标里程','对应月奖励金额',
'1月天数','1月应考核','1月实际','1月是否达标','1月奖金','1月多跑','1月可结转',
'2月考核天数','2月应考核','2月实际','2月完成率','2月是否达标','2月奖金(天数折算)',
'1+2月累计应完成','1+2月累计实际','累计完成率','累计是否达标',
'结转占位','结转金额','补发1月金额','补发1月对应','累计补发2月金额','累计补发2月对应',
'2月当月金额','2月当月对应','考核状态'])
rn=2
for r in sorted(D[2], key=lambda x: (x['销售经理'],x['车牌号'])):
k = (r['车牌号'], r['销售经理'])
g2 = G[2].get(k, {}); g1 = G[1].get(k)
js = g1['销售'] if g1 else ''
jd = g1['天数'] if g1 else 0; jt = g1['应考核'] if g1 else 0; ja = g1['实际'] if g1 else 0
jq = '达标' if (g1 and g1['有达标']) else '未达标'
jb = g1['奖金'] if g1 else 0
je = sum(r2['多跑'] for r2 in g1['recs'] if r2['是否达标']=='达标') if g1 else 0
jc = g1['可结转'] if g1 else 0
t,a = r['应考核里程(km)'], r['实际行驶里程(km)']
ct = g2.get('cum_t',0); ca = g2.get('cum_a',0); cq = g2.get('cum_q',False)
carry = g2.get('结转',0); bp1 = g2.get('补发1月',0); bp1p = g2.get('补发1月对应','')
cbp2 = g2.get('累计补发2月',0); b2 = g2.get('当月奖金',0)
WR(ws2, rn, [r['车牌号'],r['部门名称'],js,r['销售经理'],
'' if js==r['销售经理'] and js else '',
r.get('客户名称',''),r.get('合同编号',''),r.get('考核目标',''),
r['月度目标里程'],r['对应月奖励金额'],
jd,R(jt),R(ja),jq,R(jb),R(je),jc,
r['考核天数'],R(t),R(a),R(a/t,4) if t>0 else 0,r['是否达标'],R(r['奖金']),
R(ct),R(ca),R(ca/ct,4) if ct>0 else 0,'达标' if cq else '未达标',
'' if g2.get('结转占位') else '',
R(carry) if carry>0 else '', R(bp1) if bp1>0 else '', bp1p if bp1>0 else '',
R(cbp2) if cbp2>0 else '', g2.get('销售','') if cbp2>0 else '',
R(b2) if b2>0 else '', r['销售经理'] if b2>0 else '',
r.get('考核状态','')]); rn+=1
AW(ws2)
# ---- 2月汇总 ----
ws2s = wb.create_sheet('2月汇总')
rn=1
rn = write_sec(ws2s, rn, '一、结转1月多跑在2月发', feb_data['结转'])
rn = write_sec(ws2s, rn, '二、补发1月', feb_data['补发1月'])
rn = write_sec(ws2s, rn, '三、2月当月奖励', feb_data['当月'])
rn = write_sec(ws2s, rn, '四、累计达标补发2月', feb_data['累计补发2月'])
write_total(ws2s, rn, 2, feb_data)
AW(ws2s)
# ---- 里程明细3月完整过程----
ws3 = wb.create_sheet('里程明细3月')
WH(ws3, ['车牌号','部门名称','1月销售','2月销售','3月销售',
'客户名称','合同编号','考核目标','月度目标里程','对应月奖励金额',
'1月天数','1月应考核','1月实际','1月是否达标','1月奖金','1月多跑','1月可结转',
'2月天数','2月应考核','2月实际','2月是否达标','2月奖金','2月发放类型',
'3月考核天数','3月应考核','3月实际','3月完成率','3月是否达标','3月奖金(天数折算)',
'1-3月累计应完成','1-3月累计实际','累计完成率','累计是否达标',
'结转占位','结转金额','补发1月金额','补发1月对应','补发2月金额','补发2月对应',
'累计补发3月金额','累计补发3月对应','3月当月金额','3月当月对应','考核状态'])
rn=2
for r in sorted(D[3], key=lambda x: (x['销售经理'],x['车牌号'])):
k = (r['车牌号'], r['销售经理'])
g3 = G[3].get(k,{}); g2 = G[2].get(k); g1 = G[1].get(k)
js = g1['销售'] if g1 else ''
jd = g1['天数'] if g1 else 0; jt = g1['应考核'] if g1 else 0; ja = g1['实际'] if g1 else 0
jq = '达标' if (g1 and g1['有达标']) else '未达标'
jb = g1['奖金'] if g1 else 0
je = sum(r2['多跑'] for r2 in g1['recs'] if r2['是否达标']=='达标') if g1 else 0
jc = g1['可结转'] if g1 else 0
fs = g2['销售'] if g2 else ''
fd = g2['天数'] if g2 else 0; ft = g2['应考核'] if g2 else 0; fa = g2['实际'] if g2 else 0
fq = '达标' if (g2 and g2['有达标']) else '未达标'
fb = g2['奖金'] if g2 else 0
ftype = ''
if g2:
if g2.get('结转',0)>0: ftype='结转'
elif g2.get('当月奖金',0)>0: ftype='当月'
elif g2.get('累计补发2月',0)>0: ftype='累计补发'
else: ftype=''
t,a = r['应考核里程(km)'], r['实际行驶里程(km)']
ct = g3.get('cum_t',0); ca = g3.get('cum_a',0); cq = g3.get('cum_q',False)
carry = g3.get('结转',0); bj = g3.get('补发1月',0); bjp = g3.get('补发1月对应','')
bf = g3.get('补发2月',0); bfp = g3.get('补发2月对应','')
cb3 = g3.get('累计补发3月',0); b3 = g3.get('当月奖金',0)
WR(ws3, rn, [r['车牌号'],r['部门名称'],js,fs,r['销售经理'],
r.get('客户名称',''),r.get('合同编号',''),r.get('考核目标',''),
r['月度目标里程'],r['对应月奖励金额'],
jd,R(jt),R(ja),jq,R(jb),R(je),jc,
fd,R(ft),R(fa),fq,R(fb),ftype,
r['考核天数'],R(t),R(a),R(a/t,4) if t>0 else 0,r['是否达标'],R(r['奖金']),
R(ct),R(ca),R(ca/ct,4) if ct>0 else 0,'达标' if cq else '未达标',
'' if g3.get('结转占位') else '',
R(carry) if carry>0 else '', R(bj) if bj>0 else '', bjp if bj>0 else '',
R(bf) if bf>0 else '', bfp if bf>0 else '',
R(cb3) if cb3>0 else '', r['销售经理'] if cb3>0 else '',
R(b3) if b3>0 else '', r['销售经理'] if b3>0 else '',
r.get('考核状态','')]); rn+=1
AW(ws3)
# ---- 3月汇总 ----
ws3s = wb.create_sheet('3月汇总')
rn=1
rn = write_sec(ws3s, rn, '一、结转2月多跑在3月发', mar_data['结转'])
rn = write_sec(ws3s, rn, '二、补发1月', mar_data['补发1月'])
rn = write_sec(ws3s, rn, '三、补发2月', mar_data['补发2月'])
rn = write_sec(ws3s, rn, '四、3月当月奖励', mar_data['当月'])
rn = write_sec(ws3s, rn, '五、累计达标补发3月', mar_data['累计补发3月'])
write_total(ws3s, rn, 3, mar_data)
AW(ws3s)
# ---- 1月计算过程每个group一行----
ws_p1 = wb.create_sheet('1月计算过程')
WH(ws_p1, [
'车牌号','销售经理','部门',
'①记录数','②总考核天数','③总应考核里程','④总实际里程',
'⑤有达标记录','⑥达标记录奖金合计',
'⑦总多跑里程','⑧月度目标里程','⑨可结转月数=floor(⑦/⑧)',
'→1月发放金额','→发放类型'
])
rn=2
for k in sorted(G[1].keys(), key=lambda x: (x[1],x[0])):
g = G[1][k]
excess = sum(r['多跑'] for r in g['recs'] if r['是否达标']=='达标')
WR(ws_p1, rn, [
k[0], k[1], g['部门'],
len(g['recs']), g['天数'], R(g['应考核']), R(g['实际']),
'' if g['有达标'] else '', R(g['奖金']),
R(excess), g['目标km'], g['可结转'],
R(g['奖金']) if g['有达标'] else 0, '当月达标' if g['有达标'] else '未达标'
]); rn+=1
AW(ws_p1)
# ---- 2月计算过程每个group一行完整判断链----
ws_p2 = wb.create_sheet('2月计算过程')
WH(ws_p2, [
'车牌号','销售经理','部门',
# 1月group数据
'1月总应考核','1月总实际','1月有达标','1月奖金','1月多跑','1月可结转',
# 2月group数据
'2月记录数','2月总天数','2月总应考核','2月总实际','2月有达标','2月达标奖金',
# 累计
'累计应完成','累计实际','累计是否达标',
# 判断链
'判断①结转: 1月达标且可结转≥1?','→结转金额(完整月)',
'判断②补发1月: 1月未达标且累计达标?','→补发1月金额',
'判断③当月: 2月达标且无结转?','→2月当月金额',
'判断④累计补发2月: 2月未达标+无结转+累计达标?','→累计补发2月金额',
'2月发放合计'
])
rn=2
for k in sorted(G[2].keys(), key=lambda x: (x[1],x[0])):
g2 = G[2][k]; g1 = G[1].get(k)
j_q = g1['有达标'] if g1 else False
j_c = g1['可结转'] if g1 else 0
j_bonus = g1['奖金'] if g1 else 0
j_t = g1['应考核'] if g1 else 0; j_a = g1['实际'] if g1 else 0
j_excess = sum(r['多跑'] for r in g1['recs'] if r['是否达标']=='达标') if g1 else 0
ct = g2.get('cum_t',0); ca = g2.get('cum_a',0); cq = g2.get('cum_q',False)
carry = g2.get('结转',0); bp1 = g2.get('补发1月',0)
bonus2 = g2.get('当月奖金',0); cbp2 = g2.get('累计补发2月',0)
# 判断链文字
c1_check = f"1月达标={j_q}, 可结转={j_c}" if g1 else "无1月数据"
c1_result = '是→结转' if carry>0 else ''
c2_check = f"1月未达标={not j_q}, 累计达标={cq}" if g1 else "无1月"
c2_result = '是→补发' if bp1>0 else ''
c3_check = f"2月达标={g2['有达标']}, 无结转={carry==0}"
c3_result = '是→当月' if bonus2>0 else ''
c4_check = f"2月未达标={not g2['有达标']}, 无结转={carry==0}, 累计达标={cq}"
c4_result = '是→累计补发' if cbp2>0 else ''
total_feb = carry + bp1 + bonus2 + cbp2
WR(ws_p2, rn, [
k[0], k[1], g2['部门'],
R(j_t), R(j_a), '' if j_q else '', R(j_bonus), R(j_excess), j_c,
len(g2['recs']), g2['天数'], R(g2['应考核']), R(g2['实际']),
'' if g2['有达标'] else '', R(g2['奖金']),
R(ct), R(ca), '达标' if cq else '未达标',
f"{c1_check}{c1_result}", R(carry) if carry>0 else 0,
f"{c2_check}{c2_result}", R(bp1) if bp1>0 else 0,
f"{c3_check}{c3_result}", R(bonus2) if bonus2>0 else 0,
f"{c4_check}{c4_result}", R(cbp2) if cbp2>0 else 0,
R(total_feb) if total_feb>0 else 0
]); rn+=1
AW(ws_p2)
# ---- 3月计算过程 ----
ws_p3 = wb.create_sheet('3月计算过程')
WH(ws_p3, [
'车牌号','销售经理','部门',
'1月应考核','1月实际','1月有达标','1月奖金已发',
'2月应考核','2月实际','2月有达标','2月奖金已发',
'3月记录数','3月总天数','3月总应考核','3月总实际','3月有达标','3月达标奖金',
'累计应完成','累计实际','累计是否达标',
'判断①结转','→结转金额',
'判断②补发1月','→补发1月金额',
'判断③补发2月','→补发2月金额',
'判断④当月','→3月当月金额',
'判断⑤累计补发3月','→累计补发3月金额',
'3月发放合计'
])
rn=2
for k in sorted(G[3].keys(), key=lambda x: (x[1],x[0])):
g3 = G[3][k]; g2 = G[2].get(k); g1 = G[1].get(k)
j_t = g1['应考核'] if g1 else 0; j_a = g1['实际'] if g1 else 0
j_q = g1['有达标'] if g1 else False
j_paid = (g1['奖金']>0) if g1 else False
if g2 and g2.get('1月已补发',False): j_paid = True
if g1 and j_q: j_paid = True
f_t = g2['应考核'] if g2 else 0; f_a = g2['实际'] if g2 else 0
f_q = g2['有达标'] if g2 else False
f_paid = g2['2月已发'] if g2 else False
f_carry = g2['可结转'] if g2 else 0
ct = g3.get('cum_t',0); ca = g3.get('cum_a',0); cq = g3.get('cum_q',False)
carry = g3.get('结转',0); bj = g3.get('补发1月',0)
bf2 = g3.get('补发2月',0); bonus3 = g3.get('当月奖金',0); cbp3 = g3.get('累计补发3月',0)
c1 = f"2月可结转={f_carry}{'' if carry>0 else ''}"
c2 = f"1月未发={not j_paid}, 累计达标={cq}{'' if bj>0 else ''}"
c3 = f"2月未发={not f_paid}, 累计达标={cq}{'' if bf2>0 else ''}"
c4 = f"3月达标={g3['有达标']}, 无结转={carry==0}{'' if bonus3>0 else ''}"
c5 = f"3月未达标={not g3['有达标']}, 无结转={carry==0}, 累计达标={cq}{'' if cbp3>0 else ''}"
total_mar = carry + bj + bf2 + bonus3 + cbp3
WR(ws_p3, rn, [
k[0], k[1], g3['部门'],
R(j_t), R(j_a), '' if j_q else '', '' if j_paid else '',
R(f_t), R(f_a), '' if f_q else '', '' if f_paid else '',
len(g3['recs']), g3['天数'], R(g3['应考核']), R(g3['实际']),
'' if g3['有达标'] else '', R(g3['奖金']),
R(ct), R(ca), '达标' if cq else '未达标',
c1, R(carry) if carry>0 else 0,
c2, R(bj) if bj>0 else 0,
c3, R(bf2) if bf2>0 else 0,
c4, R(bonus3) if bonus3>0 else 0,
c5, R(cbp3) if cbp3>0 else 0,
R(total_mar) if total_mar>0 else 0
]); rn+=1
AW(ws_p3)
# ---- 车辆发放明细(每笔发放一行)----
ws_pay = wb.create_sheet('车辆发放明细')
WH(ws_pay, ['车牌号','考核目标','月度奖励金额',
'期数(第N期/共12期)','对应考核月','结算月(实际发放月)','发放类型',
'业务员','部门','发放金额'])
rn = 2
for plate in sorted(vehicle_payments.keys()):
info = vehicle_info.get(plate, {})
for p in vehicle_payments[plate]:
WR(ws_pay, rn, [
plate, info.get('考核目标',''), info.get('月度奖励',0),
f"{p['期数']}期/共12期", f"{p['对应考核月']}", f"{p['结算月']}",
p['类型'], p['业务员'], p['部门'], R(p['金额'])
]); rn += 1
AW(ws_pay)
# ---- 车辆奖金池总览全量492辆从参考文件车辆总览导入----
ws_pool = wb.create_sheet('车辆奖金池总览')
WH(ws_pool, ['车牌号','车架号','归属公司','车型',
'考核目标','月度奖励金额','奖金池总额(12期)',
'1月发放业务员','1月发放金额','1月发放类型',
'2月发放业务员','2月发放金额','2月发放类型',
'3月发放业务员','3月发放金额','3月发放类型',
'Q1已发期数','Q1已发金额','剩余可发期数'])
# 读取全量车辆台账
master_wb = openpyxl.load_workbook('里程任务考核_2 月核算.xlsx', data_only=True)
master_ws = master_wb['考核车辆总览']
master_h = [c.value for c in next(master_ws.iter_rows(min_row=1, max_row=1))]
master_vehicles = []
for row in master_ws.iter_rows(min_row=2, values_only=True):
r = dict(zip(master_h, row))
if r.get('车牌号'):
master_vehicles.append(r)
master_wb.close()
rn = 2
for mv in master_vehicles:
plate = mv['车牌号']
info = vehicle_info.get(plate, {})
pays = vehicle_payments.get(plate, [])
# 考核目标和月度奖励:优先从考核数据取,否则留空
target_name = info.get('考核目标', '')
monthly_bonus = info.get('月度奖励', 0)
pool_total = monthly_bonus * 12 if monthly_bonus else ''
by_month = {1: [], 2: [], 3: []}
for p in pays:
by_month[p['结算月']].append(p)
def month_summary(ml):
if not ml: return '', '', ''
persons = ', '.join(sorted(set(p['业务员'] for p in ml)))
total = sum(p['金额'] for p in ml)
types = ', '.join(sorted(set(p['类型'] for p in ml)))
return persons, R(total), types
m1p, m1a, m1t = month_summary(by_month[1])
m2p, m2a, m2t = month_summary(by_month[2])
m3p, m3a, m3t = month_summary(by_month[3])
total_periods = len(pays)
total_amount = sum(p['金额'] for p in pays)
remaining = (12 - total_periods) if monthly_bonus else ''
WR(ws_pool, rn, [
plate, mv.get('车架号',''), mv.get('归属公司',''), mv.get('车型确定',''),
target_name, monthly_bonus or '', pool_total,
m1p, m1a, m1t, m2p, m2a, m2t, m3p, m3a, m3t,
total_periods if total_periods > 0 else 0,
R(total_amount) if total_amount > 0 else 0,
remaining
]); rn += 1
AW(ws_pool)
out = '/Users/kkfluous/Downloads/里程任务考核_Q1汇总.xlsx'
wb.save(out)
print(f"\n{out}")