案例 23:小微税费减免/稳岗补贴资格判定
本案例对应 USE-CASES 场景 23「小微税费减免/稳岗补贴资格判定(诉求 21)」,属于财税合规领域,面向税务与人社部门的惠企政策兑现场景,自动完成小型微利企业资格判定、企业所得税分段优惠核算、小规模纳税人增值税征收率适用与稳岗返还定额核定。
小微企业通过统一惠企窗口申请税费减免与稳岗补贴,申报要素包括:纳税人类型(一般纳税人 GENERAL / 小规模纳税人 SMALL_SCALE)、从业人数(含劳务派遣)、资产总额、年应纳税所得额、是否属于限制或禁止行业,以及用于稳岗审核的社保连续缴纳月数、上年度裁员率、是否存在社保欠费或欠税、上年度实际缴纳失业保险费。
小型微利企业资格按三项条件同时满足判定:从业人数不超过 300 人、资产总额不超过 5000 万元、年应纳税所得额不超过 300 万元(三项临界值均含本数)。具备资格的企业企业所得税按分段实际税负核定:年应纳税所得额 100 万元以下部分实际税负 5%,超过 100 万元的部分实际税负 10%(即 5 万元 + 超出部分 × 10%);不具备资格的按 25% 法定税率缴纳。系统同时按 25% 口径计算法定应纳税额,与核定税额之差即减免额。
流转税与稳岗返还并行审核:小规模纳税人增值税减按 1% 征收率执行,一般纳税人不适用该项优惠(征收率记 0)。稳岗补贴须同时满足社保连续缴纳满 12 个月、上年度裁员率不超过 5%、无社保欠费三个条件,资格成立时按实缴失业保险费的 50% 核定补贴;企业存在欠税记录的,即使符合三项条件,稳岗返还也暂缓拨付、须清缴后另行申请。
限制或禁止行业属于硬性禁入:从事限制或禁止行业的企业一律 DENIED,所得税按法定税率完税、增值税优惠与稳岗返还全部归零,并在原因中明确禁入依据。最终决策携带小微资格、法定税额、核定税额、减免额、征收率、稳岗资格与补贴金额,以及逐项政策依据 reasons,支撑惠企政策兑现通知书的生成与税务留痕。
- 税收优惠口径随政策文件频繁调整:小型微利企业分段实际税负、1% 征收率、稳岗返还比例 50% 都可能随年度政策修订,硬编码进征管系统每次都要赶发版窗口。
- 分段税额核算容易出错:100 万以下 5%、100-300 万部分 10% 是「超额分段」而非全额分档,写成 if 套表常被误算为全额 10%。
- 资格条件与行业禁入优先级必须合规:限制行业即使三项规模全达标也不得享受,禁入判断必须先于税额与稳岗核算短路。
- 优惠种类多、结论要逐项可解释:所得税减免、增值税征收率、稳岗返还三类政策相互独立,企业不满足小微条件时还要逐条告知是人数、资产还是所得额超标。
- 欠税、欠费对补贴的影响易漏判:裁员率与社保条件达标但存在欠税的,补贴不是直接拒绝而是「暂缓拨付」,政策口径不同须区别表述。
- 金额口径要求精确:税额、补贴保留两位小数且禁止科学计数法,double 直接拼接可能产生 6000.0 之类不规范文书表述。
本案例沿用六件套骨架:入参模型 + 决策结果模型 + 规则接口 + XML 规则脚本 + Service 编排 + 6 组真实业务形态测试。
| 层次 | 职责 | 对应文件 |
|---|---|---|
| 领域模型 | 税费减免与稳岗补贴申请要素、核定结果(资格/三类金额/政策原因) | TaxReliefApplication.java、TaxReliefDecision.java |
| 规则集与 XML | 分段企业所得税、小规模征收率、稳岗资格条件、50% 返还定额 | TaxReliefRules.java、tax-relief.xml |
| 编排服务 | 小微三项条件与行业禁入、欠税暂缓、法定税额对比、金额精度与原因组装 | TaxReliefService.java |
| 测试 | 6 组企业形态(低档税率+稳岗/跨档税率/三项全超/临界值/限制行业/裁员与欠税) | TaxReliefServiceTest.java |
规则方法拆分
Section titled “规则方法拆分”| 规则方法 | 口径 | 分值/输出 |
|---|---|---|
incomeTaxWan |
具备小微资格:所得额 ≤100 万部分 ×5%,超出部分 = 5.0 +(所得额 - 100)×10%;不具备:×25% | 万元税额 |
vatLevyRate |
SMALL_SCALE 返回 0.01,其余返回 0.0(不适用该优惠) | 征收率 |
stabilizationEligible |
社保 ≥12 月、裁员率 ≤5%、无社保欠费三者同时成立 | boolean |
subsidyAmountWan |
资格成立时实缴失业保险费 ×50%,否则为 0 | 万元补贴 |
代码实现(完整可运行)
Section titled “代码实现(完整可运行)”将下列文件按源码包结构放入 JQuick-Java 工程的测试目录:两个模型放入 src/test/java/com/github/paohaijiao/demo/model/,规则接口与测试类放入 src/test/java/com/github/paohaijiao/demo/,Service 放入 src/test/java/com/github/paohaijiao/demo/service/,XML 脚本放入 src/test/resources/demo/,包名保持源码原样(com.github.paohaijiao.demo / .model / .service)。放入后执行 mvn test -Dtest=TaxReliefServiceTest 即可运行全部 6 个用例。
TaxReliefApplication.java
Section titled “TaxReliefApplication.java”package com.github.paohaijiao.demo.model;
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;
/** * 小微企业税费减免与稳岗补贴申请要素 */@Data@NoArgsConstructor@AllArgsConstructorpublic class TaxReliefApplication {
/** * 企业编号 */ private String enterpriseId;
/** * 企业名称 */ private String enterpriseName;
/** * 纳税人类型:GENERAL-一般纳税人 / SMALL_SCALE-小规模纳税人 */ private String taxpayerType;
/** * 从业人数(含劳务派遣) */ private int employeeCount;
/** * 资产总额(万元) */ private double totalAssetsWan;
/** * 年应纳税所得额(万元) */ private double annualTaxableIncomeWan;
/** * 是否属于限制或禁止行业 */ private boolean restrictedIndustry;
/** * 社保连续缴纳月数(稳岗补贴审核用) */ private int socialInsuranceMonths;
/** * 上年度裁员率(整数百分比) */ private int layoffRate;
/** * 是否存在社保欠费 */ private boolean socialArrears;
/** * 是否存在欠税 */ private boolean overdueTax;
/** * 上年度实际缴纳失业保险费(万元) */ private double paidUnemploymentInsuranceWan;}TaxReliefDecision.java
Section titled “TaxReliefDecision.java”package com.github.paohaijiao.demo.model;
import lombok.Data;
import java.util.ArrayList;import java.util.List;
/** * 税费减免与稳岗补贴核定结果 */@Datapublic class TaxReliefDecision {
/** * 企业编号 */ private String enterpriseId;
/** * 办理结论:APPROVED-可享受优惠 / DENIED-不予享受 */ private String result;
/** * 是否具备小型微利企业资格 */ private boolean smallQualified;
/** * 法定应纳企业所得税(25% 口径,万元) */ private double statutoryTaxWan;
/** * 核定应纳企业所得税(万元) */ private double incomeTaxWan;
/** * 企业所得税减免额(万元) */ private double taxSavingWan;
/** * 增值税征收率(小规模优惠为 0.01,不适用为 0) */ private double vatLevyRate;
/** * 是否具备稳岗补贴资格 */ private boolean stabilizationEligible;
/** * 核定稳岗补贴金额(万元) */ private double stabilizationSubsidyWan;
/** * 资格判定与政策依据 */ private List<String> reasons = new ArrayList<String>();
public void addReason(String reason) { this.reasons.add(reason); }}TaxReliefRules.java
Section titled “TaxReliefRules.java”package com.github.paohaijiao.demo;
import com.github.paohaijiao.xml.param.Param;
/** * 场景 23:小微企业税费减免与稳岗补贴规则集 * <p> * 小型微利企业所得税分段实际税负:100 万以下部分 5%、100-300 万部分 10%; * 小规模纳税人增值税征收率 1%;稳岗补贴为实缴失业保险费的 50%。 * 规则脚本见 {@code src/test/resources/demo/tax-relief.xml}。 */public interface TaxReliefRules {
/** 核定企业所得税(万元):符合小微条件分段优惠,否则按 25% 法定税率 */ double incomeTaxWan(@Param("incomeWan") double incomeWan, @Param("smallQualified") boolean smallQualified);
/** 增值税征收率:小规模纳税人减按 1%,一般纳税人不适用该优惠 */ double vatLevyRate(@Param("taxpayerType") String taxpayerType);
/** 稳岗补贴资格:社保满 12 月、裁员率不超过 5%、无社保欠费 */ boolean stabilizationEligible(@Param("ssMonths") int ssMonths, @Param("layoffRate") int layoffRate, @Param("noArrears") boolean noArrears);
/** 稳岗补贴定额:资格成立时为实缴失业保险费的 50% */ double subsidyAmountWan(@Param("paidUiWan") double paidUiWan, @Param("eligible") boolean eligible);}tax-relief.xml
Section titled “tax-relief.xml”<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE javas PUBLIC "-//PAOHAIJIAO//DTD API JAVA 1.0//EN" "classpath:paohaijiao/dtd/Jquick-java.dtd"><javas namespace="com.github.paohaijiao.demo.TaxReliefRules">
<!-- 企业所得税:小微分段优惠(100 万以下 5%,100-300 万部分 10%),否则 25% --> <java name="incomeTaxWan" returnClass="double"> <![CDATA[ double def incomeTaxWan(double:incomeWan, boolean:smallQualified) { double tax = 0.0; if (smallQualified) { if (incomeWan <= 100.0) { tax = incomeWan * 0.05; } else { tax = 5.0 + (incomeWan - 100.0) * 0.10; } } else { tax = incomeWan * 0.25; } return tax; } ]]> </java>
<!-- 增值税征收率:小规模 1%,一般纳税人不适用此优惠(0 表示不涉及) --> <java name="vatLevyRate" returnClass="double"> <![CDATA[ double def vatLevyRate(str:taxpayerType) { if (taxpayerType == "SMALL_SCALE") { return 0.01; } else { return 0.0; } } ]]> </java>
<!-- 稳岗补贴资格:社保 12 月以上、裁员率 5% 以下、无社保欠费 --> <java name="stabilizationEligible" returnClass="boolean"> <![CDATA[ boolean def stabilizationEligible(int:ssMonths, int:layoffRate, boolean:noArrears) { if (ssMonths >= 12) { if (layoffRate <= 5) { if (noArrears) { return true; } else { return false; } } else { return false; } } else { return false; } } ]]> </java>
<!-- 稳岗补贴定额:实缴失业保险费的 50% --> <java name="subsidyAmountWan" returnClass="double"> <![CDATA[ double def subsidyAmountWan(double:paidUiWan, boolean:eligible) { if (eligible) { return paidUiWan * 0.5; } else { return 0.0; } } ]]> </java>
</javas>TaxReliefService.java
Section titled “TaxReliefService.java”package com.github.paohaijiao.demo.service;
import com.github.paohaijiao.demo.TaxReliefRules;import com.github.paohaijiao.demo.model.TaxReliefApplication;import com.github.paohaijiao.demo.model.TaxReliefDecision;
import java.math.BigDecimal;import java.math.RoundingMode;
/** * 场景 23:小微企业税费减免 / 稳岗补贴资格判定服务 * <p> * 职责划分: * <ul> * <li><b>Java 侧</b>:小型微利企业三项条件(人数/资产/所得额)、行业禁入、 * 欠税冻结、法定税额与减免额对比核算</li> * <li><b>规则侧</b>:分段实际税负、小规模征收率、稳岗资格与返还比例,外置在 XML 中</li> * </ul> */public class TaxReliefService {
private static final int EMPLOYEE_LIMIT = 300; private static final double ASSETS_LIMIT_WAN = 5000.0; private static final double INCOME_LIMIT_WAN = 300.0;
private final TaxReliefRules rules;
public TaxReliefService(TaxReliefRules rules) { this.rules = rules; }
public TaxReliefDecision evaluate(TaxReliefApplication app) { TaxReliefDecision decision = new TaxReliefDecision(); decision.setEnterpriseId(app.getEnterpriseId());
double income = app.getAnnualTaxableIncomeWan(); double statutory = round2(income * 0.25); decision.setStatutoryTaxWan(statutory);
if (app.isRestrictedIndustry()) { decision.setResult("DENIED"); decision.setSmallQualified(false); decision.setIncomeTaxWan(statutory); decision.setTaxSavingWan(0.0); decision.setVatLevyRate(0.0); decision.setStabilizationEligible(false); decision.setStabilizationSubsidyWan(0.0); decision.addReason("企业从事限制或禁止行业,不得享受小型微利企业税收优惠及稳岗返还"); return decision; }
decision.setResult("APPROVED");
boolean employeeOk = app.getEmployeeCount() <= EMPLOYEE_LIMIT; boolean assetsOk = app.getTotalAssetsWan() <= ASSETS_LIMIT_WAN; boolean incomeOk = income <= INCOME_LIMIT_WAN; boolean qualified = employeeOk && assetsOk && incomeOk; decision.setSmallQualified(qualified);
double tax = round2(rules.incomeTaxWan(income, qualified)); decision.setIncomeTaxWan(tax); decision.setTaxSavingWan(round2(statutory - tax));
if (qualified) { decision.addReason("符合小型微利企业条件,年应纳企业所得税核定为 " + tax + " 万元," + "较法定税率减免 " + decision.getTaxSavingWan() + " 万元"); } else { decision.addReason("不满足小型微利企业条件,按 25% 法定税率缴纳企业所得税 " + statutory + " 万元"); if (!employeeOk) { decision.addReason("从业人数 " + app.getEmployeeCount() + " 人超过 300 人标准"); } if (!assetsOk) { decision.addReason("资产总额 " + money(app.getTotalAssetsWan()) + " 万元超过 5000 万元标准"); } if (!incomeOk) { decision.addReason("年应纳税所得额超过 300 万元标准"); } }
double vatRate = rules.vatLevyRate(app.getTaxpayerType()); decision.setVatLevyRate(vatRate); if (vatRate > 0.0) { decision.addReason("小规模纳税人增值税减按 1% 征收率执行"); }
boolean stable = rules.stabilizationEligible(app.getSocialInsuranceMonths(), app.getLayoffRate(), !app.isSocialArrears()); if (stable && app.isOverdueTax()) { stable = false; decision.addReason("企业存在欠税记录,稳岗返还暂缓拨付,清缴后另行申请"); } decision.setStabilizationEligible(stable); double subsidy = round2(rules.subsidyAmountWan(app.getPaidUnemploymentInsuranceWan(), stable)); decision.setStabilizationSubsidyWan(subsidy); if (stable) { decision.addReason("符合稳岗返还条件,按实缴失业保险费 50% 核定补贴 " + subsidy + " 万元"); } else if (!app.isOverdueTax()) { decision.addReason("不满足稳岗返还条件(社保连续缴纳满 12 月、裁员率 5% 以下、无社保欠费)"); } return decision; }
private double round2(double value) { return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP).doubleValue(); }
/** 金额文本:固定两位小数且禁用科学计数法 */ private String money(double value) { return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP).toPlainString(); }}TaxReliefServiceTest.java
Section titled “TaxReliefServiceTest.java”package com.github.paohaijiao.demo;
import com.github.paohaijiao.demo.model.TaxReliefApplication;import com.github.paohaijiao.demo.model.TaxReliefDecision;import com.github.paohaijiao.demo.service.TaxReliefService;import com.github.paohaijiao.xml.JQuickJava;import org.junit.Assert;import org.junit.Before;import org.junit.Test;
/** * 场景 23:小微企业税费减免 / 稳岗补贴资格判定 * <p> * 覆盖 6 组企业形态:小规模低档税率、一般纳税人跨档税率、三项标准超标、 * 临界值小微企业、限制行业禁入、裁员率与欠税影响稳岗返还。 */public class TaxReliefServiceTest {
private TaxReliefService service;
@Before public void setUp() { TaxReliefRules rules = JQuickJava.create() .createApi(TaxReliefRules.class, "demo/tax-relief.xml"); this.service = new TaxReliefService(rules); }
/** * 小规模纳税人,80 人、所得额 80 万、稳岗条件齐全 → 所得税 5% 缴 4 万,补贴 2 万 */ @Test public void shouldApplyFivePercentTaxAndStabilizationSubsidy() { TaxReliefApplication app = baseApplication("TR2026001", "SMALL_SCALE"); app.setEmployeeCount(80); app.setTotalAssetsWan(1000.0); app.setAnnualTaxableIncomeWan(80.0); app.setSocialInsuranceMonths(24); app.setLayoffRate(2); app.setPaidUnemploymentInsuranceWan(4.0);
TaxReliefDecision decision = service.evaluate(app);
Assert.assertEquals("APPROVED", decision.getResult()); Assert.assertTrue(decision.isSmallQualified()); Assert.assertEquals(20.0, decision.getStatutoryTaxWan(), 0.001); Assert.assertEquals(4.0, decision.getIncomeTaxWan(), 0.001); Assert.assertEquals(16.0, decision.getTaxSavingWan(), 0.001); Assert.assertEquals(0.01, decision.getVatLevyRate(), 0.00001); Assert.assertTrue(decision.isStabilizationEligible()); Assert.assertEquals(2.0, decision.getStabilizationSubsidyWan(), 0.001); }
/** * 一般纳税人,200 人、所得额 250 万跨档 → 5 + 150×10% = 20 万,社保不足无稳岗 */ @Test public void applySegmentedTaxForIncomeOverOneMillion() { TaxReliefApplication app = baseApplication("TR2026002", "GENERAL"); app.setEmployeeCount(200); app.setTotalAssetsWan(4000.0); app.setAnnualTaxableIncomeWan(250.0); app.setSocialInsuranceMonths(6); app.setLayoffRate(1); app.setPaidUnemploymentInsuranceWan(3.0);
TaxReliefDecision decision = service.evaluate(app);
Assert.assertTrue(decision.isSmallQualified()); Assert.assertEquals(62.5, decision.getStatutoryTaxWan(), 0.001); Assert.assertEquals(20.0, decision.getIncomeTaxWan(), 0.001); Assert.assertEquals(42.5, decision.getTaxSavingWan(), 0.001); Assert.assertEquals(0.0, decision.getVatLevyRate(), 0.00001); Assert.assertFalse(decision.isStabilizationEligible()); Assert.assertEquals(0.0, decision.getStabilizationSubsidyWan(), 0.001); }
/** * 400 人、资产 6000 万、所得额 400 万,三项标准全超 → 按 25% 完税,逐条告知 */ @Test public void shouldDenySmallTaxBenefitWhenAllLimitsExceeded() { TaxReliefApplication app = baseApplication("TR2026003", "GENERAL"); app.setEmployeeCount(400); app.setTotalAssetsWan(6000.0); app.setAnnualTaxableIncomeWan(400.0); app.setSocialInsuranceMonths(0); app.setLayoffRate(0);
TaxReliefDecision decision = service.evaluate(app);
Assert.assertFalse(decision.isSmallQualified()); Assert.assertEquals(100.0, decision.getIncomeTaxWan(), 0.001); Assert.assertEquals(0.0, decision.getTaxSavingWan(), 0.001); Assert.assertTrue(decision.getReasons().contains("从业人数 400 人超过 300 人标准")); Assert.assertTrue(decision.getReasons().contains("资产总额 6000.00 万元超过 5000 万元标准")); Assert.assertTrue(decision.getReasons().contains("年应纳税所得额超过 300 万元标准")); }
/** * 人数 300、资产 5000 万、所得额 300 万恰在临界值 → 仍具备小微资格,税 25 万 */ @Test public void shouldQualifyAtExactBoundaryValues() { TaxReliefApplication app = baseApplication("TR2026004", "GENERAL"); app.setEmployeeCount(300); app.setTotalAssetsWan(5000.0); app.setAnnualTaxableIncomeWan(300.0); app.setSocialInsuranceMonths(24); app.setLayoffRate(0);
TaxReliefDecision decision = service.evaluate(app);
Assert.assertTrue(decision.isSmallQualified()); Assert.assertEquals(75.0, decision.getStatutoryTaxWan(), 0.001); Assert.assertEquals(25.0, decision.getIncomeTaxWan(), 0.001); Assert.assertEquals(50.0, decision.getTaxSavingWan(), 0.001); }
/** * 限制行业企业即使规模符合 → 全面禁止享受,按法定税率完税 */ @Test public void shouldDenyAllBenefitsForRestrictedIndustry() { TaxReliefApplication app = baseApplication("TR2026005", "SMALL_SCALE"); app.setEmployeeCount(50); app.setTotalAssetsWan(500.0); app.setAnnualTaxableIncomeWan(80.0); app.setSocialInsuranceMonths(36); app.setLayoffRate(0); app.setPaidUnemploymentInsuranceWan(2.0); app.setRestrictedIndustry(true);
TaxReliefDecision decision = service.evaluate(app);
Assert.assertEquals("DENIED", decision.getResult()); Assert.assertFalse(decision.isSmallQualified()); Assert.assertEquals(20.0, decision.getIncomeTaxWan(), 0.001); Assert.assertEquals(0.0, decision.getTaxSavingWan(), 0.001); Assert.assertEquals(0.0, decision.getVatLevyRate(), 0.00001); Assert.assertFalse(decision.isStabilizationEligible()); Assert.assertTrue(decision.getReasons().contains( "企业从事限制或禁止行业,不得享受小型微利企业税收优惠及稳岗返还")); }
/** * 裁员率 8% 不符稳岗条件;裁员率达标但欠税的,稳岗返还暂缓 */ @Test public void shouldBlockStabilizationSubsidyForHighLayoffAndTaxDue() { TaxReliefApplication highLayoff = baseApplication("TR2026006", "SMALL_SCALE"); highLayoff.setEmployeeCount(100); highLayoff.setTotalAssetsWan(800.0); highLayoff.setAnnualTaxableIncomeWan(60.0); highLayoff.setSocialInsuranceMonths(24); highLayoff.setLayoffRate(8); highLayoff.setPaidUnemploymentInsuranceWan(4.0); TaxReliefDecision d1 = service.evaluate(highLayoff); Assert.assertTrue(d1.isSmallQualified()); Assert.assertEquals(3.0, d1.getIncomeTaxWan(), 0.001); Assert.assertFalse(d1.isStabilizationEligible()); Assert.assertEquals(0.0, d1.getStabilizationSubsidyWan(), 0.001);
TaxReliefApplication taxDue = baseApplication("TR2026007", "SMALL_SCALE"); taxDue.setEmployeeCount(100); taxDue.setTotalAssetsWan(800.0); taxDue.setAnnualTaxableIncomeWan(60.0); taxDue.setSocialInsuranceMonths(24); taxDue.setLayoffRate(2); taxDue.setPaidUnemploymentInsuranceWan(4.0); taxDue.setOverdueTax(true); TaxReliefDecision d2 = service.evaluate(taxDue); Assert.assertFalse(d2.isStabilizationEligible()); Assert.assertTrue(d2.getReasons().contains("企业存在欠税记录,稳岗返还暂缓拨付,清缴后另行申请")); }
private TaxReliefApplication baseApplication(String id, String taxpayerType) { TaxReliefApplication app = new TaxReliefApplication(); app.setEnterpriseId(id); app.setEnterpriseName("测试小微企业"); app.setTaxpayerType(taxpayerType); app.setEmployeeCount(100); app.setTotalAssetsWan(1000.0); app.setAnnualTaxableIncomeWan(100.0); app.setRestrictedIndustry(false); app.setSocialInsuranceMonths(12); app.setLayoffRate(0); app.setSocialArrears(false); app.setOverdueTax(false); app.setPaidUnemploymentInsuranceWan(0.0); return app; }}在工程根目录执行:
mvn test -Dtest=TaxReliefServiceTest测试覆盖形态
Section titled “测试覆盖形态”| 测试方法 | 构造的业务形态 | 关键断言/期望决策 |
|---|---|---|
shouldApplyFivePercentTaxAndStabilizationSubsidy |
小规模、80 人、资产 1000 万、所得额 80 万、社保 24 月、裁员 2%、实缴失业险 4 万 | APPROVED;法定 20 万、核定 4 万、减免 16 万;征收率 0.01;稳岗成立补贴 2.0 万 |
applySegmentedTaxForIncomeOverOneMillion |
一般纳税人、200 人、资产 4000 万、所得额 250 万、社保仅 6 月 | 小微资格成立;法定 62.5 万、核定 20 万(5 + 150×10%)、减免 42.5 万;征收率 0;稳岗不成立补贴 0 |
shouldDenySmallTaxBenefitWhenAllLimitsExceeded |
400 人、资产 6000 万、所得额 400 万,三项条件全超 | smallQualified=false;按 25% 完税 100 万、减免 0;原因逐条含「400 人超过 300 人」「资产总额 6000.00 万元超过 5000 万元」「所得额超过 300 万元」 |
shouldQualifyAtExactBoundaryValues |
300 人、资产 5000 万、所得额 300 万,三项均压线 | 临界值含本数,资格成立;法定 75 万、核定 25 万、减免 50 万 |
shouldDenyAllBenefitsForRestrictedIndustry |
小规模、50 人、资产 500 万、所得额 80 万但属于限制行业 | DENIED;所得税 20 万、减免 0、征收率 0、稳岗 false;原因含行业禁入说明 |
shouldBlockStabilizationSubsidyForHighLayoffAndTaxDue |
两个子场景:社保 24 月但裁员率 8%;裁员率 2% 但存在欠税 | 前者稳岗 false、补贴 0(所得税仍享 3 万);后者稳岗 false 且原因含「稳岗返还暂缓拨付,清缴后另行申请」 |
- 税率与补贴口径全量外置 XML:5%/10% 分段税负、25% 法定税率、1% 征收率、12 月/5% 稳岗条件、50% 返还比例均在脚本中,年度税费政策调整只需改 XML 重建代理,征管主系统免发版。
- 超额分段在脚本内一次算清:
incomeTaxWan对 100 万以上所得额按「5.0 + 超出部分 ×10%」计算,避免 Java 侧套表时误把全额按 10% 计税。 - 行业禁入与欠税暂缓 Java 侧短路:限制行业在所有核算前直接 DENIED 并归零三项优惠;欠税主体在规则判定之后再覆写稳岗资格,区分「不符合条件」与「暂缓拨付」两种政策表述。
- 布尔正向条件适配脚本语法:脚本不支持
!取反,Service 以!app.isSocialArrears()在 Java 侧转为正向noArrears传入,规则内只用正向嵌套 if 返回 true/false。 - 金额精度与文书口径在 Java 侧兜底:
round2用 BigDecimal HALF_UP 保留两位小数,money用 toPlainString 固定两位且禁用科学计数法,保证「资产总额 6000.00 万元」类文书表述规范。 - 不达标原因逐条装配、可审计可复议:三项规模条件各自独立判断并追加原因,法定税额、减免额、征收率、补贴金额与依据全部进入 reasons,可直接生成惠企兑现通知书。