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;