跳转到内容

案例 11:政务人才补贴资格审核

本案例对应 JQuick-Java 仓库 USE-CASES.md 中的场景 11,面向政务企服领域的人才安家、创业、租房补贴线上申报审核。系统对每份补贴申请先做失信/刑事/重复申领的一票否决,再按学历、年龄、本地社保、人才认定、创业带动就业五个维度独立评分,产出「通过 / 人工复核 / 驳回」结论;仅审核通过时,才按学历、人才类别、带动就业分项核定补贴金额,全部决策口径由 JQuick-Java 的 XML 规则代理驱动。

人才补贴是各地政务服务中的高频申报事项。申请人在线提交安家补贴(SETTLEMENT)、创业补贴(STARTUP)或租房补贴(RENT)申请,填报学历(PHD / MASTER / BACHELOR / COLLEGE)、年龄、本地社保连续缴纳月数、高层次人才认定类别(A / B / C / NONE)、是否在本市创办企业及带动就业人数,并授权审核部门核查失信被执行、刑事犯罪、同类补贴已享受记录与申报材料完整性。

审核决策分两段完成。第一段是资格闸门:失信被执行、刑事犯罪记录、已享受同类补贴三项中任一命中即一票否决直接驳回;材料不齐全的申请退回补正并转人工复核;材料齐全的申请进入五维评分,总分 110 分,75 分及以上审核通过(QUALIFIED),50 分至 74 分转人工复核(MANUAL_REVIEW),50 分以下驳回(REJECTED)。

第二段是分项定额,且只对 QUALIFIED 的申请生效:学历安家补贴按博士 10 万、硕士 6 万、本科 3 万、大专 1 万定额;人才认定奖励按 A 类 20 万、B 类 10 万、C 类 5 万定额;创业带动就业奖励按带动 ≥10 人 10 万、≥5 人 5 万、≥1 人 2 万定额,三项汇总为核定补贴金额。复核与驳回申请一律暂不定额。

除结论与定额外,决策结果还包含逐条审核依据(reasons):命中否决项的原因、材料补正提示、资格评分、处于复核区间或未达标准的说明,支撑窗口告知、人工复核与事后审计回溯。

  • 政策口径多且散落在硬编码里:五维评分的分档阈值(如社保 36/24/12/6 月)、75/50 分级线、三项补贴定额表分布在大量 if-else 中,代码可读性差,业务人员无法直接核对。
  • 政策调整频繁却要走完整发版:人才政策常按年度调整评分线与奖励金额,每次调整都需要修改 Java 代码、重新编译打包政务系统,发布窗口长、审批链路重。
  • 否决、补正、评分、定额四种逻辑耦合:一票否决优先、材料不齐补正、分数分级、仅通过才定额的先后顺序一旦写乱,就会出现「已驳回却算出补贴」这类原则性错误。
  • 五个评分维度难以独立调参与审计:学历分、年龄分、社保分、人才分、创业分若揉在一个大方法里,无法单独解释申请人每一项得了多少分,不满足政务审核的可追溯要求。
  • 信创与老旧系统环境难引入重型规则平台:不少政务系统仍运行在 JDK 8 或国产化配套 JDK 上,独立规则服务器、数据库型规则平台等重型中间件难以落地。
  • 否决与定额结果需要可解释:驳回必须给出命中的具体否决项或补正原因,通过必须给出分项金额构成,黑盒评分无法支撑行政告知与行政复议。

本案例采用「入参模型 + 决策结果模型 + 规则接口 + XML 规则脚本 + Service 编排 + JUnit 测试」六件套结构,评分口径、否决项、分级阈值与定额表全部外置在 XML 中,Service 只负责汇总与装配:

层次 职责 对应文件
领域模型 补贴申请要素、审核决策(评分/结论/分项金额/说明) SubsidyApplication.java、SubsidyDecision.java
规则集与 XML 五维评分 + 一票否决 + 分级结论 + 三项定额 SubsidyRules.java、subsidy-eligibility.xml
编排服务 五维评分汇总、否决/补正前置、仅通过时定额、说明组装 SubsidyService.java
测试 6 组申报形态(通过、临界、复核、否决、补正、驳回) SubsidyServiceTest.java

规则接口共 10 个方法,评分类每个维度一个口径,决策类只管映射:

规则方法 口径 分值/输出
scoreEducation 博士 30 / 硕士 22 / 本科 15 / 大专及其他 8 0 ~ 30
scoreAge ≤30 岁 15 / ≤35 岁 12 / ≤40 岁 8 / ≤45 岁 4 / 其余 0 0 ~ 15
scoreSocialSecurity 本地社保 ≥36 月 20 / ≥24 月 15 / ≥12 月 10 / ≥6 月 5 / 其余 0 0 ~ 20
scoreTalent A 类 25 / B 类 18 / C 类 10 / 未认定 0 0 ~ 25
scoreStartup 已创办企业且带动 ≥10 人 20 / ≥5 人 14 / ≥1 人 8;未注册 0 0 ~ 20
hardReject 失信被执行、刑事犯罪、重复申领任一命中返回 true boolean
eligibilityStage 否决优先 REJECTED → 材料不齐 MANUAL_REVIEW → ≥75 QUALIFIED / ≥50 MANUAL_REVIEW / 否则 REJECTED 结论字符串
educationAmount 博士 100000 / 硕士 60000 / 本科 30000 / 大专 10000 学历补贴定额
talentAmount A 类 200000 / B 类 100000 / C 类 50000 / 其他 0 人才奖励定额
startupAmount 已注册且带动 ≥10 人 100000 / ≥5 人 50000 / ≥1 人 20000;未注册 0 创业奖励定额

将以下六个文件按源码原包名放入 JQuick-Java 的测试工程:两个模型放在 com.github.paohaijiao.demo.model,规则接口与测试类放在 com.github.paohaijiao.demo,编排服务放在 com.github.paohaijiao.demo.service,XML 脚本放入 src/test/resources/demo/。保持目录与包名不变后,在工程根目录执行 mvn test -Dtest=SubsidyServiceTest 即可运行。

package com.github.paohaijiao.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 人才补贴申请要素(资格审核所需的申请人画像)
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SubsidyApplication {
/**
* 申请单号
*/
private String applyNo;
/**
* 申请人姓名
*/
private String applicantName;
/**
* 补贴类型:SETTLEMENT-安家补贴 / STARTUP-创业补贴 / RENT-租房补贴
*/
private String subsidyType;
/**
* 学历:PHD / MASTER / BACHELOR / COLLEGE
*/
private String education;
/**
* 年龄
*/
private int age;
/**
* 本地社保连续缴纳月数
*/
private int localSocialSecurityMonths;
/**
* 高层次人才认定类别:A / B / C / NONE
*/
private String talentCategory;
/**
* 是否在本市创办企业
*/
private boolean startupRegistered;
/**
* 创办企业带动就业人数
*/
private int startupEmployees;
/**
* 是否有失信被执行记录
*/
private boolean creditViolation;
/**
* 是否有刑事犯罪记录
*/
private boolean criminalRecord;
/**
* 是否已享受过同类补贴
*/
private boolean receivedSimilarSubsidy;
/**
* 申报材料是否齐全
*/
private boolean documentsComplete;
}
package com.github.paohaijiao.demo.model;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 人才补贴审核决策结果
*/
@Data
public class SubsidyDecision {
/**
* 申请单号
*/
private String applyNo;
/**
* 资格评分(0-110)
*/
private int qualificationScore;
/**
* 审核结论:QUALIFIED-通过 / MANUAL_REVIEW-人工复核 / REJECTED-驳回
*/
private String stage;
/**
* 核定补贴金额(仅审核通过时大于 0)
*/
private double subsidyAmount;
/**
* 学历补贴
*/
private double educationAmount;
/**
* 人才认定奖励
*/
private double talentAmount;
/**
* 创业带动就业奖励
*/
private double startupAmount;
/**
* 审核依据与说明
*/
private List<String> reasons = new ArrayList<String>();
public void addReason(String reason) {
this.reasons.add(reason);
}
}
package com.github.paohaijiao.demo;
import com.github.paohaijiao.xml.param.Param;
/**
* 场景 11:政务人才补贴资格审核规则集
* <p>
* 规则按「硬性否决前置 → 五维资格评分 → 分级结论 → 分项定额」拆分:
* <ul>
* <li>评分类:学历、年龄、本地社保、人才认定、创业带动就业</li>
* <li>决策类:一票否决、审核结论(通过/复核/驳回)、三项补贴金额</li>
* </ul>
* 规则脚本见 {@code src/test/resources/demo/subsidy-eligibility.xml}。
*/
public interface SubsidyRules {
int scoreEducation(@Param("education") String education);
int scoreAge(@Param("age") int age);
int scoreSocialSecurity(@Param("months") int months);
int scoreTalent(@Param("talentCategory") String talentCategory);
int scoreStartup(@Param("startupRegistered") boolean startupRegistered,
@Param("startupEmployees") int startupEmployees);
boolean hardReject(@Param("creditViolation") boolean creditViolation,
@Param("criminalRecord") boolean criminalRecord,
@Param("receivedSimilarSubsidy") boolean receivedSimilarSubsidy);
String eligibilityStage(@Param("qualificationScore") int qualificationScore,
@Param("hardReject") boolean hardReject,
@Param("documentsComplete") boolean documentsComplete);
double educationAmount(@Param("education") String education);
double talentAmount(@Param("talentCategory") String talentCategory);
double startupAmount(@Param("startupRegistered") boolean startupRegistered,
@Param("startupEmployees") int startupEmployees);
}
<?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.SubsidyRules">
<!-- 学历评分 -->
<java name="scoreEducation" returnClass="int">
<![CDATA[
int def scoreEducation(str:education) {
if (education == "PHD") {
return 30;
} else if (education == "MASTER") {
return 22;
} else if (education == "BACHELOR") {
return 15;
} else {
return 8;
}
}
]]>
</java>
<!-- 年龄评分:青年人才优先 -->
<java name="scoreAge" returnClass="int">
<![CDATA[
int def scoreAge(int:age) {
if (age <= 30) {
return 15;
} else if (age <= 35) {
return 12;
} else if (age <= 40) {
return 8;
} else if (age <= 45) {
return 4;
} else {
return 0;
}
}
]]>
</java>
<!-- 本地社保连续性评分 -->
<java name="scoreSocialSecurity" returnClass="int">
<![CDATA[
int def scoreSocialSecurity(int:months) {
if (months >= 36) {
return 20;
} else if (months >= 24) {
return 15;
} else if (months >= 12) {
return 10;
} else if (months >= 6) {
return 5;
} else {
return 0;
}
}
]]>
</java>
<!-- 高层次人才认定评分 -->
<java name="scoreTalent" returnClass="int">
<![CDATA[
int def scoreTalent(str:talentCategory) {
if (talentCategory == "A") {
return 25;
} else if (talentCategory == "B") {
return 18;
} else if (talentCategory == "C") {
return 10;
} else {
return 0;
}
}
]]>
</java>
<!-- 创业带动就业评分 -->
<java name="scoreStartup" returnClass="int">
<![CDATA[
int def scoreStartup(boolean:startupRegistered, int:startupEmployees) {
if (startupRegistered) {
if (startupEmployees >= 10) {
return 20;
} else if (startupEmployees >= 5) {
return 14;
} else if (startupEmployees >= 1) {
return 8;
} else {
return 0;
}
} else {
return 0;
}
}
]]>
</java>
<!-- 硬性否决:失信、刑事犯罪、重复申领 -->
<java name="hardReject" returnClass="boolean">
<![CDATA[
boolean def hardReject(boolean:creditViolation, boolean:criminalRecord, boolean:receivedSimilarSubsidy) {
if (creditViolation || criminalRecord || receivedSimilarSubsidy) {
return true;
} else {
return false;
}
}
]]>
</java>
<!-- 审核结论:硬否决优先,其次材料补正,最后按分数分级 -->
<java name="eligibilityStage" returnClass="java.lang.String">
<![CDATA[
str def eligibilityStage(int:qualificationScore, boolean:hardReject, boolean:documentsComplete) {
if (hardReject) {
return "REJECTED";
} else if (documentsComplete == false) {
return "MANUAL_REVIEW";
} else if (qualificationScore >= 75) {
return "QUALIFIED";
} else if (qualificationScore >= 50) {
return "MANUAL_REVIEW";
} else {
return "REJECTED";
}
}
]]>
</java>
<!-- 学历安家补贴定额 -->
<java name="educationAmount" returnClass="double">
<![CDATA[
double def educationAmount(str:education) {
if (education == "PHD") {
return 100000.0;
} else if (education == "MASTER") {
return 60000.0;
} else if (education == "BACHELOR") {
return 30000.0;
} else {
return 10000.0;
}
}
]]>
</java>
<!-- 人才认定奖励定额 -->
<java name="talentAmount" returnClass="double">
<![CDATA[
double def talentAmount(str:talentCategory) {
if (talentCategory == "A") {
return 200000.0;
} else if (talentCategory == "B") {
return 100000.0;
} else if (talentCategory == "C") {
return 50000.0;
} else {
return 0.0;
}
}
]]>
</java>
<!-- 创业带动就业奖励定额 -->
<java name="startupAmount" returnClass="double">
<![CDATA[
double def startupAmount(boolean:startupRegistered, int:startupEmployees) {
if (startupRegistered) {
if (startupEmployees >= 10) {
return 100000.0;
} else if (startupEmployees >= 5) {
return 50000.0;
} else if (startupEmployees >= 1) {
return 20000.0;
} else {
return 0.0;
}
} else {
return 0.0;
}
}
]]>
</java>
</javas>
package com.github.paohaijiao.demo.service;
import com.github.paohaijiao.demo.SubsidyRules;
import com.github.paohaijiao.demo.model.SubsidyApplication;
import com.github.paohaijiao.demo.model.SubsidyDecision;
/**
* 场景 11:政务人才补贴资格审核服务
* <p>
* 职责划分:
* <ul>
* <li><b>Java 侧</b>:五维评分汇总、结论装配、分项金额汇总、审核说明组装</li>
* <li><b>规则侧</b>:评分口径、一票否决项、分级阈值、补贴定额,全部外置在 XML 中</li>
* </ul>
*/
public class SubsidyService {
private final SubsidyRules rules;
public SubsidyService(SubsidyRules rules) {
this.rules = rules;
}
/**
* 审核人才补贴申请
*
* @param application 申请要素
* @return 审核决策
*/
public SubsidyDecision review(SubsidyApplication application) {
SubsidyDecision decision = new SubsidyDecision();
decision.setApplyNo(application.getApplyNo());
int score = rules.scoreEducation(application.getEducation())
+ rules.scoreAge(application.getAge())
+ rules.scoreSocialSecurity(application.getLocalSocialSecurityMonths())
+ rules.scoreTalent(application.getTalentCategory())
+ rules.scoreStartup(application.isStartupRegistered(), application.getStartupEmployees());
boolean hardReject = rules.hardReject(application.isCreditViolation(),
application.isCriminalRecord(), application.isReceivedSimilarSubsidy());
String stage = rules.eligibilityStage(score, hardReject, application.isDocumentsComplete());
decision.setQualificationScore(score);
decision.setStage(stage);
double educationAmount = rules.educationAmount(application.getEducation());
double talentAmount = rules.talentAmount(application.getTalentCategory());
double startupAmount = rules.startupAmount(application.isStartupRegistered(),
application.getStartupEmployees());
if ("QUALIFIED".equals(stage)) {
decision.setEducationAmount(educationAmount);
decision.setTalentAmount(talentAmount);
decision.setStartupAmount(startupAmount);
decision.setSubsidyAmount(educationAmount + talentAmount + startupAmount);
}
buildReasons(application, decision, hardReject);
return decision;
}
private void buildReasons(SubsidyApplication application, SubsidyDecision decision, boolean hardReject) {
if (application.isCreditViolation()) {
decision.addReason("存在失信被执行记录,触发一票否决");
}
if (application.isCriminalRecord()) {
decision.addReason("存在刑事犯罪记录,触发一票否决");
}
if (application.isReceivedSimilarSubsidy()) {
decision.addReason("已享受同类补贴,不得重复申领");
}
if (hardReject) {
return;
}
if (!application.isDocumentsComplete()) {
decision.addReason("申报材料不齐全,退回补正后转人工复核");
return;
}
decision.addReason("资格评分 " + decision.getQualificationScore() + " 分");
if ("QUALIFIED".equals(decision.getStage())) {
decision.addReason("审核通过,核定补贴 " + decision.getSubsidyAmount() + " 元");
} else if ("MANUAL_REVIEW".equals(decision.getStage())) {
decision.addReason("评分处于复核区间,转人工审核,暂不定额");
} else {
decision.addReason("资格评分未达补贴标准,驳回申请");
}
}
}
package com.github.paohaijiao.demo;
import com.github.paohaijiao.demo.model.SubsidyApplication;
import com.github.paohaijiao.demo.model.SubsidyDecision;
import com.github.paohaijiao.demo.service.SubsidyService;
import com.github.paohaijiao.xml.JQuickJava;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* 场景 11 生产级样板:政务人才补贴资格自动审核
* <p>
* 覆盖 6 组申报形态:高层次人才创业、硕士就业达标线、本科临界复核、
* 失信一票否决、材料不齐补正、低学历创业不达标。
*/
public class SubsidyServiceTest {
private SubsidyService service;
@Before
public void setUp() {
SubsidyRules rules = JQuickJava.create()
.createApi(SubsidyRules.class, "demo/subsidy-eligibility.xml");
this.service = new SubsidyService(rules);
}
/**
* 博士 A 类人才创业,带动就业 12 人 → 110 分,补贴 40 万
*/
@Test
public void shouldApproveTopTalentStartup() {
SubsidyApplication app = baseApplication("SUB-1101");
app.setEducation("PHD");
app.setAge(28);
app.setLocalSocialSecurityMonths(48);
app.setTalentCategory("A");
app.setStartupRegistered(true);
app.setStartupEmployees(12);
SubsidyDecision decision = service.review(app);
Assert.assertEquals(110, decision.getQualificationScore());
Assert.assertEquals("QUALIFIED", decision.getStage());
Assert.assertEquals(400000.0, decision.getSubsidyAmount(), 0.001);
Assert.assertEquals(100000.0, decision.getEducationAmount(), 0.001);
Assert.assertEquals(200000.0, decision.getTalentAmount(), 0.001);
Assert.assertEquals(100000.0, decision.getStartupAmount(), 0.001);
Assert.assertTrue(decision.getReasons().contains("审核通过,核定补贴 400000.0 元"));
}
/**
* 硕士 B 类人才稳定就业,评分恰为 75 达标线 → 通过,补贴 16 万
*/
@Test
public void shouldApproveAtQualificationLine() {
SubsidyApplication app = baseApplication("SUB-1102");
app.setEducation("MASTER");
app.setAge(28);
app.setLocalSocialSecurityMonths(36);
app.setTalentCategory("B");
app.setStartupRegistered(false);
app.setStartupEmployees(0);
SubsidyDecision decision = service.review(app);
Assert.assertEquals(75, decision.getQualificationScore());
Assert.assertEquals("QUALIFIED", decision.getStage());
Assert.assertEquals(160000.0, decision.getSubsidyAmount(), 0.001);
Assert.assertEquals(60000.0, decision.getEducationAmount(), 0.001);
Assert.assertEquals(100000.0, decision.getTalentAmount(), 0.001);
Assert.assertEquals(0.0, decision.getStartupAmount(), 0.001);
}
/**
* 本科 C 类人才,评分 55 处于复核区间 → 人工复核,暂不定额
*/
@Test
public void shouldRouteBorderlineApplicationToManualReview() {
SubsidyApplication app = baseApplication("SUB-1103");
app.setEducation("BACHELOR");
app.setAge(29);
app.setLocalSocialSecurityMonths(24);
app.setTalentCategory("C");
app.setStartupRegistered(false);
app.setStartupEmployees(0);
SubsidyDecision decision = service.review(app);
Assert.assertEquals(55, decision.getQualificationScore());
Assert.assertEquals("MANUAL_REVIEW", decision.getStage());
Assert.assertEquals(0.0, decision.getSubsidyAmount(), 0.001);
Assert.assertTrue(decision.getReasons().contains("评分处于复核区间,转人工审核,暂不定额"));
}
/**
* 硕士条件优秀但存在失信记录 → 一票否决直接驳回
*/
@Test
public void shouldRejectCreditViolationRegardlessOfScore() {
SubsidyApplication app = baseApplication("SUB-1104");
app.setEducation("MASTER");
app.setAge(30);
app.setLocalSocialSecurityMonths(40);
app.setTalentCategory("B");
app.setStartupRegistered(false);
app.setStartupEmployees(0);
app.setCreditViolation(true);
SubsidyDecision decision = service.review(app);
Assert.assertTrue(decision.getQualificationScore() >= 70);
Assert.assertEquals("REJECTED", decision.getStage());
Assert.assertEquals(0.0, decision.getSubsidyAmount(), 0.001);
Assert.assertTrue(decision.getReasons().contains("存在失信被执行记录,触发一票否决"));
}
/**
* 博士评分 65 但材料不齐 → 退回补正并人工复核
*/
@Test
public void shouldHoldApplicationForMissingDocuments() {
SubsidyApplication app = baseApplication("SUB-1105");
app.setEducation("PHD");
app.setAge(30);
app.setLocalSocialSecurityMonths(36);
app.setTalentCategory("NONE");
app.setStartupRegistered(false);
app.setStartupEmployees(0);
app.setDocumentsComplete(false);
SubsidyDecision decision = service.review(app);
Assert.assertEquals(65, decision.getQualificationScore());
Assert.assertEquals("MANUAL_REVIEW", decision.getStage());
Assert.assertEquals(0.0, decision.getSubsidyAmount(), 0.001);
Assert.assertTrue(decision.getReasons().contains("申报材料不齐全,退回补正后转人工复核"));
}
/**
* 大专学历创业带动 6 人就业,评分 36 未达标 → 驳回
*/
@Test
public void shouldRejectBelowStandardApplication() {
SubsidyApplication app = baseApplication("SUB-1106");
app.setEducation("COLLEGE");
app.setAge(42);
app.setLocalSocialSecurityMonths(12);
app.setTalentCategory("NONE");
app.setStartupRegistered(true);
app.setStartupEmployees(6);
SubsidyDecision decision = service.review(app);
Assert.assertEquals(36, decision.getQualificationScore());
Assert.assertEquals("REJECTED", decision.getStage());
Assert.assertEquals(0.0, decision.getSubsidyAmount(), 0.001);
Assert.assertTrue(decision.getReasons().contains("资格评分未达补贴标准,驳回申请"));
}
private SubsidyApplication baseApplication(String applyNo) {
SubsidyApplication app = new SubsidyApplication();
app.setApplyNo(applyNo);
app.setApplicantName("申请人");
app.setSubsidyType("SETTLEMENT");
app.setCreditViolation(false);
app.setCriminalRecord(false);
app.setReceivedSimilarSubsidy(false);
app.setDocumentsComplete(true);
return app;
}
}

在工程根目录执行:

Terminal window
mvn test -Dtest=SubsidyServiceTest
测试方法 构造的业务形态 关键断言/期望决策
shouldApproveTopTalentStartup 博士 A 类、28 岁、社保 48 月、创业带动 12 人(SUB-1101) 评分 110,QUALIFIED,学历 10 万 + 人才 20 万 + 创业 10 万,核定 400000.0
shouldApproveAtQualificationLine 硕士 B 类、28 岁、社保 36 月、未创业(SUB-1102) 评分恰为 75,QUALIFIED,核定 160000.0(60000+100000+0)
shouldRouteBorderlineApplicationToManualReview 本科 C 类、29 岁、社保 24 月(SUB-1103) 评分 55,MANUAL_REVIEW,补贴 0.0,说明「转人工审核,暂不定额」
shouldRejectCreditViolationRegardlessOfScore 硕士 B 类评分 ≥70 但 creditViolation=true(SUB-1104) 评分再高仍 REJECTED,补贴 0.0,含失信一票否决说明
shouldHoldApplicationForMissingDocuments 博士评分 65 但 documentsComplete=false(SUB-1105) MANUAL_REVIEW,补贴 0.0,含「退回补正后转人工复核」说明
shouldRejectBelowStandardApplication 大专、42 岁、社保 12 月、创业带动 6 人(SUB-1106) 评分 36,REJECTED,补贴 0.0,含未达标准驳回说明

博士 A 类人才创业(28 岁、社保 48 月、带动就业 12 人):

资格评分: 110 审核结论: QUALIFIED
学历补贴: 100000.0 人才奖励: 200000.0 创业奖励: 100000.0
核定补贴: 400000.0

硕士条件优秀但失信(评分 ≥70,触发一票否决):

审核结论: REJECTED 核定补贴: 0.0
说明: 存在失信被执行记录,触发一票否决
  • 评分阈值与定额表全部外置 XML,支持热更新:75/50 分级线、社保月数分档、三项补贴金额都在 subsidy-eligibility.xml 中,政策调整只需改 XML 并重建代理,无需重新编译发版。
  • 五维评分一个方法一个口径,可独立调参与审计:scoreEducation、scoreAge、scoreSocialSecurity、scoreTalent、scoreStartup 各自独立计分,Service 侧线性相加,每一分都能向申请人解释来源。
  • 一票否决与材料补正前置在规则脚本中保证顺序:eligibilityStage 先判 hardReject、再判材料完整性、最后才按 75/50 分级,否决优先级不受分数影响;脚本以 documentsComplete == false 的正向比较表达取反(脚本不使用 ! 运算符)。
  • Service 在 Java 侧做定额闸门:三项金额方法虽始终被调用,但只有 "QUALIFIED".equals(stage) 时才写入决策结果,从结构上杜绝复核/驳回申请产生补贴金额。
  • @Param 按名绑定 + 代理实例可复用:接口参数通过 @Param("education") 等名称与 XML 脚本的 str:education 形参绑定,重构不依赖参数顺序;代理在 @Before 中创建一次,六个用例复用同一实例。
  • Java 8 无重型依赖、ASM 调用链可嵌入信创环境:模型仅用 Lombok 与 JDK 集合,规则代理走 ASM 生成的调用链,无需独立规则服务器,可直接嵌入仍在 JDK 8 与国产化 JDK 上运行的政务系统。