From 633bd70dfe157fbbb00bf5c9860f506747e77e10 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 7 Jun 2026 20:14:12 +0800 Subject: [PATCH] fix(mes): 自动编码重复时支持自动重试,修复流水号落后导致的生成失败 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java | 47 +++++++++++++++++++++++++++++++---------------- yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java index 25cf9ae..13bd663 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java @@ -32,6 +32,8 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; @Validated public class MesMdAutoCodeRecordServiceImpl implements MesMdAutoCodeRecordService { + private static final int GENERATE_MAX_RETRY_COUNT = 10; + @Resource private MesMdAutoCodeRecordMapper recordMapper; @@ -63,10 +65,34 @@ public class MesMdAutoCodeRecordServiceImpl implements MesMdAutoCodeRecordServic throw exception(AUTO_CODE_GENERATE_FAILED); } - // 2.1 构建上下文 - MesMdAutoCodeContext context = new MesMdAutoCodeContext() - .setRule(rule).setParts(parts).setInputChar(inputChar); - // 2.2 遍历分段,生成编码 + // 2. 循环生成编码,跳过因 Redis 流水号落后导致的历史重复编码 + for (int i = 0; i < GENERATE_MAX_RETRY_COUNT; i++) { + // 2.1 生成编码 + MesMdAutoCodeContext context = new MesMdAutoCodeContext() + .setRule(rule).setParts(parts).setInputChar(inputChar); + String result = generateCode(rule, parts, context); + // 2.2 二次校验(防止重复) + MesMdAutoCodeRecordDO existRecord = recordMapper.selectByResult(result); + if (existRecord != null) { + continue; + } + // 2.3 保存生成记录 + MesMdAutoCodeRecordDO record = new MesMdAutoCodeRecordDO() + .setRuleId(rule.getId()).setResult(result) + .setSerialNo(context.getSerialNo()).setInputChar(inputChar); + recordMapper.insert(record); + return result; + } + + // 3. 重试多次后仍然失败,抛出异常 + throw exception(AUTO_CODE_GENERATE_FAILED); + } + + /** + * 生成编码 + */ + private String generateCode(MesMdAutoCodeRuleDO rule, List parts, + MesMdAutoCodeContext context) { StringBuilder codeBuilder = new StringBuilder(); for (MesMdAutoCodePartDO part : parts) { MesMdAutoCodePartStrategy strategy = strategyMap.get(part.getType()); @@ -78,22 +104,11 @@ public class MesMdAutoCodeRecordServiceImpl implements MesMdAutoCodeRecordServic // 拼接分段编码 codeBuilder.append(partCode); } - // 2.3 补齐处理 + // 补齐处理 String result = codeBuilder.toString(); if (Boolean.TRUE.equals(rule.getPadded()) && rule.getMaxLength() != null) { result = padCode(result, rule); } - - // 3.1 二次校验(防止重复) - MesMdAutoCodeRecordDO existRecord = recordMapper.selectByResult(result); - if (existRecord != null) { - throw exception(AUTO_CODE_GENERATE_FAILED); - } - // 3.2 保存生成记录 - MesMdAutoCodeRecordDO record = new MesMdAutoCodeRecordDO() - .setRuleId(rule.getId()).setResult(result) - .setSerialNo(context.getSerialNo()).setInputChar(inputChar); - recordMapper.insert(record); return result; } diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java index a566df9..275e13c 100644 --- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java +++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java @@ -99,6 +99,42 @@ public class MesMdAutoCodeRecordServiceImplTest { } @Test + public void testGenerateAutoCode_retryWhenResultExists() { + // 准备参数 + String ruleCode = "DV_MACHINERY_CODE"; + MesMdAutoCodeRuleDO rule = new MesMdAutoCodeRuleDO().setId(5L).setCode(ruleCode).setPadded(false); + MesMdAutoCodePartDO part1 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.FIXED_CHAR.getType()) + .setFixCharacter("M").setLength(1).setSort(1); + MesMdAutoCodePartDO part2 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.SERIAL_NUMBER.getType()) + .setSerialStartNo(1).setSerialStep(1).setLength(5).setSort(2).setCycleFlag(false); + // mock + when(ruleService.getAutoCodeRuleByCode(ruleCode)).thenReturn(rule); + when(partService.getAutoCodePartListByRuleId(5L)).thenReturn(Arrays.asList(part1, part2)); + when(fixedCharStrategy.generate(eq(part1), any(MesMdAutoCodeContext.class))).thenReturn("M"); + long[] serialNoRef = {0L}; + when(serialNumberStrategy.generate(eq(part2), any(MesMdAutoCodeContext.class))).thenAnswer(invocation -> { + MesMdAutoCodeContext context = invocation.getArgument(1); + long serialNo = ++serialNoRef[0]; + context.setSerialNo(serialNo); + return String.format("%05d", serialNo); + }); + when(recordMapper.selectByResult("M00001")).thenReturn(new MesMdAutoCodeRecordDO()); + when(recordMapper.selectByResult("M00002")).thenReturn(new MesMdAutoCodeRecordDO()); + when(recordMapper.selectByResult("M00003")).thenReturn(null); + + // 调用 + String result = recordService.generateAutoCode(ruleCode, null); + // 断言 + assertEquals("M00003", result); + ArgumentCaptor captor = ArgumentCaptor.forClass(MesMdAutoCodeRecordDO.class); + verify(recordMapper).insert(captor.capture()); + MesMdAutoCodeRecordDO record = captor.getValue(); + assertEquals(5L, record.getRuleId()); + assertEquals("M00003", record.getResult()); + assertEquals(3L, record.getSerialNo()); + } + + @Test public void testGenerateAutoCode_withInputChar() { // 准备参数 String ruleCode = "CLIENT_CODE"; -- libgit2 0.21.4