From fd654978e091d33a5a32b0c5aeff09c38b73ea80 Mon Sep 17 00:00:00 2001 From: ck-chenkang Date: Mon, 22 Jun 2026 14:19:44 +0800 Subject: [PATCH] feat: add bit sample product metadata --- .../admin/product/ErpProductController.java | 22 ++++ .../vo/product/ErpProductListReqVO.java | 15 +++ .../vo/product/ErpProductPageReqVO.java | 15 +++ .../product/vo/product/ErpProductRespVO.java | 15 +++ .../product/vo/product/ProductSaveReqVO.java | 15 +++ .../dal/dataobject/product/ErpProductDO.java | 20 ++++ .../dal/mysql/product/ErpProductMapper.java | 8 ++ .../service/product/ErpProductService.java | 1 + .../product/ErpProductServiceImpl.java | 18 +++- .../product/ErpProductServiceImplTest.java | 102 ++++++++++++++++++ 10 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImplTest.java diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java index 7b0931318..66066d063 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java @@ -116,6 +116,28 @@ public class ErpProductController { public CommonResult> getProductPage(@Valid ErpProductPageReqVO pageReqVO) { return success(productService.getProductVOPage(pageReqVO)); } + + @GetMapping("/sample-page") + @Operation(summary = "获得 BIT 样品分页") + @PreAuthorize("@ss.hasPermission('erp:bit-wms-sample:query')") + public CommonResult> getSamplePage(@Valid ErpProductPageReqVO pageReqVO) { + pageReqVO.setIsSample(true); + pageReqVO.setBizUnit("BIT"); + return success(productService.getProductVOPage(pageReqVO)); + } + + @GetMapping("/sample-simple-list") + @Operation(summary = "获得 BIT 样品精简列表") + @PreAuthorize("@ss.hasPermission('erp:bit-wms-sample:query')") + public CommonResult> getSampleSimpleList( + @RequestParam(name = "categoryType", required = false) Integer categoryType) { + ErpProductListReqVO reqVO = new ErpProductListReqVO(); + reqVO.setIsSample(true); + reqVO.setBizUnit("BIT"); + reqVO.setCategoryType(categoryType); + return success(productService.getProductVOList(reqVO)); + } + @GetMapping("/simple-list-all") @Operation(summary = "获得所有精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") public CommonResult> getAllSimpleList(@RequestParam(name = "categoryId", required = false) Integer categoryId) { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductListReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductListReqVO.java index a3349e81e..be884f60e 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductListReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductListReqVO.java @@ -24,6 +24,21 @@ public class ErpProductListReqVO { @Schema(description = "产品规格", example = "红色") private String standard; + @Schema(description = "是否样品", example = "true") + private Boolean isSample; + + @Schema(description = "样品分类", example = "CUSTOMER_SAMPLE") + private String sampleCategory; + + @Schema(description = "所属事业部", example = "BIT") + private String bizUnit; + + @Schema(description = "客户ID", example = "1001") + private Long customerId; + + @Schema(description = "客户名称", example = "ACME HK") + private String customerName; + @Schema(description = "产品 id 集合") private List ids; } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java index 5936746d1..d0270dbc5 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java @@ -33,6 +33,21 @@ public class ErpProductPageReqVO extends PageParam { @Schema(description = "产品编码", example = "P-001") private String barCode; + @Schema(description = "是否样品", example = "true") + private Boolean isSample; + + @Schema(description = "样品分类", example = "CUSTOMER_SAMPLE") + private String sampleCategory; + + @Schema(description = "所属事业部", example = "BIT") + private String bizUnit; + + @Schema(description = "客户ID", example = "1001") + private Long customerId; + + @Schema(description = "客户名称", example = "ACME HK") + private String customerName; + @Schema(description = "产品规格", example = "红色") private String standard; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java index 62f70cf71..b3acba39f 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java @@ -31,6 +31,21 @@ public class ErpProductRespVO extends ErpProductDO { @ExcelProperty("产品条码") private String barCode; + @Schema(description = "是否样品", example = "true") + private Boolean isSample; + + @Schema(description = "样品分类", example = "CUSTOMER_SAMPLE") + private String sampleCategory; + + @Schema(description = "所属事业部", example = "BIT") + private String bizUnit; + + @Schema(description = "客户ID", example = "1001") + private Long customerId; + + @Schema(description = "客户名称", example = "ACME HK") + private String customerName; + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161") private Long categoryId; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java index bad98d8a6..bfb1a1a76 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java @@ -28,6 +28,21 @@ public class ProductSaveReqVO { // @NotEmpty(message = "产品条码不能为空") private String barCode; + @Schema(description = "是否样品", example = "true") + private Boolean isSample; + + @Schema(description = "样品分类", example = "CUSTOMER_SAMPLE") + private String sampleCategory; + + @Schema(description = "所属事业部", example = "BIT") + private String bizUnit; + + @Schema(description = "客户ID", example = "1001") + private Long customerId; + + @Schema(description = "客户名称", example = "ACME HK") + private String customerName; + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161") @NotNull(message = "产品分类编号不能为空") private Long categoryId; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java index b375b7bf7..29a6c4d78 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java @@ -40,6 +40,26 @@ public class ErpProductDO extends BaseDO { * 产品条码 */ private String barCode; + /** + * 是否样品 + */ + private Boolean isSample; + /** + * 样品分类 + */ + private String sampleCategory; + /** + * 所属事业部 + */ + private String bizUnit; + /** + * 客户ID + */ + private Long customerId; + /** + * 客户名称快照 + */ + private String customerName; /** * 产品分类编号 * diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java index 0edda1a7c..e2158397d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java @@ -42,6 +42,10 @@ public interface ErpProductMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(ErpProductDO::getName, reqVO.getName()) .likeIfPresent(ErpProductDO::getBarCode, resolveCode(reqVO)) + .eqIfPresent(ErpProductDO::getIsSample, reqVO.getIsSample()) + .eqIfPresent(ErpProductDO::getBizUnit, reqVO.getBizUnit()) + .eqIfPresent(ErpProductDO::getSampleCategory, reqVO.getSampleCategory()) + .eqIfPresent(ErpProductDO::getCustomerId, reqVO.getCustomerId()) .eqIfPresent(ErpProductDO::getCategoryId, reqVO.getCategoryId()) .inIfPresent(ErpProductDO::getCategoryId, categoryIds) .betweenIfPresent(ErpProductDO::getCreateTime, reqVO.getCreateTime()) @@ -67,6 +71,10 @@ public interface ErpProductMapper extends BaseMapperX { .inIfPresent(ErpProductDO::getId, reqVO.getIds()) .likeIfPresent(ErpProductDO::getName, reqVO.getName()) .likeIfPresent(ErpProductDO::getBarCode, reqVO.getCode()) + .eqIfPresent(ErpProductDO::getIsSample, reqVO.getIsSample()) + .eqIfPresent(ErpProductDO::getBizUnit, reqVO.getBizUnit()) + .eqIfPresent(ErpProductDO::getSampleCategory, reqVO.getSampleCategory()) + .eqIfPresent(ErpProductDO::getCustomerId, reqVO.getCustomerId()) .eqIfPresent(ErpProductDO::getCategoryId, reqVO.getCategoryId()) .inIfPresent(ErpProductDO::getCategoryId, categoryIds) .likeIfPresent(ErpProductDO::getStandard, reqVO.getStandard()) diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java index 3c28c7723..c22d707a4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java @@ -76,6 +76,7 @@ public interface ErpProductService { List getProductVOListByStatus(Integer status,Integer categoryId); List getProductVOListByCategory(Integer categoryId); List getProductVOListByCategory(Integer categoryId, Integer categoryType); + List getProductVOList(ErpProductListReqVO reqVO); List buildProductVOList(List list); /** * 获得产品 VO 列表 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 f8886981b..4f301fd2d 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 @@ -72,6 +72,9 @@ import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; @Slf4j public class ErpProductServiceImpl implements ErpProductService { + private static final String PRODUCT_CODE_RULE = "PRODUCT_CODE_GENERATE"; + private static final String BIT_SAMPLE_CODE_RULE = "BIT_SAMPLE_CODE"; + @Resource private ErpProductMapper productMapper; @@ -125,6 +128,8 @@ public class ErpProductServiceImpl implements ErpProductService { String code = createReqVO.getBarCode(); boolean autoGeneratedCode = StringUtils.isBlank(code); + boolean sample = Boolean.TRUE.equals(createReqVO.getIsSample()); + String ruleCode = sample ? BIT_SAMPLE_CODE_RULE : PRODUCT_CODE_RULE; validateProductUnitRelation(createReqVO.getUnitId(), createReqVO.getPurchaseUnitId(), createReqVO.getPurchaseUnitConvertQuantity()); @@ -137,7 +142,7 @@ public class ErpProductServiceImpl implements ErpProductService { } if (autoGeneratedCode) { - code = autoCodeUtil.genSerialCode("PRODUCT_CODE_GENERATE", null); + code = autoCodeUtil.genSerialCode(ruleCode, null); } else { if (productMapper.selectOne(Wrappers.lambdaQuery() .eq(ErpProductDO::getBarCode, code)) != null) { @@ -166,7 +171,7 @@ public class ErpProductServiceImpl implements ErpProductService { // 自动生成才拼接 分类编码-流水号;手工输入则原样保存 if (autoGeneratedCode) { - product.setBarCode(productCategory.getCode() + "-" + code); + product.setBarCode(sample ? code : productCategory.getCode() + "-" + code); } else { product.setBarCode(code); } @@ -214,9 +219,9 @@ public class ErpProductServiceImpl implements ErpProductService { saveProductSuppliers(product.getId(), createReqVO.getSuppliers(), createReqVO.getDefaultSupplierId()); // 生成二维码 - CodeTypeEnum codeType = autoCodeUtil.queryCodeType("PRODUCT_CODE_GENERATE"); + CodeTypeEnum codeType = autoCodeUtil.queryCodeType(ruleCode); if (codeType==null){ - log.warn("[创建产品物料]未配置码类型,跳过生产,ruleCode={}","PRODUCT_CODE_GENERATE"); + log.warn("[创建产品物料]未配置码类型,跳过生成,ruleCode={}", ruleCode); return product.getId(); } @@ -541,6 +546,11 @@ public class ErpProductServiceImpl implements ErpProductService { ErpProductListReqVO reqVO = new ErpProductListReqVO(); reqVO.setCategoryId(categoryId == null ? null : categoryId.longValue()); reqVO.setCategoryType(categoryType); + return getProductVOList(reqVO); + } + + @Override + public List getProductVOList(ErpProductListReqVO reqVO) { List list = productMapper.selectList(reqVO); return buildProductVOList(list); } 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 new file mode 100644 index 000000000..0cf455f4f --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImplTest.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.erp.service.product; + +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.product.vo.product.ProductSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; +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 org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * {@link ErpProductServiceImpl} 的单元测试类 + */ +@ExtendWith(MockitoExtension.class) +class ErpProductServiceImplTest { + + @InjectMocks + private ErpProductServiceImpl productService; + + @Mock + private ErpProductMapper productMapper; + @Mock + private ErpProductCategoryMapper productCategoryMapper; + @Mock + private ErpProductUnitService productUnitService; + @Mock + private QrcodeRecordService qrcodeService; + @Mock + private AutoCodeUtil autoCodeUtil; + + @Test + void createProduct_whenBitSampleAndNoCode_generatesSampleCodeAndStoresMetadata() throws Exception { + ProductSaveReqVO reqVO = new ProductSaveReqVO(); + reqVO.setName("BIT 样品"); + reqVO.setBarCode(null); + reqVO.setIsSample(true); + reqVO.setSampleCategory("CUSTOMER_SAMPLE"); + reqVO.setBizUnit("BIT"); + reqVO.setCustomerId(1001L); + reqVO.setCustomerName("ACME HK"); + reqVO.setCategoryId(10L); + reqVO.setUnitId(20L); + reqVO.setStatus(0); + reqVO.setStandard("STD-1"); + + ErpProductUnitDO unit = new ErpProductUnitDO(); + unit.setId(20L); + unit.setName("PCS"); + when(productUnitService.getProductUnit(20L)).thenReturn(unit); + + ErpProductCategoryDO category = new ErpProductCategoryDO(); + category.setId(10L); + category.setName("测试分类"); + category.setCode("CAT"); + when(productCategoryMapper.selectById(10L)).thenReturn(category); + + when(productMapper.selectProductExist(any(ErpProductDO.class))).thenReturn(false); + when(autoCodeUtil.genSerialCode("BIT_SAMPLE_CODE", null)).thenReturn("SP202606220001"); + when(autoCodeUtil.queryCodeType("BIT_SAMPLE_CODE")).thenReturn(CodeTypeEnum.QR); + when(productMapper.insert(any(ErpProductDO.class))).thenAnswer(invocation -> { + ErpProductDO product = invocation.getArgument(0); + product.setId(100L); + return 1; + }); + + Long id = productService.createProduct(reqVO); + + assertEquals(100L, id); + ArgumentCaptor productCaptor = ArgumentCaptor.forClass(ErpProductDO.class); + verify(productMapper).insert(productCaptor.capture()); + ErpProductDO product = productCaptor.getValue(); + assertTrue(product.getIsSample()); + assertEquals("CUSTOMER_SAMPLE", product.getSampleCategory()); + assertEquals("BIT", product.getBizUnit()); + assertEquals(1001L, product.getCustomerId()); + assertEquals("ACME HK", product.getCustomerName()); + assertEquals("SP202606220001", product.getBarCode()); + + verify(qrcodeService).generateOrRefresh( + eq(QrcodeBizTypeEnum.PRODUCT), + eq(100L), + eq("SP202606220001"), + eq("DETAIL"), + eq(CodeTypeEnum.QR)); + } +}