V3.1.0 新增奖金发放记录sheet,汇总改为从发放记录生成
数据链路:车辆考核追踪 → 奖金发放记录 → 月汇总 - 奖金发放记录:逐条明细,含车牌/业务员/部门/客户/发放类型/考核应发/客户盈亏/亏损拦截/实发 - 亏损→红底,未匹配→黄底,正常发放→绿底 - 月汇总改为从发放记录SUM生成:考核应发→亏损筛选→最终发放 - 业务员列不带部门前缀(部门独立列) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
143
excel_writer.py
143
excel_writer.py
@@ -199,6 +199,149 @@ def write_summary_jan(wb, records, loss_data=None, plate_client=None):
|
|||||||
write_total(ws,rn,1,{'达标':jan_dl})
|
write_total(ws,rn,1,{'达标':jan_dl})
|
||||||
AW(ws)
|
AW(ws)
|
||||||
|
|
||||||
|
def build_payment_records(month, month_data, loss_data, plate_client):
|
||||||
|
"""构建奖金发放记录列表,每条考核应发一行,叠加亏损筛选"""
|
||||||
|
records = []
|
||||||
|
for cat, dl in month_data.items():
|
||||||
|
for d in dl:
|
||||||
|
client = (plate_client or {}).get(d['车牌'], '')
|
||||||
|
if loss_data:
|
||||||
|
loss_status = loss_data.get(client, '未匹配') if client else '未匹配'
|
||||||
|
else:
|
||||||
|
loss_status = '否' # 无亏损表视为不亏损
|
||||||
|
|
||||||
|
考核应发 = d['额']
|
||||||
|
if loss_status == '是':
|
||||||
|
拦截 = 考核应发; 实发 = 0
|
||||||
|
elif loss_status == '未匹配' and loss_data:
|
||||||
|
拦截 = 考核应发; 实发 = 0
|
||||||
|
else:
|
||||||
|
拦截 = 0; 实发 = 考核应发
|
||||||
|
|
||||||
|
records.append({
|
||||||
|
'车牌号': d['车牌'],
|
||||||
|
'业务员': d['销售'],
|
||||||
|
'部门': d['部门'],
|
||||||
|
'客户名称': client,
|
||||||
|
'发放类型': cat,
|
||||||
|
'考核应发': 考核应发,
|
||||||
|
'客户盈亏': loss_status,
|
||||||
|
'亏损拦截': 拦截,
|
||||||
|
'实发金额': 实发,
|
||||||
|
})
|
||||||
|
return records
|
||||||
|
|
||||||
|
def write_payment_record_sheet(wb, month, payment_records):
|
||||||
|
"""写入奖金发放记录sheet"""
|
||||||
|
ws = wb.create_sheet(f'{month}月奖金发放记录')
|
||||||
|
|
||||||
|
headers = ['车牌号','业务员','部门','客户名称','发放类型',
|
||||||
|
'考核应发','客户盈亏','亏损拦截','实发金额']
|
||||||
|
WH(ws, headers)
|
||||||
|
|
||||||
|
green_fill = PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid')
|
||||||
|
red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
|
||||||
|
yellow_fill = PatternFill(start_color='FFFFCC', end_color='FFFFCC', fill_type='solid')
|
||||||
|
|
||||||
|
rn = 2
|
||||||
|
for r in sorted(payment_records, key=lambda x: (x['业务员'], x['车牌号'])):
|
||||||
|
WR(ws, rn, [r['车牌号'], r['业务员'], r['部门'], r['客户名称'], r['发放类型'],
|
||||||
|
R(r['考核应发']), r['客户盈亏'], R(r['亏损拦截']), R(r['实发金额'])])
|
||||||
|
# 颜色
|
||||||
|
if r['客户盈亏'] == '是':
|
||||||
|
for ci in [7, 8, 9]: ws.cell(row=rn, column=ci).fill = red_fill
|
||||||
|
elif r['客户盈亏'] == '未匹配':
|
||||||
|
for ci in [7, 8, 9]: ws.cell(row=rn, column=ci).fill = yellow_fill
|
||||||
|
elif r['实发金额'] > 0:
|
||||||
|
ws.cell(row=rn, column=9).fill = green_fill
|
||||||
|
rn += 1
|
||||||
|
|
||||||
|
# 合计行
|
||||||
|
total_应发 = sum(r['考核应发'] for r in payment_records)
|
||||||
|
total_拦截 = sum(r['亏损拦截'] for r in payment_records)
|
||||||
|
total_实发 = sum(r['实发金额'] for r in payment_records)
|
||||||
|
rn += 1
|
||||||
|
WR(ws, rn, ['', '', '', '', '合计', R(total_应发), '', R(total_拦截), R(total_实发)])
|
||||||
|
for ci in range(5, 10): ws.cell(row=rn, column=ci).font = Font(bold=True)
|
||||||
|
|
||||||
|
ws.auto_filter.ref = f"A1:I1"
|
||||||
|
AW(ws)
|
||||||
|
return payment_records
|
||||||
|
|
||||||
|
def write_summary_from_records(wb, month, payment_records):
|
||||||
|
"""从奖金发放记录生成月汇总"""
|
||||||
|
ws = wb.create_sheet(f'{month}月汇总')
|
||||||
|
rn = 1
|
||||||
|
|
||||||
|
# 按发放类型分section
|
||||||
|
by_type = defaultdict(list)
|
||||||
|
for r in payment_records:
|
||||||
|
by_type[r['发放类型']].append({'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['实发金额']})
|
||||||
|
|
||||||
|
# 考核应发(按类型)
|
||||||
|
ws.cell(row=rn, column=1, value='一、考核应发明细').font=Font(bold=True, size=12); rn+=2
|
||||||
|
by_type_应发 = defaultdict(list)
|
||||||
|
for r in payment_records:
|
||||||
|
by_type_应发[r['发放类型']].append({'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['考核应发']})
|
||||||
|
for cat in sorted(by_type_应发.keys()):
|
||||||
|
rn = write_sec(ws, rn, f'考核应发-{cat}', by_type_应发[cat])
|
||||||
|
total_应发 = sum(r['考核应发'] for r in payment_records)
|
||||||
|
WR(ws, rn, ['考核应发合计', '', R(total_应发)]); ws.cell(row=rn,column=1).font=Font(bold=True,size=11); rn+=2
|
||||||
|
|
||||||
|
# 亏损拦截
|
||||||
|
blocked = [r for r in payment_records if r['客户盈亏'] == '是' and r['考核应发'] > 0]
|
||||||
|
unmatched = [r for r in payment_records if r['客户盈亏'] == '未匹配' and r['考核应发'] > 0]
|
||||||
|
if blocked or unmatched:
|
||||||
|
ws.cell(row=rn, column=1, value='二、亏损筛选').font=Font(bold=True, size=12); rn+=2
|
||||||
|
if blocked:
|
||||||
|
bl_dl = [{'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['亏损拦截']} for r in blocked]
|
||||||
|
rn = write_sec(ws, rn, '亏损拦截(客户亏损不发放)', bl_dl)
|
||||||
|
if unmatched:
|
||||||
|
um_dl = [{'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['亏损拦截']} for r in unmatched]
|
||||||
|
rn = write_sec(ws, rn, '未匹配亏损表(需人工确认)', um_dl)
|
||||||
|
total_拦截 = sum(r['亏损拦截'] for r in payment_records)
|
||||||
|
WR(ws, rn, ['拦截合计', '', R(total_拦截)]); ws.cell(row=rn,column=1).font=Font(bold=True); rn+=2
|
||||||
|
|
||||||
|
# 最终发放(按销售人员)
|
||||||
|
ws.cell(row=rn, column=1, value='三、最终发放').font=Font(bold=True, size=12); rn+=2
|
||||||
|
passed = [r for r in payment_records if r['实发金额'] > 0]
|
||||||
|
passed_dl = [{'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['实发金额']} for r in passed]
|
||||||
|
rn = write_sec(ws, rn, '最终发放明细', passed_dl)
|
||||||
|
|
||||||
|
# 最终发放合计(按销售/按部门)
|
||||||
|
total_by_person = defaultdict(lambda: {'部门':'','额':0})
|
||||||
|
for r in passed:
|
||||||
|
total_by_person[r['业务员']]['额'] += r['实发金额']
|
||||||
|
total_by_person[r['业务员']]['部门'] = r['部门']
|
||||||
|
|
||||||
|
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_by_person.keys()):
|
||||||
|
d = total_by_person[p]
|
||||||
|
WR(ws, rn, [p, d['部门'], R(d['额'])]); gt += d['额']; 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_by_person.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; rn+=2
|
||||||
|
|
||||||
|
# 汇总数字
|
||||||
|
total_实发 = sum(r['实发金额'] for r in payment_records)
|
||||||
|
total_拦截 = sum(r['亏损拦截'] for r in payment_records)
|
||||||
|
ws.cell(row=rn, column=1, value='总览').font=Font(bold=True, size=12); rn+=1
|
||||||
|
WR(ws, rn, ['考核应发', R(total_应发)]); rn+=1
|
||||||
|
WR(ws, rn, ['亏损拦截', R(total_拦截)]); rn+=1
|
||||||
|
WR(ws, rn, ['最终发放', R(total_实发)]); ws.cell(row=rn,column=1).font=Font(bold=True,size=12)
|
||||||
|
ws.cell(row=rn,column=2).font=Font(bold=True,size=12)
|
||||||
|
|
||||||
|
AW(ws)
|
||||||
|
|
||||||
|
# 保留旧函数兼容(3月无亏损表时使用)
|
||||||
def write_summary_month(wb, month, month_data, section_names, loss_data=None, plate_client=None):
|
def write_summary_month(wb, month, month_data, section_names, loss_data=None, plate_client=None):
|
||||||
ws = wb.create_sheet(f'{month}月汇总')
|
ws = wb.create_sheet(f'{month}月汇总')
|
||||||
rn=1
|
rn=1
|
||||||
|
|||||||
15
main.py
15
main.py
@@ -82,17 +82,16 @@ for settle_month in [1, 2, 3]:
|
|||||||
else:
|
else:
|
||||||
write_calc_process_mar(wb, G[1], G[2], G[3], feb_data)
|
write_calc_process_mar(wb, G[1], G[2], G[3], feb_data)
|
||||||
|
|
||||||
# Sheet 4: 汇总
|
|
||||||
if settle_month == 1:
|
|
||||||
write_summary_jan(wb, D[1], loss_data[1], plate_client)
|
|
||||||
elif settle_month == 2:
|
|
||||||
write_summary_month(wb, 2, feb_data, ['结转','补发1月','当月','累计补发2月'], loss_data[2], plate_client)
|
|
||||||
else:
|
|
||||||
write_summary_month(wb, 3, mar_data, ['结转','补发1月','补发2月','当月','累计补发3月'], loss_data[3], plate_client)
|
|
||||||
|
|
||||||
# Sheet 5: 车辆考核追踪
|
# Sheet 5: 车辆考核追踪
|
||||||
write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info, loss_data[settle_month], plate_client)
|
write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info, loss_data[settle_month], plate_client)
|
||||||
|
|
||||||
|
# Sheet 6: 奖金发放记录(叠加亏损筛选的逐条明细)
|
||||||
|
payment_records = build_payment_records(settle_month, month_data, loss_data[settle_month], plate_client)
|
||||||
|
write_payment_record_sheet(wb, settle_month, payment_records)
|
||||||
|
|
||||||
|
# Sheet 7: 月汇总(从发放记录生成)
|
||||||
|
write_summary_from_records(wb, settle_month, payment_records)
|
||||||
|
|
||||||
# Sheet 6-17: 业务员
|
# Sheet 6-17: 业务员
|
||||||
for person in sorted(all_persons.keys()):
|
for person in sorted(all_persons.keys()):
|
||||||
write_salesperson_sheet(wb, person, all_persons[person], settle_month, D, G, month_data, vehicle_payments)
|
write_salesperson_sheet(wb, person, all_persons[person], settle_month, D, G, month_data, vehicle_payments)
|
||||||
|
|||||||
Reference in New Issue
Block a user