Compare commits
14 Commits
V2.3.0
...
da487c41d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da487c41d4 | ||
|
|
ee962c97ae | ||
|
|
4f48d1986f | ||
|
|
e814013320 | ||
|
|
26361f3a95 | ||
|
|
bdbc3e4273 | ||
|
|
1ca2657f75 | ||
|
|
5a69ef2993 | ||
|
|
04b6035d52 | ||
|
|
4c43c00e73 | ||
|
|
f2de5d5500 | ||
|
|
54ecbc352f | ||
|
|
cdc4cec2ff | ||
|
|
8c2f4e73dd |
@@ -98,6 +98,26 @@ def calc_feb(G1, G2):
|
|||||||
g2['可结转'] = fc + jr
|
g2['可结转'] = fc + jr
|
||||||
g2['2月已发'] = carry>0 or bonus2>0 or cbp2>0
|
g2['2月已发'] = carry>0 or bonus2>0 or cbp2>0
|
||||||
g2['1月已补发'] = bp1>0
|
g2['1月已补发'] = bp1>0
|
||||||
|
|
||||||
|
# 补充:1月有结转但2月无考核记录的车 → 创建虚拟2月group并发放结转
|
||||||
|
for k, g1 in G1.items():
|
||||||
|
if k not in G2 and g1['可结转'] >= 1:
|
||||||
|
bf = g1['奖励额']
|
||||||
|
carry = bf
|
||||||
|
feb_data['结转'].append({'车牌':k[0],'销售':g1['销售'],'部门':g1['部门'],'额':carry})
|
||||||
|
# 创建虚拟2月group(考核里程=满月目标,实际=0)
|
||||||
|
G2[k] = {
|
||||||
|
'recs':[], '应考核':g1['目标km'], '实际':0, '奖金':0, '天数':DAYS[2],
|
||||||
|
'有达标':False, '目标km':g1['目标km'], '奖励额':g1['奖励额'],
|
||||||
|
'部门':g1['部门'], '销售':g1['销售'], '车牌':k[0],
|
||||||
|
'cum_t':g1['应考核']+g1['目标km'], 'cum_a':g1['实际'],
|
||||||
|
'cum_q': g1['实际'] >= g1['应考核']+g1['目标km'],
|
||||||
|
'结转':carry, '补发1月':0, '补发1月对应':'',
|
||||||
|
'当月奖金':0, '累计补发2月':0, '结转占位':True,
|
||||||
|
'可结转': max(0, g1['可结转'] - 1),
|
||||||
|
'2月已发':True, '1月已补发':False,
|
||||||
|
'虚拟':True, # 标记为无考核记录
|
||||||
|
}
|
||||||
return feb_data
|
return feb_data
|
||||||
|
|
||||||
def calc_mar(G1, G2, G3, feb_data):
|
def calc_mar(G1, G2, G3, feb_data):
|
||||||
@@ -134,6 +154,25 @@ def calc_mar(G1, G2, G3, feb_data):
|
|||||||
g3['结转']=carry; g3['补发1月']=bj; g3['补发1月对应']=g1['销售'] if g1 and bj>0 else ''
|
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['补发2月']=bf2; g3['补发2月对应']=g2['销售'] if g2 and bf2>0 else ''
|
||||||
g3['当月奖金']=bonus3; g3['累计补发3月']=cbp3; g3['结转占位']=carry>0
|
g3['当月奖金']=bonus3; g3['累计补发3月']=cbp3; g3['结转占位']=carry>0
|
||||||
|
|
||||||
|
# 补充:2月有结转但3月无考核记录的车
|
||||||
|
for k, g2 in G2.items():
|
||||||
|
if k not in G3 and g2.get('可结转', 0) >= 1:
|
||||||
|
bf = g2['奖励额']
|
||||||
|
carry = bf
|
||||||
|
mar_data['结转'].append({'车牌':k[0],'销售':g2['销售'],'部门':g2['部门'],'额':carry})
|
||||||
|
G3[k] = {
|
||||||
|
'recs':[], '应考核':g2['目标km'], '实际':0, '奖金':0, '天数':DAYS[3],
|
||||||
|
'有达标':False, '目标km':g2['目标km'], '奖励额':g2['奖励额'],
|
||||||
|
'部门':g2['部门'], '销售':g2['销售'], '车牌':k[0],
|
||||||
|
'cum_t':(G1.get(k,{}).get('应考核',0))+g2['应考核']+g2['目标km'],
|
||||||
|
'cum_a':(G1.get(k,{}).get('实际',0))+g2['实际'],
|
||||||
|
'cum_q':False,
|
||||||
|
'结转':carry, '补发1月':0, '补发1月对应':'',
|
||||||
|
'补发2月':0, '补发2月对应':'',
|
||||||
|
'当月奖金':0, '累计补发3月':0, '结转占位':True,
|
||||||
|
'虚拟':True,
|
||||||
|
}
|
||||||
return mar_data
|
return mar_data
|
||||||
|
|
||||||
def collect_vehicle_payments(G, feb_data, mar_data):
|
def collect_vehicle_payments(G, feb_data, mar_data):
|
||||||
@@ -169,6 +208,57 @@ def collect_vehicle_payments(G, feb_data, mar_data):
|
|||||||
for i, r in enumerate(records): r['期数'] = i + 1
|
for i, r in enumerate(records): r['期数'] = i + 1
|
||||||
return payments, info
|
return payments, info
|
||||||
|
|
||||||
|
# (归属公司+车型) → 考核目标 映射,用于补全无考核记录的车辆
|
||||||
|
VEHICLE_TARGET_MAP = {
|
||||||
|
('广州开发区交投氢能运营管理有限公司', '4.5吨冷链车'): ('交投190辆4.5T冷链车', 3000, 150),
|
||||||
|
('广州开发区交投氢能运营管理有限公司', '4.5吨货车'): ('交投40辆4.5T普货', 3000, 150),
|
||||||
|
('羚牛氢能科技(广东)有限公司', '4.5吨冷链车'): ('羚牛136辆4.5T冷链车', 5000, 260),
|
||||||
|
('羚牛氢能科技(广东)有限公司', '18吨双飞翼货车'): ('羚牛100辆18T', 6000, 1000),
|
||||||
|
('现代氢能科技(广州)有限公司', '4.5吨货车'): ('恒运50辆4.5T普货', 5000, 260),
|
||||||
|
('现代氢能科技(广州)有限公司', '4.5吨货车'): ('恒运50辆4.5T普货', 5000, 260),
|
||||||
|
}
|
||||||
|
|
||||||
|
def read_loss_data(month):
|
||||||
|
"""读取亏损表,返回 {客户名称: '是'/'否'} 字典。无亏损表返回None"""
|
||||||
|
import os
|
||||||
|
fp = f'{month}月.xlsx'
|
||||||
|
if not os.path.exists(fp):
|
||||||
|
return None
|
||||||
|
|
||||||
|
wb = openpyxl.load_workbook(fp, data_only=True)
|
||||||
|
ws = wb[wb.sheetnames[0]]
|
||||||
|
h = [c.value for c in next(ws.iter_rows(min_row=1, max_row=1))]
|
||||||
|
|
||||||
|
# 1月: 列名"项目","1月是否亏损"
|
||||||
|
# 2月: 列名"客户名称","是否亏损"
|
||||||
|
client_col = None; loss_col = None
|
||||||
|
for i, col_name in enumerate(h):
|
||||||
|
if col_name and ('项目' in str(col_name) or '客户' in str(col_name)):
|
||||||
|
client_col = i
|
||||||
|
if col_name and '亏损' in str(col_name):
|
||||||
|
loss_col = i
|
||||||
|
|
||||||
|
if client_col is None or loss_col is None:
|
||||||
|
wb.close()
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
for row in ws.iter_rows(min_row=2, values_only=True):
|
||||||
|
client = row[client_col]
|
||||||
|
loss = row[loss_col]
|
||||||
|
if client:
|
||||||
|
result[str(client).strip()] = str(loss).strip() if loss else ''
|
||||||
|
wb.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_vehicle_client_map(D):
|
||||||
|
"""从考核源数据构建 {车牌号: 客户名称} 映射(取最新月的客户名)"""
|
||||||
|
plate_client = {}
|
||||||
|
for m in sorted(D.keys()):
|
||||||
|
for r in D[m]:
|
||||||
|
plate_client[r['车牌号']] = r.get('客户名称', '')
|
||||||
|
return plate_client
|
||||||
|
|
||||||
def read_master_vehicles(fp='里程任务考核_Q1汇总.xlsx'):
|
def read_master_vehicles(fp='里程任务考核_Q1汇总.xlsx'):
|
||||||
"""从现有Q1汇总文件读取全量车辆台账"""
|
"""从现有Q1汇总文件读取全量车辆台账"""
|
||||||
wb = openpyxl.load_workbook(fp, data_only=True)
|
wb = openpyxl.load_workbook(fp, data_only=True)
|
||||||
|
|||||||
494
excel_writer.py
494
excel_writer.py
@@ -162,14 +162,204 @@ def write_calc_process_mar(wb, G1, G2, G3, feb_data):
|
|||||||
c5,R(cbp3) if cbp3>0 else 0,R(total) if total>0 else 0]); rn+=1
|
c5,R(cbp3) if cbp3>0 else 0,R(total) if total>0 else 0]); rn+=1
|
||||||
AW(ws)
|
AW(ws)
|
||||||
|
|
||||||
def write_summary_jan(wb, records):
|
def write_summary_jan(wb, records, loss_data=None, plate_client=None):
|
||||||
ws = wb.create_sheet('1月汇总')
|
ws = wb.create_sheet('1月汇总')
|
||||||
jan_dl=[{'车牌':r['车牌号'],'销售':r['销售经理'],'部门':r['部门名称'],'额':r['奖金']} for r in records if r['是否达标']=='达标']
|
jan_dl=[{'车牌':r['车牌号'],'销售':r['销售经理'],'部门':r['部门名称'],'额':r['奖金']} for r in records if r['是否达标']=='达标']
|
||||||
rn=write_sec(ws,1,'1月达标奖励',jan_dl)
|
rn=write_sec(ws,1,'1月达标奖励(考核应发)',jan_dl)
|
||||||
|
|
||||||
|
if loss_data is not None:
|
||||||
|
# 亏损拦截
|
||||||
|
blocked = []
|
||||||
|
passed = []
|
||||||
|
unmatched = []
|
||||||
|
for d in jan_dl:
|
||||||
|
client = (plate_client or {}).get(d['车牌'], '')
|
||||||
|
status = loss_data.get(client, '未匹配') if client else '未匹配'
|
||||||
|
if status == '是':
|
||||||
|
blocked.append({**d, '客户': client})
|
||||||
|
elif status == '未匹配':
|
||||||
|
unmatched.append({**d, '客户': client})
|
||||||
|
else:
|
||||||
|
passed.append(d)
|
||||||
|
|
||||||
|
rn = write_sec(ws, rn, '亏损拦截(客户亏损不发放)', blocked if blocked else [])
|
||||||
|
rn = write_sec(ws, rn, '未匹配亏损表(需人工确认)', unmatched if unmatched else [])
|
||||||
|
rn = write_sec(ws, rn, '最终发放', passed)
|
||||||
|
|
||||||
|
ws.cell(row=rn, column=1, value='汇总').font=Font(bold=True, size=11); rn+=1
|
||||||
|
total_考核 = sum(d['额'] for d in jan_dl)
|
||||||
|
total_拦截 = sum(d['额'] for d in blocked)
|
||||||
|
total_未匹配 = sum(d['额'] for d in unmatched)
|
||||||
|
total_最终 = sum(d['额'] for d in passed)
|
||||||
|
WR(ws, rn, ['考核应发', R(total_考核)]); 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); rn+=2
|
||||||
|
|
||||||
write_total(ws,rn,1,{'达标':jan_dl})
|
write_total(ws,rn,1,{'达标':jan_dl})
|
||||||
AW(ws)
|
AW(ws)
|
||||||
|
|
||||||
def write_summary_month(wb, month, month_data, section_names):
|
def build_payment_records(month, month_data, all_loss_data, plate_client):
|
||||||
|
"""构建奖金发放记录列表,每条考核应发一行,叠加亏损筛选。
|
||||||
|
all_loss_data: {1: loss_dict, 2: loss_dict, 3: loss_dict_or_None}
|
||||||
|
补发X月 → 查X月盈亏;其他 → 查当月盈亏;无客户 → 正常发放
|
||||||
|
"""
|
||||||
|
# 发放类型→查哪个月盈亏
|
||||||
|
def get_loss_month(cat, settle_month):
|
||||||
|
if '补发1月' in cat: return 1
|
||||||
|
if '补发2月' in cat: return 2
|
||||||
|
if '补发3月' in cat: return 3
|
||||||
|
return settle_month
|
||||||
|
|
||||||
|
records = []
|
||||||
|
for cat, dl in month_data.items():
|
||||||
|
loss_month = get_loss_month(cat, month)
|
||||||
|
loss_data = all_loss_data.get(loss_month)
|
||||||
|
|
||||||
|
for d in dl:
|
||||||
|
client = (plate_client or {}).get(d['车牌'], '')
|
||||||
|
|
||||||
|
# 无客户关联(如虚拟结转记录)→ 正常发放
|
||||||
|
if not client:
|
||||||
|
loss_status = '否'
|
||||||
|
elif loss_data:
|
||||||
|
loss_status = loss_data.get(client, '未匹配')
|
||||||
|
else:
|
||||||
|
loss_status = '未匹配' # 无亏损表视为未匹配,不发放
|
||||||
|
|
||||||
|
考核应发 = d['额']
|
||||||
|
if loss_status == '是':
|
||||||
|
拦截 = 考核应发; 实发 = 0
|
||||||
|
elif loss_status == '未匹配':
|
||||||
|
拦截 = 考核应发; 实发 = 0
|
||||||
|
else:
|
||||||
|
拦截 = 0; 实发 = 考核应发
|
||||||
|
|
||||||
|
records.append({
|
||||||
|
'车牌号': d['车牌'],
|
||||||
|
'业务员': d['销售'],
|
||||||
|
'部门': d['部门'],
|
||||||
|
'客户名称': client or '(无客户关联)',
|
||||||
|
'发放类型': cat,
|
||||||
|
'盈亏查询月': f'{loss_month}月',
|
||||||
|
'考核应发': 考核应发,
|
||||||
|
'客户盈亏': 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.get('盈亏查询月',''),
|
||||||
|
R(r['考核应发']), r['客户盈亏'], R(r['亏损拦截']), R(r['实发金额'])])
|
||||||
|
if r['客户盈亏'] == '是':
|
||||||
|
for ci in [8, 9, 10]: ws.cell(row=rn, column=ci).fill = red_fill
|
||||||
|
elif r['客户盈亏'] == '未匹配':
|
||||||
|
for ci in [8, 9, 10]: ws.cell(row=rn, column=ci).fill = yellow_fill
|
||||||
|
elif r['实发金额'] > 0:
|
||||||
|
ws.cell(row=rn, column=10).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, 11): ws.cell(row=rn, column=ci).font = Font(bold=True)
|
||||||
|
|
||||||
|
ws.auto_filter.ref = f"A1:J1"
|
||||||
|
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):
|
||||||
ws = wb.create_sheet(f'{month}月汇总')
|
ws = wb.create_sheet(f'{month}月汇总')
|
||||||
rn=1
|
rn=1
|
||||||
for i,cat in enumerate(section_names):
|
for i,cat in enumerate(section_names):
|
||||||
@@ -178,7 +368,47 @@ def write_summary_month(wb, month, month_data, section_names):
|
|||||||
'当月':f'{"三" if month==2 else "四"}、{month}月当月奖励',
|
'当月':f'{"三" if month==2 else "四"}、{month}月当月奖励',
|
||||||
f'累计补发{month}月':f'{"四" if month==2 else "五"}、累计达标补发{month}月'}
|
f'累计补发{month}月':f'{"四" if month==2 else "五"}、累计达标补发{month}月'}
|
||||||
rn=write_sec(ws,rn,label_map.get(cat,cat),month_data.get(cat,[]))
|
rn=write_sec(ws,rn,label_map.get(cat,cat),month_data.get(cat,[]))
|
||||||
|
|
||||||
|
# 考核应发合计
|
||||||
write_total(ws,rn,month,month_data)
|
write_total(ws,rn,month,month_data)
|
||||||
|
# 找最后一行
|
||||||
|
rn = ws.max_row + 2
|
||||||
|
|
||||||
|
if loss_data is not None:
|
||||||
|
# 合并所有发放记录
|
||||||
|
all_dl = []
|
||||||
|
for cat, dl in month_data.items():
|
||||||
|
all_dl.extend(dl)
|
||||||
|
|
||||||
|
blocked = []; passed = []; unmatched = []
|
||||||
|
for d in all_dl:
|
||||||
|
client = (plate_client or {}).get(d['车牌'], '')
|
||||||
|
status = loss_data.get(client, '未匹配') if client else '未匹配'
|
||||||
|
if status == '是':
|
||||||
|
blocked.append(d)
|
||||||
|
elif status == '未匹配':
|
||||||
|
unmatched.append(d)
|
||||||
|
else:
|
||||||
|
passed.append(d)
|
||||||
|
|
||||||
|
ws.cell(row=rn, column=1, value='═══ 亏损筛选 ═══').font=Font(bold=True, size=12); rn+=2
|
||||||
|
rn = write_sec(ws, rn, '亏损拦截(客户亏损不发放)', blocked)
|
||||||
|
rn = write_sec(ws, rn, '未匹配亏损表(需人工确认)', unmatched)
|
||||||
|
rn = write_sec(ws, rn, '最终发放', passed)
|
||||||
|
|
||||||
|
total_考核 = sum(d['额'] for d in all_dl)
|
||||||
|
total_拦截 = sum(d['额'] for d in blocked)
|
||||||
|
total_未匹配 = sum(d['额'] for d in unmatched)
|
||||||
|
total_最终 = sum(d['额'] for d in passed)
|
||||||
|
|
||||||
|
ws.cell(row=rn, column=1, value='亏损筛选汇总').font=Font(bold=True, size=11); rn+=1
|
||||||
|
WR(ws, rn, ['考核应发合计', R(total_考核)]); 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)
|
AW(ws)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -186,7 +416,8 @@ def write_summary_month(wb, month, month_data, section_names):
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
def write_salesperson_sheet(wb, person, dept, settle_month, D, G, month_data, vehicle_payments):
|
def write_salesperson_sheet(wb, person, dept, settle_month, D, G, month_data, vehicle_payments):
|
||||||
ws = wb.create_sheet(f'业务员_{person}')
|
short_dept = dept.replace('业务','') if '业务' in dept else dept
|
||||||
|
ws = wb.create_sheet(f'{short_dept}-{person}')
|
||||||
ws.cell(row=1,column=1,value=f'{person} | {dept} | {settle_month}月绩效对账单').font=Font(bold=True,size=14)
|
ws.cell(row=1,column=1,value=f'{person} | {dept} | {settle_month}月绩效对账单').font=Font(bold=True,size=14)
|
||||||
|
|
||||||
plates = set()
|
plates = set()
|
||||||
@@ -214,7 +445,10 @@ def write_salesperson_sheet(wb, person, dept, settle_month, D, G, month_data, ve
|
|||||||
if g_cur: break
|
if g_cur: break
|
||||||
if not g_cur: continue
|
if not g_cur: continue
|
||||||
|
|
||||||
first = g_cur['recs'][0]
|
if g_cur['recs']:
|
||||||
|
first = g_cur['recs'][0]
|
||||||
|
else:
|
||||||
|
first = {'合同编号':'','客户名称':'(无考核记录)','考核目标':g_cur.get('考核目标','')}
|
||||||
mkm = g_cur['目标km']
|
mkm = g_cur['目标km']
|
||||||
|
|
||||||
# 第1行:车辆信息 + 各月里程/目标
|
# 第1行:车辆信息 + 各月里程/目标
|
||||||
@@ -338,66 +572,218 @@ def write_salesperson_sheet(wb, person, dept, settle_month, D, G, month_data, ve
|
|||||||
# 新增:车辆考核追踪sheet
|
# 新增:车辆考核追踪sheet
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
def write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info):
|
def write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info, loss_data=None, plate_client=None):
|
||||||
ws = wb.create_sheet('车辆考核追踪')
|
ws = wb.create_sheet('车辆考核追踪')
|
||||||
wrap_align = Alignment(wrap_text=True, vertical='top')
|
from calc_engine import VEHICLE_TARGET_MAP, DAYS
|
||||||
|
|
||||||
# 表头:每月用一列"业务员/里程/目标/达标"(多人换行)
|
center_top = Alignment(horizontal='center', vertical='top', wrap_text=True)
|
||||||
headers = ['车牌号','车架号','归属公司','车型','考核目标','月度奖励金额']
|
left_top = Alignment(vertical='top', wrap_text=True)
|
||||||
|
green_font = Font(color='006100')
|
||||||
|
green_fill = PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid')
|
||||||
|
red_font = Font(color='9C0006')
|
||||||
|
red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
|
||||||
|
grey_fill = PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid')
|
||||||
|
blue_fill = PatternFill(start_color='DAEEF3', end_color='DAEEF3', fill_type='solid')
|
||||||
|
gold_fill = PatternFill(start_color='FFF2CC', end_color='FFF2CC', fill_type='solid')
|
||||||
|
|
||||||
|
# 表头:基本信息 + 业务员 + 每月(应考核/实际/达标) + 累计 + 发放 + 奖金池
|
||||||
|
headers = ['车牌号','车架号','归属公司','车型','考核目标','月度奖励','业务员']
|
||||||
|
info_cols = 6 # 前6列是车辆信息(需要合并)
|
||||||
for m in range(1, settle_month+1):
|
for m in range(1, settle_month+1):
|
||||||
headers.append(f'{m}月考核明细')
|
headers += [f'{m}月应考核', f'{m}月实际', f'{m}月达标']
|
||||||
if settle_month >= 2:
|
if settle_month >= 2:
|
||||||
headers += ['累计里程/目标','累计达标']
|
headers += ['累计应完成','累计实际','累计达标']
|
||||||
headers += ['本月发放明细','累计已发期数','累计已发金额','剩余可发期数']
|
if loss_data is not None:
|
||||||
|
headers += ['客户名称','客户是否亏损','考核应发','最终发放','未发放原因']
|
||||||
|
else:
|
||||||
|
headers += ['本月发放金额','发放类型']
|
||||||
|
headers += ['已发期数','已发金额','剩余期数']
|
||||||
WH(ws, headers)
|
WH(ws, headers)
|
||||||
|
ws.freeze_panes = 'H2' # 冻结车辆信息+业务员列
|
||||||
|
|
||||||
rn=2
|
# 交替行底色
|
||||||
|
stripe_a = PatternFill(start_color='FFFFFF', end_color='FFFFFF', fill_type='solid') # 白
|
||||||
|
stripe_b = PatternFill(start_color='DCE6F1', end_color='DCE6F1', fill_type='solid') # 浅蓝
|
||||||
|
vehicle_idx = 0
|
||||||
|
|
||||||
|
rn = 2
|
||||||
for mv in master_vehicles:
|
for mv in master_vehicles:
|
||||||
plate=mv['车牌号']
|
plate = mv['车牌号']
|
||||||
info=vehicle_info.get(plate, {})
|
info = vehicle_info.get(plate, {})
|
||||||
pays=vehicle_payments.get(plate, [])
|
pays = vehicle_payments.get(plate, [])
|
||||||
row=[plate,mv.get('车架号',''),mv.get('归属公司',''),mv.get('车型确定',''),
|
|
||||||
info.get('考核目标',''),info.get('月度奖励',0) or '']
|
|
||||||
|
|
||||||
cum_t=0; cum_a=0
|
target_name = info.get('考核目标','')
|
||||||
|
monthly_bonus = info.get('月度奖励',0)
|
||||||
|
if not target_name:
|
||||||
|
company = mv.get('归属公司','')
|
||||||
|
vtype = mv.get('车型确定','')
|
||||||
|
mapped = VEHICLE_TARGET_MAP.get((company, vtype))
|
||||||
|
if mapped:
|
||||||
|
target_name, _, monthly_bonus = mapped
|
||||||
|
|
||||||
|
# 收集该车所有(业务员) - 跨月去重
|
||||||
|
person_set = {}
|
||||||
for m in range(1, settle_month+1):
|
for m in range(1, settle_month+1):
|
||||||
mgs=[(k,g) for k,g in G.get(m,{}).items() if k[0]==plate]
|
for k,g in G.get(m, {}).items():
|
||||||
if mgs:
|
if k[0] == plate:
|
||||||
# 每个(车牌,销售)组一行,换行显示
|
person_set[k[1]] = g['部门']
|
||||||
lines = []
|
persons = sorted(person_set.keys())
|
||||||
for _,g in sorted(mgs, key=lambda x: x[0][1]):
|
if not persons:
|
||||||
t=g['应考核']; a=g['实际']
|
persons = [''] # 无考核记录也占一行
|
||||||
cum_t+=t; cum_a+=a
|
|
||||||
q='达标' if g['有达标'] else '未达标'
|
row_stripe = stripe_b if vehicle_idx % 2 == 1 else stripe_a
|
||||||
lines.append(f"{g['销售']}: {R(a,0)}/{R(t,0)} {q}")
|
start_rn = rn
|
||||||
row.append('\n'.join(lines))
|
for pi, person in enumerate(persons):
|
||||||
|
sd = person_set.get(person,'').replace('业务','') if person else ''
|
||||||
|
person_label = f'{sd}-{person}' if person and sd else person
|
||||||
|
|
||||||
|
# 车辆信息(只在第一行写,后面留空等合并)
|
||||||
|
if pi == 0:
|
||||||
|
row_base = [plate, mv.get('车架号',''), mv.get('归属公司',''),
|
||||||
|
mv.get('车型确定',''), target_name or '', monthly_bonus or '']
|
||||||
else:
|
else:
|
||||||
row.append('')
|
row_base = ['','','','','','']
|
||||||
|
|
||||||
if settle_month>=2:
|
row = row_base + [person_label]
|
||||||
cum_q='达标' if (cum_a>=cum_t and cum_t>0) else '未达标'
|
|
||||||
row+=[f'{R(cum_a,0)}/{R(cum_t,0)}', cum_q]
|
|
||||||
|
|
||||||
# 本月发放明细(多人多类型换行)
|
# 每月数据(按该业务员的group)
|
||||||
tp=[p for p in pays if p['结算月']==settle_month]
|
cum_t = 0; cum_a = 0
|
||||||
if tp:
|
for m in range(1, settle_month+1):
|
||||||
pay_lines = []
|
gm = G.get(m, {}).get((plate, person)) if person else None
|
||||||
for p in sorted(tp, key=lambda x: x['业务员']):
|
if gm:
|
||||||
pay_lines.append(f"{p['业务员']}: {R(p['金额'])}({p['类型']})")
|
# 逐条记录汇总(同人同月可能多条)
|
||||||
row.append('\n'.join(pay_lines))
|
t_sum = gm['应考核']; a_sum = gm['实际']
|
||||||
else:
|
cum_t += t_sum; cum_a += a_sum
|
||||||
row.append('')
|
# 每条记录的达标情况
|
||||||
|
rec_details = []
|
||||||
|
for rec in gm['recs']:
|
||||||
|
rq = rec['是否达标'] == '达标'
|
||||||
|
rec_details.append(f"{R(rec['实际行驶里程(km)'],0)}/{R(rec['应考核里程(km)'],0)}{'✓' if rq else '✗'}")
|
||||||
|
all_q = all(rec['是否达标'] == '达标' for rec in gm['recs'])
|
||||||
|
if len(gm['recs']) == 1:
|
||||||
|
detail = rec_details[0].split('✓')[0].split('✗')[0] # 只取数字
|
||||||
|
row += [R(t_sum), R(a_sum), '✓' if all_q else '✗']
|
||||||
|
else:
|
||||||
|
# 多条:显示汇总,但单元格内注明各条
|
||||||
|
row += [R(t_sum), R(a_sum), '\n'.join(rec_details)]
|
||||||
|
else:
|
||||||
|
row += ['', '', '']
|
||||||
|
|
||||||
# 奖金池(截至settle_month)
|
# 累计
|
||||||
pays_to_date=[p for p in pays if p['结算月']<=settle_month]
|
if settle_month >= 2:
|
||||||
tp_count=len(pays_to_date); tp_amt=sum(p['金额'] for p in pays_to_date)
|
if cum_t > 0:
|
||||||
row+=[tp_count,R(tp_amt) if tp_amt>0 else 0,12-tp_count]
|
cum_q = cum_a >= cum_t
|
||||||
|
row += [R(cum_t), R(cum_a), '✓' if cum_q else '✗']
|
||||||
|
else:
|
||||||
|
row += ['', '', '']
|
||||||
|
cum_q = False
|
||||||
|
else:
|
||||||
|
cum_q = False
|
||||||
|
|
||||||
WR(ws,rn,row)
|
# 本月发放(该业务员的)
|
||||||
# 对含换行的单元格设置自动换行
|
tp = [p for p in pays if p['结算月'] == settle_month and p['业务员'] == person]
|
||||||
for ci in range(len(row)):
|
考核应发 = sum(p['金额'] for p in tp) if tp else 0
|
||||||
cell = ws.cell(row=rn, column=ci+1)
|
pay_types = ', '.join(p['类型'] for p in tp) if tp else ''
|
||||||
if isinstance(cell.value, str) and '\n' in cell.value:
|
|
||||||
cell.alignment = wrap_align
|
if loss_data is not None:
|
||||||
rn+=1
|
# 有亏损表:加客户名称、亏损状态、考核应发、最终发放、未发放原因
|
||||||
AW(ws)
|
client = (plate_client or {}).get(plate, '')
|
||||||
|
loss_status = loss_data.get(client, '未匹配') if client else '未匹配'
|
||||||
|
if loss_status == '是':
|
||||||
|
final_amt = 0
|
||||||
|
reason = '客户亏损不发放' if 考核应发 > 0 else ''
|
||||||
|
elif loss_status == '未匹配':
|
||||||
|
final_amt = 0
|
||||||
|
reason = '未匹配亏损表' if 考核应发 > 0 else ''
|
||||||
|
else:
|
||||||
|
final_amt = 考核应发
|
||||||
|
reason = ''
|
||||||
|
row += [client, loss_status, R(考核应发), R(final_amt), reason]
|
||||||
|
else:
|
||||||
|
# 无亏损表:直接发放
|
||||||
|
row += [R(考核应发), pay_types]
|
||||||
|
|
||||||
|
# 奖金池(整车,只在第一行显示)
|
||||||
|
if pi == 0:
|
||||||
|
pays_to_date = [p for p in pays if p['结算月'] <= settle_month]
|
||||||
|
tp_count = len(pays_to_date); tp_amt = sum(p['金额'] for p in pays_to_date)
|
||||||
|
row += [f'{tp_count}/12', R(tp_amt) if tp_amt > 0 else 0, 12 - tp_count]
|
||||||
|
else:
|
||||||
|
row += ['', '', '']
|
||||||
|
|
||||||
|
WR(ws, rn, row)
|
||||||
|
|
||||||
|
# 美化:先刷底色(交替色),再叠加特殊色
|
||||||
|
for ci in range(1, len(headers) + 1):
|
||||||
|
ws.cell(row=rn, column=ci).fill = row_stripe
|
||||||
|
|
||||||
|
# 车辆信息列灰底(覆盖条纹)
|
||||||
|
for ci in range(1, info_cols + 1):
|
||||||
|
ws.cell(row=rn, column=ci).fill = grey_fill if vehicle_idx % 2 == 0 else PatternFill(start_color='E8E8E8', end_color='E8E8E8', fill_type='solid')
|
||||||
|
|
||||||
|
# 月度达标列着色
|
||||||
|
for m in range(1, settle_month + 1):
|
||||||
|
col_base = info_cols + 1 + (m - 1) * 3 # 业务员列后面
|
||||||
|
qual_col = col_base + 3 # 达标列
|
||||||
|
cell = ws.cell(row=rn, column=qual_col)
|
||||||
|
cell.alignment = center_top
|
||||||
|
val = cell.value
|
||||||
|
if val and '✓' in str(val) and '✗' not in str(val):
|
||||||
|
cell.fill = green_fill; cell.font = green_font
|
||||||
|
elif val and '✗' in str(val):
|
||||||
|
cell.fill = red_fill; cell.font = red_font
|
||||||
|
|
||||||
|
# 累计达标着色
|
||||||
|
if settle_month >= 2:
|
||||||
|
cum_qual_col = info_cols + 1 + settle_month * 3 + 3 # 累计达标列
|
||||||
|
cell = ws.cell(row=rn, column=cum_qual_col)
|
||||||
|
if cell.value == '✓':
|
||||||
|
cell.fill = green_fill; cell.font = Font(bold=True, color='006100')
|
||||||
|
elif cell.value == '✗':
|
||||||
|
cell.fill = red_fill; cell.font = Font(bold=True, color='9C0006')
|
||||||
|
|
||||||
|
# 发放金底
|
||||||
|
pay_col = info_cols + 1 + settle_month * 3 + (3 if settle_month >= 2 else 0) + 1
|
||||||
|
if tp:
|
||||||
|
ws.cell(row=rn, column=pay_col).fill = gold_fill
|
||||||
|
|
||||||
|
# 奖金池蓝底
|
||||||
|
if pi == 0 and tp_count > 0:
|
||||||
|
pool_col = pay_col + 2
|
||||||
|
ws.cell(row=rn, column=pool_col).fill = blue_fill
|
||||||
|
ws.cell(row=rn, column=pool_col).font = Font(bold=True)
|
||||||
|
|
||||||
|
rn += 1
|
||||||
|
|
||||||
|
# 合并车辆信息列(如果多人)
|
||||||
|
if len(persons) > 1:
|
||||||
|
for ci in range(1, info_cols + 1):
|
||||||
|
ws.merge_cells(start_row=start_rn, start_column=ci,
|
||||||
|
end_row=start_rn + len(persons) - 1, end_column=ci)
|
||||||
|
ws.cell(row=start_rn, column=ci).alignment = Alignment(vertical='center', wrap_text=True)
|
||||||
|
# 奖金池列也合并
|
||||||
|
for offset in [2, 3, 4]: # 已发期数/已发金额/剩余期数
|
||||||
|
pool_col = pay_col + offset
|
||||||
|
ws.merge_cells(start_row=start_rn, start_column=pool_col,
|
||||||
|
end_row=start_rn + len(persons) - 1, end_column=pool_col)
|
||||||
|
|
||||||
|
vehicle_idx += 1
|
||||||
|
|
||||||
|
# 列宽
|
||||||
|
# 隐藏BCD列(车架号/归属公司/车型)
|
||||||
|
for cl in ['B','C','D']:
|
||||||
|
ws.column_dimensions[cl].hidden = True
|
||||||
|
col_widths = {'A':12,'B':18,'C':18,'D':10,'E':18,'F':8,'G':14}
|
||||||
|
for cl, w in col_widths.items():
|
||||||
|
ws.column_dimensions[cl].width = w
|
||||||
|
# 月度列
|
||||||
|
start = ord('H')
|
||||||
|
for m in range(settle_month):
|
||||||
|
for i in range(3):
|
||||||
|
cl = chr(start + m*3 + i)
|
||||||
|
if cl <= 'Z': ws.column_dimensions[cl].width = 12
|
||||||
|
# 剩余列
|
||||||
|
rem = start + settle_month * 3
|
||||||
|
for i in range(10):
|
||||||
|
cl = chr(rem + i)
|
||||||
|
if cl <= 'Z': ws.column_dimensions[cl].width = 14
|
||||||
|
|||||||
43
main.py
43
main.py
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""按月生成独立Excel文件 - 里程考核绩效"""
|
"""按月生成独立Excel文件 - 里程考核绩效(含亏损筛选)"""
|
||||||
import os, openpyxl
|
import os, openpyxl
|
||||||
from calc_engine import *
|
from calc_engine import *
|
||||||
from excel_writer import *
|
from excel_writer import *
|
||||||
@@ -23,6 +23,22 @@ mar_data = calc_mar(G[1], G[2], G[3], feb_data)
|
|||||||
vehicle_payments, vehicle_info = collect_vehicle_payments(G, feb_data, mar_data)
|
vehicle_payments, vehicle_info = collect_vehicle_payments(G, feb_data, mar_data)
|
||||||
master_vehicles = read_master_vehicles()
|
master_vehicles = read_master_vehicles()
|
||||||
|
|
||||||
|
# 亏损表
|
||||||
|
print("\n读取亏损表...")
|
||||||
|
loss_data = {}
|
||||||
|
for m in [1,2,3]:
|
||||||
|
ld = read_loss_data(m)
|
||||||
|
if ld:
|
||||||
|
loss_clients = sum(1 for v in ld.values() if v == '是')
|
||||||
|
print(f" {m}月: {len(ld)}个客户, 其中亏损{loss_clients}个")
|
||||||
|
loss_data[m] = ld
|
||||||
|
else:
|
||||||
|
print(f" {m}月: 无亏损表")
|
||||||
|
loss_data[m] = None
|
||||||
|
|
||||||
|
# 车牌→客户名称映射
|
||||||
|
plate_client = get_vehicle_client_map(D)
|
||||||
|
|
||||||
# 所有业务员
|
# 所有业务员
|
||||||
all_persons = {}
|
all_persons = {}
|
||||||
for m in G:
|
for m in G:
|
||||||
@@ -33,8 +49,8 @@ for m in G:
|
|||||||
jan_total = sum(r['奖金'] for r in D[1] if r['是否达标']=='达标')
|
jan_total = sum(r['奖金'] for r in D[1] if r['是否达标']=='达标')
|
||||||
feb_total = sum(sum(d['额'] for d in v) for v in feb_data.values())
|
feb_total = sum(sum(d['额'] for d in v) for v in feb_data.values())
|
||||||
mar_total = sum(sum(d['额'] for d in v) for v in mar_data.values())
|
mar_total = sum(sum(d['额'] for d in v) for v in mar_data.values())
|
||||||
print(f"\n1月: {jan_total:.2f}, 2月: {feb_total:.2f}, 3月: {mar_total:.2f}")
|
print(f"\n考核应发: 1月{jan_total:.2f}, 2月{feb_total:.2f}, 3月{mar_total:.2f}")
|
||||||
print(f"Q1总计: {jan_total + feb_total + mar_total:.2f}")
|
print(f"Q1考核应发合计: {jan_total + feb_total + mar_total:.2f}")
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 按月生成
|
# 按月生成
|
||||||
@@ -66,21 +82,20 @@ 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: 汇总
|
# Sheet 5: 车辆考核追踪
|
||||||
if settle_month == 1:
|
write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info, loss_data[settle_month], plate_client)
|
||||||
write_summary_jan(wb, D[1])
|
|
||||||
elif settle_month == 2:
|
|
||||||
write_summary_month(wb, 2, feb_data, ['结转','补发1月','当月','累计补发2月'])
|
|
||||||
else:
|
|
||||||
write_summary_month(wb, 3, mar_data, ['结转','补发1月','补发2月','当月','累计补发3月'])
|
|
||||||
|
|
||||||
# Sheet 5-16: 业务员
|
# Sheet 6: 奖金发放记录(叠加亏损筛选,补发查对应月盈亏)
|
||||||
|
payment_records = build_payment_records(settle_month, month_data, loss_data, 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: 业务员
|
||||||
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)
|
||||||
|
|
||||||
# Sheet 17: 车辆考核追踪
|
|
||||||
write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info)
|
|
||||||
|
|
||||||
# 删除默认空sheet
|
# 删除默认空sheet
|
||||||
if 'Sheet' in wb.sheetnames:
|
if 'Sheet' in wb.sheetnames:
|
||||||
del wb['Sheet']
|
del wb['Sheet']
|
||||||
|
|||||||
Reference in New Issue
Block a user