#!/usr/bin/env python3 """生成 离职人员6月奖金处理明细 — 当月转嫁,其他不发了(18T: 1000/0/1000/1000)""" import os, openpyxl, warnings from openpyxl.styles import Font, PatternFill, Alignment, Border, Side from openpyxl.utils import get_column_letter from collections import defaultdict from calc_engine import * warnings.filterwarnings('ignore') os.chdir('/Users/kkfluous/Downloads') # ── Full calc (same as main.py) ── print("读取源数据...") D = {} for m in range(1, 7): fp = f'租赁任务考核_2026年{m}月.xlsx' if os.path.exists(fp): D[m] = read_file(fp, m) print(f" {m}月: {len(D[m])}条") G = {m: grp(D[m], m) for m in D} calc_jan_carryover(G[1]) all_data = {} all_data[1] = {'当月': [{'车牌': k[0], '销售': g['销售'], '部门': g['部门'], '额': g['奖金']} for k, g in G[1].items() if g['奖金'] > 0]} for m in range(2, 7): if m not in G: continue data_m, G[m] = calc_month(m, G, all_data, G[m-1], G[m]) # ── Resignation config ── RESIGNATIONS = { '赵连飞': {'dept': '业务二部', 'transfer_to': '刘念念'}, '伍仲文': {'dept': '业务六部', 'transfer_to': '钟祥'}, '岑彦': {'dept': '业务六部', 'transfer_to': '钟祥'}, } resigned = set(RESIGNATIONS.keys()) settle_month = 6 month_data = all_data[settle_month] # ── Collect resigned payments from all_data[6] ── detail_records = [] for ptype, items in month_data.items(): for it in items: if it['销售'] not in resigned: continue name = it['销售'] amount = it['额'] is_dangyue = (ptype == '当月') transfer_to = RESIGNATIONS[name]['transfer_to'] handling = f'转{transfer_to}(需确认)' if is_dangyue else '不发了' transfer_disp = transfer_to if is_dangyue else '—' note = '6月当月达标,转新销售' if is_dangyue else f'{ptype},不发了' # Get client info from D[6] client = '' target_name = '' for r in D.get(settle_month, []): if r['车牌号'] == it['车牌'] and r['销售经理'] == name: client = r.get('客户名称', '') target_name = r.get('考核目标', '') break # Get group info g6 = G[settle_month].get((it['车牌'], name)) monthly_bonus = g6['奖励达标'] if g6 else 0 days = g6['天数'] if g6 else '' # 盈亏查询月 if ptype == '当月' or ptype == f'累计补发{settle_month}月': loss_month = settle_month elif ptype == '结转': loss_month = settle_month elif ptype.startswith('补发'): try: loss_month = int(ptype.replace('补发', '').replace('月', '')) except: loss_month = settle_month else: loss_month = settle_month detail_records.append({ 'name': name, 'plate': it['车牌'], 'pay_type': ptype, 'amount': amount, 'handling': handling, 'transfer': transfer_disp, 'note': note, 'client': client, 'loss_month': loss_month, 'loss_status': '否', 'monthly_bonus': monthly_bonus, 'days': days, 'target': target_name, }) print(f"离职人员发放记录: {len(detail_records)} 条") # ── Styles ── HEAD_FILL = PatternFill('solid', fgColor='4472C4') HEAD_FONT = Font(bold=True, color='FFFFFF', size=10) SUB_FILL = PatternFill('solid', fgColor='D9E1F2') ALT_FILL = PatternFill('solid', fgColor='F2F2F2') TITLE_FNT = Font(bold=True, size=14) NOTE_FNT = Font(size=10, color='C00000') NORM_FNT = Font(size=10) BOLD_FNT = Font(bold=True, size=10) THIN = Side('thin', color='B4B4B4') BORD = Border(THIN, THIN, THIN, THIN) CC = Alignment(horizontal='center', vertical='center', wrap_text=True) LL = Alignment(horizontal='left', vertical='center', wrap_text=True) def hdr(ws, r, nc): for c in range(1, nc+1): cell = ws.cell(row=r, column=c) cell.fill = HEAD_FILL; cell.font = HEAD_FONT; cell.alignment = CC; cell.border = BORD def drw(ws, r, nc, alt=False): for c in range(1, nc+1): cell = ws.cell(row=r, column=c) cell.font = NORM_FNT; cell.alignment = CC; cell.border = BORD if alt: cell.fill = ALT_FILL wb = openpyxl.Workbook() # ═══════════════════════════════════════ # Sheet 1: 离职人员发放处理总览 # ═══════════════════════════════════════ ws1 = wb.active ws1.title = '离职人员发放处理总览' ws1.merge_cells('A1:G1') ws1.cell(row=1, column=1, value='2026年6月核算 — 离职人员奖金处理方案').font = TITLE_FNT ws1.cell(row=1, column=1).alignment = CC ws1.row_dimensions[1].height = 30 ws1.merge_cells('A2:G2') ws1.cell(row=2, column=1, value='处理规则:仅6月当月达标奖金转给新接手的销售(需与其他部门确认是否发放);其余结转、补发、累计补发等一律不发了。').font = NOTE_FNT ws1.cell(row=2, column=1).alignment = LL ws1.row_dimensions[2].height = 22 r = 4 oh = ['离职人员', '部门', '业务转嫁至', '不发了', '转新销售(需确认)', '原考核应发合计'] for c, h in enumerate(oh, 1): ws1.cell(row=r, column=c, value=h) hdr(ws1, r, 6) r += 1 total_not = 0; total_trf = 0 for name in ['赵连飞', '伍仲文', '岑彦']: info = RESIGNATIONS[name] recs = [p for p in detail_records if p['name'] == name] not_pay = sum(p['amount'] for p in recs if p['pay_type'] != '当月') transfer = sum(p['amount'] for p in recs if p['pay_type'] == '当月') total_not += not_pay; total_trf += transfer ws1.cell(row=r, column=1, value=name) ws1.cell(row=r, column=2, value=info['dept']) ws1.cell(row=r, column=3, value=info['transfer_to']) ws1.cell(row=r, column=4, value=round(not_pay, 2)) ws1.cell(row=r, column=5, value=round(transfer, 2)) ws1.cell(row=r, column=6, value=round(not_pay+transfer, 2)) drw(ws1, r, 6) ws1.row_dimensions[r].height = 22 r += 1 # 合计 for c in range(1, 7): ws1.cell(row=r, column=c).fill = SUB_FILL ws1.cell(row=r, column=c).border = BORD ws1.cell(row=r, column=c).font = BOLD_FNT ws1.cell(row=r, column=c).alignment = CC ws1.cell(row=r, column=1, value='合计') ws1.cell(row=r, column=4, value=round(total_not, 2)) ws1.cell(row=r, column=5, value=round(total_trf, 2)) ws1.cell(row=r, column=6, value=round(total_not+total_trf, 2)) r += 2 ws1.merge_cells(start_row=r, start_column=1, end_row=r, end_column=6) ws1.cell(row=r, column=1, value='转嫁接收方汇总(需与其他部门确认是否发放)').font = Font(bold=True, size=12, color='1F4E78') ws1.cell(row=r, column=1).alignment = CC r += 1 for c, hh in enumerate(['接收人', '来源离职人员', '转嫁金额', '备注'], 1): ws1.cell(row=r, column=c, value=hh) hdr(ws1, r, 4) r += 1 by_recv = defaultdict(lambda: {'sources':[], 'amt':0}) for rec in detail_records: if rec['pay_type'] == '当月': t = rec['transfer'] by_recv[t]['sources'].append(rec['name']) by_recv[t]['amt'] += rec['amount'] for receiver in ['刘念念', '钟祥']: d = by_recv[receiver] ws1.cell(row=r, column=1, value=receiver) ws1.cell(row=r, column=2, value='、'.join(sorted(set(d['sources'])))) ws1.cell(row=r, column=3, value=round(d['amt'], 2)) ws1.cell(row=r, column=4, value='需与相关部门确认是否发放给新销售') drw(ws1, r, 4) r += 1 for i, w in enumerate([14, 22, 18, 18, 18, 18], 1): ws1.column_dimensions[get_column_letter(i)].width = w # ═══════════════════════════════════════ # Sheet 2: 发放明细(逐条) # ═══════════════════════════════════════ ws2 = wb.create_sheet('发放明细(逐条)') ws2.merge_cells('A1:M1') ws2.cell(row=1, column=1, value='离职人员 — 6月考核应发逐条明细').font = TITLE_FNT ws2.cell(row=1, column=1).alignment = CC ws2.row_dimensions[1].height = 28 dh = ['离职人员', '车牌号', '发放类型', '考核应发', '盈亏查询月', '客户名称', '客户盈亏', '处理方式', '转嫁接收人', '6月考核天数', '月度奖励', '考核目标', '备注'] r2 = 3 for c, h in enumerate(dh, 1): ws2.cell(row=r2, column=c, value=h) hdr(ws2, r2, 13) r2 += 1 name_order = ['赵连飞', '伍仲文', '岑彦'] detail_records.sort(key=lambda x: (name_order.index(x['name']), 0 if x['pay_type']=='当月' else 1, x['plate'])) for i, rec in enumerate(detail_records): ws2.cell(row=r2, column=1, value=rec['name']) ws2.cell(row=r2, column=2, value=rec['plate']) ws2.cell(row=r2, column=3, value=rec['pay_type']) ws2.cell(row=r2, column=4, value=round(rec['amount'], 2)) ws2.cell(row=r2, column=5, value=f"{rec['loss_month']}月") ws2.cell(row=r2, column=6, value=rec['client']) ws2.cell(row=r2, column=7, value=rec['loss_status']) ws2.cell(row=r2, column=8, value=rec['handling']) ws2.cell(row=r2, column=9, value=rec['transfer']) ws2.cell(row=r2, column=10, value=rec['days'] if rec['days'] else '') ws2.cell(row=r2, column=11, value=rec['monthly_bonus'] if rec['monthly_bonus'] else '') ws2.cell(row=r2, column=12, value=rec['target']) ws2.cell(row=r2, column=13, value=rec['note']) drw(ws2, r2, 13, alt=(i%2==1)) ws2.row_dimensions[r2].height = 22 r2 += 1 # 合计行 ws2.cell(row=r2, column=3, value='合计') ws2.cell(row=r2, column=4, value=round(sum(r['amount'] for r in detail_records), 2)) for c in range(1, 14): ws2.cell(row=r2, column=c).fill = SUB_FILL ws2.cell(row=r2, column=c).border = BORD ws2.cell(row=r2, column=c).font = BOLD_FNT ws2.cell(row=r2, column=c).alignment = CC for i, w in enumerate([10, 12, 14, 14, 10, 24, 8, 18, 14, 12, 10, 22, 28], 1): ws2.column_dimensions[get_column_letter(i)].width = w # ═══════════════════════════════════════ # Sheets 3-5: 个人明细 # ═══════════════════════════════════════ for name, title_txt, transfer_to in [ ('赵连飞', '赵连飞(2026-04-30离职,业务转→刘念念)', '刘念念'), ('伍仲文', '伍仲文(2026-05-09离职,业务转→钟祥)', '钟祥'), ('岑彦', '岑彦(2026-05-09离职,业务转→钟祥)', '钟祥'), ]: ws = wb.create_sheet(name) ws.merge_cells('A1:K1') ws.cell(row=1, column=1, value=title_txt).font = TITLE_FNT ws.cell(row=1, column=1).alignment = CC ws.row_dimensions[1].height = 28 ph = ['车牌号', '发放类型', '考核应发', '盈亏查询月', '客户名称', '客户盈亏', '处理方式', '6月考核天数', '月度奖励', '考核目标', '备注'] r3 = 3 for c, h in enumerate(ph, 1): ws.cell(row=r3, column=c, value=h) hdr(ws, r3, 11) r3 += 1 person_recs = [p for p in detail_records if p['name'] == name] dangyue_recs = [p for p in person_recs if p['pay_type'] == '当月'] other_recs = [p for p in person_recs if p['pay_type'] != '当月'] for i, rec in enumerate(person_recs): h_disp = rec['handling'] ws.cell(row=r3, column=1, value=rec['plate']) ws.cell(row=r3, column=2, value=rec['pay_type']) ws.cell(row=r3, column=3, value=round(rec['amount'], 2)) ws.cell(row=r3, column=4, value=f"{rec['loss_month']}月") ws.cell(row=r3, column=5, value=rec['client']) ws.cell(row=r3, column=6, value=rec['loss_status']) ws.cell(row=r3, column=7, value=h_disp) ws.cell(row=r3, column=8, value=rec['days'] if rec['days'] else '') ws.cell(row=r3, column=9, value=rec['monthly_bonus'] if rec['monthly_bonus'] else '') ws.cell(row=r3, column=10, value=rec['target']) ws.cell(row=r3, column=11, value=rec['note']) drw(ws, r3, 11, alt=(i%2==1)) ws.row_dimensions[r3].height = 22 r3 += 1 dn = sum(p['amount'] for p in dangyue_recs) ot = sum(p['amount'] for p in other_recs) gt = dn + ot # 不发了小计 ws.cell(row=r3, column=2, value='不发了小计').font = BOLD_FNT ws.cell(row=r3, column=3, value=round(ot, 2)).font = BOLD_FNT for c in range(1, 12): ws.cell(row=r3, column=c).fill = SUB_FILL; ws.cell(row=r3, column=c).border = BORD ws.cell(row=r3, column=2).alignment = CC; ws.cell(row=r3, column=3).alignment = CC r3 += 1 # 转嫁小计 ws.cell(row=r3, column=2, value=f'转{transfer_to}小计').font = BOLD_FNT ws.cell(row=r3, column=3, value=round(dn, 2)).font = BOLD_FNT ws.cell(row=r3, column=11, value='需与其他部门确认').font = Font(size=9, color='C00000') for c in range(1, 12): ws.cell(row=r3, column=c).fill = SUB_FILL; ws.cell(row=r3, column=c).border = BORD ws.cell(row=r3, column=2).alignment = CC; ws.cell(row=r3, column=3).alignment = CC r3 += 1 # 合计 ws.cell(row=r3, column=2, value='合计').font = BOLD_FNT ws.cell(row=r3, column=3, value=round(gt, 2)).font = BOLD_FNT for c in range(1, 12): ws.cell(row=r3, column=c).fill = SUB_FILL; ws.cell(row=r3, column=c).border = BORD ws.cell(row=r3, column=2).alignment = CC; ws.cell(row=r3, column=3).alignment = CC for i, w in enumerate([12, 14, 14, 10, 26, 8, 18, 12, 10, 22, 30], 1): ws.column_dimensions[get_column_letter(i)].width = w # ═══════════════════════════════════════ # Sheets 6-7: 转嫁明细 # ═══════════════════════════════════════ for title_txt, sources, receiver in [ ('转嫁至刘念念的奖金 — 来源:赵连飞(2026-04-30离职)', ['赵连飞'], '刘念念'), ('转嫁至钟祥的奖金 — 来源:伍仲文(2026-05-09离职)、岑彦(2026-05-09离职)', ['伍仲文', '岑彦'], '钟祥'), ]: ws = wb.create_sheet(f'转{receiver}明细') ws.merge_cells('A1:K1') ws.cell(row=1, column=1, value=title_txt).font = TITLE_FNT ws.cell(row=1, column=1).alignment = CC ws.row_dimensions[1].height = 28 ws.merge_cells('A2:K2') ws.cell(row=2, column=1, value='⚠ 以下金额需与其他部门确认是否可发放给新销售').font = NOTE_FNT ws.cell(row=2, column=1).alignment = LL th = ['来源离职人员', '车牌号', '发放类型', '考核应发', '盈亏查询月', '客户名称', '客户盈亏', '6月考核天数', '月度奖励', '考核目标', '备注'] r4 = 4 for c, h in enumerate(th, 1): ws.cell(row=r4, column=c, value=h) hdr(ws, r4, 11) r4 += 1 trf_recs = [p for p in detail_records if p['name'] in sources and p['pay_type'] == '当月'] for i, rec in enumerate(trf_recs): ws.cell(row=r4, column=1, value=rec['name']) ws.cell(row=r4, column=2, value=rec['plate']) ws.cell(row=r4, column=3, value='当月') ws.cell(row=r4, column=4, value=round(rec['amount'], 2)) ws.cell(row=r4, column=5, value=f"{rec['loss_month']}月") ws.cell(row=r4, column=6, value=rec['client']) ws.cell(row=r4, column=7, value=rec['loss_status']) ws.cell(row=r4, column=8, value=rec['days'] if rec['days'] else '') ws.cell(row=r4, column=9, value=rec['monthly_bonus'] if rec['monthly_bonus'] else '') ws.cell(row=r4, column=10, value=rec['target']) ws.cell(row=r4, column=11, value='需确认是否发给新销售') drw(ws, r4, 11, alt=(i%2==1)) ws.row_dimensions[r4].height = 22 r4 += 1 ws.cell(row=r4, column=3, value='合计') ws.cell(row=r4, column=4, value=round(sum(r['amount'] for r in trf_recs), 2)) for c in range(1, 12): ws.cell(row=r4, column=c).fill = SUB_FILL; ws.cell(row=r4, column=c).border = BORD ws.cell(row=r4, column=c).font = BOLD_FNT; ws.cell(row=r4, column=c).alignment = CC for i, w in enumerate([14, 12, 14, 14, 10, 26, 8, 12, 10, 22, 22], 1): ws.column_dimensions[get_column_letter(i)].width = w # ── Save ── out = '离职人员6月奖金处理明细.xlsx' wb.save(out) print(f'\n✅ {out} ({len(wb.sheetnames)} sheets)') print(f'\n汇总:') for name in ['赵连飞', '伍仲文', '岑彦']: recs = [p for p in detail_records if p['name'] == name] not_pay = sum(p['amount'] for p in recs if p['pay_type'] != '当月') trf = sum(p['amount'] for p in recs if p['pay_type'] == '当月') print(f' {name}: 不发了={not_pay:.2f} 转{RESIGNATIONS[name]["transfer_to"]}={trf:.2f} 合计={not_pay+trf:.2f}') print(f' 总计: 不发了={total_not:.2f} 转新销售={total_trf:.2f}')