"""R10原创构造算例;仅用标准库,任何工作目录均写回脚本同目录。""" from decimal import Decimal, ROUND_HALF_UP from pathlib import Path from math import ceil import json D = Decimal def rounded(n): return float(D(str(n)).quantize(D('0.01'), rounding=ROUND_HALF_UP)) def cash_path(opening, incomes, expenses): balance = opening rows = [] for month, (income, expense) in enumerate(zip(incomes, expenses), 1): before = balance balance += income - expense rows.append(dict(month=month, opening=before, income=income, expense=expense, closing=balance)) return dict(rows=rows, final=balance, minimum=min(r['closing'] for r in rows), total_income=sum(incomes), total_expense=sum(expenses)) def annual_tax(base): for cap, rate, quick in [(36000,'.03',0),(144000,'.10',2520),(300000,'.20',16920),(420000,'.25',31920),(660000,'.30',52920),(960000,'.35',85920),(D('Infinity'),'.45',181920)]: if base <= cap: return max(D(0), D(base)*D(rate)-D(quick)) out = {} a = [15000]*12 b = [17000]*12 b[-1] += 30000 delay = [17000]*12 out['DJ2-082'] = dict(constructed=True, inputs=dict(opening=24000, floor=15000, monthly_expense=18000, A_fixed_net=15000, B_fixed_net=17000, B_conditional_net_bonus=30000, bonus_month=12), A=cash_path(24000,a,[18000]*12), B=cash_path(24000,b,[18000]*12), B_bonus_outside=cash_path(24000,delay,[18000]*12)) rows=[]; cumulative=0; paid=D(0) for month in range(1,13): gross=14000 if month<=3 else 18000 deduction=2000 if month<=3 else 2400 cumulative+=gross-deduction-5000 target=annual_tax(cumulative) tax=max(D(0),target-paid);paid+=tax rows.append(dict(month=month,gross=gross,confirmed_deduction=deduction,cumulative_tax_base=cumulative,withheld=rounded(tax),net=rounded(D(gross-deduction)-tax))) out['DJ2-083']=dict(constructed=True,inputs=dict(year=2026,resident=True,same_employer_all_year=True,probation_months=3,base_monthly_deduction=5000,special_additional=0,other_income=0,withholding_relief=0),rows=rows,total_gross=sum(r['gross'] for r in rows),total_deductions=sum(r['confirmed_deduction'] for r in rows),total_withheld=rounded(paid),total_net=rounded(sum(D(str(r['net'])) for r in rows)),wrong_full_regular_gross=18000*12) costs=dict(moving=3200,travel=1200,temporary_housing=3600,overlap_rent=4000) increment=19500-16500-1800 out['DJ2-084']=dict(constructed=True,inputs=dict(old_net=16500,new_net=19500,monthly_extra_cost=1800,nonrefundable=costs,new_deposit=9000,old_deposit_refund=6000,refund_month=3),monthly_increment=increment,nonrefundable_total=sum(costs.values()),economic_payback_months=ceil(sum(costs.values())/increment),peak_initial_outflow=sum(costs.values())+9000,rows=[dict(month=m,increment=increment,refund=6000 if m==3 else 0,economic_balance=-12000+m*increment,cash_balance=-21000+m*increment+(6000 if m>=3 else 0)) for m in range(1,14)]) events=[('2026-11-02','房租',-7000),('2026-11-06','还款',-4000),('2026-11-10','生活支出',-2000),('2026-11-15','最后工资',9000),('2026-11-20','报销',3600),('2026-11-25','生活支出',-3000),('2026-12-05','新工作首次工资',16000)] def daily(opening, events): bal=opening; rr=[] for date,name,amount in events: bal+=amount;rr.append(dict(date=date,name=name,change=amount,balance=bal)) return dict(rows=rr,minimum=min(r['balance'] for r in rr),final=bal) out['DJ2-085']=dict(constructed=True,inputs=dict(opening=10000,events=events,repayment_is_existing_contract_assumption=True),base=daily(10000,events),reimbursement_late=daily(10000,[(d,n,a) for d,n,a in events if n!='报销']+[('2026-12-08','报销',3600)]),november=cash_path(10000,[12600],[16000])) gross=420000;threshold=300000;base=max(0,gross-threshold);tax=annual_tax(base) out['DJ2-086']=dict(constructed=True,inputs=dict(confirmed_total=gross,constructed_exempt_threshold=threshold,not_a_city_standard=True,payment_gross=[250000,170000],tax_all_in_second_batch=True),tax_base=base,tax=rounded(tax),net=rounded(gross-tax),batches=[dict(date='2026-11-30',gross=250000,tax=0,net=250000),dict(date='2026-12-31',gross=170000,tax=rounded(tax),net=rounded(D(170000)-tax))],wrong_monthly_table_tax=rounded(D(base)*D('.45')-15160),wrong_whole_amount_tax=rounded(annual_tax(gross)),threshold_change=dict(threshold=330000,base=90000,tax=rounded(annual_tax(90000)),net=rounded(D(gross)-annual_tax(90000)))) out['DJ2-087']=dict(constructed=True,inputs=dict(A_monthly_net=17000,B_monthly_net=16000,A_employer_hf=600,B_employer_hf=2400,A_meal_face=300,B_meal_face=1000,A_insurance_face=200,B_insurance_face=400,A_actual_saved=250,B_actual_saved=500,monthly_other_bills=15500),A=dict(face_total=18100,cash=17000,restricted=600,noncash=500,saved=250,cash_surplus=1750),B=dict(face_total=19800,cash=16000,restricted=2400,noncash=1400,saved=500,cash_surplus=1000)) def hourly(cash,work,commute,cost): return dict(cash=cash,work_hours=work,commute_hours=commute,cash_per_work_hour=rounded(D(cash)/D(work)),cash_per_occupied_hour=rounded(D(cash)/D(work+commute)),after_cost_per_occupied_hour=rounded(D(cash-cost)/D(work+commute))) out['DJ2-088']=dict(constructed=True,inputs=dict(A_net=216000,B_net=252000,A_regular_hours=1920,B_regular_hours=1920,A_overtime=120,B_overtime=480,A_commute=240,B_commute=480,A_extra_cost=4800,B_extra_cost=12000,working_days=240,no_legal_hours_judgment=True),A=hourly(216000,2040,240,4800),B=hourly(252000,2400,480,12000),B_short_commute=hourly(252000,2400,240,12000),B_busy=hourly(252000,2640,480,12000),B_equal_after_cost_cash=rounded(D(211200)/D(2280)*D(2880)+12000)) out['DJ2-089']=dict(constructed=True,inputs=dict(A_fixed_net=18000,A_bonus=0,B_fixed_net=16500,B_bonus_net_scenarios=[0,24000,48000],expense=17500,opening=20000,bonus_month=12),A=cash_path(20000,[18000]*12,[17500]*12),scenarios=[dict(name=name,bonus=bonus,annual_income=16500*12+bonus,annual_difference=16500*12+bonus-216000,path=cash_path(20000,[16500]*11+[16500+bonus],[17500]*12)) for name,bonus in [('保底',0),('条件',24000),('上限',48000)]],required_bonus_to_match_A=18000) out['DJ2-090']=dict(constructed=True,inputs=dict(opening=18000,monthly_living=10000,receipts=[12000,0,15000],gap_month=2,confirmed_scenario_social=1800,confirmed_scenario_hf=1200,stress_social=2400,stress_hf=1800,all_contributions_are_hypothetical_not_eligibility=True),no_amount_confirmed=dict(status='unknown',not_zero=True),scenario=cash_path(18000,[12000,0,15000],[10000,13000,10000]),stress=cash_path(18000,[12000,0,15000],[10000,14200,10000])) assert set(out)=={f'DJ2-{i:03}' for i in range(82,91)} assert out['DJ2-082']['B']['final']==42000 assert out['DJ2-084']['economic_payback_months']==10 assert out['DJ2-085']['base']['minimum']==-3000 assert out['DJ2-086']['tax']==9480 assert out['DJ2-090']['scenario']['minimum']==7000 Path(__file__).with_suffix('.json').write_text(json.dumps(out,ensure_ascii=False,indent=2)+'\n',encoding='utf-8') print('R10:九篇构造算例复算完成,JSON写入脚本同目录。')