Commit 0635d13de328e14818644d901ccae7b7fa6d30cb

Authored by YunaiV
1 parent e6fd0322

✨ feat(mes): 更新单白班结束时间为18:00,新增排班计划单元测试

yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/cal/MesCalShiftTypeEnum.java
@@ -19,7 +19,7 @@ import java.util.List; @@ -19,7 +19,7 @@ import java.util.List;
19 public enum MesCalShiftTypeEnum implements ArrayValuable<Integer> { 19 public enum MesCalShiftTypeEnum implements ArrayValuable<Integer> {
20 20
21 SINGLE(1, "单白班", ListUtil.of( 21 SINGLE(1, "单白班", ListUtil.of(
22 - Pair.of("白班", new String[]{"08:00", "17:00"}) 22 + Pair.of("白班", new String[]{"08:00", "18:00"})
23 )), 23 )),
24 TWO(2, "两班倒", ListUtil.of( 24 TWO(2, "两班倒", ListUtil.of(
25 Pair.of("白班", new String[]{"08:00", "20:00"}), 25 Pair.of("白班", new String[]{"08:00", "20:00"}),
@@ -45,7 +45,7 @@ public enum MesCalShiftTypeEnum implements ArrayValuable&lt;Integer&gt; { @@ -45,7 +45,7 @@ public enum MesCalShiftTypeEnum implements ArrayValuable&lt;Integer&gt; {
45 * 班次配置列表 45 * 班次配置列表
46 * 46 *
47 * key: 班次名称(如 "白班", "夜班", "中班") 47 * key: 班次名称(如 "白班", "夜班", "中班")
48 - * value: [startTime, endTime](如 ["08:00", "17:00"]) 48 + * value: [startTime, endTime](如 ["08:00", "18:00"])
49 */ 49 */
50 private final List<Pair<String, String[]>> shifts; 50 private final List<Pair<String, String[]>> shifts;
51 51
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.cal.plan;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.cal.plan.vo.MesCalPlanSaveReqVO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanDO;
  6 +import cn.iocoder.yudao.module.mes.dal.mysql.cal.plan.MesCalPlanMapper;
  7 +import cn.iocoder.yudao.module.mes.enums.cal.MesCalPlanStatusEnum;
  8 +import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftMethodEnum;
  9 +import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum;
  10 +import cn.iocoder.yudao.module.mes.service.cal.team.MesCalTeamShiftService;
  11 +import org.junit.jupiter.api.Test;
  12 +import org.springframework.context.annotation.Import;
  13 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  14 +
  15 +import jakarta.annotation.Resource;
  16 +
  17 +import java.time.LocalDateTime;
  18 +
  19 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  20 +import static org.junit.jupiter.api.Assertions.*;
  21 +import static org.mockito.Mockito.*;
  22 +
  23 +/**
  24 + * {@link MesCalPlanServiceImpl} 的单元测试
  25 + *
  26 + * @author 芋道源码
  27 + */
  28 +@Import(MesCalPlanServiceImpl.class)
  29 +public class MesCalPlanServiceImplTest extends BaseDbUnitTest {
  30 +
  31 + @Resource
  32 + private MesCalPlanServiceImpl planService;
  33 +
  34 + @Resource
  35 + private MesCalPlanMapper planMapper;
  36 +
  37 + @MockitoBean
  38 + private MesCalPlanShiftService planShiftService;
  39 + @MockitoBean
  40 + private MesCalPlanTeamService planTeamService;
  41 + @MockitoBean
  42 + private MesCalTeamShiftService teamShiftService;
  43 +
  44 + @Test
  45 + public void testCreatePlan_singleShift_addDefaultShift() {
  46 + // 准备参数
  47 + MesCalPlanSaveReqVO reqVO = new MesCalPlanSaveReqVO();
  48 + reqVO.setCode("PLAN-SINGLE-001");
  49 + reqVO.setName("单白班默认班次");
  50 + reqVO.setCalendarType(1);
  51 + reqVO.setStartDate(LocalDateTime.of(2026, 4, 1, 0, 0));
  52 + reqVO.setEndDate(LocalDateTime.of(2026, 4, 30, 0, 0));
  53 + reqVO.setShiftType(MesCalShiftTypeEnum.SINGLE.getType());
  54 + reqVO.setShiftMethod(MesCalShiftMethodEnum.DAY.getMethod());
  55 + reqVO.setShiftCount(1);
  56 +
  57 + // 调用
  58 + Long planId = planService.createPlan(reqVO);
  59 +
  60 + // 断言 1:计划状态为草稿
  61 + MesCalPlanDO plan = planMapper.selectById(planId);
  62 + assertEquals(MesCalPlanStatusEnum.PREPARE.getStatus(), plan.getStatus());
  63 + // 断言 2:自动生成默认班次
  64 + verify(planShiftService).addDefaultPlanShift(planId, MesCalShiftTypeEnum.SINGLE.getType());
  65 + }
  66 +
  67 + @Test
  68 + public void testConfirmPlan_syncGenerateTeamShiftRecords() {
  69 + // mock 数据:插入一条草稿状态的排班计划
  70 + MesCalPlanDO plan = randomPojo(MesCalPlanDO.class, o -> {
  71 + o.setCalendarType(1);
  72 + o.setStartDate(LocalDateTime.of(2026, 4, 1, 0, 0));
  73 + o.setEndDate(LocalDateTime.of(2026, 4, 3, 0, 0));
  74 + o.setStatus(MesCalPlanStatusEnum.PREPARE.getStatus());
  75 + o.setShiftType(MesCalShiftTypeEnum.SINGLE.getType());
  76 + o.setShiftMethod(MesCalShiftMethodEnum.DAY.getMethod());
  77 + o.setShiftCount(1);
  78 + });
  79 + planMapper.insert(plan);
  80 + // mock 方法:班组数量满足要求
  81 + when(planTeamService.getPlanTeamCountByPlanId(plan.getId())).thenReturn(1L);
  82 +
  83 + // 调用
  84 + planService.confirmPlan(plan.getId());
  85 +
  86 + // 断言 1:计划状态更新为已确认
  87 + MesCalPlanDO updatePlan = planMapper.selectById(plan.getId());
  88 + assertEquals(MesCalPlanStatusEnum.CONFIRMED.getStatus(), updatePlan.getStatus());
  89 + // 断言 2:触发生成班组排班记录
  90 + verify(teamShiftService).generateTeamShiftRecords(plan.getId());
  91 + }
  92 +
  93 + @Test
  94 + public void testDeletePlan_notCascadeDeleteTeamShift() {
  95 + // mock 数据:插入一条草稿状态的排班计划
  96 + MesCalPlanDO plan = randomPojo(MesCalPlanDO.class, o -> {
  97 + o.setCalendarType(1);
  98 + o.setStartDate(LocalDateTime.of(2026, 4, 1, 0, 0));
  99 + o.setEndDate(LocalDateTime.of(2026, 4, 3, 0, 0));
  100 + o.setStatus(MesCalPlanStatusEnum.PREPARE.getStatus());
  101 + o.setShiftType(MesCalShiftTypeEnum.SINGLE.getType());
  102 + o.setShiftMethod(MesCalShiftMethodEnum.DAY.getMethod());
  103 + o.setShiftCount(1);
  104 + });
  105 + planMapper.insert(plan);
  106 +
  107 + // 调用
  108 + planService.deletePlan(plan.getId());
  109 +
  110 + // 断言 1:计划被删除
  111 + assertNull(planMapper.selectById(plan.getId()));
  112 + // 断言 2:级联删除班次和班组关联
  113 + verify(planShiftService).deletePlanShiftByPlanId(plan.getId());
  114 + verify(planTeamService).deleteByPlanId(plan.getId());
  115 + // 断言 3:不级联删除班组排班记录
  116 + verify(teamShiftService, never()).deleteByPlanId(plan.getId());
  117 + }
  118 +
  119 +}
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/cal/plan/MesCalPlanShiftServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.cal.plan;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanShiftDO;
  5 +import cn.iocoder.yudao.module.mes.dal.mysql.cal.plan.MesCalPlanShiftMapper;
  6 +import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum;
  7 +import org.junit.jupiter.api.Test;
  8 +import org.springframework.context.annotation.Import;
  9 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  10 +
  11 +import jakarta.annotation.Resource;
  12 +
  13 +import java.util.List;
  14 +
  15 +import static org.junit.jupiter.api.Assertions.*;
  16 +
  17 +/**
  18 + * {@link MesCalPlanShiftServiceImpl} 的单元测试
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@Import(MesCalPlanShiftServiceImpl.class)
  23 +public class MesCalPlanShiftServiceImplTest extends BaseDbUnitTest {
  24 +
  25 + @Resource
  26 + private MesCalPlanShiftServiceImpl planShiftService;
  27 +
  28 + @Resource
  29 + private MesCalPlanShiftMapper planShiftMapper;
  30 +
  31 + @MockitoBean
  32 + private MesCalPlanService planService;
  33 +
  34 + @Test
  35 + public void testAddDefaultPlanShift_singleShift_use18Clock() {
  36 + // 准备参数
  37 + Long planId = 1001L;
  38 +
  39 + // 调用
  40 + planShiftService.addDefaultPlanShift(planId, MesCalShiftTypeEnum.SINGLE.getType());
  41 +
  42 + // 断言:生成 1 条默认班次(白班 08:00~18:00)
  43 + List<MesCalPlanShiftDO> shifts = planShiftMapper.selectListByPlanId(planId);
  44 + assertEquals(1, shifts.size());
  45 + MesCalPlanShiftDO shift = shifts.get(0);
  46 + assertEquals(planId, shift.getPlanId());
  47 + assertEquals(1, shift.getSort());
  48 + assertEquals("白班", shift.getName());
  49 + assertEquals("08:00", shift.getStartTime());
  50 + assertEquals("18:00", shift.getEndTime());
  51 + }
  52 +
  53 +}
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.cal.team;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanShiftDO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanTeamDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamShiftDO;
  8 +import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamShiftMapper;
  9 +import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftMethodEnum;
  10 +import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum;
  11 +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanService;
  12 +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanShiftService;
  13 +import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanTeamService;
  14 +import org.junit.jupiter.api.Test;
  15 +import org.springframework.context.annotation.Import;
  16 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  17 +
  18 +import jakarta.annotation.Resource;
  19 +
  20 +import java.time.LocalDateTime;
  21 +import java.util.Comparator;
  22 +import java.util.List;
  23 +
  24 +import static org.junit.jupiter.api.Assertions.*;
  25 +import static org.mockito.Mockito.*;
  26 +
  27 +/**
  28 + * {@link MesCalTeamShiftServiceImpl} 的单元测试
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +@Import(MesCalTeamShiftServiceImpl.class)
  33 +public class MesCalTeamShiftServiceImplTest extends BaseDbUnitTest {
  34 +
  35 + @Resource
  36 + private MesCalTeamShiftServiceImpl teamShiftService;
  37 +
  38 + @Resource
  39 + private MesCalTeamShiftMapper teamShiftMapper;
  40 +
  41 + @MockitoBean
  42 + private MesCalPlanService planService;
  43 + @MockitoBean
  44 + private MesCalPlanShiftService planShiftService;
  45 + @MockitoBean
  46 + private MesCalPlanTeamService planTeamService;
  47 +
  48 + @Test
  49 + public void testGenerateTeamShiftRecords_threeShift_rotateThreeStates() {
  50 + // 准备参数
  51 + Long planId = 3001L;
  52 + // mock 方法:排班计划(三班倒、按天轮班、3 天)
  53 + MesCalPlanDO plan = MesCalPlanDO.builder()
  54 + .id(planId)
  55 + .code("PLAN-THREE-001")
  56 + .name("三班倒轮转")
  57 + .calendarType(1)
  58 + .startDate(LocalDateTime.of(2026, 4, 1, 0, 0))
  59 + .endDate(LocalDateTime.of(2026, 4, 3, 0, 0))
  60 + .shiftType(MesCalShiftTypeEnum.THREE.getType())
  61 + .shiftMethod(MesCalShiftMethodEnum.DAY.getMethod())
  62 + .shiftCount(1)
  63 + .build();
  64 + List<MesCalPlanShiftDO> shifts = List.of(
  65 + MesCalPlanShiftDO.builder().id(11L).planId(planId).sort(1).name("白班").startTime("08:00").endTime("16:00").build(),
  66 + MesCalPlanShiftDO.builder().id(12L).planId(planId).sort(2).name("中班").startTime("16:00").endTime("00:00").build(),
  67 + MesCalPlanShiftDO.builder().id(13L).planId(planId).sort(3).name("夜班").startTime("00:00").endTime("08:00").build()
  68 + );
  69 + List<MesCalPlanTeamDO> teams = List.of(
  70 + MesCalPlanTeamDO.builder().id(21L).planId(planId).teamId(101L).build(),
  71 + MesCalPlanTeamDO.builder().id(22L).planId(planId).teamId(102L).build(),
  72 + MesCalPlanTeamDO.builder().id(23L).planId(planId).teamId(103L).build()
  73 + );
  74 + when(planService.getPlan(planId)).thenReturn(plan);
  75 + when(planShiftService.getPlanShiftListByPlanId(planId)).thenReturn(shifts);
  76 + when(planTeamService.getPlanTeamListByPlanId(planId)).thenReturn(teams);
  77 +
  78 + // 调用
  79 + teamShiftService.generateTeamShiftRecords(planId);
  80 +
  81 + // 断言:3 天 × 3 班次 = 9 条排班记录,班组按天轮转
  82 + List<MesCalTeamShiftDO> records = teamShiftMapper.selectListByPlanId(planId);
  83 + records.sort(Comparator.comparing(MesCalTeamShiftDO::getDay).thenComparing(MesCalTeamShiftDO::getSort));
  84 + assertEquals(9, records.size());
  85 + // 断言:第 1 天(shiftIndex=0):A 白班、B 中班、C 夜班
  86 + assertRecord(records.get(0), LocalDateTime.of(2026, 4, 1, 0, 0), 1, 101L, 11L);
  87 + assertRecord(records.get(1), LocalDateTime.of(2026, 4, 1, 0, 0), 2, 102L, 12L);
  88 + assertRecord(records.get(2), LocalDateTime.of(2026, 4, 1, 0, 0), 3, 103L, 13L);
  89 + // 断言:第 2 天(shiftIndex=1):C 白班、A 中班、B 夜班
  90 + assertRecord(records.get(3), LocalDateTime.of(2026, 4, 2, 0, 0), 1, 103L, 11L);
  91 + assertRecord(records.get(4), LocalDateTime.of(2026, 4, 2, 0, 0), 2, 101L, 12L);
  92 + assertRecord(records.get(5), LocalDateTime.of(2026, 4, 2, 0, 0), 3, 102L, 13L);
  93 + // 断言:第 3 天(shiftIndex=2):B 白班、C 中班、A 夜班
  94 + assertRecord(records.get(6), LocalDateTime.of(2026, 4, 3, 0, 0), 1, 102L, 11L);
  95 + assertRecord(records.get(7), LocalDateTime.of(2026, 4, 3, 0, 0), 2, 103L, 12L);
  96 + assertRecord(records.get(8), LocalDateTime.of(2026, 4, 3, 0, 0), 3, 101L, 13L);
  97 + }
  98 +
  99 + private static void assertRecord(MesCalTeamShiftDO actual, LocalDateTime day, Integer sort,
  100 + Long teamId, Long shiftId) {
  101 + assertEquals(day, actual.getDay());
  102 + assertEquals(sort, actual.getSort());
  103 + assertEquals(teamId, actual.getTeamId());
  104 + assertEquals(shiftId, actual.getShiftId());
  105 + }
  106 +
  107 +}
yudao-module-mes/src/test/resources/application-unit-test.yaml
@@ -10,7 +10,7 @@ spring: @@ -10,7 +10,7 @@ spring:
10 # 数据源配置项 10 # 数据源配置项
11 datasource: 11 datasource:
12 name: ruoyi-vue-pro 12 name: ruoyi-vue-pro
13 - url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 13 + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value,day; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写
14 driver-class-name: org.h2.Driver 14 driver-class-name: org.h2.Driver
15 username: sa 15 username: sa
16 password: 16 password:
yudao-module-mes/src/test/resources/sql/clean.sql
  1 +DELETE FROM "mes_cal_team_shift";
  2 +DELETE FROM "mes_cal_plan_team";
  3 +DELETE FROM "mes_cal_plan_shift";
  4 +DELETE FROM "mes_cal_plan";
1 DELETE FROM "mes_md_auto_code_rule"; 5 DELETE FROM "mes_md_auto_code_rule";
2 DELETE FROM "mes_md_auto_code_part"; 6 DELETE FROM "mes_md_auto_code_part";
3 DELETE FROM "mes_md_auto_code_record"; 7 DELETE FROM "mes_md_auto_code_record";
yudao-module-mes/src/test/resources/sql/create_tables.sql
1 -- ---------------------------- 1 -- ----------------------------
  2 +-- MES 排班计划
  3 +-- ----------------------------
  4 +CREATE TABLE IF NOT EXISTS "mes_cal_plan" (
  5 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  6 + "code" varchar(64) DEFAULT NULL,
  7 + "name" varchar(255) DEFAULT NULL,
  8 + "calendar_type" tinyint DEFAULT NULL,
  9 + "start_date" timestamp DEFAULT NULL,
  10 + "end_date" timestamp DEFAULT NULL,
  11 + "shift_type" tinyint DEFAULT NULL,
  12 + "shift_method" tinyint DEFAULT NULL,
  13 + "shift_count" int DEFAULT NULL,
  14 + "status" tinyint DEFAULT NULL,
  15 + "remark" varchar(500) DEFAULT NULL,
  16 + "creator" varchar(64) DEFAULT '',
  17 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  18 + "updater" varchar(64) DEFAULT '',
  19 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  20 + "deleted" bit NOT NULL DEFAULT FALSE,
  21 + "tenant_id" bigint NOT NULL DEFAULT 0,
  22 + PRIMARY KEY ("id")
  23 +);
  24 +
  25 +-- ----------------------------
  26 +-- MES 排班计划班次
  27 +-- ----------------------------
  28 +CREATE TABLE IF NOT EXISTS "mes_cal_plan_shift" (
  29 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  30 + "plan_id" bigint DEFAULT NULL,
  31 + "sort" int DEFAULT NULL,
  32 + "name" varchar(64) DEFAULT NULL,
  33 + "start_time" varchar(10) DEFAULT NULL,
  34 + "end_time" varchar(10) DEFAULT NULL,
  35 + "remark" varchar(500) DEFAULT NULL,
  36 + "creator" varchar(64) DEFAULT '',
  37 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  38 + "updater" varchar(64) DEFAULT '',
  39 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  40 + "deleted" bit NOT NULL DEFAULT FALSE,
  41 + "tenant_id" bigint NOT NULL DEFAULT 0,
  42 + PRIMARY KEY ("id")
  43 +);
  44 +
  45 +-- ----------------------------
  46 +-- MES 排班计划班组
  47 +-- ----------------------------
  48 +CREATE TABLE IF NOT EXISTS "mes_cal_plan_team" (
  49 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  50 + "plan_id" bigint DEFAULT NULL,
  51 + "team_id" bigint DEFAULT NULL,
  52 + "remark" varchar(500) DEFAULT NULL,
  53 + "creator" varchar(64) DEFAULT '',
  54 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  55 + "updater" varchar(64) DEFAULT '',
  56 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  57 + "deleted" bit NOT NULL DEFAULT FALSE,
  58 + "tenant_id" bigint NOT NULL DEFAULT 0,
  59 + PRIMARY KEY ("id")
  60 +);
  61 +
  62 +-- ----------------------------
  63 +-- MES 班组排班
  64 +-- ----------------------------
  65 +CREATE TABLE IF NOT EXISTS "mes_cal_team_shift" (
  66 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  67 + "plan_id" bigint DEFAULT NULL,
  68 + "team_id" bigint DEFAULT NULL,
  69 + "shift_id" bigint DEFAULT NULL,
  70 + "day" timestamp DEFAULT NULL,
  71 + "sort" int DEFAULT NULL,
  72 + "remark" varchar(500) DEFAULT NULL,
  73 + "creator" varchar(64) DEFAULT '',
  74 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  75 + "updater" varchar(64) DEFAULT '',
  76 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  77 + "deleted" bit NOT NULL DEFAULT FALSE,
  78 + "tenant_id" bigint NOT NULL DEFAULT 0,
  79 + PRIMARY KEY ("id")
  80 +);
  81 +
  82 +-- ----------------------------
2 -- MES 编码规则表 83 -- MES 编码规则表
3 -- ---------------------------- 84 -- ----------------------------
4 CREATE TABLE IF NOT EXISTS "mes_md_auto_code_rule" ( 85 CREATE TABLE IF NOT EXISTS "mes_md_auto_code_rule" (