V1.0.0 里程考核绩效汇总脚本
核心计算逻辑: - 每条记录独立达标判断和奖金计算(按天折算) - 按(车牌号+销售经理)分组做结转/累计/补发 - 结转:floor(多跑/月度目标)≥1 → 完整月奖金,占当月名额 - 补发:累计全部达标后补发未达标月份 - 累计补发当月:当月未达标+无结转+累计达标 - 12个月奖金池追踪 Excel输出12个sheet: - 考核奖励规则 - 里程明细1/2/3月(逐条记录+发放归类) - 1/2/3月汇总(分section+按人/部门) - 1/2/3月计算过程(每组一行,完整判断链) - 车辆发放明细(每笔发放一行,含期数) - 车辆奖金池总览(全量492辆) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
695
generate_q1_summary.py
Normal file
695
generate_q1_summary.py
Normal file
@@ -0,0 +1,695 @@
|
||||
#!/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 '', '当月达标' 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月金额',
|
||||
'最终发放类型','最终发放金额'
|
||||
])
|
||||
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 '否'
|
||||
|
||||
final_type = '结转' if carry>0 else ('当月' if bonus2>0 else ('累计补发2月' if cbp2>0 else '无'))
|
||||
final_amt = carry or bonus2 or cbp2 or 0
|
||||
# 补发1月是额外的,不影响2月的发放类型
|
||||
if bp1>0: final_type += '+补发1月'
|
||||
if bp1>0: final_amt += bp1
|
||||
|
||||
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 '',
|
||||
f"{c2_check} → {c2_result}", R(bp1) if bp1>0 else '',
|
||||
f"{c3_check} → {c3_result}", R(bonus2) if bonus2>0 else '',
|
||||
f"{c4_check} → {c4_result}", R(cbp2) if cbp2>0 else '',
|
||||
final_type, R(final_amt) if final_amt>0 else ''
|
||||
]); 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月金额',
|
||||
'最终发放类型','最终发放金额'
|
||||
])
|
||||
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 '否'}"
|
||||
|
||||
parts = []
|
||||
total = 0
|
||||
if carry>0: parts.append('结转'); total+=carry
|
||||
if bj>0: parts.append('补发1月'); total+=bj
|
||||
if bf2>0: parts.append('补发2月'); total+=bf2
|
||||
if bonus3>0: parts.append('当月'); total+=bonus3
|
||||
if cbp3>0: parts.append('累计补发3月'); total+=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 '',
|
||||
c2, R(bj) if bj>0 else '',
|
||||
c3, R(bf2) if bf2>0 else '',
|
||||
c4, R(bonus3) if bonus3>0 else '',
|
||||
c5, R(cbp3) if cbp3>0 else '',
|
||||
'+'.join(parts) if parts else '无', R(total) if total>0 else ''
|
||||
]); 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}")
|
||||
Reference in New Issue
Block a user