案例 22:国资项目立项投资额度合规校验
本案例对应 USE-CASES 场景 22「国资项目立项投资额度合规校验(诉求 18)」,属于国资监管领域,面向国有企业投资立项上会前的合规审查环节,自动完成投资额度对应审批层级判定、负面清单与资金红线核验,并按授权额度与投向对核定出资额分段截断。
国有企业投资项目立项前须报送合规审查,项目要素包括:项目类型(主业 MAIN / 非主业 NON_MAIN / 金融类 FINANCIAL / 房地产类 REAL_ESTATE)、申报总投资额、自有资金占比、资产负债率、董事会已授权出资额度、是否出具可行性研究报告与风险评估报告、预期年收益率。审查结论分三档:合规通过 COMPLIANT、附条件通过 CONDITIONAL(须补正材料或压降负债后上会)、不合规 NON_COMPLIANT。
审批权限按投资额度分层级:10000 万元及以上须报国资监管机构 SASAC,5000 万元及以上报集团董事会 GROUP,1000 万元及以上报公司董事会 BOARD,300 万元及以上报经营层 EXECUTIVE,其余由内部决策机构 INTERNAL 决策。系统同时对申报总投资额与董事会已授权出资额分别计算应履行层级(requiredLevel)与现有授权层级(grantedLevel),授权不足时要求上提审批程序。
出资额还要受投向与授权双重管控:核定出资额先在申报额与授权额之间取小;非主业项目在 3000 万元处封顶;金融类、房地产类属负面清单,核定出资额清零。硬性不合规项还包括:投向金融或房地产负面清单、非主业单笔投资 5000 万元以上未专项报批、自有资金比例低于 30% 红线、资产负债率超过 80% 红线。
附条件项覆盖非主业(5000 万以下)专项论证、自有资金比例处于 30%-40%、资产负债率处于 70%-80%、缺少可研或风评报告、预期收益率低于 3% 资金成本基准、授权层级不足等情形;当无阻断项但核定出资额小于申报额时,另附出资额截断说明。决策结果携带应履行/已授权两层级、核定出资额与全部 findings,直接形成上会合规意见。
- 审批权限阈值随授权办法修订:300/1000/5000/10000 万四级阈值与层级名称由集团授权管理办法规定,换届或办法修订后需要快速调整,硬编码进投资系统发版周期长。
- 投向管控是分段截断而非简单否决:授权额与申报额取小、非主业 3000 万封顶、金融地产清零,截断规则用 Java 分支写散后难以核对口径。
- 合规项分阻断与附条件两类:红线项必须判 NON_COMPLIANT,材料缺失、比例偏低只能判 CONDITIONAL,两类条件混写容易出现「以附条件放过红线」的错误。
- 审批层级既要比高低又要出中文名称:SASAC/GROUP/BOARD 等编码要先数值化比较,再映射回「国资监管机构/集团董事会」等中文层级写入整改意见。
- 立项意见须可追溯、可审计:国资监管要求每一条不合规项、上提审批路径、核定出资额都能在上会材料中逐条呈现。
- 国资信创环境与存量 JDK 8 系统约束:不能为单一合规环节引入重型规则平台。
本案例沿用六件套骨架:入参模型 + 决策结果模型 + 规则接口 + XML 规则脚本 + Service 编排 + 6 组真实业务形态测试。
| 层次 | 职责 | 对应文件 |
|---|---|---|
| 领域模型 | 国企投资立项要素、合规决策结果(结论/两层级/核定出资额/不合规项) | SoeInvestmentApplication.java、InvestmentComplianceDecision.java |
| 规则集与 XML | 审批层级额度阈值、授权与投向分段截断口径 | SoeInvestmentRules.java、soe-investment.xml |
| 编排服务 | 负面清单与资金红线核验、阻断/附条件分流、层级数值比较与中文名映射 | SoeInvestmentService.java |
| 测试 | 6 组投资形态(主业合规/三项附条件/地产否决/非主业截断/自有资金红线/授权上提) | SoeInvestmentServiceTest.java |
规则方法拆分
Section titled “规则方法拆分”| 规则方法 | 口径 | 分值/输出 |
|---|---|---|
approvalLevel |
额度对应审批层级:≥10000 万 SASAC、≥5000 万 GROUP、≥1000 万 BOARD、≥300 万 EXECUTIVE、否则 INTERNAL | 五种层级 |
cappedApprovedWan |
申报额与授权额取小;NON_MAIN 超 3000 万截断至 3000;FINANCIAL / REAL_ESTATE 清零 | 万元出资额 |
代码实现(完整可运行)
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=SoeInvestmentServiceTest 即可运行全部 6 个用例。
SoeInvestmentApplication.java
Section titled “SoeInvestmentApplication.java”package com.github.paohaijiao.demo.model;
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;
/** * 国有企业投资项目立项要素 */@Data@NoArgsConstructor@AllArgsConstructorpublic class SoeInvestmentApplication {
/** * 项目编号 */ private String projectId;
/** * 项目名称 */ private String projectName;
/** * 项目类型:MAIN-主业 / NON_MAIN-非主业 / FINANCIAL-金融类 / REAL_ESTATE-房地产类 */ private String projectType;
/** * 申报总投资额(万元) */ private int totalInvestmentWan;
/** * 自有资金占总投资比例(整数百分比) */ private int selfOwnedRatio;
/** * 资产负债率(整数百分比) */ private int debtRatio;
/** * 董事会已授权出资额度(万元) */ private int boardApprovalAmountWan;
/** * 是否出具可行性研究报告 */ private boolean hasFeasibilityReport;
/** * 是否出具风险评估报告 */ private boolean hasRiskAssessment;
/** * 预期年收益率(整数百分比) */ private int expectedReturnRate;}InvestmentComplianceDecision.java
Section titled “InvestmentComplianceDecision.java”package com.github.paohaijiao.demo.model;
import lombok.Data;
import java.util.ArrayList;import java.util.List;
/** * 国资投资项目立项合规决策结果 */@Datapublic class InvestmentComplianceDecision {
/** * 项目编号 */ private String projectId;
/** * 合规结论:COMPLIANT-合规通过 / CONDITIONAL-附条件通过 / NON_COMPLIANT-不合规 */ private String result;
/** * 按投资额应履行的审批层级:SASAC / GROUP / BOARD / EXECUTIVE / INTERNAL */ private String requiredLevel;
/** * 现有授权对应的审批层级 */ private String grantedLevel;
/** * 经负面清单、授权额度截断后的核定出资额(万元) */ private int cappedAmountWan;
/** * 不合规项与整改要求 */ private List<String> findings = new ArrayList<String>();
public void addFinding(String finding) { this.findings.add(finding); }}SoeInvestmentRules.java
Section titled “SoeInvestmentRules.java”package com.github.paohaijiao.demo;
import com.github.paohaijiao.xml.param.Param;
/** * 场景 22:国资项目立项投资额度合规规则集 * <p> * 按投资额度划分审批层级(300/1000/5000/10000 万四级阈值), * 并按负面清单与授权额度对出资额分段截断。 * 规则脚本见 {@code src/test/resources/demo/soe-investment.xml}。 */public interface SoeInvestmentRules {
/** 投资额度对应的审批层级:国资委 / 集团 / 公司董事会 / 经营层 / 内部 */ String approvalLevel(@Param("amountWan") int amountWan);
/** 核定出资额:授权额度与申报额取小,非主业 3000 万封顶,金融地产清零 */ int cappedApprovedWan(@Param("requestedWan") int requestedWan, @Param("grantedWan") int grantedWan, @Param("projectType") String projectType);}soe-investment.xml
Section titled “soe-investment.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.SoeInvestmentRules">
<!-- 审批层级:10000/5000/1000/300 万四级阈值 --> <java name="approvalLevel" returnClass="java.lang.String"> <![CDATA[ str def approvalLevel(int:amountWan) { if (amountWan >= 10000) { return "SASAC"; } else if (amountWan >= 5000) { return "GROUP"; } else if (amountWan >= 1000) { return "BOARD"; } else if (amountWan >= 300) { return "EXECUTIVE"; } else { return "INTERNAL"; } } ]]> </java>
<!-- 出资额截断:授权与申报取小,非主业 3000 万封顶,金融地产清零 --> <java name="cappedApprovedWan" returnClass="int"> <![CDATA[ int def cappedApprovedWan(int:requestedWan, int:grantedWan, str:projectType) { int limit = grantedWan; if (requestedWan < limit) { limit = requestedWan; } if (projectType == "NON_MAIN") { if (limit > 3000) { limit = 3000; } } if (projectType == "FINANCIAL") { limit = 0; } if (projectType == "REAL_ESTATE") { limit = 0; } return limit; } ]]> </java>
</javas>SoeInvestmentService.java
Section titled “SoeInvestmentService.java”package com.github.paohaijiao.demo.service;
import com.github.paohaijiao.demo.SoeInvestmentRules;import com.github.paohaijiao.demo.model.InvestmentComplianceDecision;import com.github.paohaijiao.demo.model.SoeInvestmentApplication;
import java.util.ArrayList;import java.util.List;
/** * 场景 22:国资项目立项投资额度合规校验服务 * <p> * 职责划分: * <ul> * <li><b>Java 侧</b>:负面清单、资金红线、材料完备性、审批层级高低等合规项核验</li> * <li><b>规则侧</b>:审批层级的额度阈值、出资额分段截断口径,外置在 XML 中</li> * </ul> */public class SoeInvestmentService {
private final SoeInvestmentRules rules;
public SoeInvestmentService(SoeInvestmentRules rules) { this.rules = rules; }
public InvestmentComplianceDecision review(SoeInvestmentApplication app) { InvestmentComplianceDecision decision = new InvestmentComplianceDecision(); decision.setProjectId(app.getProjectId());
String requiredLevel = rules.approvalLevel(app.getTotalInvestmentWan()); String grantedLevel = rules.approvalLevel(app.getBoardApprovalAmountWan()); decision.setRequiredLevel(requiredLevel); decision.setGrantedLevel(grantedLevel);
int capped = rules.cappedApprovedWan(app.getTotalInvestmentWan(), app.getBoardApprovalAmountWan(), app.getProjectType()); decision.setCappedAmountWan(capped);
List<String> blocking = new ArrayList<String>(); List<String> conditional = new ArrayList<String>();
if ("FINANCIAL".equals(app.getProjectType()) || "REAL_ESTATE".equals(app.getProjectType())) { blocking.add("投向金融类、房地产类负面清单领域,不符合国有资本投资方向"); } if ("NON_MAIN".equals(app.getProjectType()) && app.getTotalInvestmentWan() >= 5000) { blocking.add("非主业单笔投资 5000 万元以上须专项报批,本次不予通过"); } if (app.getSelfOwnedRatio() < 30) { blocking.add("自有资金比例 " + app.getSelfOwnedRatio() + "% 低于 30% 监管红线"); } if (app.getDebtRatio() > 80) { blocking.add("资产负债率 " + app.getDebtRatio() + "% 超过 80% 管控红线"); }
if ("NON_MAIN".equals(app.getProjectType()) && app.getTotalInvestmentWan() < 5000) { conditional.add("非主业投资须出具专项论证报告并说明协同效应"); } if (app.getSelfOwnedRatio() >= 30 && app.getSelfOwnedRatio() < 40) { conditional.add("自有资金比例偏低(低于 40%),须进一步落实资金来源"); } if (app.getDebtRatio() > 70 && app.getDebtRatio() <= 80) { conditional.add("资产负债率偏高(70%-80%),须同步报送负债压降方案"); } if (!app.isHasFeasibilityReport()) { conditional.add("缺少可行性研究报告,须补正后再上会"); } if (!app.isHasRiskAssessment()) { conditional.add("缺少风险评估报告,须补正后再上会"); } if (app.getExpectedReturnRate() < 3) { conditional.add("预期收益率 " + app.getExpectedReturnRate() + "% 低于 3% 资金成本基准,须重新测算"); } if (levelRank(grantedLevel) < levelRank(requiredLevel)) { conditional.add("现有授权层级(" + levelName(grantedLevel) + ")不足,须报" + levelName(requiredLevel) + "履行审批程序"); } if (blocking.isEmpty() && capped < app.getTotalInvestmentWan()) { conditional.add("出资额受授权额度与投向管控约束,核定出资 " + capped + " 万元"); }
for (String finding : blocking) { decision.addFinding(finding); } for (String finding : conditional) { decision.addFinding(finding); }
if (!blocking.isEmpty()) { decision.setResult("NON_COMPLIANT"); } else if (!conditional.isEmpty()) { decision.setResult("CONDITIONAL"); } else { decision.setResult("COMPLIANT"); } return decision; }
private int levelRank(String level) { if ("SASAC".equals(level)) { return 4; } if ("GROUP".equals(level)) { return 3; } if ("BOARD".equals(level)) { return 2; } if ("EXECUTIVE".equals(level)) { return 1; } return 0; }
private String levelName(String level) { if ("SASAC".equals(level)) { return "国资监管机构"; } if ("GROUP".equals(level)) { return "集团董事会"; } if ("BOARD".equals(level)) { return "公司董事会"; } if ("EXECUTIVE".equals(level)) { return "经营层"; } return "内部决策机构"; }}SoeInvestmentServiceTest.java
Section titled “SoeInvestmentServiceTest.java”package com.github.paohaijiao.demo;
import com.github.paohaijiao.demo.model.InvestmentComplianceDecision;import com.github.paohaijiao.demo.model.SoeInvestmentApplication;import com.github.paohaijiao.demo.service.SoeInvestmentService;import com.github.paohaijiao.xml.JQuickJava;import org.junit.Assert;import org.junit.Before;import org.junit.Test;
/** * 场景 22:国资项目立项投资额度合规校验 * <p> * 覆盖 6 组投资形态:主业大额合规通过、多项条件性通过、房地产负面清单、 * 非主业大额截断、自有资金红线、授权层级不足上提审批。 */public class SoeInvestmentServiceTest {
private SoeInvestmentService service;
@Before public void setUp() { SoeInvestmentRules rules = JQuickJava.create() .createApi(SoeInvestmentRules.class, "demo/soe-investment.xml"); this.service = new SoeInvestmentService(rules); }
/** * 主业 8000 万、自有 45%、负债 65%、材料齐全、授权充分、收益 8% → 合规通过 */ @Test public void shouldPassCompliantMainBusinessInvestment() { SoeInvestmentApplication app = baseApplication("SOE2026001", "MAIN", 8000); app.setSelfOwnedRatio(45); app.setDebtRatio(65); app.setBoardApprovalAmountWan(8000); app.setExpectedReturnRate(8);
InvestmentComplianceDecision decision = service.review(app);
Assert.assertEquals("COMPLIANT", decision.getResult()); Assert.assertEquals("GROUP", decision.getRequiredLevel()); Assert.assertEquals("GROUP", decision.getGrantedLevel()); Assert.assertEquals(8000, decision.getCappedAmountWan()); Assert.assertEquals(0, decision.getFindings().size()); }
/** * 主业 600 万但自有资金偏低、负债偏高、缺风评 → 附条件通过,三项整改 */ @Test public void shouldPassConditionallyWithThreeFindings() { SoeInvestmentApplication app = baseApplication("SOE2026002", "MAIN", 600); app.setSelfOwnedRatio(35); app.setDebtRatio(72); app.setBoardApprovalAmountWan(600); app.setHasRiskAssessment(false); app.setExpectedReturnRate(5);
InvestmentComplianceDecision decision = service.review(app);
Assert.assertEquals("CONDITIONAL", decision.getResult()); Assert.assertEquals("EXECUTIVE", decision.getRequiredLevel()); Assert.assertEquals(600, decision.getCappedAmountWan()); Assert.assertTrue(decision.getFindings().contains( "自有资金比例偏低(低于 40%),须进一步落实资金来源")); Assert.assertTrue(decision.getFindings().contains( "资产负债率偏高(70%-80%),须同步报送负债压降方案")); Assert.assertTrue(decision.getFindings().contains("缺少风险评估报告,须补正后再上会")); }
/** * 房地产类投资 5000 万 → 负面清单否决,核定出资 0 */ @Test public void shouldRejectRealEstateNegativeList() { SoeInvestmentApplication app = baseApplication("SOE2026003", "REAL_ESTATE", 5000); app.setSelfOwnedRatio(50); app.setDebtRatio(50); app.setBoardApprovalAmountWan(5000); app.setExpectedReturnRate(8);
InvestmentComplianceDecision decision = service.review(app);
Assert.assertEquals("NON_COMPLIANT", decision.getResult()); Assert.assertEquals("GROUP", decision.getRequiredLevel()); Assert.assertEquals(0, decision.getCappedAmountWan()); Assert.assertTrue(decision.getFindings().contains( "投向金融类、房地产类负面清单领域,不符合国有资本投资方向")); }
/** * 非主业 6000 万 → 超专项报批红线否决,出资额截断至 3000 万 */ @Test public void shouldRejectLargeNonMainInvestmentAndCapAt3000() { SoeInvestmentApplication app = baseApplication("SOE2026004", "NON_MAIN", 6000); app.setSelfOwnedRatio(50); app.setDebtRatio(50); app.setBoardApprovalAmountWan(6000); app.setExpectedReturnRate(6);
InvestmentComplianceDecision decision = service.review(app);
Assert.assertEquals("NON_COMPLIANT", decision.getResult()); Assert.assertEquals(3000, decision.getCappedAmountWan()); Assert.assertTrue(decision.getFindings().contains( "非主业单笔投资 5000 万元以上须专项报批,本次不予通过")); }
/** * 主业 2000 万但自有资金仅 25% → 触碰 30% 红线不予通过 */ @Test public void shouldRejectForSelfOwnedRatioBelowRedLine() { SoeInvestmentApplication app = baseApplication("SOE2026005", "MAIN", 2000); app.setSelfOwnedRatio(25); app.setDebtRatio(50); app.setBoardApprovalAmountWan(2000); app.setExpectedReturnRate(6);
InvestmentComplianceDecision decision = service.review(app);
Assert.assertEquals("NON_COMPLIANT", decision.getResult()); Assert.assertEquals("BOARD", decision.getRequiredLevel()); Assert.assertEquals(2000, decision.getCappedAmountWan()); Assert.assertTrue(decision.getFindings().contains( "自有资金比例 25% 低于 30% 监管红线")); }
/** * 申报 4000 万仅获经营层 500 万授权 → 须报公司董事会,核定出资截断至 500 万 */ @Test public void shouldRequireHigherApprovalLevel() { SoeInvestmentApplication app = baseApplication("SOE2026006", "MAIN", 4000); app.setSelfOwnedRatio(50); app.setDebtRatio(60); app.setBoardApprovalAmountWan(500); app.setExpectedReturnRate(6);
InvestmentComplianceDecision decision = service.review(app);
Assert.assertEquals("CONDITIONAL", decision.getResult()); Assert.assertEquals("BOARD", decision.getRequiredLevel()); Assert.assertEquals("EXECUTIVE", decision.getGrantedLevel()); Assert.assertEquals(500, decision.getCappedAmountWan()); Assert.assertTrue(decision.getFindings().contains( "现有授权层级(经营层)不足,须报公司董事会履行审批程序")); Assert.assertTrue(decision.getFindings().contains( "出资额受授权额度与投向管控约束,核定出资 500 万元")); }
private SoeInvestmentApplication baseApplication(String id, String type, int amount) { SoeInvestmentApplication app = new SoeInvestmentApplication(); app.setProjectId(id); app.setProjectName("测试投资项目"); app.setProjectType(type); app.setTotalInvestmentWan(amount); app.setSelfOwnedRatio(50); app.setDebtRatio(60); app.setBoardApprovalAmountWan(amount); app.setHasFeasibilityReport(true); app.setHasRiskAssessment(true); app.setExpectedReturnRate(6); return app; }}在工程根目录执行:
mvn test -Dtest=SoeInvestmentServiceTest测试覆盖形态
Section titled “测试覆盖形态”| 测试方法 | 构造的业务形态 | 关键断言/期望决策 |
|---|---|---|
shouldPassCompliantMainBusinessInvestment |
主业 8000 万、自有 45%、负债 65%、授权 8000 万、双报告齐全、收益 8% | COMPLIANT;required/granted 均为 GROUP;核定出资 8000 万;findings 0 条 |
shouldPassConditionallyWithThreeFindings |
主业 600 万、自有 35%、负债 72%、授权 600 万、缺风评、收益 5% | CONDITIONAL;required EXECUTIVE;核定 600 万;findings 含落实资金来源、报送负债压降方案、补风评三条 |
shouldRejectRealEstateNegativeList |
房地产类 5000 万、授权 5000 万、其余达标 | NON_COMPLIANT;required GROUP;核定出资 0;findings 含「金融类、房地产类负面清单」 |
shouldRejectLargeNonMainInvestmentAndCapAt3000 |
非主业 6000 万、授权 6000 万 | NON_COMPLIANT(5000 万以上须专项报批);核定出资截断至 3000 万 |
shouldRejectForSelfOwnedRatioBelowRedLine |
主业 2000 万但自有资金仅 25% | NON_COMPLIANT;required BOARD;核定出资 2000 万;findings 含「自有资金比例 25% 低于 30% 监管红线」 |
shouldRequireHigherApprovalLevel |
主业申报 4000 万但仅获 500 万经营层授权 | CONDITIONAL;required BOARD、granted EXECUTIVE;核定出资截断至 500 万;findings 含上提公司董事会审批与「核定出资 500 万元」两条 |
- 审批阈值与截断口径全量外置 XML:四级额度阈值、取小、非主业 3000 万封顶、金融地产清零均在两个脚本方法内,授权管理办法修订时只改 XML 即可,投资主系统免发版。
- 「取小 + 分段截断」在一个脚本方法内闭环:
cappedApprovedWan先在授权额与申报额间取小,再按投向逐段压降,Service 拿到的核定出资额必然同时满足授权与投向两条约束。 - 阻断项与附条件项分流装配:Service 用 blocking / conditional 两个列表归集,红线非空即 NON_COMPLIANT,红线空而整改项非空才 CONDITIONAL,杜绝以附条件放过红线。
- 层级编码数值化比较、中文名独立映射:
levelRank将五级编码映射为 0-4 比较高低,levelName单独维护「国资监管机构/集团董事会/公司董事会/经营层/内部决策机构」中文口径,比较逻辑与上会文案互不污染。 - 截断说明仅在无阻断项时挂接:出资额被管控收窄且项目本身可上会时,才追加「核定出资 X 万元」附条件说明,避免与负面清单否决意见自相矛盾。
@Param按名绑定 + ASM 动态代理 + Java 8 无重型依赖:可直接嵌入国企存量投资管理系统与信创配套 JDK 环境,合规意见逐条可审计。