Files
mileage-bonus/outputs/september-20261009/audit_history/历史与9月发放核验.ipynb
T
shishengliang 65904c8270 feat: add assessment workbench and September reconciliation
Preserve August hydrogen revision and September audit evidence; calculate interrupted vehicle history across all prior months. Record remaining carry-policy and layout-baseline discrepancies.
2026-10-09 18:21:45 +08:00

98 lines
8.0 KiB
Plaintext

{
"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"
]
}
]
}