Case 24: Business license annual review
This case corresponds to USE-CASES scenario 24, “Industry license annual review compliance check (requirement 23)”. It belongs to the government supervision domain, using the food business license annual review as the template, targeting market regulators’ annual compliance review of licensed businesses. It automatically performs positive scoring across eight dimensions, tiers conclusions into pass / conditional pass / fail, and applies red-line rejection for expired licenses and major violations.
Industry scenario
Section titled “Industry scenario”Food businesses must submit annual license review materials every year. Declared elements cover both business qualifications and daily compliance: whether the license is within its validity period, whether the business license is valid, the number of expired health certificates and the total number of employees who should hold health certificates, food safety training coverage, whether a food safety officer is assigned as required, the number of general non-conformities found in routine inspections, whether last year’s non-conformities have been rectified, the number of valid consumer complaints during the year, the environmental hygiene rating (A/B/C), whether food safety liability insurance is held, and the number of major violations during the year.
The annual review uses positive scoring across eight dimensions with a full score of 100: health certificate management 20 points (zero expiry gives full marks; expiry ratio below 10% gives 12, below 30% gives 6), food safety training 15 points (coverage 100%/80%/60% gives 15/12/8, otherwise 2), food safety officer 10 points, inspection defects 15 points (0 / ≤2 / ≤5 items give 15/10/5), rectification 10 points, complaint handling 10 points (0 / ≤3 / ≤10 cases give 10/6/2), environmental hygiene 10 points (A/B/C give 10/6/0), and food safety liability insurance 10 points (no insurance still earns a base score of 5).
Review conclusions have four tiers: total score >=85 is PASS, >=70 is CONDITIONAL, otherwise FAIL; in addition, a separate REJECT red-line tier bypasses scoring entirely with three red lines: the license has exceeded its validity period, the business license is invalid or revoked, or there are major food safety violations during the year. Businesses receiving CONDITIONAL or FAIL also receive itemized non-conformity notices, including transferring staff with expired health certificates, supplementary training and re-examination, assigning a food safety officer, rectifying defects, closing the rectification loop, handling complaints, suspending business for C-level hygiene, and a recommendation to take out liability insurance.
The decision result carries the total compliance score, per-dimension score details (including each dimension’s maximum as denominator and the total-score line), and the list of non-conformities and rectification requirements, directly generating the annual review conclusion and the deadline-based rectification notice; PASS businesses get no non-conformity list. When the total number of employees who should hold health certificates is 0 (missing ledger), the Java side directly assigns 0 points and requires the ledger to be rebuilt within a deadline in the non-conformities, without calling the ratio rule — eliminating the divide-by-zero problem at the source.
Business pain points
Section titled “Business pain points”- Scoring rules are retuned annually with review guidelines: per-dimension bracket scores, the 85/70 tier lines, and the training coverage and complaint count thresholds may all be revised every year; hard-coding them into the supervision system makes adjustments costly.
- Ratio dimensions are error-prone with integer arithmetic: if the 10%/30% health certificate expiry checks are written as integer division, the result truncates to 0, letting heavily expired stores still get full marks.
- Red lines must reject before scoring: businesses with expired licenses or major violations must not pass the review because of full marks on other dimensions; the red-line short-circuit order is the compliance baseline.
- Divide-by-zero and missing-ledger scenarios need a fallback: when the total number of required health certificates is 0, the ratio cannot be computed; it must be identified separately as “no ledger established” and scored 0.
- Rectification opinions must map one-to-one to lost points: stores with conditional pass or fail need specific notices about staff transfers, supplementary training, rectification, and insurance; a vague conclusion cannot support front-line enforcement.
- Front-line supervision environments with domestic-stack and legacy JDK 8 constraints: annual review systems are mostly legacy government applications, so a heavy standalone platform cannot be introduced just for scoring.
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 | License annual review declared elements and review decision result (conclusion / total score / score details / non-conformities) | LicenseReviewApplication.java, LicenseReviewDecision.java |
| Rule set and XML | Eight-dimension scoring rules, health certificate ratio tiers, 85/70 conclusion lines | LicenseAnnualReviewRules.java, license-annual-review.xml |
| Orchestration service | Three red-line front-loaded rejections, divide-by-zero protection, eight-dimension aggregation, itemized non-conformity notices | LicenseAnnualReviewService.java |
| Tests | 6 business scenarios (full-score pass / minor conditional pass / serious fail / major violation / expired license / 85-point boundary) | LicenseAnnualReviewServiceTest.java |
Rule method breakdown
Section titled “Rule method breakdown”| Rule method | Rule | Score / output |
|---|---|---|
scoreHealth |
Zero expiry 20; expiry ratio below 10% (expired x10 less than total) 12; below 30% (expired x10 less than total x3) 6; otherwise 0 | 0-20 |
scoreTraining |
Coverage >=100% gives 15, >=80% gives 12, >=60% gives 8, otherwise 2 | 2-15 |
scoreOfficer |
Food safety officer assigned 10, otherwise 0 | 0/10 |
scoreDefects |
0 defects 15, ≤2 gives 10, ≤5 gives 5, otherwise 0 | 0-15 |
scoreRectification |
Last year’s non-conformities rectified 10, otherwise 0 | 0/10 |
scoreComplaints |
0 complaints 10, ≤3 gives 6, ≤10 gives 2, otherwise 0 | 0-10 |
scoreEnvironment |
Hygiene rating A 10, B 6, otherwise (including C) 0 | 0-10 |
scoreInsurance |
Liability insurance held 10, not held keeps a base score of 5 | 5/10 |
reviewLevel |
Total score >=85 PASS, >=70 CONDITIONAL, otherwise FAIL | Three conclusions |
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=LicenseAnnualReviewServiceTest to execute all 6 test cases.
LicenseReviewApplication.java
Section titled “LicenseReviewApplication.java”package com.github.paohaijiao.demo.model;
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;
/** * 食品经营许可证年审申报要素 */@Data@NoArgsConstructor@AllArgsConstructorpublic class LicenseReviewApplication {
/** * 许可证编号 */ private String licenseId;
/** * 经营主体名称 */ private String enterpriseName;
/** * 许可证是否在有效期内 */ private boolean validWithinPeriod;
/** * 营业执照是否有效 */ private boolean businessLicenseValid;
/** * 健康证过期人数 */ private int healthCertificateExpired;
/** * 应持健康证总人数 */ private int healthCertificateTotal;
/** * 食品安全培训覆盖率(整数百分比) */ private int trainingRate;
/** * 是否按规定配备食品安全员 */ private boolean foodSafetyOfficer;
/** * 日常监督检查一般不符合项数 */ private int defectCount;
/** * 上年度不符合项是否完成整改 */ private boolean rectificationCompleted;
/** * 年内有效消费投诉件数 */ private int complaintCount;
/** * 环境卫生量化等级:A / B / C */ private String environmentalRating;
/** * 是否投保食品安全责任险 */ private boolean liabilityInsurance;
/** * 年度重大违法违规次数 */ private int majorViolationCount;}LicenseReviewDecision.java
Section titled “LicenseReviewDecision.java”package com.github.paohaijiao.demo.model;
import lombok.Data;
import java.util.ArrayList;import java.util.List;
/** * 许可证年审合规决策结果 */@Datapublic class LicenseReviewDecision {
/** * 许可证编号 */ private String licenseId;
/** * 年审结论:PASS-通过 / CONDITIONAL-附条件通过 / FAIL-不予通过 / REJECT-红线驳回 */ private String result;
/** * 合规评分(0-100) */ private int totalScore;
/** * 各维度得分明细 */ private List<String> scoreDetails = new ArrayList<String>();
/** * 不合规项与整改要求 */ private List<String> nonConformities = new ArrayList<String>();
public void addScoreDetail(String detail) { this.scoreDetails.add(detail); }
public void addNonConformity(String nonConformity) { this.nonConformities.add(nonConformity); }}LicenseAnnualReviewRules.java
Section titled “LicenseAnnualReviewRules.java”package com.github.paohaijiao.demo;
import com.github.paohaijiao.xml.param.Param;
/** * 场景 24:行业许可证(食品经营)年审合规评分规则集 * <p> * 八个维度正向计分,满分 100:健康证 20 / 培训 15 / 食安员 10 / 缺陷项 15 * / 整改 10 / 投诉 10 / 环境等级 10 / 责任险 10;85 通过、70 附条件。 * 规则脚本见 {@code src/test/resources/demo/license-annual-review.xml}。 */public interface LicenseAnnualReviewRules {
/** 健康证合规得分:零过期满分,过期比例 10%/30% 两段,交叉相乘避免整数除法 */ int scoreHealth(@Param("expired") int expired, @Param("total") int total);
/** 食安培训覆盖率得分:100% 满分,80%/60% 两段 */ int scoreTraining(@Param("rate") int rate);
/** 是否配备食品安全员 */ int scoreOfficer(@Param("hasOfficer") boolean hasOfficer);
/** 日常检查缺陷项得分:0 项满分,2 项/5 项两段 */ int scoreDefects(@Param("defectCount") int defectCount);
/** 上年度问题整改完成情况 */ int scoreRectification(@Param("completed") boolean completed);
/** 有效投诉得分:0 件满分,3 件/10 件两段 */ int scoreComplaints(@Param("complaintCount") int complaintCount);
/** 环境卫生量化等级得分 */ int scoreEnvironment(@Param("rating") String rating);
/** 食品安全责任险投保情况(未投保仍得基础分 5) */ int scoreInsurance(@Param("hasInsurance") boolean hasInsurance);
/** 年审结论:85 分通过,70 分附条件,其余不予通过 */ String reviewLevel(@Param("totalScore") int totalScore);}license-annual-review.xml
Section titled “license-annual-review.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.LicenseAnnualReviewRules">
<!-- 健康证:expired/total 比率用交叉相乘(expired*10 对 total、total*3) --> <java name="scoreHealth" returnClass="int"> <![CDATA[ int def scoreHealth(int:expired, int:total) { if (expired == 0) { return 20; } else if (expired * 10 < total) { return 12; } else if (expired * 10 < total * 3) { return 6; } else { return 0; } } ]]> </java>
<!-- 培训覆盖率 --> <java name="scoreTraining" returnClass="int"> <![CDATA[ int def scoreTraining(int:rate) { if (rate >= 100) { return 15; } else if (rate >= 80) { return 12; } else if (rate >= 60) { return 8; } else { return 2; } } ]]> </java>
<!-- 食品安全员配备 --> <java name="scoreOfficer" returnClass="int"> <![CDATA[ int def scoreOfficer(boolean:hasOfficer) { if (hasOfficer) { return 10; } else { return 0; } } ]]> </java>
<!-- 日常检查缺陷项 --> <java name="scoreDefects" returnClass="int"> <![CDATA[ int def scoreDefects(int:defectCount) { if (defectCount == 0) { return 15; } else if (defectCount <= 2) { return 10; } else if (defectCount <= 5) { return 5; } else { return 0; } } ]]> </java>
<!-- 上年度整改 --> <java name="scoreRectification" returnClass="int"> <![CDATA[ int def scoreRectification(boolean:completed) { if (completed) { return 10; } else { return 0; } } ]]> </java>
<!-- 有效投诉 --> <java name="scoreComplaints" returnClass="int"> <![CDATA[ int def scoreComplaints(int:complaintCount) { if (complaintCount == 0) { return 10; } else if (complaintCount <= 3) { return 6; } else if (complaintCount <= 10) { return 2; } else { return 0; } } ]]> </java>
<!-- 环境卫生量化等级 --> <java name="scoreEnvironment" returnClass="int"> <![CDATA[ int def scoreEnvironment(str:rating) { if (rating == "A") { return 10; } else if (rating == "B") { return 6; } else { return 0; } } ]]> </java>
<!-- 食安责任险 --> <java name="scoreInsurance" returnClass="int"> <![CDATA[ int def scoreInsurance(boolean:hasInsurance) { if (hasInsurance) { return 10; } else { return 5; } } ]]> </java>
<!-- 年审结论分档 --> <java name="reviewLevel" returnClass="java.lang.String"> <![CDATA[ str def reviewLevel(int:totalScore) { if (totalScore >= 85) { return "PASS"; } else if (totalScore >= 70) { return "CONDITIONAL"; } else { return "FAIL"; } } ]]> </java>
</javas>LicenseAnnualReviewService.java
Section titled “LicenseAnnualReviewService.java”package com.github.paohaijiao.demo.service;
import com.github.paohaijiao.demo.LicenseAnnualReviewRules;import com.github.paohaijiao.demo.model.LicenseReviewApplication;import com.github.paohaijiao.demo.model.LicenseReviewDecision;
/** * 场景 24:行业许可证年审合规校验服务 * <p> * 职责划分: * <ul> * <li><b>Java 侧</b>:三条红线前置驳回、八维得分汇总、不合规项逐项告知</li> * <li><b>规则侧</b>:八维计分口径与通过/附条件/不通过阈值,外置在 XML 中</li> * </ul> */public class LicenseAnnualReviewService {
private final LicenseAnnualReviewRules rules;
public LicenseAnnualReviewService(LicenseAnnualReviewRules rules) { this.rules = rules; }
public LicenseReviewDecision review(LicenseReviewApplication app) { LicenseReviewDecision decision = new LicenseReviewDecision(); decision.setLicenseId(app.getLicenseId());
if (!app.isValidWithinPeriod()) { decision.setResult("REJECT"); decision.addNonConformity("许可证已超过有效期,须重新申领后再经营"); return decision; } if (!app.isBusinessLicenseValid()) { decision.setResult("REJECT"); decision.addNonConformity("营业执照失效或被吊销,不予年审"); return decision; } if (app.getMajorViolationCount() >= 1) { decision.setResult("REJECT"); decision.addNonConformity("年度内存在 " + app.getMajorViolationCount() + " 次重大食品安全违法违规记录,不予年审"); return decision; }
int health = app.getHealthCertificateTotal() <= 0 ? 0 : rules.scoreHealth(app.getHealthCertificateExpired(), app.getHealthCertificateTotal()); int training = rules.scoreTraining(app.getTrainingRate()); int officer = rules.scoreOfficer(app.isFoodSafetyOfficer()); int defects = rules.scoreDefects(app.getDefectCount()); int rectification = rules.scoreRectification(app.isRectificationCompleted()); int complaints = rules.scoreComplaints(app.getComplaintCount()); int environment = rules.scoreEnvironment(app.getEnvironmentalRating()); int insurance = rules.scoreInsurance(app.isLiabilityInsurance()); int total = health + training + officer + defects + rectification + complaints + environment + insurance;
decision.addScoreDetail("健康证管理: " + health + " / 20"); decision.addScoreDetail("食安培训: " + training + " / 15"); decision.addScoreDetail("食安员配备: " + officer + " / 10"); decision.addScoreDetail("检查缺陷项: " + defects + " / 15"); decision.addScoreDetail("问题整改: " + rectification + " / 10"); decision.addScoreDetail("投诉处置: " + complaints + " / 10"); decision.addScoreDetail("环境卫生: " + environment + " / 10"); decision.addScoreDetail("食安责任险: " + insurance + " / 10"); decision.addScoreDetail("合规总分: " + total); decision.setTotalScore(total); decision.setResult(rules.reviewLevel(total));
if (!"PASS".equals(decision.getResult())) { buildNonConformities(app, decision); } return decision; }
private void buildNonConformities(LicenseReviewApplication app, LicenseReviewDecision decision) { if (app.getHealthCertificateTotal() <= 0) { decision.addNonConformity("未建立从业人员健康证管理台账,须限期补建"); } else if (app.getHealthCertificateExpired() > 0) { decision.addNonConformity(app.getHealthCertificateExpired() + " 名从业人员健康证已过期,须立即调离接触直接入口食品岗位"); } if (app.getTrainingRate() < 80) { decision.addNonConformity("食品安全培训覆盖率 " + app.getTrainingRate() + "% 低于 80%,须补训补考"); } if (!app.isFoodSafetyOfficer()) { decision.addNonConformity("未按规定配备食品安全总监或食品安全员"); } if (app.getDefectCount() > 0) { decision.addNonConformity("日常监督检查发现 " + app.getDefectCount() + " 项一般不符合项,须逐项整改"); } if (!app.isRectificationCompleted()) { decision.addNonConformity("上年度不符合项未完成整改闭环,须提交整改报告"); } if (app.getComplaintCount() > 0) { decision.addNonConformity("年内有效消费投诉 " + app.getComplaintCount() + " 件,须优化处置时效"); } if ("C".equals(app.getEnvironmentalRating())) { decision.addNonConformity("环境卫生量化等级为 C 级,须停业整顿后复查"); } if (!app.isLiabilityInsurance()) { decision.addNonConformity("建议投保食品安全责任保险,完善风险分担机制"); } }}LicenseAnnualReviewServiceTest.java
Section titled “LicenseAnnualReviewServiceTest.java”package com.github.paohaijiao.demo;
import com.github.paohaijiao.demo.model.LicenseReviewApplication;import com.github.paohaijiao.demo.model.LicenseReviewDecision;import com.github.paohaijiao.demo.service.LicenseAnnualReviewService;import com.github.paohaijiao.xml.JQuickJava;import org.junit.Assert;import org.junit.Before;import org.junit.Test;
/** * 场景 24:食品经营许可证年审合规校验 * <p> * 覆盖 6 组主体形态:标杆门店满分通过、轻微问题附条件、问题门店不予通过、 * 重大违规红线、证照失效红线、85 分临界通过。 */public class LicenseAnnualReviewServiceTest {
private LicenseAnnualReviewService service;
@Before public void setUp() { LicenseAnnualReviewRules rules = JQuickJava.create() .createApi(LicenseAnnualReviewRules.class, "demo/license-annual-review.xml"); this.service = new LicenseAnnualReviewService(rules); }
/** * 各项全合规标杆门店 → 100 分通过 */ @Test public void shouldPassModelStoreWithFullScore() { LicenseReviewApplication app = baseApplication("LIC2026001"); app.setHealthCertificateExpired(0); app.setHealthCertificateTotal(10); app.setTrainingRate(100); app.setFoodSafetyOfficer(true); app.setDefectCount(0); app.setRectificationCompleted(true); app.setComplaintCount(0); app.setEnvironmentalRating("A"); app.setLiabilityInsurance(true);
LicenseReviewDecision decision = service.review(app);
Assert.assertEquals(100, decision.getTotalScore()); Assert.assertEquals("PASS", decision.getResult()); Assert.assertEquals(0, decision.getNonConformities().size()); Assert.assertTrue(decision.getScoreDetails().contains("健康证管理: 20 / 20")); }
/** * 个别健康证过期、2 项缺陷、2 件投诉、B 级环境、未投保 → 71 分附条件通过 */ @Test public void shouldPassConditionallyWithMinorIssues() { LicenseReviewApplication app = baseApplication("LIC2026002"); app.setHealthCertificateExpired(1); app.setHealthCertificateTotal(20); app.setTrainingRate(85); app.setFoodSafetyOfficer(true); app.setDefectCount(2); app.setRectificationCompleted(true); app.setComplaintCount(2); app.setEnvironmentalRating("B"); app.setLiabilityInsurance(false);
LicenseReviewDecision decision = service.review(app);
Assert.assertEquals(71, decision.getTotalScore()); Assert.assertEquals("CONDITIONAL", decision.getResult()); Assert.assertTrue(decision.getScoreDetails().contains("健康证管理: 12 / 20")); Assert.assertTrue(decision.getNonConformities().contains( "日常监督检查发现 2 项一般不符合项,须逐项整改")); Assert.assertTrue(decision.getNonConformities().contains( "建议投保食品安全责任保险,完善风险分担机制")); }
/** * 健康证大面积过期、无食安员、缺陷多、未整改、投诉多、C 级环境 → 7 分不予通过 */ @Test public void shouldFailStoreWithSeriousNonConformities() { LicenseReviewApplication app = baseApplication("LIC2026003"); app.setHealthCertificateExpired(8); app.setHealthCertificateTotal(20); app.setTrainingRate(50); app.setFoodSafetyOfficer(false); app.setDefectCount(7); app.setRectificationCompleted(false); app.setComplaintCount(12); app.setEnvironmentalRating("C"); app.setLiabilityInsurance(false);
LicenseReviewDecision decision = service.review(app);
Assert.assertEquals(7, decision.getTotalScore()); Assert.assertEquals("FAIL", decision.getResult()); Assert.assertTrue(decision.getNonConformities().contains( "环境卫生量化等级为 C 级,须停业整顿后复查")); Assert.assertTrue(decision.getNonConformities().contains( "未按规定配备食品安全总监或食品安全员")); Assert.assertTrue(decision.getScoreDetails().contains("食安培训: 2 / 15")); }
/** * 其余全合规但年度内发生重大违规 → 红线直接驳回 */ @Test public void shouldRejectForMajorViolation() { LicenseReviewApplication app = baseApplication("LIC2026004"); app.setHealthCertificateExpired(0); app.setHealthCertificateTotal(8); app.setTrainingRate(100); app.setFoodSafetyOfficer(true); app.setDefectCount(0); app.setRectificationCompleted(true); app.setComplaintCount(0); app.setEnvironmentalRating("A"); app.setLiabilityInsurance(true); app.setMajorViolationCount(1);
LicenseReviewDecision decision = service.review(app);
Assert.assertEquals("REJECT", decision.getResult()); Assert.assertTrue(decision.getNonConformities().contains( "年度内存在 1 次重大食品安全违法违规记录,不予年审")); }
/** * 许可证过期、营业执照失效分别驳回 */ @Test public void shouldRejectForInvalidLicenseAndBusinessLicense() { LicenseReviewApplication expired = baseApplication("LIC2026005"); expired.setValidWithinPeriod(false); LicenseReviewDecision d1 = service.review(expired); Assert.assertEquals("REJECT", d1.getResult()); Assert.assertTrue(d1.getNonConformities().contains("许可证已超过有效期,须重新申领后再经营"));
LicenseReviewApplication revoked = baseApplication("LIC2026006"); revoked.setBusinessLicenseValid(false); LicenseReviewDecision d2 = service.review(revoked); Assert.assertEquals("REJECT", d2.getResult()); Assert.assertTrue(d2.getNonConformities().contains("营业执照失效或被吊销,不予年审")); }
/** * 恰好 85 分通过线:投诉 5 件、B 级环境但其他项满分 → PASS,不再列不合规项 */ @Test public void shouldPassAtExactScoreThreshold() { LicenseReviewApplication app = baseApplication("LIC2026007"); app.setHealthCertificateExpired(0); app.setHealthCertificateTotal(12); app.setTrainingRate(80); app.setFoodSafetyOfficer(true); app.setDefectCount(0); app.setRectificationCompleted(true); app.setComplaintCount(5); app.setEnvironmentalRating("B"); app.setLiabilityInsurance(true);
LicenseReviewDecision decision = service.review(app);
Assert.assertEquals(85, decision.getTotalScore()); Assert.assertEquals("PASS", decision.getResult()); Assert.assertEquals(0, decision.getNonConformities().size()); Assert.assertTrue(decision.getScoreDetails().contains("投诉处置: 2 / 10")); }
private LicenseReviewApplication baseApplication(String licenseId) { LicenseReviewApplication app = new LicenseReviewApplication(); app.setLicenseId(licenseId); app.setEnterpriseName("测试餐饮单位"); app.setValidWithinPeriod(true); app.setBusinessLicenseValid(true); app.setHealthCertificateExpired(0); app.setHealthCertificateTotal(10); app.setTrainingRate(100); app.setFoodSafetyOfficer(true); app.setDefectCount(0); app.setRectificationCompleted(true); app.setComplaintCount(0); app.setEnvironmentalRating("A"); app.setLiabilityInsurance(true); app.setMajorViolationCount(0); return app; }}Run & verified results
Section titled “Run & verified results”Run from the project root:
mvn test -Dtest=LicenseAnnualReviewServiceTestTest coverage
Section titled “Test coverage”| Test method | Business scenario constructed | Key assertions / expected decision |
|---|---|---|
shouldPassModelStoreWithFullScore |
Zero expired health certificates, 100% training, officer assigned, zero defects, rectified, zero complaints, A rating, insured | 100 points PASS; 0 non-conformities; details contain “健康证管理: 20 / 20” |
shouldPassConditionallyWithMinorIssues |
1 of 20 health certificates expired, 85% training, 2 defects, 2 complaints, B rating, not insured | 71 points CONDITIONAL; details contain “健康证管理: 12 / 20”; non-conformities contain the 2-defect rectification and the liability insurance recommendation |
shouldFailStoreWithSeriousNonConformities |
8 of 20 expired, 50% training, no officer, 7 defects, not rectified, 12 complaints, C rating, not insured | 7 points FAIL; contains “C 级,须停业整顿后复查” and “未按规定配备食品安全总监或食品安全员”; details contain “食安培训: 2 / 15” |
shouldRejectForMajorViolation |
Everything else compliant but majorViolationCount=1 | REJECT (red line precedes scoring); contains “年度内存在 1 次重大食品安全违法违规记录,不予年审” |
shouldRejectForInvalidLicenseAndBusinessLicense |
Two sub-scenarios: expired license; invalid business license | Both REJECT; hitting “须重新申领后再经营” and “营业执照失效或被吊销,不予年审” respectively |
shouldPassAtExactScoreThreshold |
80% training, 5 complaints (2 points), B rating (6 points), everything else full marks | Exactly 85 points PASS (passes at the line); 0 non-conformities; details contain “投诉处置: 2 / 10” |
Technical highlights
Section titled “Technical highlights”- Scoring rules fully externalized to XML: the bracket scores of all eight dimensions, the 10%/30% health certificate ratio lines, and the 85/70 conclusion lines all live in the script; annual retuning of the review guidelines only requires editing the XML and rebuilding the proxy, with no release of the main supervision system.
- Cross-multiplication avoids the integer division trap: the script uses integer arithmetic without automatic float promotion, so
scoreHealthexpresses the 10%/30% ratios asexpired * 10 < totalandexpired * 10 < total * 3, avoiding the misjudgment ofexpired / totaltruncating to 0. - Three red lines short-circuit on the Java side: expired license, invalid business license, and major violations return REJECT in sequence before the eight-dimension scoring, so a red-line business can never pass the review on high scores elsewhere.
- Divide-by-zero protection merged with the missing-ledger case: when
healthCertificateTotal ≤ 0, the Java side directly assigns 0 points without calling the ratio rule and requires rebuilding the health certificate ledger in the non-conformities, eliminating script-side divide-by-zero errors. - Positive scoring plus itemized notices for lost points: the Service aggregates nine score detail lines (including the total compliance score) and generates rectification notices item by item from the original declared values only for non-PASS businesses; PASS lists no issues, producing the conclusion letter and rectification notice in one pass.
@Paramname binding + ASM dynamic proxy + Java 8 with no heavy dependencies: the 9 rule methods share a single proxy, embeddable into legacy annual review systems and domestic-stack JDKs, with an explainable and reviewable scoring process.