刘光辉
昨天 bb638871a7fb692d80f1b7a758f991dc0879002c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package jnpf.limsService.support;
 
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
 
/**
 * 取样终止申请流程状态同步的静态回归检查。
 */
public class LimsSxtQuyangZhongzhiShenqingFlowStatusChecks {
 
    private static final Path REPOSITORY_ROOT = Paths.get("").toAbsolutePath().normalize();
 
    public static void main(String[] args) throws IOException {
        String service = read("jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsSxtJihuaServiceImpl.java");
        String entity = read("jnpf-lims/jnpf-lims-entity/src/main/java/jnpf/limsEntity/LimsSxtQuyangZhongzhiShenqingEntity.java");
        String mapper = read("jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsMapper/LimsSxtQuyangZhongzhiShenqingMapper.java");
        String childEntity = read("jnpf-lims/jnpf-lims-entity/src/main/java/jnpf/limsEntity/LimsSxtQuyangZhongzhiShenqingZixiangEntity.java");
        String childMapper = read("jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsMapper/LimsSxtQuyangZhongzhiShenqingZixiangMapper.java");
        String bizStatus = read("jnpf-lims/jnpf-lims-entity/src/main/java/jnpf/limsEntity/BizStatus.java");
        String schema = read("docs/pg-migration-ddl/self_built_tables_pg.sql");
        String migration = read("docs/pg-migration-ddl/update_lims_sxt_quyang_zhongzhi_shenqing_biz_status_20260723.sql");
        String qingyandanLinkMigration = read("docs/pg-migration-ddl/update_lims_sxt_quyang_zhongzhi_shenqing_qingyandan_link_20260723.sql");
 
        require(entity, "@TableName(\"lims_sxt_quyang_zhongzhi_shenqing\")",
                "sampling termination entity must map the application table");
        require(entity, "private String bizStatus;", "entity must expose biz_status");
        require(entity, "private String fTenantId;", "entity must expose the composite primary-key tenant id");
        require(mapper, "SuperMapper<LimsSxtQuyangZhongzhiShenqingEntity>",
                "sampling termination mapper must support status updates");
        require(childEntity, "@TableName(\"lims_sxt_quyang_zhongzhi_shenqing_zixiang\")",
                "sampling termination child entity must map selected sampling tasks");
        require(childEntity, "@TableField(\"qingyandan_id\")",
                "sampling termination child must retain its selected qingyandan id");
        require(childMapper, "SuperMapper<LimsSxtQuyangZhongzhiShenqingZixiangEntity>",
                "sampling termination child mapper must load selected sampling tasks");
        require(bizStatus, "DELETED(\"deleted\", \"已废弃\")",
                "sampling termination must reuse the existing deleted status");
        requireAbsent(bizStatus, "TERMINATED(",
                "sampling termination must not introduce a separate terminated status");
        require(service, "findQuyangZhongzhiShenqingByFlow",
                "flow synchronization must locate sampling termination applications");
        require(service, "syncQuyangZhongzhiShenqingStarted",
                "start events must set sampling termination applications to processing");
        require(service, "syncQuyangZhongzhiShenqingEnded",
                "end events must set sampling termination applications to completed");
        require(service, "syncApprovedQuyangTerminationStatus",
                "approved termination events must synchronize linked sampling applications");
        require(service, "BizStatus.DELETED", "approved termination must set the sampling status to deleted");
        require(service, "BizStatus.PENDING_FETCH", "only pending sampling applications may be terminated");
        require(service, "terminatePendingQingyandan(LimsSxtQuyangZhongzhiShenqingZixiangEntity child)",
                "termination must update the qingyandan id saved by the selected child");
        require(service, "多个取样终止申请关联同一流程任务",
                "duplicate sampling termination flow bindings must be rejected");
        require(service, "getFTenantId", "sampling termination status updates must be tenant-scoped");
        require(schema, "biz_status varchar(50) DEFAULT 'pending'",
                "fresh PostgreSQL schema must default sampling termination applications to pending");
        require(schema, "qingyandan_id varchar(50)",
                "fresh PostgreSQL schema must retain selected qingyandan ids");
        require(migration, "ALTER TABLE lims_sxt_quyang_zhongzhi_shenqing",
                "existing PostgreSQL deployments must receive the status column migration");
        require(migration, "ADD COLUMN IF NOT EXISTS biz_status varchar(50);",
                "migration must add the status column without a default before historical backfill");
        require(migration, "SET biz_status = CASE", "migration must backfill existing application statuses");
        require(migration, "OR (biz_status = 'pending' AND f_flow_state IN (1, 2, 3, 4, 5, 6, 7, 8, 9))",
                "migration must correct pending defaults created while importing historical non-pending workflows");
        requireOrder(migration, "UPDATE lims_sxt_quyang_zhongzhi_shenqing",
                "ALTER COLUMN biz_status SET DEFAULT 'pending'",
                "migration must backfill historical statuses before applying the default");
        require(qingyandanLinkMigration, "ADD COLUMN IF NOT EXISTS qingyandan_id varchar(50)",
                "existing PostgreSQL deployments must receive the qingyandan link column");
    }
 
    private static String read(String relativePath) throws IOException {
        return new String(Files.readAllBytes(REPOSITORY_ROOT.resolve(relativePath)), StandardCharsets.UTF_8);
    }
 
    private static void require(String source, String expected, String message) {
        if (!source.contains(expected)) {
            throw new AssertionError(message);
        }
    }
 
    private static void requireAbsent(String source, String unexpected, String message) {
        if (source.contains(unexpected)) {
            throw new AssertionError(message);
        }
    }
 
    private static void requireOrder(String source, String first, String second, String message) {
        if (source.indexOf(first) >= source.indexOf(second)) {
            throw new AssertionError(message);
        }
    }
}