diff --git a/sql/mysql/2026-06-23-bit-sample-wms-print-template-type-v3.sql b/sql/mysql/2026-06-23-bit-sample-wms-print-template-type-v3.sql new file mode 100644 index 000000000..b74ccf441 --- /dev/null +++ b/sql/mysql/2026-06-23-bit-sample-wms-print-template-type-v3.sql @@ -0,0 +1,21 @@ +-- BIT 样品仓打印模板类型补充 v3 +-- 说明: +-- 1. 2026-06-22-bit-sample-wms.sql 已作为种子执行后,不再修改原文件。 +-- 2. 保留现有 print_template_type: 6 = 产线。 +-- 3. 本文件仅补充 BIT 样品标签、BIT 库位标签两个打印模板类型。 + +INSERT INTO system_dict_data + (sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) +SELECT 7, 'BIT样品标签', '7', 'print_template_type', 0, 'primary', '', 'qrcodeUrl,name,code', '1', NOW(), '1', NOW(), b'0' +WHERE NOT EXISTS ( + SELECT 1 FROM system_dict_data + WHERE dict_type = 'print_template_type' AND value = '7' +); + +INSERT INTO system_dict_data + (sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) +SELECT 8, 'BIT库位标签', '8', 'print_template_type', 0, 'success', '', 'qrcodeUrl,name,code', '1', NOW(), '1', NOW(), b'0' +WHERE NOT EXISTS ( + SELECT 1 FROM system_dict_data + WHERE dict_type = 'print_template_type' AND value = '8' +); diff --git a/sql/mysql/2026-06-23-bit-sample-wms-silent-print-v4.sql b/sql/mysql/2026-06-23-bit-sample-wms-silent-print-v4.sql new file mode 100644 index 000000000..a8758a496 --- /dev/null +++ b/sql/mysql/2026-06-23-bit-sample-wms-silent-print-v4.sql @@ -0,0 +1,21 @@ +-- BIT 样品仓静默打印业务场景补充 v4 +-- 说明: +-- 1. 2026-06-22-bit-sample-wms.sql 已作为种子执行后,不再修改原文件。 +-- 2. 本文件补充打印机配置管理使用的 mes_business_scenario 字典数据。 +-- 3. print_template_type 仍由 v3 文件维护:7 = BIT样品标签,8 = BIT库位标签。 + +INSERT INTO system_dict_data + (sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) +SELECT 90, 'BIT样品标签打印', 'BIT_SAMPLE_LABEL_PRINT', 'mes_business_scenario', 0, 'primary', '', 'BIT样品仓样品标签静默打印', '1', NOW(), '1', NOW(), b'0' +WHERE NOT EXISTS ( + SELECT 1 FROM system_dict_data + WHERE dict_type = 'mes_business_scenario' AND value = 'BIT_SAMPLE_LABEL_PRINT' +); + +INSERT INTO system_dict_data + (sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) +SELECT 91, 'BIT库位标签打印', 'BIT_LOCATION_LABEL_PRINT', 'mes_business_scenario', 0, 'success', '', 'BIT样品仓库位标签静默打印', '1', NOW(), '1', NOW(), b'0' +WHERE NOT EXISTS ( + SELECT 1 FROM system_dict_data + WHERE dict_type = 'mes_business_scenario' AND value = 'BIT_LOCATION_LABEL_PRINT' +); diff --git a/yudao-module-common/yudao-module-common-biz/pom.xml b/yudao-module-common/yudao-module-common-biz/pom.xml index 6498dc13a..dea1ea711 100644 --- a/yudao-module-common/yudao-module-common-biz/pom.xml +++ b/yudao-module-common/yudao-module-common-biz/pom.xml @@ -70,6 +70,11 @@ com.google.zxing javase + + cn.iocoder.boot + yudao-spring-boot-starter-test + test + - \ No newline at end of file + diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordService.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordService.java index ddf5a0ef2..0c7b55578 100644 --- a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordService.java +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordService.java @@ -67,6 +67,8 @@ public interface QrcodeRecordService { String selectQrcodeUrlByIdAndCode(String code, Long id, String code1); + String selectQrcodeUrlByIdAndCodeAndType(String bizType, Long bizId, String bizCode, CodeTypeEnum codeType); + Map selectQrcodeUrlMapByBizTypeAndIds(String bizType, Collection bizIds); Map resolveScanBizId(String type, Long id, String code); diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImpl.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImpl.java index 2a6e193ab..eddfa8dca 100644 --- a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImpl.java +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImpl.java @@ -177,6 +177,7 @@ public class QrcodeRecordServiceImpl implements QrcodeRecordService { record.setBizType(bizType.getCode()); record.setBizId(bizId); record.setBizCode(bizCode); + record.setCodeType(CodeTypeEnum.QR.getCode()); record.setQrScene(qrScene); record.setQrContent(qrContent); record.setFileName(fileName); @@ -336,6 +337,26 @@ public class QrcodeRecordServiceImpl implements QrcodeRecordService { } + @Override + public String selectQrcodeUrlByIdAndCodeAndType(String bizType, Long bizId, String bizCode, CodeTypeEnum codeType) { + if (StrUtil.isBlank(bizType) || bizId == null || StrUtil.isBlank(bizCode) || codeType == null) { + return null; + } + + QrcodeRecordDO record = qrcodeRecordMapper.selectOne(Wrappers.lambdaQuery() + .eq(QrcodeRecordDO::getBizType, bizType) + .eq(QrcodeRecordDO::getBizId, bizId) + .eq(QrcodeRecordDO::getBizCode, bizCode) + .eq(QrcodeRecordDO::getCodeType, codeType.getCode()) + .eq(QrcodeRecordDO::getStatus, 1) + .last("limit 1")); + + if (record == null || StrUtil.isBlank(record.getQrcodeFileUrl())) { + return null; + } + return record.getQrcodeFileUrl(); + } + @Override public Map selectQrcodeUrlMapByBizTypeAndIds(String bizType, Collection bizIds) { if (StrUtil.isBlank(bizType) || bizIds == null || bizIds.isEmpty()) { @@ -529,7 +550,7 @@ public class QrcodeRecordServiceImpl implements QrcodeRecordService { .eq(QrcodeRecordDO::getBizType, bizType.getCode()) .eq(QrcodeRecordDO::getBizId, bizId) .eq(QrcodeRecordDO::getBizCode, bizCode) -// .eq(QrcodeRecordDO::getCodeType, normalizedCodeType) + .eq(QrcodeRecordDO::getCodeType, normalizedCodeType) .eq(QrcodeRecordDO::getQrScene, qrScene) .last("limit 1") ); diff --git a/yudao-module-common/yudao-module-common-biz/src/test/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImplTest.java b/yudao-module-common/yudao-module-common-biz/src/test/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImplTest.java new file mode 100644 index 000000000..3afaf4781 --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/test/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImplTest.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.common.service.qrcordrecord; + +import cn.iocoder.yudao.module.common.dal.dataobject.qrcoderecord.QrcodeRecordDO; +import cn.iocoder.yudao.module.common.dal.mysql.qrcoderecord.QrcodeRecordMapper; +import cn.iocoder.yudao.module.common.enums.CodeTypeEnum; +import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class QrcodeRecordServiceImplTest { + + private QrcodeRecordServiceImpl qrcodeRecordService; + + @Mock + private FileApi fileApi; + @Mock + private QrcodeRecordMapper qrcodeRecordMapper; + + @BeforeEach + void setUp() { + qrcodeRecordService = new QrcodeRecordServiceImpl(Collections.emptyList()); + ReflectionTestUtils.setField(qrcodeRecordService, "fileApi", fileApi); + ReflectionTestUtils.setField(qrcodeRecordService, "qrcodeRecordMapper", qrcodeRecordMapper); + ReflectionTestUtils.setField(qrcodeRecordService, "width", 120); + ReflectionTestUtils.setField(qrcodeRecordService, "height", 120); + ReflectionTestUtils.setField(qrcodeRecordService, "defaultBucket", "common-qrcode"); + } + + @Test + void generateOrRefresh_whenQr_storesQrCodeType() throws Exception { + Map file = new HashMap<>(); + file.put("fileUrl", "https://file/qr.png"); + when(fileApi.createFile(any(), any(), any())).thenReturn(file); + + qrcodeRecordService.generateOrRefresh(QrcodeBizTypeEnum.PRODUCT, 10L, "SP001", "DETAIL"); + + ArgumentCaptor recordCaptor = ArgumentCaptor.forClass(QrcodeRecordDO.class); + verify(qrcodeRecordMapper).insert(recordCaptor.capture()); + assertEquals("QR", recordCaptor.getValue().getCodeType()); + } + + @Test + void selectQrcodeUrlByIdAndCodeAndType_filtersByCodeType() { + QrcodeRecordDO qrRecord = new QrcodeRecordDO(); + qrRecord.setQrcodeFileUrl("https://file/qr.png"); + when(qrcodeRecordMapper.selectOne(any())).thenReturn(qrRecord); + + String url = qrcodeRecordService.selectQrcodeUrlByIdAndCodeAndType( + QrcodeBizTypeEnum.PRODUCT.getCode(), 10L, "SP001", CodeTypeEnum.QR); + + assertEquals("https://file/qr.png", url); + verify(qrcodeRecordMapper).selectOne(any()); + } + + @Test + void regenerateByCodeType_filtersExistingRecordByRequestedCodeType() throws Exception { + Map file = new HashMap<>(); + file.put("fileUrl", "https://file/qr.png"); + when(fileApi.createFile(any(), any(), any())).thenReturn(file); + + qrcodeRecordService.regenerateByCodeType(QrcodeBizTypeEnum.PRODUCT, 10L, "SP001", "DETAIL", "QR"); + + verify(qrcodeRecordMapper).selectOne(any()); + + ArgumentCaptor recordCaptor = ArgumentCaptor.forClass(QrcodeRecordDO.class); + verify(qrcodeRecordMapper).insert(recordCaptor.capture()); + assertEquals("QR", recordCaptor.getValue().getCodeType()); + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java index 34b631281..e00d1d099 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImpl.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.erp.service.bitwms; +import cn.iocoder.yudao.module.common.enums.CodeTypeEnum; import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum; import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService; +import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsInboundReqVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLabelRespVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsMoveReqVO; @@ -29,6 +31,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.math.BigDecimal; +import java.io.UnsupportedEncodingException; import java.time.LocalDateTime; import java.util.Collections; import java.util.LinkedHashMap; @@ -50,8 +53,10 @@ public class BitWmsServiceImpl implements BitWmsService { private static final String SAMPLE_IN_TYPE = "样品入库"; private static final String SAMPLE_OUT_TYPE = "样品出库"; private static final String SAMPLE_MOVE_TYPE = "样品移库"; - private static final int SAMPLE_PRINT_TEMPLATE_TYPE = 6; - private static final int LOCATION_PRINT_TEMPLATE_TYPE = 7; + private static final String BIT_SAMPLE_CODE_RULE = "BIT_SAMPLE_CODE"; + private static final String BIT_WAREHOUSE_LOCATION_CODE_RULE = "BIT_WAREHOUSE_LOCATION_CODE"; + private static final int SAMPLE_PRINT_TEMPLATE_TYPE = 7; + private static final int LOCATION_PRINT_TEMPLATE_TYPE = 8; @Resource private ErpProductService productService; @@ -69,6 +74,8 @@ public class BitWmsServiceImpl implements BitWmsService { private ErpStockService stockService; @Resource private QrcodeRecordService qrcodeRecordService; + @Resource + private AutoCodeUtil autoCodeUtil; @Override @Transactional(rollbackFor = Exception.class) @@ -166,8 +173,8 @@ public class BitWmsServiceImpl implements BitWmsService { @Override public BitWmsLabelRespVO getSampleLabel(Long productId) { ErpProductRespVO product = validateBitSample(productId); - String qrcodeUrl = qrcodeRecordService.selectQrcodeUrlByIdAndCode( - QrcodeBizTypeEnum.PRODUCT.getCode(), product.getId(), product.getBarCode()); + String qrcodeUrl = resolveCodeUrl(QrcodeBizTypeEnum.PRODUCT, product.getId(), product.getBarCode(), + autoCodeUtil.queryCodeType(BIT_SAMPLE_CODE_RULE)); Map printData = new LinkedHashMap<>(); printData.put("id", product.getId()); printData.put("code", product.getBarCode()); @@ -185,8 +192,8 @@ public class BitWmsServiceImpl implements BitWmsService { if (location == null) { throw exception(WAREHOUSE_LOCATION_NOT_EXISTS); } - String qrcodeUrl = qrcodeRecordService.selectQrcodeUrlByIdAndCode( - QrcodeBizTypeEnum.WAREHOUSE_LOCATION.getCode(), location.getId(), location.getCode()); + String qrcodeUrl = resolveCodeUrl(QrcodeBizTypeEnum.WAREHOUSE_LOCATION, location.getId(), location.getCode(), + autoCodeUtil.queryCodeType(BIT_WAREHOUSE_LOCATION_CODE_RULE)); Map printData = new LinkedHashMap<>(); printData.put("id", location.getId()); printData.put("code", location.getCode()); @@ -221,6 +228,24 @@ public class BitWmsServiceImpl implements BitWmsService { return "出库原因:" + outReason + ";" + remark; } + private String resolveCodeUrl(QrcodeBizTypeEnum bizType, Long bizId, String bizCode, CodeTypeEnum codeType) { + if (codeType == null) { + return qrcodeRecordService.selectQrcodeUrlByIdAndCode(bizType.getCode(), bizId, bizCode); + } + String codeUrl = qrcodeRecordService.selectQrcodeUrlByIdAndCodeAndType( + bizType.getCode(), bizId, bizCode, codeType); + if (codeUrl != null) { + return codeUrl; + } + try { + qrcodeRecordService.generateOrRefresh(bizType, bizId, bizCode, "DETAIL", codeType); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + return qrcodeRecordService.selectQrcodeUrlByIdAndCodeAndType( + bizType.getCode(), bizId, bizCode, codeType); + } + private BitWmsLabelRespVO buildLabel(String type, Long id, String code, String name, String qrcodeUrl, String templateJson, Map printData) { BitWmsLabelRespVO respVO = new BitWmsLabelRespVO(); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java index 4f301fd2d..47e7901cb 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java @@ -395,8 +395,7 @@ public class ErpProductServiceImpl implements ErpProductService { ErpProductCategoryDO erpProductCategoryDO = productCategoryMapper.selectOne(Wrappers.lambdaQuery().eq(ErpProductCategoryDO::getId, product.getSubCategoryId())); - String qrcodeUrl = qrcodeService.selectQrcodeUrlByIdAndCode( - QrcodeBizTypeEnum.PRODUCT.getCode(), id, product.getBarCode()); + String qrcodeUrl = resolveProductCodeUrl(product); product.setQrcodeUrl(qrcodeUrl); ErpProductRespVO respVO = BeanUtils.toBean(product, ErpProductRespVO.class); @@ -798,24 +797,53 @@ public class ErpProductServiceImpl implements ErpProductService { @Override public void regenerateCode(Long id, String code) throws UnsupportedEncodingException { - if(productMapper.selectById(id)==null){ + ErpProductDO product = productMapper.selectById(id); + if(product == null){ throw exception(PRODUCT_NOT_EXISTS); } if(StringUtils.isBlank(code)){ throw exception(PRODUCT_CODE_NOT_EXISTS); } - CodeTypeEnum moldCodeGenerate = autoCodeUtil.queryCodeType("PRODUCT_CODE_GENERATE"); -//s + CodeTypeEnum codeType = autoCodeUtil.queryCodeType(resolveProductRuleCode(product)); + if (codeType == null) { + log.warn("[刷新产品物料码图]未配置码类型,跳过生成,productId={}", id); + return; + } qrcodeService.regenerateByCodeType( QrcodeBizTypeEnum.PRODUCT, id, code, "DETAIL", - moldCodeGenerate.getCode() + codeType.getCode() ); } + private String resolveProductCodeUrl(ErpProductDO product) { + CodeTypeEnum codeType = autoCodeUtil.queryCodeType(resolveProductRuleCode(product)); + if (codeType == null) { + return qrcodeService.selectQrcodeUrlByIdAndCode( + QrcodeBizTypeEnum.PRODUCT.getCode(), product.getId(), product.getBarCode()); + } + String codeUrl = qrcodeService.selectQrcodeUrlByIdAndCodeAndType( + QrcodeBizTypeEnum.PRODUCT.getCode(), product.getId(), product.getBarCode(), codeType); + if (StrUtil.isNotBlank(codeUrl)) { + return codeUrl; + } + try { + qrcodeService.generateOrRefresh(QrcodeBizTypeEnum.PRODUCT, product.getId(), product.getBarCode(), + "DETAIL", codeType); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + return qrcodeService.selectQrcodeUrlByIdAndCodeAndType( + QrcodeBizTypeEnum.PRODUCT.getCode(), product.getId(), product.getBarCode(), codeType); + } + + private String resolveProductRuleCode(ErpProductDO product) { + return Boolean.TRUE.equals(product.getIsSample()) ? BIT_SAMPLE_CODE_RULE : PRODUCT_CODE_RULE; + } + private ErpProductDO convertToProductDO(ErpProductImportExcelVO importProduct) { ErpProductDO productDO = BeanUtils.toBean(importProduct, ErpProductDO.class); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java index 01b234720..9f6807ab7 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/bitwms/BitWmsServiceImplTest.java @@ -1,12 +1,19 @@ package cn.iocoder.yudao.module.erp.service.bitwms; import cn.iocoder.yudao.framework.test.core.util.AssertUtils; +import cn.iocoder.yudao.module.common.enums.CodeTypeEnum; +import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum; +import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService; +import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsInboundReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLabelRespVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsMoveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsOutboundReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.warehouselocation.WarehouseLocationMapper; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; @@ -25,6 +32,7 @@ import java.math.BigDecimal; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE2; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -40,11 +48,19 @@ class BitWmsServiceImplTest { @Mock private ErpProductService productService; @Mock + private ErpProductMapper productMapper; + @Mock + private WarehouseLocationMapper warehouseLocationMapper; + @Mock private ErpStockInService stockInService; @Mock private ErpStockMoveService stockMoveService; @Mock private ErpStockService stockService; + @Mock + private QrcodeRecordService qrcodeRecordService; + @Mock + private AutoCodeUtil autoCodeUtil; @Test void inbound_createsSampleStockInWithBitType() { @@ -117,10 +133,61 @@ class BitWmsServiceImplTest { verify(stockMoveService).updateStockMoveStatus(eq(300L), eq(ErpAuditStatus.APPROVE.getStatus())); } + @Test + void getSampleLabel_whenRuleIsQr_returnsQrUrl() throws Exception { + ErpProductRespVO product = buildBitSampleProduct(); + when(productService.getProduct(10L)).thenReturn(product); + when(autoCodeUtil.queryCodeType("BIT_SAMPLE_CODE")).thenReturn(CodeTypeEnum.QR); + when(qrcodeRecordService.selectQrcodeUrlByIdAndCodeAndType( + QrcodeBizTypeEnum.PRODUCT.getCode(), 10L, "SP001", CodeTypeEnum.QR)) + .thenReturn("https://file/qr.png"); + when(productMapper.selectPrintTemplate(7)).thenReturn("{\"panels\":[]}"); + + BitWmsLabelRespVO label = bitWmsService.getSampleLabel(10L); + + assertEquals("https://file/qr.png", label.getQrcodeUrl()); + assertEquals("https://file/qr.png", label.getPrintData().get("qrcodeUrl")); + verify(qrcodeRecordService, never()).generateOrRefresh( + QrcodeBizTypeEnum.PRODUCT, 10L, "SP001", "DETAIL", CodeTypeEnum.QR); + } + + @Test + void getSampleLabel_whenRuleIsQrAndQrMissing_generatesQrThenReturnsUrl() throws Exception { + ErpProductRespVO product = buildBitSampleProduct(); + when(productService.getProduct(10L)).thenReturn(product); + when(autoCodeUtil.queryCodeType("BIT_SAMPLE_CODE")).thenReturn(CodeTypeEnum.QR); + when(qrcodeRecordService.selectQrcodeUrlByIdAndCodeAndType( + QrcodeBizTypeEnum.PRODUCT.getCode(), 10L, "SP001", CodeTypeEnum.QR)) + .thenReturn(null) + .thenReturn("https://file/qr.png"); + + BitWmsLabelRespVO label = bitWmsService.getSampleLabel(10L); + + assertEquals("https://file/qr.png", label.getQrcodeUrl()); + verify(qrcodeRecordService).generateOrRefresh( + QrcodeBizTypeEnum.PRODUCT, 10L, "SP001", "DETAIL", CodeTypeEnum.QR); + } + + @Test + void getSampleLabel_whenRuleIsBarcode_returnsBarcodeUrl() throws Exception { + ErpProductRespVO product = buildBitSampleProduct(); + when(productService.getProduct(10L)).thenReturn(product); + when(autoCodeUtil.queryCodeType("BIT_SAMPLE_CODE")).thenReturn(CodeTypeEnum.BARCODE); + when(qrcodeRecordService.selectQrcodeUrlByIdAndCodeAndType( + QrcodeBizTypeEnum.PRODUCT.getCode(), 10L, "SP001", CodeTypeEnum.BARCODE)) + .thenReturn("https://file/barcode.png"); + + BitWmsLabelRespVO label = bitWmsService.getSampleLabel(10L); + + assertEquals("https://file/barcode.png", label.getQrcodeUrl()); + assertEquals("https://file/barcode.png", label.getPrintData().get("qrcodeUrl")); + } + private ErpProductRespVO buildBitSampleProduct() { ErpProductRespVO product = new ErpProductRespVO(); product.setId(10L); product.setName("BIT 样品"); + product.setBarCode("SP001"); product.setIsSample(true); product.setBizUnit("BIT"); product.setCategoryId(50L); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImplTest.java b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImplTest.java index 0cf455f4f..0ad8f1e0d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImplTest.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImplTest.java @@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductCategoryMapper; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.productpackagingschemerel.ProductPackagingSchemeRelMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.productsupplierrel.ProductSupplierRelMapper; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -17,6 +19,8 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.util.Collections; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -43,6 +47,10 @@ class ErpProductServiceImplTest { private QrcodeRecordService qrcodeService; @Mock private AutoCodeUtil autoCodeUtil; + @Mock + private ProductPackagingSchemeRelMapper productPackagingSchemeRelMapper; + @Mock + private ProductSupplierRelMapper productSupplierRelMapper; @Test void createProduct_whenBitSampleAndNoCode_generatesSampleCodeAndStoresMetadata() throws Exception { @@ -99,4 +107,45 @@ class ErpProductServiceImplTest { eq("DETAIL"), eq(CodeTypeEnum.QR)); } + + @Test + void getProduct_whenBitSampleRuleIsQr_returnsQrUrl() { + ErpProductDO product = new ErpProductDO(); + product.setId(100L); + product.setName("BIT 样品"); + product.setBarCode("SP202606220001"); + product.setIsSample(true); + + when(productMapper.selectById(100L)).thenReturn(product); + when(autoCodeUtil.queryCodeType("BIT_SAMPLE_CODE")).thenReturn(CodeTypeEnum.QR); + when(qrcodeService.selectQrcodeUrlByIdAndCodeAndType( + QrcodeBizTypeEnum.PRODUCT.getCode(), 100L, "SP202606220001", CodeTypeEnum.QR)) + .thenReturn("https://file/sample-qr.png"); + when(productMapper.selectDevicesByProductId(100L)).thenReturn(Collections.emptyList()); + when(productMapper.selectMoldsByProductId(100L)).thenReturn(Collections.emptyList()); + when(productPackagingSchemeRelMapper.selectListByProductId(100L)).thenReturn(Collections.emptyList()); + when(productSupplierRelMapper.selectListByProductId(100L)).thenReturn(Collections.emptyList()); + + assertEquals("https://file/sample-qr.png", productService.getProduct(100L).getQrcodeUrl()); + } + + @Test + void regenerateCode_whenBitSampleRuleIsQr_regeneratesQr() throws Exception { + ErpProductDO product = new ErpProductDO(); + product.setId(100L); + product.setBarCode("SP202606220001"); + product.setIsSample(true); + + when(productMapper.selectById(100L)).thenReturn(product); + when(autoCodeUtil.queryCodeType("BIT_SAMPLE_CODE")).thenReturn(CodeTypeEnum.QR); + + productService.regenerateCode(100L, "SP202606220001"); + + verify(qrcodeService).regenerateByCodeType( + QrcodeBizTypeEnum.PRODUCT, + 100L, + "SP202606220001", + "DETAIL", + CodeTypeEnum.QR.getCode()); + } } diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/printtemplate/vo/PrintTemplateTypeEnum.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/printtemplate/vo/PrintTemplateTypeEnum.java index 0deb9d556..83e175261 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/printtemplate/vo/PrintTemplateTypeEnum.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/printtemplate/vo/PrintTemplateTypeEnum.java @@ -12,8 +12,9 @@ public enum PrintTemplateTypeEnum { KEY_COMPONENT(3), MOLD(4), SPARE_PARTS(5), - SAMPLE(6), - WAREHOUSE_LOCATION(7); + PRODUCTION_LINE(6), + BIT_SAMPLE(7), + BIT_WAREHOUSE_LOCATION(8); private final Integer value;