diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java index a11b52b7c..3188f9632 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java @@ -103,6 +103,15 @@ public class ProductSpuRespDTO { */ private Integer stock; + // ========== 物流相关字段 ========= + + /** + * 物流配置模板编号 + * + * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 + */ + private Long deliveryTemplateId; + // ========== 统计相关字段 ========= /** diff --git a/yudao-module-mall/yudao-module-product-biz/pom.xml b/yudao-module-mall/yudao-module-product-biz/pom.xml index 08b3c7533..674f49fc4 100644 --- a/yudao-module-mall/yudao-module-product-biz/pom.xml +++ b/yudao-module-mall/yudao-module-product-biz/pom.xml @@ -23,7 +23,12 @@ yudao-module-product-api ${revision} - + + + cn.iocoder.boot + yudao-module-trade-api + ${revision} + cn.iocoder.boot yudao-module-member-api diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppCommentController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppCommentController.java index a5621c57a..e1f1df3ea 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppCommentController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppCommentController.java @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentCreat import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO; import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert; -import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; import cn.iocoder.yudao.module.product.service.comment.ProductCommentService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -18,6 +17,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -37,8 +37,13 @@ public class AppCommentController { @GetMapping("/page") @Operation(summary = "获得商品评价分页") public CommonResult> getCommentPage(@Valid AppCommentPageReqVO pageVO) { - PageResult pageResult = productCommentService.getCommentPage(pageVO, Boolean.TRUE); - return success(ProductCommentConvert.INSTANCE.convertPage02(pageResult)); + return success(productCommentService.getCommentPage(pageVO, Boolean.TRUE)); + } + + @GetMapping("/get-count") + @Operation(summary = "获得商品评价分页 tab count") + public CommonResult> getCommentPage(@Valid Long spuId) { + return success(productCommentService.getCommentPageTabsCount(spuId, Boolean.TRUE)); } @PostMapping(value = "/create") diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java index f557d7779..8dbff09c3 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java @@ -14,8 +14,57 @@ import javax.validation.constraints.NotNull; @ToString(callSuper = true) public class AppCommentPageReqVO extends PageParam { + /** + * 所有 + */ + public static final Integer ALL = 0; + + /** + * 所有数量 key + */ + public static final String ALL_COUNT = "allCount"; + + /** + * 好评 + */ + public static final Integer FAVOURABLE_COMMENT = 1; + + /** + * 好评数量 key + */ + public static final String FAVOURABLE_COMMENT_COUNT = "favourableCommentCount"; + + /** + * 中评 + */ + public static final Integer MEDIOCRE_COMMENT = 2; + + /** + * 中评数量 key + */ + public static final String MEDIOCRE_COMMENT_COUNT = "mediocreCommentCount"; + + /** + * 差评 + */ + public static final Integer NEGATIVE_COMMENT = 3; + + /** + * 差评数量 key + */ + public static final String NEGATIVE_COMMENT_COUNT = "negativeCommentCount"; + + /** + * 默认匿名昵称 + */ + public static final String ANONYMOUS_NICKNAME = "匿名用户"; + @Schema(description = "商品SPU编号", example = "29502") @NotNull(message = "商品SPU编号不能为空") private Long spuId; + @Schema(description = "app 评论页 tab 类型 (0 全部、1 好评、2 中评、3 差评)", example = "0") + @NotNull(message = "商品SPU编号不能为空") + private Integer type; + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentRespVO.java index 43aeb2355..cd532ed4c 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentRespVO.java @@ -5,7 +5,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import javax.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.List; @@ -27,7 +26,7 @@ public class AppCommentRespVO extends AppCommentBaseVO { @Schema(description = "订单项编号", required = true, example = "24965") private Long id; - @Schema(description = "是否匿名:[0:不匿名 1:匿名]", required = true) + @Schema(description = "是否匿名", required = true) private Boolean anonymous; @Schema(description = "交易订单编号", required = true, example = "24428") @@ -36,7 +35,7 @@ public class AppCommentRespVO extends AppCommentBaseVO { @Schema(description = "交易订单项编号", required = true, example = "8233") private Long orderItemId; - @Schema(description = "商家是否回复:[1:回复 0:未回复]", required = true) + @Schema(description = "商家是否回复", required = true) private Boolean replied; @Schema(description = "回复管理员编号", example = "22212") @@ -60,4 +59,6 @@ public class AppCommentRespVO extends AppCommentBaseVO { @Schema(description = "创建时间", required = true) private LocalDateTime createTime; + @Schema(description = "最终评分", required = true) + private Integer finalScore; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java index 693e8e911..49f9524f0 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java @@ -6,11 +6,7 @@ import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetail import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; -import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; -import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; -import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -23,12 +19,8 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; -import java.util.List; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_ENABLE; -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; @Tag(name = "用户 APP - 商品 SPU") @RestController @@ -38,10 +30,6 @@ public class AppProductSpuController { @Resource private ProductSpuService productSpuService; - @Resource - private ProductSkuService productSkuService; - @Resource - private ProductPropertyValueService productPropertyValueService; @GetMapping("/page") @Operation(summary = "获得商品 SPU 分页") @@ -50,23 +38,12 @@ public class AppProductSpuController { return success(ProductSpuConvert.INSTANCE.convertPageForGetSpuPage(pageResult)); } + // TODO 芋艿:等会看看 @GetMapping("/get-detail") @Operation(summary = "获得商品 SPU 明细") @Parameter(name = "id", description = "编号", required = true) public CommonResult getSpuDetail(@RequestParam("id") Long id) { - // 获得商品 SPU - ProductSpuDO spu = productSpuService.getSpu(id); - if (spu == null) { - throw exception(SPU_NOT_EXISTS); - } - if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { - throw exception(SPU_NOT_ENABLE); - } - - // 查询商品 SKU - List skus = productSkuService.getSkuListBySpuId(spu.getId()); - // 拼接 - return success(ProductSpuConvert.INSTANCE.convertForGetSpuDetail(spu, skus)); + return success(productSpuService.getAppProductSpuDetail(id)); } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java index 34b6f6604..e7e3c8ba6 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java @@ -21,6 +21,15 @@ import lombok.*; @AllArgsConstructor public class ProductPropertyDO extends BaseDO { + /** + * 默认属性id + */ + public static final Long PROPERTY_ID = 0L; + /** + * 默认属性名字 + */ + public static final String PROPERTY_NAME = "默认"; + /** * 主键 */ diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java index d73fe06b2..a632c8f11 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java @@ -22,6 +22,15 @@ import lombok.*; @AllArgsConstructor public class ProductPropertyValueDO extends BaseDO { + /** + * 默认属性值id + */ + public static final Long VALUE_ID = 0L; + /** + * 默认属性值名字 + */ + public static final String VALUE_NAME = "默认"; + /** * 主键 */ diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java index e378f53ce..b010167cc 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.product.dal.mysql.comment; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -34,11 +35,33 @@ public interface ProductCommentMapper extends BaseMapperX { .orderByDesc(ProductCommentDO::getId)); } + static void appendTabQuery(LambdaQueryWrapperX queryWrapper, Integer type) { + // 构建好评查询语句 + if (ObjectUtil.equal(type, AppCommentPageReqVO.FAVOURABLE_COMMENT)) { + // 好评计算 (商品评分星级+服务评分星级) >= 8 + queryWrapper.apply("(scores + benefit_scores) >= 8"); + } + // 构建中评查询语句 + if (ObjectUtil.equal(type, AppCommentPageReqVO.MEDIOCRE_COMMENT)) { + // 中评计算 (商品评分星级+服务评分星级) > 4 且 (商品评分星级+服务评分星级) < 8 + queryWrapper.apply("(scores + benefit_scores) > 4 and (scores + benefit_scores) < 8"); + } + // 构建差评查询语句 + if (ObjectUtil.equal(type, AppCommentPageReqVO.NEGATIVE_COMMENT)) { + // 差评计算 (商品评分星级+服务评分星级) <= 4 + queryWrapper.apply("(scores + benefit_scores) <= 4"); + } + } + default PageResult selectPage(AppCommentPageReqVO reqVO, Boolean visible) { - return selectPage(reqVO, new LambdaQueryWrapperX() + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() .eqIfPresent(ProductCommentDO::getSpuId, reqVO.getSpuId()) - .eqIfPresent(ProductCommentDO::getVisible, visible) - .orderByDesc(ProductCommentDO::getId)); + .eqIfPresent(ProductCommentDO::getVisible, visible); + // 构建评价查询语句 + appendTabQuery(queryWrapper, reqVO.getType()); + // 按评价时间排序最新的显示在前面 + queryWrapper.orderByDesc(ProductCommentDO::getCreateTime); + return selectPage(reqVO, queryWrapper); } default void updateCommentVisible(Long id, Boolean visible) { @@ -74,4 +97,13 @@ public interface ProductCommentMapper extends BaseMapperX { update(null, lambdaUpdateWrapper); } + default Long selectTabCount(Long spuId, Boolean visible, Integer type) { + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() + .eqIfPresent(ProductCommentDO::getSpuId, spuId) + .eqIfPresent(ProductCommentDO::getVisible, visible); + // 构建评价查询语句 + appendTabQuery(queryWrapper, type); + return selectCount(queryWrapper); + } + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java index 0b6ef5ed0..6da00caf4 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java @@ -1,12 +1,9 @@ package cn.iocoder.yudao.module.product.dal.mysql.sku; import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @@ -63,23 +60,4 @@ public interface ProductSkuMapper extends BaseMapperX { return selectList(new QueryWrapper().apply("stock <= warn_stock")); } - // TODO @puhui999:貌似 IN 不出来数据哈。直接全部查询出来,处理就好列; - /** - * 更新 sku 属性值时使用的分页查询 - * - * @param pageParam 页面参数 - * @return {@link PageResult}<{@link ProductSkuDO}> - */ - default PageResult selectPage(PageParam pageParam) { - return selectPage(pageParam, new LambdaQueryWrapper().isNotNull(ProductSkuDO::getProperties)); - } - - /** - * 查询 sku properties 不等于 null 的数量 - * - * @return {@link Long} - */ - default Long selectCountByPropertyNotNull() { - return selectCount(new LambdaQueryWrapper().isNotNull(ProductSkuDO::getProperties)); - } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java index ab4f127ba..7e64c802d 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java @@ -68,7 +68,10 @@ public class ProductCategoryServiceImpl implements ProductCategoryService { throw exception(CATEGORY_EXISTS_CHILDREN); } // 校验分类是否绑定了 SPU - validateProductCategoryIsHaveBindSpu(id); + Long count = productSpuService.getSpuCountByCategoryId(id); + if (0 != count) { + throw exception(CATEGORY_HAVE_BIND_SPU); + } // 删除 productCategoryMapper.deleteById(id); } @@ -96,14 +99,6 @@ public class ProductCategoryServiceImpl implements ProductCategoryService { } } - // TODO @puhui999:不用抽方法,因为不太会复用这个方法哈。 - private void validateProductCategoryIsHaveBindSpu(Long id) { - Long count = productSpuService.getSpuCountByCategoryId(id); - if (0 != count) { - throw exception(CATEGORY_HAVE_BIND_SPU); - } - } - @Override public ProductCategoryDO getCategory(Long id) { return productCategoryMapper.selectById(id); diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java index 6f5e1b59f..0c315b94f 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java @@ -7,10 +7,13 @@ import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommen import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentAdditionalReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Map; + /** * 商品评论 Service 接口 * @@ -50,7 +53,7 @@ public interface ProductCommentService { * @param visible 是否可见 * @return 商品评价分页 */ - PageResult getCommentPage(AppCommentPageReqVO pageVO, Boolean visible); + PageResult getCommentPage(AppCommentPageReqVO pageVO, Boolean visible); /** * 创建商品评论 @@ -68,4 +71,12 @@ public interface ProductCommentService { */ void additionalComment(MemberUserRespDTO user, AppCommentAdditionalReqVO createReqVO); + /** + * 评论页面标签数 + * + * @param spuId spu id + * @param visible 是否可见 + * @return 获得商品评价分页 tab count + */ + Map getCommentPageTabsCount(Long spuId, Boolean visible); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java index 2fe331d59..edec1c651 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.product.service.comment; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO; @@ -7,17 +8,28 @@ import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommen import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentAdditionalReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO; +import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert; import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND; /** * 商品评论 Service 实现类 @@ -30,6 +42,11 @@ public class ProductCommentServiceImpl implements ProductCommentService { @Resource private ProductCommentMapper productCommentMapper; + @Resource + private TradeOrderApi tradeOrderApi; + + @Resource + private ProductSpuService productSpuService; @Override public PageResult getCommentPage(ProductCommentPageReqVO pageReqVO) { @@ -53,13 +70,48 @@ public class ProductCommentServiceImpl implements ProductCommentService { } @Override - public PageResult getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) { - return productCommentMapper.selectPage(pageVO, visible); + public Map getCommentPageTabsCount(Long spuId, Boolean visible) { + Map countMap = new HashMap<>(4); + // 查询商品 id = spuId 的所有评论数量 + countMap.put(AppCommentPageReqVO.ALL_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.ALL)); + // 查询商品 id = spuId 的所有好评数量 + countMap.put(AppCommentPageReqVO.FAVOURABLE_COMMENT_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.FAVOURABLE_COMMENT)); + // 查询商品 id = spuId 的所有中评数量 + countMap.put(AppCommentPageReqVO.MEDIOCRE_COMMENT_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT)); + // 查询商品 id = spuId 的所有差评数量 + countMap.put(AppCommentPageReqVO.NEGATIVE_COMMENT_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT)); + return countMap; + } + + @Override + public PageResult getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) { + PageResult result = ProductCommentConvert.INSTANCE.convertPage02(productCommentMapper.selectPage(pageVO, visible)); + result.getList().forEach(item -> { + // 判断用户是否选择匿名 + if (ObjectUtil.equal(item.getAnonymous(), true)) { + item.setUserNickname(AppCommentPageReqVO.ANONYMOUS_NICKNAME); + } + // 计算评价最终综合评分 最终星数 = (商品评星 + 服务评星) / 2 + BigDecimal sumScore = new BigDecimal(item.getScores() + item.getBenefitScores()); + BigDecimal divide = sumScore.divide(BigDecimal.valueOf(2L), 0, RoundingMode.DOWN); + item.setFinalScore(divide.intValue()); + }); + return result; } @Override public void createComment(ProductCommentDO productComment, Boolean system) { if (!system) { + // TODO 判断订单是否存在 fix + TradeOrderRespDTO order = tradeOrderApi.getOrder(productComment.getOrderId()); + if (null == order) { + throw exception(ORDER_NOT_FOUND); + } + // TODO 判断 SPU 是否存在 fix + ProductSpuDO spu = productSpuService.getSpu(productComment.getSpuId()); + if (null == spu) { + throw exception(SPU_NOT_EXISTS); + } // 判断当前订单的当前商品用户是否评价过 ProductCommentDO exist = productCommentMapper.findByUserIdAndOrderIdAndSpuId(productComment.getId(), productComment.getOrderId(), productComment.getSpuId()); if (null != exist) { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java index 518b1065c..44bf95e71 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java @@ -71,8 +71,8 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { // 更新 ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO); productPropertyMapper.updateById(updateObj); - // TODO @puhui:是不是只要传递变量,不传递整个 updateObj 变量哈 - productSkuService.updateSkuProperty(updateObj); + // 更新 sku 相关属性 + productSkuService.updateSkuProperty(updateObj.getId(), updateObj.getName()); } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java index 2666f13f4..6b4d1e9c8 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java @@ -73,10 +73,8 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ // 更新 ProductPropertyValueDO updateObj = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO); productPropertyValueMapper.updateById(updateObj); - - // TODO 芋艿:更新时,需要看看 sku 表 fix - // TODO @puhui:是不是只要传递变量,不传递整个 updateObj 变量哈 - productSkuService.updateSkuPropertyValue(updateObj); + // 更新 sku 相关属性 + productSkuService.updateSkuPropertyValue(updateObj.getId(), updateObj.getName()); } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java index f66b9d829..9ee2c00a2 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java @@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.product.service.sku; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import java.util.Collection; @@ -111,16 +109,18 @@ public interface ProductSkuService { /** * 更新 sku 属性 * - * @param updateObj 属性对象 + * @param propertyId 属性 id + * @param propertyName 属性名 * @return int 影响的行数 */ - int updateSkuProperty(ProductPropertyDO updateObj); + int updateSkuProperty(Long propertyId, String propertyName); /** * 更新 sku 属性值 * - * @param updateObj 属性值对象 + * @param propertyValueId 属性值 id + * @param propertyValueName 属性值名字 * @return int 影响的行数 */ - int updateSkuPropertyValue(ProductPropertyValueDO updateObj); + int updateSkuPropertyValue(Long propertyValueId, String propertyValueName); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java index 8e0a1c9a1..6b317bf22 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java @@ -2,9 +2,8 @@ package cn.iocoder.yudao.module.product.service.sku; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; @@ -80,16 +79,25 @@ public class ProductSkuServiceImpl implements ProductSkuService { @Override public void validateSkuList(List skus, Boolean specType) { - // 非多规格,不需要校验 - if (ObjectUtil.notEqual(specType, true)) { - return; - } - // 0、校验skus是否为空 if (CollUtil.isEmpty(skus)) { throw exception(SKU_NOT_EXISTS); } - + // 单规格处理 + if (ObjectUtil.equal(specType, false)) { + ProductSkuCreateOrUpdateReqVO skuVO = skus.get(0); + // 赋予单规格默认属性 + List properties = new ArrayList<>(); + ProductSkuBaseVO.Property property = new ProductSkuBaseVO.Property(); + property.setPropertyId(ProductPropertyDO.PROPERTY_ID); + property.setPropertyName(ProductPropertyDO.PROPERTY_NAME); + property.setValueId(ProductPropertyValueDO.VALUE_ID); + property.setValueName(ProductPropertyValueDO.VALUE_NAME); + properties.add(property); + skuVO.setProperties(properties); + // 单规格不需要后续的校验 + return; + } // 1、校验属性项存在 Set propertyIds = skus.stream().filter(p -> p.getProperties() != null) // 遍历多个 Property 属性 @@ -156,81 +164,51 @@ public class ProductSkuServiceImpl implements ProductSkuService { } @Override - public int updateSkuProperty(ProductPropertyDO updateObj) { - // TODO 看了一下数据库有关于 json 字符串的处理,怕数据库出现兼容问题这里还是用数据库常规操作来实现 - // TODO @puhui999:直接全部查询处理,批量处理就好列;一般项目的商品不会超过几十万的哈。 - Long count = productSkuMapper.selectCountByPropertyNotNull(); - int currentPage = 1; + public int updateSkuProperty(Long propertyId, String propertyName) { + // 获取所有的 sku + List skuDOList = productSkuMapper.selectList(); + // 处理后需要更新的 sku List updateSkus = new ArrayList<>(); - if (count == 0) { + if (CollUtil.isEmpty(skuDOList)) { return 0; } - int pageSize = 100; - for (int i = 0; i <= count / 100; i++) { - PageParam pageParam = new PageParam().setPageNo(currentPage + i).setPageSize(pageSize); - // 分页查找出 sku 属性不为 null 的 - PageResult skuPage = productSkuMapper.selectPage(pageParam); - List records = skuPage.getList(); - if (CollUtil.isEmpty(records)) { - break; - } - records.stream().filter(sku -> sku.getProperties() != null) - .forEach(sku -> sku.getProperties().forEach(property -> { - if (property.getPropertyId().equals(updateObj.getId())) { - property.setPropertyName(updateObj.getName()); - updateSkus.add(sku); - } - })); - } + skuDOList.stream().filter(sku -> sku.getProperties() != null) + .forEach(sku -> sku.getProperties().forEach(property -> { + if (property.getPropertyId().equals(propertyId)) { + property.setPropertyName(propertyName); + updateSkus.add(sku); + } + })); if (CollUtil.isEmpty(updateSkus)) { return 0; } - // TODO @puhui999:貌似 updateBatch 自己会拆分批次,这里不用再拆分了 - // 每批处理的大小 - int batchSize = 1000; - for (int i = 0; i < updateSkus.size(); i += batchSize) { - List batchSkuDOs = updateSkus.subList(i, Math.min(i + batchSize, updateSkus.size())); - productSkuMapper.updateBatch(batchSkuDOs, batchSize); - } + + productSkuMapper.updateBatch(updateSkus); return updateSkus.size(); } @Override - public int updateSkuPropertyValue(ProductPropertyValueDO updateObj) { - // TODO 看了一下数据库有关于 json 字符串的处理,怕数据库出现兼容问题这里还是用数据库常规操作来实现 - Long count = productSkuMapper.selectCountByPropertyNotNull(); - int currentPage = 1; + public int updateSkuPropertyValue(Long propertyValueId, String propertyValueName) { + // 获取所有的 sku + List skuDOList = productSkuMapper.selectList(); + // 处理后需要更新的 sku List updateSkus = new ArrayList<>(); - if (count == 0) { + if (CollUtil.isEmpty(skuDOList)) { return 0; } - int pageSize = 100; - for (int i = 0; i <= count / 100; i++) { - PageParam pageParam = new PageParam().setPageNo(currentPage + i).setPageSize(pageSize); - // 分页查找出 sku 属性不为 null 的 - PageResult skuPage = productSkuMapper.selectPage(pageParam); - List records = skuPage.getList(); - if (CollUtil.isEmpty(records)) { - break; - } - records.stream() - .filter(sku -> sku.getProperties() != null) - .forEach(sku -> sku.getProperties().forEach(property -> { - if (property.getValueId().equals(updateObj.getId())) { - property.setValueName(updateObj.getName()); - updateSkus.add(sku); - } - })); - } + skuDOList.stream() + .filter(sku -> sku.getProperties() != null) + .forEach(sku -> sku.getProperties().forEach(property -> { + if (property.getValueId().equals(propertyValueId)) { + property.setValueName(propertyValueName); + updateSkus.add(sku); + } + })); if (CollUtil.isEmpty(updateSkus)) { return 0; } - // 每批处理的大小 - int batchSize = 1000; - for (int i = 0; i < updateSkus.size(); i += batchSize) { - List batchSkuDOs = updateSkus.subList(i, Math.min(i + batchSize, updateSkus.size())); - productSkuMapper.updateBatch(batchSkuDOs, batchSize); - } + + productSkuMapper.updateBatch(updateSkus); return updateSkus.size(); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java index 5eeca1adb..be6851191 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.service.spu; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; @@ -135,4 +136,11 @@ public interface ProductSpuService { */ Long getSpuCountByCategoryId(Long id); + /** + * 通过 spu id 获取商品 SPU 明细 + * + * @param id id + * @return 用户 App - 商品 SPU 明细 + */ + AppProductSpuDetailRespVO getAppProductSpuDetail(Long id); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 9aecfb52e..45097c3a6 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -7,15 +7,21 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; import cn.iocoder.yudao.module.product.service.brand.ProductBrandService; import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import com.google.common.collect.Maps; import org.springframework.context.annotation.Lazy; @@ -51,6 +57,9 @@ public class ProductSpuServiceImpl implements ProductSpuService { private ProductBrandService brandService; @Resource private ProductCategoryService categoryService; + @Resource + @Lazy // 循环依赖,避免报错 + private ProductPropertyValueService productPropertyValueService; @Override @Transactional(rollbackFor = Exception.class) @@ -141,7 +150,11 @@ public class ProductSpuServiceImpl implements ProductSpuService { // 校验存在 validateSpuExists(id); // 校验商品状态不是回收站不能删除 - validateSpuStatus(id); + ProductSpuDO spuDO = productSpuMapper.selectById(id); + // 判断 SPU 状态是否为回收站 + if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) { + throw exception(SPU_NOT_RECYCLE); + } // 删除 SPU productSpuMapper.deleteById(id); @@ -155,20 +168,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { } } - /** - * 验证 SPU 状态是否为回收站 - * - * @param id id - */ - // TODO puhui999:感觉不用独立出来一个方法,直接在 deleteSpu 方法中校验即可 - private void validateSpuStatus(Long id) { - ProductSpuDO spuDO = productSpuMapper.selectById(id); - // 判断 SPU 状态是否为回收站 - if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) { - throw exception(SPU_NOT_RECYCLE); - } - } - @Override public ProductSpuDO getSpu(Long id) { return productSpuMapper.selectById(id); @@ -263,4 +262,35 @@ public class ProductSpuServiceImpl implements ProductSpuService { return productSpuMapper.selectCount(ProductSpuDO::getCategoryId, id); } + @Override + public AppProductSpuDetailRespVO getAppProductSpuDetail(Long id) { + // 获得商品 SPU + ProductSpuDO spu = getSpu(id); + if (spu == null) { + throw exception(SPU_NOT_EXISTS); + } + if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { + throw exception(SPU_NOT_ENABLE); + } + + // 查询商品 SKU + List skus = productSkuService.getSkuListBySpuId(spu.getId()); + List propertyValues = new ArrayList<>(); + // 单规格商品 赋予默认属性值 + if (ObjectUtil.equal(spu.getSpecType(), false)) { + ProductPropertyValueDetailRespBO respBO = new ProductPropertyValueDetailRespBO(); + respBO.setPropertyId(ProductPropertyDO.PROPERTY_ID); + respBO.setPropertyName(ProductPropertyDO.PROPERTY_NAME); + respBO.setValueId(ProductPropertyValueDO.VALUE_ID); + respBO.setValueName(ProductPropertyValueDO.VALUE_NAME); + propertyValues.add(respBO); + } else { + // 多规格商品则查询商品属性 + propertyValues = productPropertyValueService + .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus)); + } + // 拼接 + return ProductSpuConvert.INSTANCE.convertForGetSpuDetail(spu, skus, propertyValues); + } + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java index af1d529d8..24d912025 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java +++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java @@ -11,15 +11,22 @@ import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommen import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentAdditionalReqVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO; import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert; import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper; import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Lazy; import javax.annotation.Resource; +import java.time.LocalDateTime; import java.util.Date; +import java.util.Map; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; @@ -39,8 +46,14 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest { private ProductCommentMapper productCommentMapper; @Resource + @Lazy private ProductCommentServiceImpl productCommentService; + @MockBean + private TradeOrderApi tradeOrderApi; + @MockBean + private ProductSpuService productSpuService; + public String generateNo() { return DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999); } @@ -70,6 +83,23 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest { o.setScores(ProductCommentScoresEnum.FOUR.getScores()); o.setReplied(Boolean.TRUE); o.setVisible(Boolean.TRUE); + o.setId(generateId()); + o.setUserId(generateId()); + o.setAnonymous(Boolean.TRUE); + o.setOrderId(generateId()); + o.setOrderItemId(generateId()); + o.setSpuId(generateId()); + o.setSkuId(generateId()); + o.setDescriptionScores(ProductCommentScoresEnum.FOUR.getScores()); + o.setBenefitScores(ProductCommentScoresEnum.FOUR.getScores()); + o.setDeliveryScores(ProductCommentScoresEnum.FOUR.getScores()); + o.setContent("真好吃"); + o.setReplyUserId(generateId()); + o.setReplyContent("确实"); + o.setReplyTime(LocalDateTime.now()); + o.setAdditionalTime(LocalDateTime.now()); + o.setCreateTime(LocalDateTime.now()); + o.setUpdateTime(LocalDateTime.now()); }); productCommentMapper.insert(productComment); @@ -77,7 +107,7 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest { Long spuId = productComment.getSpuId(); // 测试 userNickname 不匹配 - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setUserNickname("王三"))); + productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setUserNickname("王三").setScores(ProductCommentScoresEnum.ONE.getScores()))); // 测试 orderId 不匹配 productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setOrderId(generateId()))); // 测试 spuId 不匹配 @@ -107,8 +137,25 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest { PageResult all = productCommentService.getCommentPage(new ProductCommentPageReqVO()); assertEquals(8, all.getTotal()); - PageResult visible = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE); - assertEquals(7, visible.getTotal()); + // 测试获取所有商品分页评论数据 + PageResult result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE); + assertEquals(7, result1.getTotal()); + + // 测试获取所有商品分页中评数据 + PageResult result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); + assertEquals(2, result2.getTotal()); + + // 测试获取指定 spuId 商品分页中评数据 + PageResult result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); + assertEquals(2, result3.getTotal()); + + // 测试分页 tab count + Map tabsCount = productCommentService.getCommentPageTabsCount(spuId, Boolean.TRUE); + assertEquals(6, tabsCount.get(AppCommentPageReqVO.ALL_COUNT)); + assertEquals(4, tabsCount.get(AppCommentPageReqVO.FAVOURABLE_COMMENT_COUNT)); + assertEquals(2, tabsCount.get(AppCommentPageReqVO.MEDIOCRE_COMMENT_COUNT)); + assertEquals(0, tabsCount.get(AppCommentPageReqVO.NEGATIVE_COMMENT_COUNT)); + } @Test diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java new file mode 100644 index 000000000..8dc2aaced --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.trade.api.order; + +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; + +/** + * 订单 API 接口 + * + * @author HUIHUI + */ +public interface TradeOrderApi { + + /** + * 获取订单通过订单 id + * + * @param id id + * @return 订单信息 Response DTO + */ + TradeOrderRespDTO getOrder(Long id); + +} diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java new file mode 100644 index 000000000..b9d362407 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.trade.api.order.dto; + +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 订单信息 Response DTO + * + * @author HUIHUI + */ +@Data +public class TradeOrderRespDTO { + + // ========== 订单基本信息 ========== + /** + * 订单编号,主键自增 + */ + private Long id; + /** + * 订单流水号 + *

+ * 例如说,1146347329394184195 + */ + private String no; + /** + * 订单类型 + *

+ * 枚举 {@link TradeOrderTypeEnum} + */ + private Integer type; + /** + * 订单来源 + *

+ * 枚举 {@link TerminalEnum} + */ + private Integer terminal; + /** + * 用户编号 + *

+ * 关联 MemberUserDO 的 id 编号 + */ + private Long userId; + /** + * 用户 IP + */ + private String userIp; + /** + * 用户备注 + */ + private String userRemark; + /** + * 订单状态 + *

+ * 枚举 {@link TradeOrderStatusEnum} + */ + private Integer status; + /** + * 购买的商品数量 + */ + private Integer productCount; + /** + * 订单完成时间 + */ + private LocalDateTime finishTime; + /** + * 订单取消时间 + */ + private LocalDateTime cancelTime; + /** + * 取消类型 + *

+ * 枚举 {@link TradeOrderCancelTypeEnum} + */ + private Integer cancelType; + /** + * 商家备注 + */ + private String remark; + /** + * 是否评价 + *

+ * true - 已评价 + * false - 未评价 + */ + private Boolean commentStatus; + +} diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java new file mode 100644 index 000000000..5b0e37dcc --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.trade.api; \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-trade-biz/pom.xml b/yudao-module-mall/yudao-module-trade-biz/pom.xml index 4eb0164d4..24b2097ba 100644 --- a/yudao-module-mall/yudao-module-trade-biz/pom.xml +++ b/yudao-module-mall/yudao-module-trade-biz/pom.xml @@ -23,7 +23,6 @@ yudao-module-trade-api ${revision} - cn.iocoder.boot yudao-module-product-api @@ -44,6 +43,11 @@ yudao-module-member-api ${revision} + + cn.iocoder.boot + yudao-module-system-api + ${revision} + diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java new file mode 100644 index 000000000..3abdb2a9d --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.api.order; + +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; +import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 订单 API 接口实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class TradeOrderApiImpl implements TradeOrderApi { + + @Resource + private TradeOrderService tradeOrderService; + + @Override + public TradeOrderRespDTO getOrder(Long id) { + return TradeOrderConvert.INSTANCE.convert(tradeOrderService.getOrder(id)); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java new file mode 100644 index 000000000..5b0e37dcc --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.trade.api; \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java index 572c04e99..8f87e358e 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java @@ -70,14 +70,14 @@ public class DeliveryExpressTemplateController { return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list)); } - // TODO @puhui999:DeliveryExpressTemplateRespVO 搞个 simple 的哈 + // TODO @puhui999:DeliveryExpressTemplateRespVO 搞个 simple 的哈 fix @GetMapping("/list-all-simple") @Operation(summary = "获取快递模版精简信息列表", description = "主要用于前端的下拉选项") - public CommonResult> getSimpleTemplateList() { + public CommonResult> getSimpleTemplateList() { // 获取运费模版列表,只要开启状态的 List list = deliveryExpressTemplateService.getDeliveryExpressTemplateList(); // 排序后,返回给前端 - return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list)); + return success(DeliveryExpressTemplateConvert.INSTANCE.convertList1(list)); } @GetMapping("/page") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java new file mode 100644 index 000000000..37abbd06d --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Schema(description = "管理后台 - 模版精简信息 Response VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeliveryExpressTemplateSimpleRespVO { + + @Schema(description = "模版编号", required = true, example = "1024") + private Long id; + + @Schema(description = "模板名称", required = true, example = "测试模版") + private String name; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java index af247367c..aadaf42f3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java @@ -28,11 +28,13 @@ public interface DeliveryExpressTemplateConvert { List convertList(List list); + List convertList1(List list); + PageResult convertPage(PageResult page); default DeliveryExpressTemplateDetailRespVO convert(DeliveryExpressTemplateDO bean, List chargeList, - List freeList){ + List freeList) { DeliveryExpressTemplateDetailRespVO respVO = convert2(bean); respVO.setTemplateCharge(convertTemplateChargeList(chargeList)); respVO.setTemplateFree(convertTemplateFreeList(freeList)); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index c53ae4d0a..8c5501b53 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; +import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO; @@ -62,6 +63,8 @@ public interface TradeOrderConvert { TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address); + TradeOrderRespDTO convert(TradeOrderDO orderDO); + default List convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) { return CollectionUtils.convertList(calculateRespBO.getItems(), item -> { TradeOrderItemDO orderItem = convert(item); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java index 080e7af7d..6ec95a27a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java @@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplat import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; +import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; import javax.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Map; /** * 快递运费模板 Service 接口 @@ -73,11 +75,21 @@ public interface DeliveryExpressTemplateService { /** * 校验快递运费模板 - * + *

* 如果校验不通过,抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常 * * @param templateId 模板编号 * @return 快递运费模板 */ DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); + + /** + * 基于指定的 SPU 编号数组和收件人地址区域编号. 获取匹配运费模板 + * + * @param ids SPU 编号列表 + * @param areaId 区域编号 + * @return Map (spuId -> 运费模板设置) + */ + Map getExpressTemplateBySpuIdsAndArea(Collection ids, Integer areaId); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java index 5160be41e..87b2d4920 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.trade.service.delivery; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; @@ -9,6 +12,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemp import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper; import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateMapper; +import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -17,6 +21,7 @@ import javax.annotation.Resource; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert.INSTANCE; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_TEMPLATE_NAME_DUPLICATE; @@ -37,6 +42,8 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla private DeliveryExpressTemplateChargeMapper expressTemplateChargeMapper; @Resource private DeliveryExpressTemplateFreeMapper expressTemplateFreeMapper; + @Resource + private ProductSpuApi productSpuApi; @Override @Transactional(rollbackFor = Exception.class) @@ -216,4 +223,50 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla return template; } + @Override + public Map getExpressTemplateBySpuIdsAndArea(Collection spuIds, Integer areaId) { + Assert.notNull(areaId, "区域编号 {} 不能为空", areaId); + List spuList = productSpuApi.getSpuList(spuIds); + if (CollUtil.isEmpty(spuList)) { + return Collections.emptyMap(); + } + Map spuMap = convertMap(spuList, ProductSpuRespDTO::getDeliveryTemplateId); + List templateList = expressTemplateMapper.selectBatchIds(spuMap.keySet()); + Map result = new HashMap<>(templateList.size()); + templateList.forEach(item -> { + if (spuMap.containsKey(item.getId())) { + ProductSpuRespDTO spuDTO = spuMap.get(item.getId()); + SpuDeliveryExpressTemplateRespBO bo = new SpuDeliveryExpressTemplateRespBO() + .setSpuId(spuDTO.getId()).setAreaId(areaId) + .setChargeMode(item.getChargeMode()) + .setTemplateCharge(findMatchExpressTemplateCharge(item.getId(), areaId)) + .setTemplateFree(findMatchExpressTemplateFree(item.getId(), areaId)); + result.put(spuDTO.getId(), bo); + } + }); + return result; + } + + private DeliveryExpressTemplateChargeDO findMatchExpressTemplateCharge(Long templateId, Integer areaId) { + List list = expressTemplateChargeMapper.selectListByTemplateId(templateId); + for (DeliveryExpressTemplateChargeDO item : list) { + // 第一个匹配的返回。 areaId 不能重复 + if (item.getAreaIds().contains(areaId)) { + return item; + } + } + return null; + } + + private DeliveryExpressTemplateFreeDO findMatchExpressTemplateFree(Long templateId, Integer areaId) { + List list = expressTemplateFreeMapper.selectListByTemplateId(templateId); + for (DeliveryExpressTemplateFreeDO item : list) { + // 第一个匹配的返回。 areaId 不能重复 + if (item.getAreaIds().contains(areaId)) { + return item; + } + } + return null; + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java new file mode 100644 index 000000000..87d04001b --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/bo/SpuDeliveryExpressTemplateRespBO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.trade.service.delivery.bo; + +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; +import lombok.Data; + +/** + * SPU 运费模板配置 Resp BO + * + * @author jason + */ +@Data +public class SpuDeliveryExpressTemplateRespBO { + + /** + * 配送计费方式 + *

+ * 枚举 {@link DeliveryExpressChargeModeEnum} + */ + private Integer chargeMode; + + /** + * 运费模板快递运费设置 + */ + private DeliveryExpressTemplateChargeDO templateCharge; + + /** + * 运费模板包邮设置 + */ + private DeliveryExpressTemplateFreeDO templateFree; + + /** + * SPU 编号 + *

+ * 关联 ProductSpuDO 的 id 编号 + */ + private Long spuId; + + /** + * 区域编号 + */ + private Integer areaId; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 8e75dd985..666841eee 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -6,7 +6,9 @@ import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.TerminalEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.member.api.address.AddressApi; @@ -21,6 +23,11 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; +import cn.iocoder.yudao.module.system.api.notify.dto.NotifyTemplateReqDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.enums.notify.NotifyTemplateTypeEnum; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; @@ -29,6 +36,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettle import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; @@ -38,6 +46,7 @@ import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.*; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; import cn.iocoder.yudao.module.trade.service.price.TradePriceService; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; @@ -74,6 +83,8 @@ public class TradeOrderServiceImpl implements TradeOrderService { private TradeCartService tradeCartService; @Resource private TradePriceService tradePriceService; + @Resource + private DeliveryExpressService deliveryExpressService; @Resource private ProductSkuApi productSkuApi; @@ -85,7 +96,10 @@ public class TradeOrderServiceImpl implements TradeOrderService { private CouponApi couponApi; @Resource private MemberUserApi memberUserApi; - + @Resource + private AdminUserApi adminUserApi; + @Resource + private NotifyMessageSendApi notifyMessageSendApi; @Resource private TradeOrderProperties tradeOrderProperties; @@ -123,7 +137,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { /** * 计算订单价格 * - * @param userId 用户编号 + * @param userId 用户编号 * @param settlementReqVO 结算信息 * @return 订单价格 */ @@ -162,7 +176,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { /** * 校验收件地址是否存在 * - * @param userId 用户编号 + * @param userId 用户编号 * @param addressId 收件地址编号 * @return 收件地址 */ @@ -181,7 +195,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); order.setType(TradeOrderTypeEnum.NORMAL.getType()); order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); - order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); + order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? // 支付信息 order.setAdjustPrice(0).setPayed(false); @@ -201,12 +215,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { /** * 执行创建完创建完订单后的逻辑 - * + *

* 例如说:优惠劵的扣减、积分的扣减、支付单的创建等等 * - * @param userId 用户编号 - * @param createReqVO 创建订单请求 - * @param tradeOrderDO 交易订单 + * @param userId 用户编号 + * @param createReqVO 创建订单请求 + * @param tradeOrderDO 交易订单 * @param calculateRespBO 订单价格计算结果 */ private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, @@ -265,11 +279,11 @@ public class TradeOrderServiceImpl implements TradeOrderService { /** * 校验交易订单满足被支付的条件 - * + *

* 1. 交易订单未支付 * 2. 支付单已支付 * - * @param id 交易订单编号 + * @param id 交易订单编号 * @param payOrderId 支付订单编号 * @return 交易订单 */ @@ -324,8 +338,11 @@ public class TradeOrderServiceImpl implements TradeOrderService { public void deliveryOrder(Long userId, TradeOrderDeliveryReqVO deliveryReqVO) { // 校验并获得交易订单(可发货) TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId()); - - // TODO 芋艿:logisticsId 校验存在 + // TODO 芋艿:logisticsId 校验存在 发货物流公司 fix + DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId()); + if (deliveryExpress == null) { + throw exception(DELIVERY_EXPRESS_NOT_EXISTS); + } // 更新 TradeOrderDO 状态为已发货,等待收货 int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), @@ -338,8 +355,32 @@ public class TradeOrderServiceImpl implements TradeOrderService { // TODO 芋艿:发送订单变化的消息 - // TODO 芋艿:发送站内信 - + // TODO 芋艿:发送站内信 fix + // 1、获取模版编码为 order_delivery 的模版,判断是否存在 存在放回 true + if (!notifyMessageSendApi.validateNotifyTemplate("order_delivery")) { + // 1、1 站内信模版不存在则创建模版 + NotifyTemplateReqDTO templateReqDTO = new NotifyTemplateReqDTO(); + templateReqDTO.setName("订单发货通知模版"); + templateReqDTO.setCode("order_delivery"); + templateReqDTO.setType(NotifyTemplateTypeEnum.NOTIFICATION_MESSAGE.getType()); // 系统消息 + // 获取操作用户 + // AdminUserRespDTO user = adminUserApi.getUser(userId); + // templateReqDTO.setNickname(user.getNickname()); + templateReqDTO.setNickname(UserTypeEnum.ADMIN.getName()); + templateReqDTO.setContent("订单:{orderId}{msg}"); + templateReqDTO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + notifyMessageSendApi.createNotifyTemplate(templateReqDTO); + } + // 2、构造消息 + Map msgMap = new HashMap<>(); + msgMap.put("orderId", deliveryReqVO.getId()); + msgMap.put("msg", TradeOrderStatusEnum.DELIVERED.getStatus()); + // 2、发送站内信 + notifyMessageSendApi.sendSingleMessageToAdmin( + new NotifySendSingleToUserReqDTO() + .setUserId(userId) + .setTemplateCode("order_delivery") + .setTemplateParams(msgMap)); // TODO 芋艿:OrderLog // TODO 设计:like:是否要单独一个 delivery 发货单表??? @@ -349,7 +390,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { /** * 校验交易订单满足被发货的条件 - * + *

* 1. 交易订单未发货 * * @param id 交易订单编号 @@ -363,7 +404,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { } // 校验订单是否是待发货状态 if (!TradeOrderStatusEnum.isUndelivered(order.getStatus()) - || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) { + || ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) { throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED); } return order; @@ -397,11 +438,11 @@ public class TradeOrderServiceImpl implements TradeOrderService { /** * 校验交易订单满足可售货的条件 - * + *

* 1. 交易订单待收货 * * @param userId 用户编号 - * @param id 交易订单编号 + * @param id 交易订单编号 * @return 交易订单 */ private TradeOrderDO validateOrderReceivable(Long userId, Long id) { @@ -476,7 +517,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, Integer refundPrice) { // 如果退款成功,则 refundPrice 非空 if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()) - && refundPrice == null) { + && refundPrice == null) { throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id)); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java index 7f9d333ae..ff5faea26 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.trade.service.price.bo; -import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import lombok.Data; @@ -53,14 +52,6 @@ public class TradePriceCalculateReqBO { */ private Integer deliveryType; - /** - * 配送模板编号 - * - * 关联 {@link DeliveryExpressTemplateDO#getId()} - */ - // TODO @jason:运费模版,是不是每个 SKU 传入哈 - private Long templateId; - /** * 商品 SKU 数组 */ diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java index 1f53bf8cc..46399b203 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java @@ -1,17 +1,17 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; -import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; -import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper; -import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; +import cn.iocoder.yudao.module.trade.service.delivery.bo.SpuDeliveryExpressTemplateRespBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; @@ -19,7 +19,6 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.annotation.Resource; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -39,14 +38,8 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { private AddressApi addressApi; @Resource private ProductSkuApi productSkuApi; - @Resource private DeliveryExpressTemplateService deliveryExpressTemplateService; - // TODO @jason:走 Service 哈。Mapper 只允许自己的 Service 调用,保护好数据结构; - @Resource - private DeliveryExpressTemplateChargeMapper templateChargeMapper; - @Resource - private DeliveryExpressTemplateFreeMapper templateFreeMapper; @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { @@ -54,66 +47,45 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { return; } - - if (param.getTemplateId() == null || param.getAddressId() == null) { + // 1.2 得到收件地址区域 + if (param.getAddressId() == null) { return; } - // 1.2 校验运费模板是否存在 - DeliveryExpressTemplateDO template = deliveryExpressTemplateService.validateDeliveryExpressTemplate(param.getTemplateId()); - - // 得到包邮配置 - List expressTemplateFreeList = templateFreeMapper.selectListByTemplateId(template.getId()); - Map areaTemplateFreeMap = new HashMap<>(); - expressTemplateFreeList.forEach(item -> { - for (Integer areaId : item.getAreaIds()) { - // TODO 需要保证 areaId 不能重复 - if (!areaTemplateFreeMap.containsKey(areaId)) { - areaTemplateFreeMap.put(areaId, item); - } - } - }); - // 得到快递运费配置 - List expressTemplateChargeList = templateChargeMapper.selectListByTemplateId(template.getId()); - Map areaTemplateChargeMap = new HashMap<>(); - expressTemplateChargeList.forEach(item -> { - for (Integer areaId : item.getAreaIds()) { - // areaId 不能重复 - if (!areaTemplateChargeMap.containsKey(areaId)) { - areaTemplateChargeMap.put(areaId, item); - } - } - }); - // 得到收件地址区域 AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); - // 1.3 计算快递费用 - calculateDeliveryPrice(address.getAreaId(), template.getChargeMode(), - areaTemplateFreeMap, areaTemplateChargeMap, result); + Assert.notNull(address, "收件人({})的地址,不能为空", param.getUserId()); + + //1.3 过滤出已选中的商品SKU + List selectedItem = filterList(result.getItems(), OrderItem::getSelected); + + Map spuExpressTemplateMap = + deliveryExpressTemplateService.getExpressTemplateBySpuIdsAndArea( + convertSet(selectedItem, OrderItem::getSpuId), address.getAreaId()); + + // 1.4 计算配送费用 + if (CollUtil.isNotEmpty(spuExpressTemplateMap)) { + calculateDeliveryPrice(selectedItem, spuExpressTemplateMap, result); + } + } - /** - * 校验订单是否满足包邮条件 - * - * @param receiverAreaId 收件人地区的区域编号 - * @param chargeMode 配送计费方式 - * @param areaTemplateFreeMap 运费模板包邮区域设置 Map - * @param areaTemplateChargeMap 运费模板快递费用设置 Map - */ - private void calculateDeliveryPrice(Integer receiverAreaId, - Integer chargeMode, - Map areaTemplateFreeMap, - Map areaTemplateChargeMap, + private void calculateDeliveryPrice(List selectedSkus, + Map spuExpressTemplateMap, TradePriceCalculateRespBO result) { - // 过滤出已选中的商品SKU - List selectedItem = filterList(result.getItems(), OrderItem::getSelected); - Set skuIds = convertSet(selectedItem, OrderItem::getSkuId); + Set skuIds = convertSet(selectedSkus, OrderItem::getSkuId); // 得到SKU 详情。得到 重量体积 Map skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId); - // 一个 spuId 可能对应多条订单商品 SKU - // TODO @jason:得确认下,按照 sku 算,还是 spu 算; - Map> spuIdItemMap = convertMultiMap(selectedItem, OrderItem::getSpuId); + // 按spu 来计算商品的运费 一个 spuId 可能对应多条订单商品 SKU, + Map> spuIdItemMap = convertMultiMap(selectedSkus, OrderItem::getSpuId); + // 依次计算每个 SPU 的快递运费 for (Map.Entry> entry : spuIdItemMap.entrySet()) { + Long spuId = entry.getKey(); List orderItems = entry.getValue(); + SpuDeliveryExpressTemplateRespBO templateBO = spuExpressTemplateMap.get(spuId); + if (templateBO == null) { + // 记录错误日志 + continue; + } // 总件数, 总金额, 总重量, 总体积 int totalCount = 0; int totalPrice = 0; @@ -121,51 +93,67 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { double totalVolume = 0; for (OrderItem orderItem : orderItems) { totalCount += orderItem.getCount(); - totalPrice += orderItem.getPrice(); // TODO jason:应该按照 payPrice? + totalPrice += orderItem.getPayPrice(); // 先按应付总金额来算,后面确认一下 ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId()); if (skuResp != null) { - totalWeight = totalWeight + skuResp.getWeight(); // TODO @jason:* 数量 - totalVolume = totalVolume + skuResp.getVolume(); + totalWeight = totalWeight + skuResp.getWeight() * orderItem.getCount(); + totalVolume = totalVolume + skuResp.getVolume() * orderItem.getCount(); } } // 优先判断是否包邮. 如果包邮不计算快递运费 - if (areaTemplateFreeMap.containsKey(receiverAreaId) && - checkExpressFree(chargeMode, totalCount, totalWeight, - totalVolume, totalPrice, areaTemplateFreeMap.get(receiverAreaId))) { + if (checkExpressFree(templateBO.getChargeMode(), totalCount, totalWeight, + totalVolume, totalPrice, templateBO.getTemplateFree())) { + continue; + } + if (templateBO.getTemplateCharge() == null) { continue; } // 计算快递运费 - // TODO @jason:貌似也可以抽成 checkExpressFree 类似方法 - if (areaTemplateChargeMap.containsKey(receiverAreaId)) { - DeliveryExpressTemplateChargeDO templateCharge = areaTemplateChargeMap.get(receiverAreaId); - DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); - switch (chargeModeEnum) { - case PIECE: { - calculateExpressFeeBySpu(totalCount, templateCharge, orderItems); - break; - } - case WEIGHT: { - calculateExpressFeeBySpu(totalWeight, templateCharge, orderItems); - break; - } - case VOLUME: { - calculateExpressFeeBySpu(totalVolume, templateCharge, orderItems); - break; - } - } - } + calculateExpressFeeByChargeMode(totalCount, totalWeight, totalVolume, + templateBO.getChargeMode(), templateBO.getTemplateCharge(), orderItems); + } TradePriceCalculatorHelper.recountAllPrice(result); } /** - * 按 spu 来计算快递费用 + * 按配送方式来计算运费 + * + * @param totalCount 总件数 + * @param totalWeight 总重量 + * @param totalVolume 总体积 + * @param chargeMode 配送计费方式 + * @param templateCharge 快递运费配置 + * @param orderItems SKU 商品项目 + */ + private void calculateExpressFeeByChargeMode(double totalCount, double totalWeight, double totalVolume, + int chargeMode, DeliveryExpressTemplateChargeDO templateCharge, + List orderItems) { + DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); + switch (chargeModeEnum) { + case PIECE: { + calculateExpressFee(totalCount, templateCharge, orderItems); + break; + } + case WEIGHT: { + calculateExpressFee(totalWeight, templateCharge, orderItems); + break; + } + case VOLUME: { + calculateExpressFee(totalVolume, templateCharge, orderItems); + break; + } + } + } + + /** + * 计算 SKU 商品快递费用 * * @param total 总件数/总重量/总体积 * @param templateCharge 快递运费配置 * @param orderItems SKU 商品项目 */ - private void calculateExpressFeeBySpu(double total, DeliveryExpressTemplateChargeDO templateCharge, List orderItems) { + private void calculateExpressFee(double total, DeliveryExpressTemplateChargeDO templateCharge, List orderItems) { int deliveryPrice; if (total <= templateCharge.getStartCount()) { deliveryPrice = templateCharge.getStartPrice(); @@ -176,8 +164,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { int extraPrice = templateCharge.getExtraPrice() * extraNum; deliveryPrice = templateCharge.getStartPrice() + extraPrice; } - // TODO @芋艿 分摊快递费用到 SKU. 是不是搞复杂了; - // TODO @jason:因为退费的时候,可能按照 SKU 考虑退费金额 + // 分摊快递费用到 SKU. 退费的时候,可能按照 SKU 考虑退费金额 divideDeliveryPrice(deliveryPrice, orderItems); } @@ -207,6 +194,9 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { */ private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight, double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) { + if (templateFree == null) { + return false; + } DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); switch (chargeModeEnum) { case PIECE: diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java index facedfade..8e816d880 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApi.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.system.api.notify; import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; +import cn.iocoder.yudao.module.system.api.notify.dto.NotifyTemplateReqDTO; import javax.validation.Valid; @@ -27,4 +28,8 @@ public interface NotifyMessageSendApi { */ Long sendSingleMessageToMember(@Valid NotifySendSingleToUserReqDTO reqDTO); + + boolean validateNotifyTemplate(String orderDelivery); + + void createNotifyTemplate(NotifyTemplateReqDTO templateReqDTO); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java new file mode 100644 index 000000000..09d5b6fff --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/notify/dto/NotifyTemplateReqDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.system.api.notify.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Data +public class NotifyTemplateReqDTO { + + @NotEmpty(message = "模版名称不能为空") + private String name; + + @NotNull(message = "模版编码不能为空") + private String code; + + @NotNull(message = "模版类型不能为空") + private Integer type; + + @NotEmpty(message = "发送人名称不能为空") + private String nickname; + + @NotEmpty(message = "模版内容不能为空") + private String content; + + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}") + private Integer status; + + private String remark; + +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java new file mode 100644 index 000000000..dccfb1977 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/notify/NotifyTemplateTypeEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.enums.notify; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知模板类型枚举 + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum NotifyTemplateTypeEnum { + + /** + * 系统消息 + */ + SYSTEM_MESSAGE(2), + /** + * 通知消息 + */ + NOTIFICATION_MESSAGE(1); + + private final Integer type; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java index fc5ba1d12..ee169a1c3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/notify/NotifyMessageSendApiImpl.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.system.api.notify; import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; -import cn.iocoder.yudao.module.system.service.notify.NotifyMessageService; +import cn.iocoder.yudao.module.system.api.notify.dto.NotifyTemplateReqDTO; import cn.iocoder.yudao.module.system.service.notify.NotifySendService; import org.springframework.stereotype.Service; @@ -30,4 +30,14 @@ public class NotifyMessageSendApiImpl implements NotifyMessageSendApi { reqDTO.getTemplateCode(), reqDTO.getTemplateParams()); } + @Override + public boolean validateNotifyTemplate(String orderDelivery) { + return false; + } + + @Override + public void createNotifyTemplate(NotifyTemplateReqDTO templateReqDTO) { + + } + }