From a3633fc6ef4b6c72f2eae5b30e7662eb822a7cb9 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Mon, 20 Oct 2025 18:07:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=A7=E5=93=81=E6=98=8E=E7=BB=86=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProductDetailsPageReqVO.java | 16 +- .../ProductDetailsSaveReqVO.java | 14 +- .../funds/products/ProductsDetailDO.java | 21 -- .../funds/products/ProductsDetailMapper.java | 37 +-- .../products/ProductsDetailServiceImpl.java | 69 +--- .../ProductsDetailServiceImplTest.java | 294 ++++++++++++++++++ .../src/test/resources/sql/create_tables.sql | 22 +- 7 files changed, 345 insertions(+), 128 deletions(-) create mode 100644 cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImplTest.java diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsPageReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsPageReqVO.java index 46c834f80..f929bd0e6 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsPageReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsPageReqVO.java @@ -1,7 +1,6 @@ package com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails; import com.cf.imes.framework.common.pojo.PageParam; -import com.cf.imes.module.system.validation.products.ProductType; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -21,22 +20,12 @@ public class ProductDetailsPageReqVO extends PageParam { @Schema(description = "产品ID", example = "1") private Long productId; - @Schema(description = "购买方式", example = "0") - @ProductType - private Integer purchaseType; - @Schema(description = "产品时长", example = "1") - private String duration; - - @Schema(description = "正常产量", example = "") - private BigDecimal output; + private Integer duration; @Schema(description = "赠送市场", example = "1") private String giftDuration; - @Schema(description = "赠送产量", example = "") - private BigDecimal giftOutput; - @Schema(description = "产品原价", example = "100") private BigDecimal originalPrice; @@ -46,7 +35,4 @@ public class ProductDetailsPageReqVO extends PageParam { @Schema(description = "产品现价", example = "80") private BigDecimal currentPrice; - @Schema(description = "是否特惠", example = "0") - private Boolean isDiscounted; - } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsSaveReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsSaveReqVO.java index 11b808fa3..652cd289a 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsSaveReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/funds/products/vo/productDetails/ProductDetailsSaveReqVO.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.Digits; +import jakarta.validation.constraints.Min; import lombok.Data; import jakarta.validation.constraints.NotNull; @@ -25,19 +26,16 @@ public class ProductDetailsSaveReqVO { @Schema(description = "购买方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") private Integer purchaseType = ProductsPurchaseTypeEnum.DURATION.getStatus(); - @Schema(description = "产品时间,格式:时长值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private String duration; + @Schema(description = "产品时长,格式:时长值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Min(value = 1, message = "产品时长必须大于0") + @NotNull(message = "产品时长不能为空") + private Integer duration; @Schema(description = "产品时长单位,0:年", example = "1") @ProductDurationUnitValid + @NotNull(message = "产品时长单位不能为空") private Integer durationUnit; - @Schema(description = "产品产量", requiredMode = Schema.RequiredMode.REQUIRED, example = "") - private BigDecimal output; - - @Schema(description = "赠送产量", requiredMode = Schema.RequiredMode.REQUIRED, example = "") - private BigDecimal giftOutput; - @Schema(description = "折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.8") @DecimalMax(value = "100", message = "折扣必须小于等于100") @DecimalMin(value = "0", message = "折扣必须大于等于0") diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/products/ProductsDetailDO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/products/ProductsDetailDO.java index 22a8f6d8a..18a434541 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/products/ProductsDetailDO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/funds/products/ProductsDetailDO.java @@ -35,11 +35,6 @@ public class ProductsDetailDO extends BaseDO { */ private Long productId; - /** - * 产品明细购买方式 0时长 1产量 - */ - private Integer purchaseType; - /** * 正常时间,不加赠送时间 */ @@ -50,24 +45,8 @@ public class ProductsDetailDO extends BaseDO { */ private Integer durationUnit; - /** - * 正常产量,不加赠送产量 - */ - @TableField("`output`") - private BigDecimal output; - - /** - * 赠送产量 - */ - private BigDecimal giftOutput; - /** * 折扣 */ private BigDecimal discount; - - /** - * 是否特惠: 0否1是 - */ - private Boolean isDiscounted; } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/products/ProductsDetailMapper.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/products/ProductsDetailMapper.java index ff953dafe..3145d59d7 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/products/ProductsDetailMapper.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/funds/products/ProductsDetailMapper.java @@ -7,8 +7,6 @@ import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetai import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO; import org.apache.ibatis.annotations.Mapper; -import java.math.BigDecimal; - /** * 产品明细表 product_details Mapper * @@ -17,23 +15,32 @@ import java.math.BigDecimal; @Mapper public interface ProductsDetailMapper extends BaseMapperX { + /** + * 分页查询 + * + * @param reqVO + * @return + */ default PageResult selectPage(ProductDetailsPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(ProductsDetailDO::getPurchaseType, reqVO.getPurchaseType()) .eqIfPresent(ProductsDetailDO::getProductId, reqVO.getProductId()) .eqIfPresent(ProductsDetailDO::getDuration, reqVO.getDuration()) - .eqIfPresent(ProductsDetailDO::getOutput, reqVO.getOutput()) - .eqIfPresent(ProductsDetailDO::getGiftOutput, reqVO.getGiftOutput()) .eqIfPresent(ProductsDetailDO::getDiscount, reqVO.getDiscount()) - .eqIfPresent(ProductsDetailDO::getIsDiscounted, reqVO.getIsDiscounted()) .eqIfPresent(ProductsDetailDO::getDeleted, false) .orderByAsc(ProductsDetailDO::getDuration) ); } - - // 时长查重,添加productId为查询条件 - default int selectCountByDuration(Long productId, Long productDetailId, String duration, Integer durationUnit) { + /** + * 查询产品id下相同时长、时长单位的数量 + * + * @param productId + * @param productDetailId + * @param duration + * @param durationUnit + * @return + */ + default int selectCountByDuration(Long productId, Long productDetailId, Integer duration, Integer durationUnit) { LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX<>(); queryWrapper.eq(ProductsDetailDO::getProductId, productId) .eq(ProductsDetailDO::getDeleted, false) @@ -42,16 +49,4 @@ public interface ProductsDetailMapper extends BaseMapperX { .neIfPresent(ProductsDetailDO::getId, productDetailId); return Math.toIntExact(selectCount(queryWrapper)); } - - - - // 产量查重 - default int selectCountByOutput(BigDecimal output, Long productId) { - LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX<>(); - queryWrapper.eq(ProductsDetailDO::getProductId, productId) - .eq(ProductsDetailDO::getDeleted, false) - .eq(ProductsDetailDO::getDuration, output); - return Math.toIntExact(selectCount(queryWrapper)); - - } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImpl.java index 92efc8933..7db1357af 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImpl.java @@ -16,7 +16,6 @@ import com.cf.imes.module.system.dal.mysql.funds.products.ProductsDetailMapper; import com.cf.imes.module.system.dal.mysql.funds.products.ProductsMapper; import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum; import com.cf.imes.module.system.enums.products.ProductStatusEnum; -import com.cf.imes.module.system.enums.products.ProductsPurchaseTypeEnum; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -48,17 +47,8 @@ public class ProductsDetailServiceImpl implements ProductsDetailService { // 校验是否有这个产品 validateProductExistAndNotOnList(createReqVO.getProductId()); - if (ProductsPurchaseTypeEnum.DURATION.getStatus().equals(createReqVO.getPurchaseType())) { - // 校验时长 - checkDuration(createReqVO.getDuration(), createReqVO.getDurationUnit()); - - // 查询是否有重复的定价 - checkProductDetails(createReqVO); - - } else if (createReqVO.getPurchaseType().equals(ProductsPurchaseTypeEnum.OUTPUT.getStatus())) { - // todo 暂不支持产量 - throw exception(PRODUCTS_OUTPUT_NOT_SUPPORT); - } + // 查询是否有重复的定价 + checkProductDetails(createReqVO); ProductsDetailDO productDetailsDO = BeanUtils.toBean(createReqVO, ProductsDetailDO.class); productDetailsMapper.insert(productDetailsDO); @@ -73,16 +63,8 @@ public class ProductsDetailServiceImpl implements ProductsDetailService { validateProductDetailsExists(updateReqVO.getId()); - if (updateReqVO.getPurchaseType().equals(ProductsPurchaseTypeEnum.DURATION.getStatus())) { - // 校验时长 - checkDuration(updateReqVO.getDuration(), updateReqVO.getDurationUnit()); - // 校验同时长是否还有其他的定价规则 - checkProductDetails(updateReqVO); - - } else if (updateReqVO.getPurchaseType().equals(ProductsPurchaseTypeEnum.OUTPUT.getStatus())) { - // todo 暂不支持产量 - throw exception(PRODUCTS_OUTPUT_NOT_SUPPORT); - } + // 校验同时长是否还有其他的定价规则 + checkProductDetails(updateReqVO); productDetailsMapper.update(new LambdaUpdateWrapper() .eq(ProductsDetailDO::getId, updateReqVO.getId()) @@ -132,29 +114,6 @@ public class ProductsDetailServiceImpl implements ProductsDetailService { } - /** - * 校验时长 - * - * @param duration - * @param timeUnit - * @return - */ - private void checkDuration(String duration, Integer timeUnit) { - AssertUtils.notEmpty(duration, PRODUCTS_DURATION_NOT_NULL); - AssertUtils.notEmpty(timeUnit, PRODUCTS_DURATION_NOT_NULL); - - // 校验时长值 - if (!duration.matches("^\\d+$")) { - throw exception(PRODUCTS_DURATION_INT_ERR); - } - - int timeValue = Integer.parseInt(duration); - if (timeValue <= 0) { - throw exception(PRODUCTS_DURATION_INT_ERR); - } - } - - /** * 产品是否存在 * @@ -203,20 +162,12 @@ public class ProductsDetailServiceImpl implements ProductsDetailService { */ private void checkProductDetails(ProductDetailsSaveReqVO createReqVO) { int count; - if (createReqVO.getPurchaseType() == 0) { - String duration = createReqVO.getDuration(); - Integer durationUnit = createReqVO.getDurationUnit(); - // 时长去重 - count = productDetailsMapper.selectCountByDuration(createReqVO.getProductId(), createReqVO.getId(), duration, durationUnit); - if (count > 0) { - throw ServiceExceptionUtil.exception(PRODUCTS_DETAIL_DURATION_EXIST, duration, ProductDurationUnitEnum.getDesc(durationUnit)); - } - } else if (createReqVO.getPurchaseType() == 1) { - //产量去重 - count = productDetailsMapper.selectCountByOutput(createReqVO.getOutput(), createReqVO.getProductId()); - if (count > 0) { - throw exception(PRODUCTS_DETAIL_OUTPUT_EXIST); - } + Integer duration = createReqVO.getDuration(); + Integer durationUnit = createReqVO.getDurationUnit(); + // 时长去重 + count = productDetailsMapper.selectCountByDuration(createReqVO.getProductId(), createReqVO.getId(), duration, durationUnit); + if (count > 0) { + throw ServiceExceptionUtil.exception(PRODUCTS_DETAIL_DURATION_EXIST, duration, ProductDurationUnitEnum.getDesc(durationUnit)); } } diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImplTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImplTest.java new file mode 100644 index 000000000..1df9457c2 --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/funds/products/ProductsDetailServiceImplTest.java @@ -0,0 +1,294 @@ +package com.cf.imes.module.system.service.funds.products; + +import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest; +import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO; +import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsSaveReqVO; +import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO; +import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO; +import com.cf.imes.module.system.dal.mysql.funds.products.ProductsDetailMapper; +import com.cf.imes.module.system.dal.mysql.funds.products.ProductsMapper; +import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum; +import com.cf.imes.module.system.enums.products.ProductStatusEnum; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.bean.override.mockito.MockitoBean; + +import java.math.BigDecimal; + +import static com.cf.imes.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static com.cf.imes.framework.test.core.util.AssertUtils.assertPojoEquals; +import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException; +import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_DETAIL_DURATION_EXIST; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_DETAIL_NO_EXIST; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_DETAIL_NO_UPDATE; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_NOT_NOLIST; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.PRODUCTS_NO_EXIST; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +/** + * @author Gqr + * @since 2025/10/14 13:48 + */ +@Import(ProductsDetailServiceImpl.class) +public class ProductsDetailServiceImplTest extends BaseDbAndRedisUnitTest { + @Resource + private ProductsDetailServiceImpl productsDetailService; + + @Resource + private ProductsDetailMapper productsDetailMapper; + + @MockitoBean + private ProductsMapper productsMapper; + + @Test + void testCreateProductDetails() { + // mock下架状态的产品 + ProductsDO mockProduct = new ProductsDO(); + mockProduct.setId(123L); + mockProduct.setDeleted(false); + mockProduct.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus()); + + when(productsMapper.selectOne(any())).thenReturn(mockProduct); + + ProductDetailsSaveReqVO productDetailsSaveReqVO = randomPojo(ProductDetailsSaveReqVO.class, p -> { + p.setId(null); + }); + + // 调用 + Long id = productsDetailService.create(productDetailsSaveReqVO); + // 断言 + assertNotNull(id); + // 校验记录的属性是否正确 + ProductsDetailDO productsDetailDO = productsDetailMapper.selectById(id); + assertPojoEquals(productDetailsSaveReqVO, productsDetailDO, "id"); + } + + @Test + void testCreateProductDetails_ProductNotExist() { + ProductDetailsSaveReqVO productDetailsSaveReqVO = randomPojo(ProductDetailsSaveReqVO.class); + when(productsMapper.selectOne(any())).thenReturn(null); + + assertServiceException(() -> productsDetailService.create(productDetailsSaveReqVO), + PRODUCTS_NO_EXIST); + + ProductsDO mockProduct = new ProductsDO(); + mockProduct.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus()); + when(productsMapper.selectOne(any())).thenReturn(mockProduct); + + assertServiceException(() -> productsDetailService.create(productDetailsSaveReqVO), + PRODUCTS_DETAIL_NO_UPDATE); + } + + @Test + void testCheckProductDetails_duplicate() { + // mock下架状态的产品 + ProductsDO mockProduct = new ProductsDO(); + mockProduct.setId(123L); + mockProduct.setDeleted(false); + mockProduct.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus()); + + when(productsMapper.selectOne(any())).thenReturn(mockProduct); + // 插入一条与 createReqVO 冲突的数据 + ProductsDetailDO existing = new ProductsDetailDO(); + existing.setProductId(1L); + existing.setDuration(12); + existing.setDurationUnit(0); + existing.setDeleted(false); + productsDetailMapper.insert(existing); + + // 模拟新增同样 duration + unit 的记录 + ProductDetailsSaveReqVO reqVO = new ProductDetailsSaveReqVO() + .setProductId(existing.getProductId()) + .setDuration(existing.getDuration()) + .setDurationUnit(existing.getDurationUnit()); + + assertServiceException(() -> productsDetailService.create(reqVO), + PRODUCTS_DETAIL_DURATION_EXIST, reqVO.getDuration(), ProductDurationUnitEnum.getDesc(reqVO.getDurationUnit())); + } + + @Test + void updateProductDetails() { + // mock下架状态的产品 + ProductsDO mockProduct = new ProductsDO(); + mockProduct.setId(123L); + mockProduct.setDeleted(false); + mockProduct.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus()); + + when(productsMapper.selectOne(any())).thenReturn(mockProduct); + + ProductsDetailDO detail = new ProductsDetailDO(); + detail.setProductId(mockProduct.getId()); + detail.setDuration(12); + detail.setDurationUnit(1); + detail.setDeleted(false); + productsDetailMapper.insert(detail); + + // 构造请求 + ProductDetailsSaveReqVO reqVO = new ProductDetailsSaveReqVO() + .setId(detail.getId()) + .setProductId(mockProduct.getId()) + .setDuration(6) + .setDurationUnit(0); + + // 调用 + productsDetailService.update(reqVO); + + // 验证结果 + ProductsDetailDO updated = productsDetailMapper.selectById(detail.getId()); + assertEquals(6, updated.getDuration()); + } + + @Test + void deleteTest(){ + // mock下架状态的产品 + ProductsDO mockProduct = new ProductsDO(); + mockProduct.setId(123L); + mockProduct.setDeleted(false); + mockProduct.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus()); + + when(productsMapper.selectOne(any())).thenReturn(mockProduct); + + ProductsDetailDO detail = new ProductsDetailDO(); + detail.setProductId(mockProduct.getId()); + detail.setDuration(12); + detail.setDurationUnit(1); + detail.setDeleted(false); + productsDetailMapper.insert(detail); + + // 调用删除 + productsDetailService.delete(detail.getId()); + + // 验证确实被删 + assertNull(productsDetailMapper.selectById(detail.getId())); + } + + @Test + void testGet_success() { + // 插入一条数据 + ProductsDetailDO detail = new ProductsDetailDO(); + detail.setId(321L); + detail.setDeleted(false); + detail.setProductId(123L); + productsDetailMapper.insert(detail); + + ProductsDetailDO result = productsDetailService.get(detail.getId()); + assertNotNull(result); + assertEquals(321L, result.getId()); + assertEquals(123L, result.getProductId()); + } + + @Test + void testGetPage_success() { + ProductsDetailDO detail = randomPojo(ProductsDetailDO.class, o -> { + o.setProductId(123L); + o.setDuration(1); + o.setDurationUnit(ProductDurationUnitEnum.YEAR.getCode()); + o.setDiscount(BigDecimal.valueOf(100)); + o.setDeleted(false); + }); + + productsDetailMapper.insert(detail); + + // 不匹配 productId + productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setProductId(321L))); + + // 不匹配 duration + productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setDuration(2))); + + // 不匹配 discount + productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setDiscount(BigDecimal.valueOf(99)))); + + // 被逻辑删除 + productsDetailMapper.insert(cloneIgnoreId(detail, o -> o.setDeleted(true))); + + // ============ 构造查询参数 ============ + ProductDetailsPageReqVO reqVO = new ProductDetailsPageReqVO(); + reqVO.setProductId(123L); + reqVO.setDuration(1); + reqVO.setDiscount(BigDecimal.valueOf(100)); + reqVO.setPageNo(1); + reqVO.setPageSize(10); + + // ============ 调用方法 ============ + PageResult pageResult = productsDetailService.getPage(reqVO); + + // ============ 断言结果 ============ + assertEquals(1, pageResult.getTotal(), "分页结果数量应为1"); + assertEquals(1, pageResult.getList().size(), "分页列表长度应为1"); + assertPojoEquals(detail, pageResult.getList().get(0)); + } + + @Test + void validateProductDetailsExists_idNull(){ + assertServiceException(() -> productsDetailService.validateProductDetailsExists(null), PRODUCTS_DETAIL_NO_EXIST); + } + + @Test + void validateProductDetailsExists_notExist(){ + assertServiceException(() -> productsDetailService.validateProductDetailsExists(1234567L), PRODUCTS_DETAIL_NO_EXIST); + } + + + @Test + void testValidateProductExist_success() { + // 模拟返回一个正常的产品 + ProductsDO product = new ProductsDO(); + product.setId(1L); + product.setDeleted(false); + product.setStatus(ProductStatusEnum.PRODUCT_UPDATES.getStatus()); + + when(productsMapper.selectOne(any())).thenReturn(product); + + ProductsDO result = productsDetailService.validateProductExist(1L); + + assertNotNull(result); + assertEquals(1L, result.getId()); + } + + @Test + void testValidateProductExist_notExist() { + // 模拟数据库返回 null + when(productsMapper.selectOne(any())).thenReturn(null); + + assertServiceException(() -> productsDetailService.validateProductExist(1L), PRODUCTS_NO_EXIST); + } + + @Test + void testValidateProductExist_statusNotUp() { + ProductsDO product = new ProductsDO(); + product.setId(1L); + product.setDeleted(false); + product.setStatus(ProductStatusEnum.PRODUCT_DELIS.getStatus()); // 非 PRODUCT_UPDATES 状态 + + when(productsMapper.selectOne(any())).thenReturn(product); + + assertServiceException(() -> productsDetailService.validateProductExist(1L), PRODUCTS_NOT_NOLIST); + } + + @Test + void testGetProductDetailOneYearDiscount_exists() { + // 模拟数据库返回一年期明细 + ProductsDetailDO detailDO = new ProductsDetailDO(); + detailDO.setProductId(1L); + detailDO.setDuration(1); + detailDO.setDurationUnit(ProductDurationUnitEnum.YEAR.getCode()); + detailDO.setDiscount(BigDecimal.valueOf(85)); + productsDetailMapper.insert(detailDO); + + BigDecimal discount = productsDetailService.getProductDetailOneYearDiscount(1L); + assertEquals(BigDecimal.valueOf(85), discount); + } + + @Test + void testGetProductDetailOneYearDiscount_notExist() { + BigDecimal discount = productsDetailService.getProductDetailOneYearDiscount(123L); + assertEquals(BigDecimal.valueOf(100), discount); + } +} diff --git a/cf-module-system/cf-module-system-biz/src/test/resources/sql/create_tables.sql b/cf-module-system/cf-module-system-biz/src/test/resources/sql/create_tables.sql index fdef1cf76..b750b8525 100644 --- a/cf-module-system/cf-module-system-biz/src/test/resources/sql/create_tables.sql +++ b/cf-module-system/cf-module-system-biz/src/test/resources/sql/create_tables.sql @@ -686,16 +686,30 @@ CREATE TABLE IF NOT EXISTS "process_group" ( ) COMMENT '工序组表 process_group'; CREATE TABLE IF NOT EXISTS "products" ( - "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "product_name" varchar(64) NOT NULL, + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "product_name" varchar(64) NOT NULL, "status" tinyint DEFAULT 1 NOT NULL, "software_id" bigint NOT NULL, "price" decimal(8,2), "description" varchar, "creator" varchar DEFAULT '', - "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, "updater" varchar DEFAULT '', - "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, "deleted" bit NOT NULL DEFAULT FALSE, PRIMARY KEY ("id") ) COMMENT '产品表'; + +CREATE TABLE IF NOT EXISTS "products_details" ( + "id" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "product_id" BIGINT NOT NULL, + "duration" VARCHAR, + "duration_unit" TINYINT, + "discount" DECIMAL(3), + "creator" VARCHAR DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") + ) COMMENT '产品购买信息表 products_details';