wwh недель назад: 2
Родитель
Сommit
ef65fad876

+ 0 - 6
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/service/impl/BizVaccinationDataServiceImpl.java

@@ -157,12 +157,6 @@ public class BizVaccinationDataServiceImpl implements IBizVaccinationDataService
157
                 BizVaccinationData row = VaccinationDataExcelParser.toEntity(parsed, statYear, statMonth,
157
                 BizVaccinationData row = VaccinationDataExcelParser.toEntity(parsed, statYear, statMonth,
158
                         town.getDeptId(), town.getDeptName(), village.getDeptId(), village.getDeptName());
158
                         town.getDeptId(), town.getDeptName(), village.getDeptId(), village.getDeptName());
159
                 VaccinationDataValidation.validateRowForSave(row, townDeptSupport);
159
                 VaccinationDataValidation.validateRowForSave(row, townDeptSupport);
160
-                String warn = VaccinationDataValidation.buildActualExceedShouldWarn(row);
161
-                if (StringUtils.isNotEmpty(warn))
162
-                {
163
-                    result.addWarn("第" + parsed.getExcelRowNum() + "行[" + parsed.getTownName() + "/"
164
-                            + parsed.getVillageName() + "]: " + warn);
165
-                }
166
                 String batchKey = row.getStatYear() + "|" + row.getStatMonth() + "|" + row.getVillageDeptId();
160
                 String batchKey = row.getStatYear() + "|" + row.getStatMonth() + "|" + row.getVillageDeptId();
167
                 if (!batchKeys.add(batchKey))
161
                 if (!batchKeys.add(batchKey))
168
                 {
162
                 {

+ 5 - 5
baqing-admin/src/main/java/com/ruoyi/web/modules/industryservice/support/VaccinationDataValidation.java

@@ -41,6 +41,7 @@ public final class VaccinationDataValidation
41
 
41
 
42
         validateNonNegative(row.getShouldVaccinateCount(), "应免数");
42
         validateNonNegative(row.getShouldVaccinateCount(), "应免数");
43
         validateNonNegative(row.getActualVaccinateCount(), "实免数");
43
         validateNonNegative(row.getActualVaccinateCount(), "实免数");
44
+        validateActualNotExceedShould(row);
44
         if (StringUtils.isNotEmpty(row.getRemark()) && row.getRemark().length() > 500)
45
         if (StringUtils.isNotEmpty(row.getRemark()) && row.getRemark().length() > 500)
45
         {
46
         {
46
             throw new ServiceException("备注不能超过500字");
47
             throw new ServiceException("备注不能超过500字");
@@ -56,17 +57,16 @@ public final class VaccinationDataValidation
56
         }
57
         }
57
     }
58
     }
58
 
59
 
59
-    /** 实免数大于应免数时给出软警告(不阻断保存) */
60
-    public static String buildActualExceedShouldWarn(BizVaccinationData row)
60
+    /** 实免数须小于等于应免数(两者均非空时) */
61
+    public static void validateActualNotExceedShould(BizVaccinationData row)
61
     {
62
     {
62
         if (row == null || row.getShouldVaccinateCount() == null || row.getActualVaccinateCount() == null)
63
         if (row == null || row.getShouldVaccinateCount() == null || row.getActualVaccinateCount() == null)
63
         {
64
         {
64
-            return null;
65
+            return;
65
         }
66
         }
66
         if (row.getActualVaccinateCount() > row.getShouldVaccinateCount())
67
         if (row.getActualVaccinateCount() > row.getShouldVaccinateCount())
67
         {
68
         {
68
-            return "实免数大于应免数";
69
+            throw new ServiceException("实免数不能大于应免数");
69
         }
70
         }
70
-        return null;
71
     }
71
     }
72
 }
72
 }

+ 9 - 5
baqing-admin/src/test/java/com/ruoyi/web/modules/industryservice/support/VaccinationDataExcelParserTest.java

@@ -1,13 +1,14 @@
1
 package com.ruoyi.web.modules.industryservice.support;
1
 package com.ruoyi.web.modules.industryservice.support;
2
 
2
 
3
 import static org.junit.jupiter.api.Assertions.assertEquals;
3
 import static org.junit.jupiter.api.Assertions.assertEquals;
4
-import static org.junit.jupiter.api.Assertions.assertTrue;
4
+import static org.junit.jupiter.api.Assertions.assertThrows;
5
 
5
 
6
 import java.io.InputStream;
6
 import java.io.InputStream;
7
 import java.util.List;
7
 import java.util.List;
8
 import org.junit.jupiter.api.DisplayName;
8
 import org.junit.jupiter.api.DisplayName;
9
 import org.junit.jupiter.api.Test;
9
 import org.junit.jupiter.api.Test;
10
 import org.springframework.core.io.ClassPathResource;
10
 import org.springframework.core.io.ClassPathResource;
11
+import com.ruoyi.common.exception.ServiceException;
11
 import com.ruoyi.web.modules.industryservice.support.VaccinationDataExcelParser.ParsedRow;
12
 import com.ruoyi.web.modules.industryservice.support.VaccinationDataExcelParser.ParsedRow;
12
 
13
 
13
 @DisplayName("VaccinationDataExcelParser")
14
 @DisplayName("VaccinationDataExcelParser")
@@ -46,8 +47,8 @@ class VaccinationDataExcelParserTest
46
     }
47
     }
47
 
48
 
48
     @Test
49
     @Test
49
-    @DisplayName("免疫率派生与百分比格式化")
50
-    void derivedImmunityRate()
50
+    @DisplayName("免疫率派生与实免不超过应免硬校验")
51
+    void derivedImmunityRateAndActualConstraint()
51
     {
52
     {
52
         com.ruoyi.web.modules.industryservice.domain.BizVaccinationData row =
53
         com.ruoyi.web.modules.industryservice.domain.BizVaccinationData row =
53
                 new com.ruoyi.web.modules.industryservice.domain.BizVaccinationData();
54
                 new com.ruoyi.web.modules.industryservice.domain.BizVaccinationData();
@@ -56,8 +57,11 @@ class VaccinationDataExcelParserTest
56
         VaccinationDataDerivedSupport.applyDerived(row);
57
         VaccinationDataDerivedSupport.applyDerived(row);
57
         assertEquals("98.33", row.getImmunityRate().toPlainString());
58
         assertEquals("98.33", row.getImmunityRate().toPlainString());
58
         assertEquals("98.33%", VaccinationDataDerivedSupport.formatImmunityRatePercent(row.getImmunityRate()));
59
         assertEquals("98.33%", VaccinationDataDerivedSupport.formatImmunityRatePercent(row.getImmunityRate()));
59
-        assertTrue(VaccinationDataValidation.buildActualExceedShouldWarn(row) == null);
60
+        VaccinationDataValidation.validateActualNotExceedShould(row);
61
+
60
         row.setActualVaccinateCount(13000);
62
         row.setActualVaccinateCount(13000);
61
-        assertEquals("实免数大于应免数", VaccinationDataValidation.buildActualExceedShouldWarn(row));
63
+        ServiceException ex = assertThrows(ServiceException.class,
64
+                () -> VaccinationDataValidation.validateActualNotExceedShould(row));
65
+        assertEquals("实免数不能大于应免数", ex.getMessage());
62
     }
66
     }
63
 }
67
 }

+ 2 - 1
doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报功能需求.md

@@ -18,7 +18,7 @@
18
 - 唯一键:所属年份 + 所属月份 + 所属村。
18
 - 唯一键:所属年份 + 所属月份 + 所属村。
19
 - 导入:存在则更新、不存在则插入(不按年月先删后插)。
19
 - 导入:存在则更新、不存在则插入(不按年月先删后插)。
20
 - 派生(保存时计算并落库):**免疫率 = (实免数 / 应免数) × 100**,保留 2 位小数(应免数 > 0 且实免数非空;如 98.33;界面/导出展示为 `98.33%`)。
20
 - 派生(保存时计算并落库):**免疫率 = (实免数 / 应免数) × 100**,保留 2 位小数(应免数 > 0 且实免数非空;如 98.33;界面/导出展示为 `98.33%`)。
21
-- 实免数大于应免数时允许保存;导入可返回软警告
21
+- **约束:实免数 ≤ 应免数**(两者均填写时;保存与导入均硬拦截,不允许超过)
22
 
22
 
23
 ---
23
 ---
24
 
24
 
@@ -49,3 +49,4 @@
49
 | --- | --- |
49
 | --- | --- |
50
 | 1.0 | 首版:CRUD + upsert 导入 + 导出 |
50
 | 1.0 | 首版:CRUD + upsert 导入 + 导出 |
51
 | 1.1 | 免疫率改为 (实免数/应免数)×100,保留 2 位小数落库 |
51
 | 1.1 | 免疫率改为 (实免数/应免数)×100,保留 2 位小数落库 |
52
+| 1.2 | 约束:实免数 ≤ 应免数(硬校验) |

+ 1 - 1
doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报技术方案.md

@@ -34,7 +34,7 @@ Excel 列:0 序号、1 乡镇、2 村、3 应免数、4 实免数、5 免疫
34
 | `VaccinationDataExcelParser` | 识别主表头,跳过子表头/空白/合计 |
34
 | `VaccinationDataExcelParser` | 识别主表头,跳过子表头/空白/合计 |
35
 | `VaccinationDataExcelExporter` | 基于模板写数据 |
35
 | `VaccinationDataExcelExporter` | 基于模板写数据 |
36
 | `VaccinationDataDerivedSupport` | 免疫率计算与百分比格式化 |
36
 | `VaccinationDataDerivedSupport` | 免疫率计算与百分比格式化 |
37
-| `VaccinationDataValidation` | 年月/村校验、非负整数、软警告 |
37
+| `VaccinationDataValidation` | 年月/村校验、非负整数、实免≤应免硬校验 |
38
 
38
 
39
 ---
39
 ---
40
 
40
 

+ 2 - 2
doc/产业数据模型及服务/疫苗接种数据填报/疫苗接种数据填报测试用例.md

@@ -10,7 +10,7 @@
10
 | VD-04 | 修改 | 改应免/实免 | 免疫率重算 |
10
 | VD-04 | 修改 | 改应免/实免 | 免疫率重算 |
11
 | VD-05 | 删除 | 删除一条 | 物理删除成功 |
11
 | VD-05 | 删除 | 删除一条 | 物理删除成功 |
12
 | VD-06 | 未来月 | 选未来年月保存 | 拒绝 |
12
 | VD-06 | 未来月 | 选未来年月保存 | 拒绝 |
13
-| VD-07 | 实免>应免 | 保存/导入 | 允许;导入可有软警告 |
13
+| VD-07 | 实免>应免 | 保存/导入 | 拒绝(硬校验) |
14
 | VD-08 | 下载模板 | 点下载模板 | 得到官方 xlsx |
14
 | VD-08 | 下载模板 | 点下载模板 | 得到官方 xlsx |
15
 | VD-09 | 导入 upsert | 上传模板示例行,再导入同村改数 | 首次新增、再次更新 |
15
 | VD-09 | 导入 upsert | 上传模板示例行,再导入同村改数 | 首次新增、再次更新 |
16
 | VD-10 | 导出 | 选年月,可选乡镇 | 按模板填充;免疫率为百分比;无合计行 |
16
 | VD-10 | 导出 | 选年月,可选乡镇 | 按模板填充;免疫率为百分比;无合计行 |
@@ -21,4 +21,4 @@
21
 | --- | --- | --- |
21
 | --- | --- | --- |
22
 | VD-UT-01 | `VaccinationDataExcelParserTest` | 官方模板解析出 2 条示例行 |
22
 | VD-UT-01 | `VaccinationDataExcelParserTest` | 官方模板解析出 2 条示例行 |
23
 | VD-UT-02 | 同上 | 主表头行索引=2,子表头跳过 |
23
 | VD-UT-02 | 同上 | 主表头行索引=2,子表头跳过 |
24
-| VD-UT-03 | 同上 | 免疫率派生与软警告 |
24
+| VD-UT-03 | 同上 | 免疫率派生与实免≤应免硬校验 |