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.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
from pathlib import Path
|
||||
from collections import defaultdict,Counter
|
||||
from decimal import Decimal,ROUND_HALF_UP
|
||||
import json,hashlib
|
||||
import openpyxl
|
||||
P=Path(__file__).resolve().parent
|
||||
def load(p):return json.loads(p.read_text())
|
||||
def cents(x):return float(Decimal(str(x)).quantize(Decimal('.01'),rounding=ROUND_HALF_UP))
|
||||
d=load(P/'september_calculation.json');inp=load(P/'inputs.json');aug=load(P.parent/'hydrogen-history-20260916/august_calculation.json')
|
||||
seen=set();byrow=defaultdict(list);sources=Counter();tests=set(inp['tests'])
|
||||
for x in d['daily']:
|
||||
k=x['plate'],x['date'];assert k not in seen;seen.add(k)
|
||||
t=inp['matrices']['meter'].get(k[0],{}).get(k[1]);g=inp['matrices']['gps'].get(k[0],{}).get(k[1]);h=inp['matrices']['hydrogen'].get(k[0],{}).get(k[1])
|
||||
is_test=k[0] in tests and t is not None and g is not None and Decimal(str(t))-Decimal(str(g))>Decimal(50)
|
||||
unknown=k[0] in tests and (t is None or g is None)
|
||||
expected=g if is_test else h if h is not None else g if unknown else t
|
||||
assert x['included']==expected,(k,x['included'],expected)
|
||||
byrow[x['source_row']].append(expected);sources[x['selection']]+=1
|
||||
for r in d['records']:
|
||||
vals=byrow[r['源表行']]
|
||||
assert len(vals)==r['考核天数']
|
||||
assert r['实际行驶里程(km)']==cents(sum(Decimal(str(v)) for v in vals if v is not None))
|
||||
assert r['缺口天数']==sum(v is None for v in vals)
|
||||
assert r['新政策']==(r['车牌号'] in inp['policy_plates'])
|
||||
history={(r['month'],r['plate'],r['sales']):r for r in d['historical_months']}
|
||||
prior={(g['plate'],g['sales']):g for g in aug['groups']}
|
||||
payments=defaultdict(dict)
|
||||
for l in d['ledger']:
|
||||
k=l['plate'],l['sales'];assert l['category'] not in payments[k];payments[k][l['category']]=l
|
||||
assert l['amount']==cents(Decimal(str(l['base']))*Decimal(str(l['days']))/Decimal(str(l['month_days'])))
|
||||
if l['assessment_month']<9:assert not history[(l['assessment_month'],*k)]['settled']
|
||||
for g in d['groups']:
|
||||
k=g['plate'],g['sales'];ps=payments[k];p=prior.get(k)
|
||||
assert abs(g['cum_target']-sum(t or 0 for t,a in g['history']))<.02
|
||||
assert abs(g['cum_actual']-sum(a or 0 for t,a in g['history']))<.02
|
||||
if g['previous_carry']>=1:
|
||||
assert '结转' in ps and '当月' not in ps and '累计补发9月' not in ps
|
||||
else:assert '结转' not in ps
|
||||
if '累计补发9月' in ps:assert not g['qualified'] and g['cum_qualified']
|
||||
if not g['virtual']:
|
||||
for m in range(1,9):
|
||||
old=history.get((m,*k));eligible=old and not old['settled'] and g['cum_qualified']
|
||||
assert (f'补发{m}月' in ps)==bool(eligible),(k,m)
|
||||
assert len(seen)==8737
|
||||
assert cents(sum(l['amount'] for l in d['ledger']))==d['summary']['amount']
|
||||
for x in d['sources'].values():assert hashlib.sha256(Path(x['path']).read_bytes()).hexdigest()==x['sha256']
|
||||
fp=P/'里程任务考核_2026年9月_含缺口核算.xlsx'
|
||||
if fp.exists():
|
||||
w=openpyxl.load_workbook(fp,data_only=True,read_only=True)
|
||||
assert cents(w['9月汇总(新版界面)']['J2'].value)==d['summary']['amount']
|
||||
rows=list(w['业务考核视图'].values)
|
||||
for row,r in zip(rows[1:],d['records']):
|
||||
assert row[14]==r['实际行驶里程(km)'] and row[23]==r['缺口天数']
|
||||
if r['缺口天数']==r['考核天数']:assert row[16]=='待补里程'
|
||||
wr=list(w['逐日取数依据'].values)
|
||||
for row,x in zip(wr[1:],d['daily']):
|
||||
if x['included'] is None:assert row[11] in (None,'')
|
||||
else:assert abs(row[11]-x['included'])<1e-8
|
||||
errors=[(s.title,c.coordinate,c.value) for s in w for row in s for c in row if c.data_type=='e']
|
||||
assert not errors,errors[:10]
|
||||
w.close()
|
||||
result=dict(status='passed',amount=d['summary']['amount'],ledger_items=len(d['ledger']),vehicle_days=len(seen),gaps=len(d['gaps']),source_files_unchanged=True,daily_selection_checked=True,ledger_independently_reconciled=True,duplicate_historical_backpay=False,formula_errors=errors)
|
||||
(P/'verification.json').write_text(json.dumps(result,ensure_ascii=False,indent=2));print(json.dumps(result,ensure_ascii=False,indent=2))
|
||||
else:print('Independent calculation checks passed; waiting for workbook export.')
|
||||
Reference in New Issue
Block a user