How the China 个体工商户 (individual business) calculator is verified

Inputs

InputFieldType
Annual business profit (CNY)profitAnnualnumber
Social insurancesocialInsurancestring
Chosen monthly contribution base (7,270 to 36,348)contributionBasenumber
I also have salary or other comprehensive incomehasSalaryboolean

The formula

Each derived value below is computed by the Valem engine from the expression shown, in this order. Nothing else runs — there is no hidden code path.

Derived valueFieldFormula (JSONata)
Si BasesiBase$clampFloorCap($n(contributionBase), $const.siBaseFloor, $const.siBaseCap)
Your social insurance for the yearsocialInsuranceAnnualsocialInsurance = 'none' ? 0 : $round((siBase * $const.flexPensionRate + siBase * $const.flexUnemploymentRate + $const.flexMedicalMonthly) * 12, 2)
Taxable business incometaxableIncome($v := $n(profitAnnual) - (hasSalary ? 0 : socialInsuranceAnnual + $const.basicDeductionAnnual); $round($v > 0 ? $v : 0, 2))
Tax at 5–35%taxBeforeRelief$round($bandedCharge(taxableIncome, [{"upTo": $const.bizBand1, "rate": $const.bizRate1}, {"upTo": $const.bizBand2, "rate": $const.bizRate2}, {"upTo": $const.bizBand3, "rate": $const.bizRate3}, {"upTo": $const.bizBand4, "rate": $const.bizRate4}, {"upTo": null, "rate": $const.bizRate5}]), 2)
Halving relief (first 2 million)halvingRelief($t := taxableIncome < $const.halvingCap ? taxableIncome : $const.halvingCap; $round($bandedCharge($t, [{"upTo": $const.bizBand1, "rate": $const.bizRate1}, {"upTo": $const.bizBand2, "rate": $const.bizRate2}, {"upTo": $const.bizBand3, "rate": $const.bizRate3}, {"upTo": $const.bizBand4, "rate": $const.bizRate4}, {"upTo": null, "rate": $const.bizRate5}]) * $const.halvingShare, 2))
Income tax after the halvingincomeTax$round(taxBeforeRelief - halvingRelief, 2)
Net income / yearnetIncome$round($max([0, $n(profitAnnual) - socialInsuranceAnnual - incomeTax]), 2)

Rates and thresholds

The expressions above read these as $const. They are the figures the annual refresh replaces, so they live as data rather than being written into the formulas — which is what makes a year-on-year change a one-line diff instead of an edit to arithmetic.

ConstantValue
basicDeductionAnnual60000
bizBand130000
bizBand290000
bizBand3300000
bizBand4500000
bizRate10.05
bizRate20.1
bizRate30.2
bizRate40.3
bizRate50.35
halvingShare0.5
halvingCap2000000
siBaseFloor7270
siBaseCap36348
flexPensionRate0.2
flexUnemploymentRate0.01
flexMedicalMonthly593.68

Test vectors (7)

Every case is executed against this model on each build, by the Java engine and independently by a JavaScript one. A mismatch of a single cent fails the build, so the page cannot ship advertising a figure the model no longer produces.

Case 1 — E1 200,000 profit, Beijing insurance at the 7,270 floor: 25,444.56 of insurance, 12,411.09 before the halving, 6,205.54 relief

given profitAnnual200000
given socialInsurancebeijing
given contributionBase7270
given hasSalaryno
expect socialInsuranceAnnual25444.56
expect taxableIncome114555.44
expect taxBeforeRelief12411.09
expect halvingRelief6205.54
expect incomeTax6205.55

Case 2 — E1b 200,000 profit insured elsewhere: 140,000 taxable, 17,500 halved to 8,750

given profitAnnual200000
given socialInsurancenone
given contributionBase7270
given hasSalaryno
expect taxableIncome140000
expect taxBeforeRelief17500
expect halvingRelief8750
expect incomeTax8750
expect netIncome191250

Case 3 — E2 taxable income of exactly 80,000 — STA 解读 example 2 with no other relief: 6,500 tax, relief 3,250

given profitAnnual165444.56
given socialInsurancebeijing
given contributionBase7270
given hasSalaryno
expect taxableIncome80000
expect taxBeforeRelief6500
expect halvingRelief3250
expect incomeTax3250

Case 4 — E3 taxable income of 2,400,000 — STA 解读 example 3 with no other relief: half the tax on the first 2 million (317,250)

given profitAnnual2460000
given socialInsurancenone
given contributionBase7270
given hasSalaryno
expect taxableIncome2400000
expect taxBeforeRelief774500
expect halvingRelief317250
expect incomeTax457250

Case 5 — E4 at or below 60,000 with no insurance: nothing taxable

given profitAnnual60000
given socialInsurancenone
given contributionBase7270
given hasSalaryno
expect taxableIncome0
expect incomeTax0
expect netIncome60000

Case 6 — E5 base above the cap is clamped to 36,348

given profitAnnual500000
given socialInsurancebeijing
given contributionBase50000
given hasSalaryno
expect siBase36348
expect socialInsuranceAnnual98721.12

Case 7 — E6 200,000 profit with salary income elsewhere: no 60,000 deduction or insurance here, 29,500 halved to 14,750

given profitAnnual200000
given socialInsurancebeijing
given contributionBase7270
given hasSalaryyes
expect taxableIncome200000
expect taxBeforeRelief29500
expect halvingRelief14750
expect incomeTax14750
expect netIncome159805.44

Sources

Check it yourself — and reuse it

The whole model as JSON — inputs, outputs, formulas, vectors and sources in one re-runnable document.

This model is published under CC BY 4.0: use it, adapt it, build on it, with attribution. The licence covers the model — the expression of each rule and the arrangement of the catalog. The rates and thresholds are law, and nobody licenses those; the sources above are where they come from.

← Back to the China 个体工商户 (individual business) calculator

Built with Valem — a live, verifiable calculator you can fork and embed.