{ "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" } }, "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 1—8月与9月发放只读核验\n", "先阅读核对报告,代码只读取原表并写出核验结果,不修改奖金工作簿。" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "\"\"\"Read-only audit. No business workbook or calculation state is modified.\"\"\"\n", "from pathlib import Path\n", "from collections import Counter,defaultdict\n", "from decimal import Decimal,ROUND_HALF_UP\n", "import json,hashlib,calendar\n", "import openpyxl\n", "P=Path('/Users/shishengliang/Code/lingniu/mileage-bonus/outputs/september-20261009/audit_history');S=P.parent;H=S.parent/'hydrogen-history-20260916'\n", "load=lambda p:json.loads(p.read_text())\n", "d=load(S/'september_calculation.json');aug=load(H/'august_calculation.json');paid=load(H/'historical_paid.json')\n", "money=lambda v:float(Decimal(str(v)).quantize(Decimal('.01'),rounding=ROUND_HALF_UP))\n", "key=lambda x:(x['plate'],x['sales'])\n", "groups={key(g):g for g in d['groups']};prior={key(g):g for g in aug['groups']}\n", "hist={(x['month'],x['plate'],x['sales']):x for x in d['historical_months']}\n", "settled={(r['assessment_month'],r['plate'],r['owner']) for r in paid}\n", "settled.update((l['assessment_month'],*key(l)) for l in aug['ledger'] if l['gross_amount']>0)\n", "carry_paid=Counter((r['plate'],r['owner']) for r in paid if r['category']=='结转')\n", "carry_paid.update(key(l) for l in aug['ledger'] if l['category']=='结转' and l['amount']>0)\n", "ledger={(l['plate'],l['sales'],l['category']):l for l in d['ledger']}\n", "assert len(ledger)==len(d['ledger'])\n", "expected={};details=[];carry_basis=[];balance_inconsistent=[];status_inconsistent=[];used_inconsistent=[];cross_owner=[]\n", "for k,g in groups.items():\n", " rows=[r for r in d['records'] if (r['车牌号'],r['销售经理'])==k]\n", " hist_t=sum(x['target'] for h,x in hist.items() if h[1:]==k)\n", " hist_a=sum(x['actual'] for h,x in hist.items() if h[1:]==k)\n", " full_t=money(hist_t+g['target']);full_a=money(hist_a+g['actual']);cq=full_a>=full_t and full_t>0\n", " assert abs(full_t-g['cum_target'])<.02 and abs(full_a-g['cum_actual'])<.02,k\n", " prev=prior.get(k,{})\n", " locked=prev.get('carry_left',0)\n", " if locked>=1:expected[(*k,'结转')]=money(g['reward'])\n", " else:\n", " current=sum(Decimal(str(r['月奖励']))*Decimal(str(r['考核天数']))/30 for r in rows if r['实际行驶里程(km)']>=r['应考核里程(km)'])\n", " if current:expected[(*k,'当月')]=money(current)\n", " if cq and not g['virtual']:\n", " for m in range(1,9):\n", " old=hist.get((m,*k))\n", " if old and (m,*k) not in settled:expected[(*k,f'补发{m}月')]=money(Decimal(str(old['reward']))*Decimal(str(old['days']))/calendar.monthrange(2026,m)[1])\n", " if not any(r['实际行驶里程(km)']>=r['应考核里程(km)'] for r in rows) and locked<1:\n", " expected[(*k,'累计补发9月')]=money(Decimal(str(g['reward']))*Decimal(str(g['days']))/30)\n", " used_actual=carry_paid[k]+int(locked>=1)\n", " if used_actual!=g['used_carry']:used_inconsistent.append(dict(plate=k[0],sales=k[1],ledger_used=used_actual,stored_used=g['used_carry']))\n", " recomputed_prior=max(0,int(max(0,hist_a-hist_t)//g['monthly_target'])-carry_paid[k])\n", " recomputed_balance=max(0,int(max(0,full_a-full_t)//g['monthly_target'])-used_actual)\n", " evidence=dict(plate=k[0],sales=k[1],aug_cumulative_target=money(hist_t),aug_cumulative_actual=money(hist_a),monthly_target=g['monthly_target'],carry_paid_jan_aug=carry_paid[k],aug_saved_balance=locked,aug_formula_balance=recomputed_prior,sep_saved_balance=g['carry_left'],sep_formula_balance=recomputed_balance,sep_payment=g['total'],virtual=g['virtual'])\n", " if recomputed_prior!=locked:carry_basis.append(evidence)\n", " if recomputed_balance!=g['carry_left']:balance_inconsistent.append(evidence)\n", " if cq!=g['cum_qualified']:status_inconsistent.append(dict(plate=k[0],sales=k[1],target=full_t,actual=full_a,stored=g['cum_qualified'],calculated=cq,virtual=g['virtual']))\n", " if g['virtual']:\n", " other=[l for l in d['ledger'] if l['plate']==k[0] and l['sales']!=k[1]]\n", " if other:cross_owner.append(dict(plate=k[0],carry_owner=k[1],carry_amount=ledger.get((*k,'结转'),{}).get('amount',0),current_payments=[{f:l[f] for f in ['sales','category','amount']} for l in other]))\n", " for l in d['ledger']:\n", " if key(l)==k and l['assessment_month']<9:\n", " assert (l['assessment_month'],*k) not in settled\n", " details.append({**{f:l[f] for f in ['plate','sales','category','amount']},'aug_cumulative_target':prev.get('cum_target'),'aug_cumulative_actual':prev.get('cum_actual'),'sep_cumulative_target':full_t,'sep_cumulative_actual':full_a,'historically_unpaid':True})\n", "missing=[dict(plate=k[0],sales=k[1],category=k[2],expected=v,actual=ledger.get(k,{}).get('amount',0)) for k,v in expected.items() if abs(v-ledger.get(k,{}).get('amount',0))>.001]\n", "extra=[dict(plate=k[0],sales=k[1],category=k[2],actual=l['amount'],expected=expected.get(k,0)) for k,l in ledger.items() if abs(l['amount']-expected.get(k,0))>.001]\n", "source_checks={}\n", "for tag,x in d['sources'].items():source_checks[tag]=hashlib.sha256(Path(x['path']).read_bytes()).hexdigest()==x['sha256']\n", "fp=S/'里程任务考核_2026年9月_含缺口核算.xlsx';wb=openpyxl.load_workbook(fp,data_only=True,read_only=True)\n", "xrows=list(wb['9月奖金发放记录'].values)\n", "excel_ledger={(r[0],r[1],r[4]):r[9] for r in xrows[1:] if r[0] and r[0]!='合计' and isinstance(r[9],(int,float))}\n", "assert excel_ledger=={k:l['amount'] for k,l in ledger.items()}\n", "errors=[(s.title,c.coordinate,c.value) for s in wb for row in s for c in row if c.data_type=='e'];wb.close()\n", "assert not errors\n", "by_cat={c:money(sum(l['amount'] for l in d['ledger'] if l['category']==c)) for c in d['categories']}\n", "virtual_pay=[l for l in d['ledger'] if l['virtual']]\n", "gap_pay=[l for l in d['ledger'] if l['gap_days']>0 or l['history_gap_days']>0]\n", "wholly=[r for r in d['records'] if r['缺口天数']==r['考核天数']]\n", "out=dict(amount=d['summary']['amount'],ledger_items=len(ledger),expected_amount_under_locked_aug_carry=money(sum(expected.values())),missing_payments=missing,extra_payments=extra,categories=by_cat,historical_backpay=details,prior_carry_basis_differences=carry_basis,next_balance_differences=balance_inconsistent,cumulative_status_inconsistencies=status_inconsistent,used_count_differences=used_inconsistent,cross_owner_payments=cross_owner,virtual_count=len(virtual_pay),virtual_amount=money(sum(l['amount'] for l in virtual_pay)),gap_payment_count=len(gap_pay),gap_payment_amount=money(sum(l['amount'] for l in gap_pay)),wholly_missing=[{f:r[f] for f in ['车牌号','销售经理','考核天数']} for r in wholly],source_hash_checks=source_checks,excel_ledger_matches=True,formula_errors=errors,workbook_sha256=hashlib.sha256(fp.read_bytes()).hexdigest())\n", "(P/'audit_results.json').write_text(json.dumps(out,ensure_ascii=False,indent=2));print(json.dumps({k:v for k,v in out.items() if k not in ['next_balance_differences','cumulative_status_inconsistencies','source_hash_checks','historical_backpay']},ensure_ascii=False,indent=2));print('NEXT_BALANCES',len(balance_inconsistent),'STATUS',len(status_inconsistent))\n" ] } ] }