Case 22: SOE investment compliance
This case corresponds to USE-CASES scenario 22, “Compliance review of investment amounts for SOE project approval (requirement 18)”. It belongs to the state-owned assets supervision domain, targeting the pre-meeting compliance review stage before an SOE investment project is submitted for approval. It automatically determines the approval level corresponding to the investment amount, verifies the negative list and capital red lines, and caps the approved contribution in stages according to the authorized amount and investment direction.
Industry scenario
Section titled “Industry scenario”Before approval, SOE investment projects must undergo compliance review. Project elements include: project type (core business MAIN / non-core business NON_MAIN / financial FINANCIAL / real estate REAL_ESTATE), declared total investment, self-owned capital ratio, debt-to-asset ratio, board-authorized contribution amount, whether a feasibility study report and a risk assessment report have been issued, and the expected annual return rate. The review conclusion has three tiers: COMPLIANT (approved), CONDITIONAL (approved with conditions, requiring supplementary materials or debt reduction before the meeting), and NON_COMPLIANT.
Approval authority is tiered by investment amount: 100 million yuan or more must be reported to the state-owned assets regulator (SASAC), 50 million yuan or more to the group board (GROUP), 10 million yuan or more to the company board (BOARD), 3 million yuan or more to the executive management (EXECUTIVE), and the rest is decided by the internal decision body (INTERNAL). The system computes the required level (requiredLevel) from the declared total investment and the granted level (grantedLevel) from the board-authorized contribution amount separately; when the authorization is insufficient, it requires escalation of the approval procedure.
The contribution amount is subject to dual control by direction and authorization: the approved contribution first takes the smaller of the declared amount and the authorized amount; non-core business projects are capped at 30 million yuan; financial and real estate projects are on the negative list and their approved contribution is zeroed out. Hard non-compliance items also include: investing in financial or real estate negative-list sectors, a single non-core-business investment of 50 million yuan or more without special approval, a self-owned capital ratio below the 30% red line, and a debt-to-asset ratio above the 80% red line.
Conditional items cover non-core-business investments (below 50 million yuan) requiring special justification, a self-owned capital ratio between 30% and 40%, a debt-to-asset ratio between 70% and 80%, missing feasibility or risk assessment reports, an expected return rate below the 3% cost-of-capital benchmark, and insufficient authorization level. When there are no blocking items but the approved contribution is lower than the declared amount, a contribution capping note is appended. The decision result carries both the required and granted levels, the approved contribution, and all findings, directly forming the compliance opinion for the meeting.
Business pain points
Section titled “Business pain points”- Approval authority thresholds change with authorization policy revisions: the four thresholds 3/10/50/100 million yuan and the level names are defined by the group authorization management policy; after a leadership change or policy revision they must be adjusted quickly, while hard-coding them into the investment system leads to long release cycles.
- Direction control is staged capping, not simple rejection: taking the smaller of the authorized and declared amounts, capping non-core business at 30 million yuan, and zeroing out financial/real estate are capping rules that become hard to reconcile when scattered across Java branches.
- Compliance items split into blocking and conditional categories: red-line items must be judged NON_COMPLIANT, while missing materials or low ratios can only be CONDITIONAL; mixing the two categories easily leads to the error of “letting a red line pass as conditional”.
- Approval levels must be compared and rendered as Chinese names: codes like SASAC/GROUP/BOARD must first be numericized for comparison, then mapped back to Chinese level names such as “国资监管机构/集团董事会” for the rectification opinion.
- Approval opinions must be traceable and auditable: state-owned assets supervision requires every non-compliance item, escalation path, and approved contribution to be presented item by item in the meeting materials.
- Domestic-stack SOE environments and legacy JDK 8 systems: a heavy rule platform cannot be introduced for a single compliance step.
Solution architecture
Section titled “Solution architecture”This case follows the six-piece skeleton: input model + decision result model + rule interface + XML rule script + Service orchestration + 6 groups of tests based on real business scenarios.
| Layer | Responsibility | Files |
|---|---|---|
| Domain model | SOE investment approval elements and compliance decision result (conclusion / two levels / approved contribution / non-compliance items) | SoeInvestmentApplication.java, InvestmentComplianceDecision.java |
| Rule set and XML | Approval-level amount thresholds, authorization and direction staged capping rules | SoeInvestmentRules.java, soe-investment.xml |
| Orchestration service | Negative list and capital red-line checks, blocking/conditional triage, level numeric comparison and Chinese name mapping | SoeInvestmentService.java |
| Tests | 6 investment scenarios (core business compliant / three conditional items / real estate veto / non-core capping / self-owned capital red line / authorization escalation) | SoeInvestmentServiceTest.java |
Rule method breakdown
Section titled “Rule method breakdown”| Rule method | Rule | Score / output |
|---|---|---|
approvalLevel |
Approval level for an amount: >=100M yuan SASAC, >=50M GROUP, >=10M BOARD, >=3M EXECUTIVE, otherwise INTERNAL | Five levels |
cappedApprovedWan |
Take the smaller of declared and authorized amounts; NON_MAIN capped at 3000 wan; FINANCIAL / REAL_ESTATE zeroed | Contribution in wan yuan |
Code implementation (complete & runnable)
Section titled “Code implementation (complete & runnable)”Place the following files into the test directory of a JQuick-Java project following the source package structure: the two models go into src/test/java/com/github/paohaijiao/demo/model/, the rule interface and test class into src/test/java/com/github/paohaijiao/demo/, the Service into src/test/java/com/github/paohaijiao/demo/service/, and the XML script into src/test/resources/demo/, keeping the original package names (com.github.paohaijiao.demo / .model / .service). Then run mvn test -Dtest=SoeInvestmentServiceTest to execute all 6 test cases.
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; }}Run & verified results
Section titled “Run & verified results”Run from the project root:
mvn test -Dtest=SoeInvestmentServiceTestTest coverage
Section titled “Test coverage”| Test method | Business scenario constructed | Key assertions / expected decision |
|---|---|---|
shouldPassCompliantMainBusinessInvestment |
Core business 80M yuan, self-owned 45%, debt 65%, authorized 80M, both reports complete, return 8% | COMPLIANT; required/granted both GROUP; approved contribution 80M; 0 findings |
shouldPassConditionallyWithThreeFindings |
Core business 6M yuan, self-owned 35%, debt 72%, authorized 6M, missing risk assessment, return 5% | CONDITIONAL; required EXECUTIVE; approved 6M; findings contain the three items: securing funding sources, submitting a debt-reduction plan, and supplementing the risk assessment |
shouldRejectRealEstateNegativeList |
Real estate 50M yuan, authorized 50M, everything else compliant | NON_COMPLIANT; required GROUP; approved contribution 0; findings contain “金融类、房地产类负面清单” |
shouldRejectLargeNonMainInvestmentAndCapAt3000 |
Non-core business 60M yuan, authorized 60M | NON_COMPLIANT (50M+ requires special approval); approved contribution capped at 30M |
shouldRejectForSelfOwnedRatioBelowRedLine |
Core business 20M yuan but self-owned capital only 25% | NON_COMPLIANT; required BOARD; approved contribution 20M; findings contain “自有资金比例 25% 低于 30% 监管红线” |
shouldRequireHigherApprovalLevel |
Declared 40M yuan but only 5M authorized at executive level | CONDITIONAL; required BOARD, granted EXECUTIVE; approved contribution capped at 5M; findings contain escalation to the company board and “核定出资 500 万元” |
Technical highlights
Section titled “Technical highlights”- Approval thresholds and capping rules fully externalized to XML: the four amount thresholds, the min-of-two rule, the 30M non-core cap, and the financial/real-estate zeroing all live inside two script methods; when the authorization management policy is revised, only the XML changes and the investment system needs no release.
- “Min + staged capping” closed inside one script method:
cappedApprovedWanfirst takes the smaller of the authorized and declared amounts, then reduces it stage by stage by direction, so the approved contribution returned to the Service always satisfies both the authorization and direction constraints. - Blocking and conditional items assembled separately: the Service collects them into blocking / conditional lists; a non-empty red-line list means NON_COMPLIANT, and only an empty red-line list with non-empty rectification items yields CONDITIONAL, eliminating “letting a red line pass as conditional”.
- Level codes numericized for comparison, Chinese names mapped separately:
levelRankmaps the five level codes to 0-4 for comparison, whilelevelNameindependently maintains the Chinese names “国资监管机构/集团董事会/公司董事会/经营层/内部决策机构”, keeping comparison logic and meeting-document wording from polluting each other. - Capping note attached only when there are no blocking items: the conditional note “核定出资 X 万元” is appended only when the contribution is narrowed by controls and the project itself can still go to the meeting, avoiding contradiction with a negative-list rejection opinion.
@Paramname binding + ASM dynamic proxy + Java 8 with no heavy dependencies: embeddable directly into legacy SOE investment management systems and domestic-stack JDK environments, with item-by-item auditable compliance opinions.