From 98aae5ed1a176283f937834b9074eb1f755a5b0f Mon Sep 17 00:00:00 2001 From: dongshanshan Date: Tue, 31 Oct 2023 16:51:56 +0800 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=E4=BC=9A=E5=91=98=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/core/mapper/BaseMapperX.java | 7 ++ .../favorite/ProductFavoriteController.java | 104 ++++++++++++++++++ .../favorite/vo/ProductFavoriteBaseVO.java | 21 ++++ .../vo/ProductFavoriteBatchReqVO.java | 21 ++++ .../favorite/vo/ProductFavoritePageReqVO.java | 35 ++++++ .../favorite/vo/ProductFavoriteReqVO.java | 17 +++ .../favorite/vo/ProductFavoriteRespVO.java | 22 ++++ .../favorite/ProductFavoriteConvert.java | 19 ++++ .../favorite/ProductFavoriteDetailDO.java | 16 +++ .../mysql/favorite/ProductFavoriteMapper.java | 36 ++++++ .../favorite/ProductFavoriteService.java | 10 +- .../favorite/ProductFavoriteServiceImpl.java | 8 +- 12 files changed, 314 insertions(+), 2 deletions(-) create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteReqVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java index d70c216260..2654bec52f 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java @@ -12,6 +12,7 @@ import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.baomidou.mybatisplus.extension.toolkit.Db; import com.github.yulichang.base.MPJBaseMapper; +import com.github.yulichang.interfaces.MPJBaseJoin; import org.apache.ibatis.annotations.Param; import java.util.Collection; @@ -132,4 +133,10 @@ default void saveOrUpdateBatch(Collection collection) { Db.saveOrUpdateBatch(collection); } + default PageResult selectJoinPage(PageParam pageParam, @Param("resultTypeClass_Eg1sG") Class var2, @Param("ew") MPJBaseJoin queryWrapper) { + IPage mpPage = MyBatisUtils.buildPage(pageParam); + selectJoinPage(mpPage, var2, queryWrapper); + // 转换返回 + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); + } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java new file mode 100644 index 0000000000..e59c108276 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteBatchReqVO; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteReqVO; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteRespVO; +import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; +import cn.iocoder.yudao.module.product.service.favorite.ProductFavoriteService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 商品收藏") +@RestController +@RequestMapping("/product/favorite") +@Validated +public class ProductFavoriteController { + + @Resource + private ProductFavoriteService productFavoriteService; + + @PostMapping("/create") + @Operation(summary = "添加单个商品收藏") + @PreAuthorize("@ss.hasPermission('product:favorite:create')") + public CommonResult createFavorite(@Valid @RequestBody ProductFavoriteReqVO reqVO) { + return success(productFavoriteService.createFavorite(reqVO.getUserId(), reqVO.getSpuId())); + } + + @PostMapping("/create-list") + @Operation(summary = "添加多个商品收藏") + @PreAuthorize("@ss.hasPermission('product:favorite:create')") + public CommonResult createFavoriteList(@Valid @RequestBody ProductFavoriteBatchReqVO reqVO) { + // todo @jason:待实现;如果有已经收藏的,不用报错,忽略即可; + return success(Boolean.TRUE); + } + + @DeleteMapping("/delete") + @Operation(summary = "取消单个商品收藏") + @PreAuthorize("@ss.hasPermission('product:favorite:delete')") + public CommonResult deleteFavorite(@Valid @RequestBody ProductFavoriteReqVO reqVO) { + productFavoriteService.deleteFavorite(reqVO.getUserId(), reqVO.getSpuId()); + return success(Boolean.TRUE); + } + + @DeleteMapping("/delete-list") + @Operation(summary = "取消单个商品收藏") + @PreAuthorize("@ss.hasPermission('product:favorite:delete')") + public CommonResult deleteFavoriteList(@Valid @RequestBody ProductFavoriteBatchReqVO reqVO) { + // todo @jason:待实现 +// productFavoriteService.deleteFavorite(getLoginUserId(), reqVO.getSpuId()); + return success(Boolean.TRUE); + } + + @GetMapping("/page") + @Operation(summary = "获得商品收藏分页") + @PreAuthorize("@ss.hasPermission('product:favorite:query')") + public CommonResult> getFavoritePage(@Valid ProductFavoritePageReqVO pageVO) { + PageResult favoritePage = productFavoriteService.getFavoritePageByFilter(pageVO); + if (CollUtil.isEmpty(favoritePage.getList())) { + return success(PageResult.empty()); + } + + // 得到商品 spu 信息 + List favorites = ProductFavoriteConvert.INSTANCE.convertList2admin(favoritePage.getList()); + + // 转换 VO 结果 + PageResult pageResult = new PageResult<>(favoritePage.getTotal()); + pageResult.setList(favorites); + + return success(pageResult); + } + + @PostMapping(value = "/exits") + @Operation(summary = "检查是否收藏过商品") + @PreAuthenticated + public CommonResult isFavoriteExists(@Valid @RequestBody ProductFavoriteReqVO reqVO) { + ProductFavoriteDO favorite = productFavoriteService.getFavorite(reqVO.getUserId(), reqVO.getSpuId()); + return success(favorite != null); + } + + @GetMapping(value = "/get-count") + @Operation(summary = "获得商品收藏数量") + @Parameter(name = "userId", description = "用户编号", required = true) + @PreAuthenticated + public CommonResult getFavoriteCount(@RequestParam("userId") Long userId) { + return success(productFavoriteService.getFavoriteCount(userId)); + } + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java new file mode 100644 index 0000000000..72b2613d52 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 商品收藏 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class ProductFavoriteBaseVO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5036") + @NotNull(message = "用户编号不能为空") + private Long userId; + + + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java new file mode 100644 index 0000000000..d779ff3a86 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; +import java.util.List; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "管理后台 - 商品收藏的批量 Request VO") +@Data +@ToString(callSuper = true) +public class ProductFavoriteBatchReqVO extends ProductFavoriteBaseVO{ + + @Schema(description = "商品 SPU 编号数组", requiredMode = REQUIRED, example = "29502") + @NotNull(message = "商品 SPU 编号数组不能为空") + private List spuIds; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java new file mode 100644 index 0000000000..37f8cecc38 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 商品收藏分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductFavoritePageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "5036") + private Long userId; + + @Schema(description = "商品 SPU 编号", example = "32734") + private Long spuId; + + @Schema(description = "收藏时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "商品名称", example = "5036") + private String name; + + @Schema(description = "关键字", example = "5036") + private String keyword; +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteReqVO.java new file mode 100644 index 0000000000..3c22226434 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 商品收藏的单个 Response VO") +@Data +@ToString(callSuper = true) +public class ProductFavoriteReqVO extends ProductFavoriteBaseVO { + + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32734") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java new file mode 100644 index 0000000000..255fc631b1 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; + +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +@Schema(description = "管理后台 - 商品收藏 Response VO") +@Data +@ToString(callSuper = true) +public class ProductFavoriteRespVO extends ProductSpuRespVO { + + @Schema(description = "userId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + private Long userId; + + @Schema(description = "spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + private Long spuId; + + @Schema(description = "收藏状态", example = "1") + private Integer favoriteStatus; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java index b15afacb24..22ffb85774 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.product.convert.favorite; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteRespVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -34,4 +37,20 @@ default List convertList(List favorites, L return resultList; } + @Mapping(target = "id", source = "favorite.id") + @Mapping(target = "userId", source = "favorite.userId") + @Mapping(target = "spuId", source = "favorite.spuId") + @Mapping(target = "createTime", source = "favorite.createTime") + @Mapping(target = "favoriteStatus", constant = "1") + ProductFavoriteRespVO convert2admin(ProductSpuDO spu, ProductFavoriteDO favorite); + + default List convertList2admin(List favorites) { + List resultList = new ArrayList<>(favorites.size()); + for (ProductFavoriteDetailDO favorite : favorites) { + resultList.add(convert2admin(favorite.getSpuDO(), favorite)); + } + return resultList; + } + + PageResult convertPage(PageResult page); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java new file mode 100644 index 0000000000..ba4d5b557c --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.product.dal.dataobject.favorite; + +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import lombok.Data; + +/** + * 商品收藏 DO + * + * @author 芋道源码 + */ +@Data +public class ProductFavoriteDetailDO extends ProductFavoriteDO { + + ProductSpuDO spuDO; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java index 54d9d2dd63..08a5c30638 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java @@ -2,9 +2,15 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.annotations.Mapper; @Mapper @@ -21,6 +27,36 @@ default PageResult selectPageByUserAndType(Long userId, AppFa .orderByDesc(ProductFavoriteDO::getId)); } + default PageResult selectPageByUserAndFields(ProductFavoritePageReqVO reqVO) { + MPJLambdaWrapper wrapper = new MPJLambdaWrapper() + .selectAll(ProductFavoriteDO.class) + .eq(ProductFavoriteDO::getUserId, reqVO.getUserId()) + .selectAssociation(ProductSpuDO.class, ProductFavoriteDetailDO::getSpuDO); + if(StringUtils.isNotEmpty(reqVO.getName())){ + wrapper.likeRight(ProductSpuDO::getName, reqVO.getName()); + } + if(StringUtils.isNotEmpty(reqVO.getName()) && StringUtils.isNotEmpty(reqVO.getKeyword())){ + wrapper.or(); + } + if(StringUtils.isNotEmpty(reqVO.getKeyword())){ + wrapper.likeRight(ProductSpuDO::getKeyword, reqVO.getKeyword()); + } + + if(reqVO.getCreateTime() != null){ + if (reqVO.getCreateTime()[0] != null && reqVO.getCreateTime()[1] != null) { + wrapper.between(ProductFavoriteDO::getCreateTime, reqVO.getCreateTime()[0], reqVO.getCreateTime()[1]); + } + if (reqVO.getCreateTime()[0] != null) { + wrapper.ge(ProductFavoriteDO::getCreateTime, reqVO.getCreateTime()[0]); + } + if (reqVO.getCreateTime()[1] != null) { + wrapper.le(ProductFavoriteDO::getCreateTime, reqVO.getCreateTime()[1]); + } + } + + return selectJoinPage(reqVO, ProductFavoriteDetailDO.class, wrapper); + } + default Long selectCountByUserId(Long userId) { return selectCount(ProductFavoriteDO::getUserId, userId); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java index 00aeddb8a3..87c9854a9a 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.product.service.favorite; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; import javax.validation.Valid; @@ -37,6 +39,13 @@ public interface ProductFavoriteService { */ PageResult getFavoritePage(Long userId, @Valid AppFavoritePageReqVO reqVO); + /** + * 分页查询用户收藏列表 + * + * @param reqVO 请求 vo + */ + PageResult getFavoritePageByFilter(@Valid ProductFavoritePageReqVO reqVO); + /** * 获取收藏过商品 * @@ -52,5 +61,4 @@ public interface ProductFavoriteService { * @return 数量 */ Long getFavoriteCount(Long userId); - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java index 983cbf83ca..0f8d30ec02 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.product.service.favorite; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; +import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; import cn.iocoder.yudao.module.product.dal.mysql.favorite.ProductFavoriteMapper; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -33,7 +35,6 @@ public Long createFavorite(Long userId, Long spuId) { if (favorite != null) { throw exception(FAVORITE_EXISTS); } - ProductFavoriteDO entity = ProductFavoriteConvert.INSTANCE.convert(userId, spuId); productFavoriteMapper.insert(entity); return entity.getId(); @@ -54,6 +55,11 @@ public PageResult getFavoritePage(Long userId, @Valid AppFavo return productFavoriteMapper.selectPageByUserAndType(userId, reqVO); } + @Override + public PageResult getFavoritePageByFilter(@Valid ProductFavoritePageReqVO reqVO) { + return productFavoriteMapper.selectPageByUserAndFields(reqVO); + } + @Override public ProductFavoriteDO getFavorite(Long userId, Long spuId) { return productFavoriteMapper.selectByUserIdAndSpuId(userId, spuId); From 989d7c44d0b4c60e64bb49e59132b471f294fc99 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 4 Nov 2023 22:52:41 +0800 Subject: [PATCH 02/11] =?UTF-8?q?code=20review=20=E5=BA=97=E9=93=BA?= =?UTF-8?q?=E8=A3=85=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 +- .../diy/vo/template/DiyTemplateBaseVO.java | 4 +- .../dal/dataobject/diy/DiyPageDO.java | 2 + .../dal/dataobject/diy/DiyTemplateDO.java | 3 + .../service/diy/DiyPageServiceImpl.java | 8 ++- .../service/diy/DiyTemplateServiceImpl.java | 7 ++- yudao-server/pom.xml | 62 +++++++++---------- 7 files changed, 54 insertions(+), 38 deletions(-) diff --git a/pom.xml b/pom.xml index dae40f3dc9..7f7c140bbe 100644 --- a/pom.xml +++ b/pom.xml @@ -15,12 +15,12 @@ yudao-module-system yudao-module-infra - + yudao-module-member - - + yudao-module-pay + yudao-module-mall diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java index 7959b6c264..b79c7231fd 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/diy/vo/template/DiyTemplateBaseVO.java @@ -3,7 +3,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import javax.validation.constraints.NotNull; +import javax.validation.constraints.NotEmpty; import java.util.List; /** @@ -14,7 +14,7 @@ public class DiyTemplateBaseVO { @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题") - @NotNull(message = "模板名称不能为空") + @NotEmpty(message = "模板名称不能为空") private String name; @Schema(description = "备注", example = "默认主题") diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java index e5e3f4208d..7e1044104b 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyPageDO.java @@ -32,6 +32,8 @@ public class DiyPageDO extends BaseDO { private Long id; /** * 装修模板编号 + * + * 关联 {@link DiyTemplateDO#getId()} */ private Long templateId; /** diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java index a50fd4dde8..684a6f9cb8 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/diy/DiyTemplateDO.java @@ -14,6 +14,9 @@ /** * 装修模板 DO * + * 1. 新建一个模版,下面可以包含多个 {@link DiyPageDO} 页面,例如说首页、我的 + * 2. 如果需要使用某个模版,则将 {@link #used} 设置为 true,表示已使用,有且仅有一个 + * * @author owen */ @TableName(value = "promotion_diy_template", autoResultMap = true) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java index d82b9b8ed4..69f96ad8f7 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyPageServiceImpl.java @@ -42,7 +42,6 @@ public Long createDiyPage(DiyPageCreateReqVO createReqVO) { DiyPageDO diyPage = DiyPageConvert.INSTANCE.convert(createReqVO); diyPage.setProperty("{}"); diyPageMapper.insert(diyPage); - // 返回 return diyPage.getId(); } @@ -57,6 +56,13 @@ public void updateDiyPage(DiyPageUpdateReqVO updateReqVO) { diyPageMapper.updateById(updateObj); } + /** + * 校验 Page 页面,在一个 template 模版下的名字是唯一的 + * + * @param id Page 编号 + * @param templateId 模版编号 + * @param name Page 名字 + */ void validateNameUnique(Long id, Long templateId, String name) { if (templateId != null || StrUtil.isBlank(name)) { return; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java index 41025c5d68..530b31b946 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/diy/DiyTemplateServiceImpl.java @@ -32,9 +32,11 @@ public class DiyTemplateServiceImpl implements DiyTemplateService { @Resource private DiyTemplateMapper diyTemplateMapper; + @Resource private DiyPageService diyPageService; + // TODO @疯狂:事务; @Override public Long createDiyTemplate(DiyTemplateCreateReqVO createReqVO) { // 校验名称唯一 @@ -120,9 +122,11 @@ public PageResult getDiyTemplatePage(DiyTemplatePageReqVO pageReq } @Override + // TODO @疯狂:事务; public void useDiyTemplate(Long id) { // 校验存在 validateDiyTemplateExists(id); + // TODO @疯狂:要不已使用的情况,抛个业务异常? // 已使用的更新为未使用 DiyTemplateDO used = diyTemplateMapper.selectByUsed(true); if (used != null) { @@ -136,8 +140,8 @@ public void useDiyTemplate(Long id) { this.updateUsed(id, true, LocalDateTime.now()); } - @Transactional(rollbackFor = Exception.class) @Override + @Transactional(rollbackFor = Exception.class) public void updateDiyTemplateProperty(DiyTemplatePropertyUpdateRequestVO updateReqVO) { // 校验存在 validateDiyTemplateExists(updateReqVO.getId()); @@ -151,6 +155,7 @@ public DiyTemplateDO getUsedDiyTemplate() { return diyTemplateMapper.selectByUsed(true); } + // TODO @疯狂:挪到 useDiyTemplate 下面,改名 updateTemplateUsed 会不会好点哈; /** * 更新模板是否使用 * diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 87a961778f..4463bd7fbd 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -37,11 +37,11 @@ - - - - - + + cn.iocoder.boot + yudao-module-member-biz + ${revision} + @@ -56,11 +56,11 @@ - - - - - + + cn.iocoder.boot + yudao-module-pay-biz + ${revision} + @@ -69,27 +69,27 @@ - - - - - - - - - - - - - - - - - - - - - + + + cn.iocoder.boot + yudao-module-promotion-biz + ${revision} + + + cn.iocoder.boot + yudao-module-product-biz + ${revision} + + + cn.iocoder.boot + yudao-module-trade-biz + ${revision} + + + cn.iocoder.boot + yudao-module-statistics-biz + ${revision} + From 09d45e639348aaf944da43b6628127a0dd05e165 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Mon, 6 Nov 2023 11:33:08 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E8=BD=AC=E8=B4=A6=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=BD=AC=E8=B4=A6=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/mysql/pay_wallet.sql | 10 +++- .../notify/dto/PayTransferNotifyReqDTO.java | 27 +++++++++++ .../module/pay/enums/ErrorCodeConstants.java | 7 ++- .../pay/enums/notify/PayNotifyTypeEnum.java | 1 + .../admin/demo/PayDemoOrderController.java | 4 +- .../admin/demo/PayDemoTransferController.java | 15 +++++- .../{ => order}/PayDemoOrderCreateReqVO.java | 5 +- .../vo/{ => order}/PayDemoOrderRespVO.java | 2 +- .../pay/convert/demo/PayDemoOrderConvert.java | 4 +- .../pay/dal/dataobject/app/PayAppDO.java | 5 ++ .../dataobject/notify/PayNotifyTaskDO.java | 4 ++ .../pay/service/demo/PayDemoOrderService.java | 2 +- .../service/demo/PayDemoOrderServiceImpl.java | 2 +- .../service/demo/PayDemoTransferService.java | 8 ++++ .../demo/PayDemoTransferServiceImpl.java | 46 +++++++++++++++++++ .../service/notify/PayNotifyServiceImpl.java | 13 ++++++ .../transfer/PayTransferServiceImpl.java | 36 +++++++-------- 17 files changed, 160 insertions(+), 31 deletions(-) create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java rename yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/{ => order}/PayDemoOrderCreateReqVO.java (76%) rename yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/{ => order}/PayDemoOrderRespVO.java (96%) diff --git a/sql/mysql/pay_wallet.sql b/sql/mysql/pay_wallet.sql index 291428ffab..9153948bfb 100644 --- a/sql/mysql/pay_wallet.sql +++ b/sql/mysql/pay_wallet.sql @@ -245,4 +245,12 @@ INSERT INTO system_menu( VALUES ( '转账订单', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 0, 'PayTransfer' - ); \ No newline at end of file + ); + +-- 转账通知脚本 + +ALTER TABLE `pay_app` + ADD COLUMN `transfer_notify_url` varchar(1024) NOT NULL COMMENT '转账结果的回调地址' AFTER `refund_notify_url`; +ALTER TABLE `pay_notify_task` + MODIFY COLUMN `merchant_order_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '商户订单编号' AFTER `status`, + ADD COLUMN `merchant_transfer_id` varchar(64) COMMENT '商户转账单编号' AFTER `merchant_order_id`; \ No newline at end of file diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java new file mode 100644 index 0000000000..14ba64463a --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/notify/dto/PayTransferNotifyReqDTO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.pay.api.notify.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 转账单的通知 Request DTO + * + * @author jason + */ +@Data +public class PayTransferNotifyReqDTO { + + /** + * 商户转账单号 + */ + @NotEmpty(message = "商户转账单号不能为空") + private String merchantTransferId; + + /** + * 转账订单编号 + */ + @NotNull(message = "转账订单编号不能为空") + private Long payTransferId; +} diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java index 95835a4b68..8fc38e61cc 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java @@ -65,12 +65,13 @@ public interface ErrorCodeConstants { // ========== 转账模块 1-007-009-000 ========== ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}"); - ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账交易单不存在"); + ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在"); ErrorCode PAY_TRANSFER_STATUS_IS_SUCCESS = new ErrorCode(1_007_009_002, "转账单已成功转账"); ErrorCode PAY_TRANSFER_EXISTS = new ErrorCode(1_007_009_003, "已经存在转账单"); ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经存在,请查询转账订单相关状态"); ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账"); ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中"); + // ========== 示例订单 1-007-900-000 ========== ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1_007_900_000, "示例订单不存在"); ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1_007_900_001, "示例订单更新支付状态失败,订单不是【未支付】状态"); @@ -84,4 +85,8 @@ public interface ErrorCodeConstants { ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1_007_900_009, "发起退款失败,退款单编号不匹配"); ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1_007_900_010, "发起退款失败,退款单金额不匹配"); + // ========== 示例转账订单 1-007-901-001 ========== + ErrorCode DEMO_TRANSFER_NOT_FOUND = new ErrorCode(1_007_901_001, "示例转账单不存在"); + ErrorCode DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR = new ErrorCode(1_007_901_002, "转账失败,转账单编号不匹配"); + ErrorCode DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH = new ErrorCode(1_007_901_003, "转账失败,转账单金额不匹配"); } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java index 8c259d93c1..873e015c6a 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/notify/PayNotifyTypeEnum.java @@ -14,6 +14,7 @@ public enum PayNotifyTypeEnum { ORDER(1, "支付单"), REFUND(2, "退款单"), + TRANSFER(3, "转账单") ; /** diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java index 1e3a61eec5..60c04c290d 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoOrderController.java @@ -6,8 +6,8 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO; -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO; import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert; import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java index f6c7b31c0c..ca01a1edbc 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoTransferController.java @@ -3,6 +3,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayTransferNotifyReqDTO; import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferRespVO; import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert; @@ -14,6 +16,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import javax.validation.Valid; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -33,9 +36,19 @@ public CommonResult createDemoTransfer(@Valid @RequestBody PayDemoTransfer } @GetMapping("/page") - @Operation(summary = "获得示例订单分页") + @Operation(summary = "获得示例转账订单分页") public CommonResult> getDemoTransferPage(@Valid PageParam pageVO) { PageResult pageResult = demoTransferService.getDemoTransferPage(pageVO); return success(PayDemoTransferConvert.INSTANCE.convertPage(pageResult)); } + + @PostMapping("/update-status") + @Operation(summary = "更新示例转账订单的转账状态") // 由 pay-module 转账服务,进行回调 + @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现 + @OperateLog(enable = false) // 禁用操作日志,因为没有操作人 + public CommonResult updateDemoTransferStatus(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) { + demoTransferService.updateDemoTransferStatus(Long.valueOf(notifyReqDTO.getMerchantTransferId()), + notifyReqDTO.getPayTransferId()); + return success(true); + } } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderCreateReqVO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java similarity index 76% rename from yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderCreateReqVO.java rename to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java index 9960ada489..6c82a0ab6d 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderCreateReqVO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderCreateReqVO.java @@ -1,9 +1,8 @@ -package cn.iocoder.yudao.module.pay.controller.admin.demo.vo; +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order; -import lombok.*; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; -import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; @Schema(description = "管理后台 - 示例订单创建 Request VO") diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderRespVO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java similarity index 96% rename from yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderRespVO.java rename to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java index 3404844dc8..cb305631d0 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/PayDemoOrderRespVO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/order/PayDemoOrderRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.pay.controller.admin.demo.vo; +package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java index 313e5d266e..8fca997919 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/demo/PayDemoOrderConvert.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.pay.convert.demo; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO; -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderRespVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderRespVO; import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java index 977eff93a0..8f3490fc74 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/app/PayAppDO.java @@ -54,4 +54,9 @@ public class PayAppDO extends BaseDO { */ private String refundNotifyUrl; + /** + * 转账结果的回调地址 + */ + private String transferNotifyUrl; + } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java index 181a328024..7bfabad3ff 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java @@ -66,6 +66,10 @@ public class PayNotifyTaskDO extends TenantBaseDO { * 商户订单编号 */ private String merchantOrderId; + /** + * 商户转账单编号 + */ + private String merchantTransferId; /** * 通知状态 * diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java index e6822e6264..cf870253f8 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderService.java @@ -2,7 +2,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; import javax.validation.Valid; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java index 7e1090248e..57ff806370 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; -import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO; +import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.order.PayDemoOrderCreateReqVO; import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO; import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoOrderMapper; import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java index 9116dcd9ae..fb01ec43df 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferService.java @@ -28,4 +28,12 @@ public interface PayDemoTransferService { * @param pageVO 分页查询参数 */ PageResult getDemoTransferPage(PageParam pageVO); + + /** + * 更新转账业务示例订单的转账状态 + * + * @param id 编号 + * @param payTransferId 转账单编号 + */ + void updateDemoTransferStatus(Long id, Long payTransferId); } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java index e892e44460..8de98da1ed 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java @@ -1,18 +1,25 @@ package cn.iocoder.yudao.module.pay.service.demo; +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.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert; import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoTransferMapper; +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import javax.validation.Validator; +import java.util.Objects; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.WAITING; /** @@ -33,6 +40,8 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { @Resource private PayDemoTransferMapper demoTransferMapper; @Resource + private PayTransferService payTransferService; + @Resource private Validator validator; @Override @@ -50,4 +59,41 @@ public Long createDemoTransfer(@Valid PayDemoTransferCreateReqVO vo) { public PageResult getDemoTransferPage(PageParam pageVO) { return demoTransferMapper.selectPage(pageVO); } + + @Override + public void updateDemoTransferStatus(Long id, Long payTransferId) { + PayTransferDO payTransfer = validateDemoTransferStatusCanUpdate(id, payTransferId); + // 更新示例订单状态 + if (payTransfer != null) { + demoTransferMapper.updateById(new PayDemoTransferDO().setId(id) + .setPayTransferId(payTransferId) + .setPayChannelCode(payTransfer.getChannelCode()) + .setTransferStatus(payTransfer.getStatus()) + .setTransferTime(payTransfer.getSuccessTime())); + } + } + + private PayTransferDO validateDemoTransferStatusCanUpdate(Long id, Long payTransferId) { + PayDemoTransferDO demoTransfer = demoTransferMapper.selectById(id); + if (demoTransfer == null) { + throw exception(DEMO_TRANSFER_NOT_FOUND); + } + if (PayTransferStatusEnum.isSuccess(demoTransfer.getTransferStatus()) + || PayTransferStatusEnum.isClosed(demoTransfer.getTransferStatus())) { + // 无需更新返回 null + return null; + } + PayTransferDO transfer = payTransferService.getTransfer(payTransferId); + if (transfer == null) { + throw exception(PAY_TRANSFER_NOT_FOUND); + } + if (!Objects.equals(demoTransfer.getPrice(), transfer.getPrice())) { + throw exception(DEMO_TRANSFER_FAIL_PRICE_NOT_MATCH); + } + if (ObjectUtil.notEqual(transfer.getMerchantTransferId(), id.toString())) { + throw exception(DEMO_TRANSFER_FAIL_TRANSFER_ID_ERROR); + } + // TODO 校验账号 + return transfer; + } } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java index f6b17c5653..1d356cf492 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java @@ -13,11 +13,13 @@ import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO; +import cn.iocoder.yudao.module.pay.api.notify.dto.PayTransferNotifyReqDTO; import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper; import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper; import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; @@ -25,6 +27,7 @@ import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; @@ -73,6 +76,9 @@ public class PayNotifyServiceImpl implements PayNotifyService { @Resource @Lazy // 循环依赖,避免报错 private PayRefundService refundService; + @Resource + @Lazy // 循环依赖,避免报错 + private PayTransferService transferService; @Resource private PayNotifyTaskMapper notifyTaskMapper; @@ -100,6 +106,10 @@ public void createPayNotifyTask(Integer type, Long dataId) { PayRefundDO refundDO = refundService.getRefund(task.getDataId()); task.setAppId(refundDO.getAppId()) .setMerchantOrderId(refundDO.getMerchantOrderId()).setNotifyUrl(refundDO.getNotifyUrl()); + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) { + PayTransferDO transfer = transferService.getTransfer(task.getDataId()); + task.setAppId(transfer.getAppId()).setMerchantTransferId(transfer.getMerchantTransferId()) + .setNotifyUrl(transfer.getNotifyUrl()); } // 执行插入 @@ -214,6 +224,9 @@ private CommonResult executeNotifyInvoke(PayNotifyTaskDO task) { } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.REFUND.getType())) { request = PayRefundNotifyReqDTO.builder().merchantOrderId(task.getMerchantOrderId()) .payRefundId(task.getDataId()).build(); + } else if (Objects.equals(task.getType(), PayNotifyTypeEnum.TRANSFER.getType())) { + request = new PayTransferNotifyReqDTO().setMerchantTransferId(task.getMerchantTransferId()) + .setPayTransferId(task.getDataId()); } else { throw new RuntimeException("未知的通知任务类型:" + JsonUtils.toJsonString(task)); } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java index 014a7aae7f..27b9807bdf 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java @@ -12,12 +12,15 @@ import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper; import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; import cn.iocoder.yudao.module.pay.service.app.PayAppService; import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; +import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -51,6 +54,8 @@ public class PayTransferServiceImpl implements PayTransferService { @Resource private PayChannelService channelService; @Resource + private PayNotifyService notifyService; + @Resource private PayNoRedisDAO noRedisDAO; @Resource private Validator validator; @@ -73,7 +78,7 @@ public Long createTransfer(PayTransferCreateReqDTO reqDTO) { // 1.1 校验转账单是否可以提交 validateTransferCanCreate(reqDTO.getAppId(), reqDTO.getMerchantTransferId()); // 1.2 校验 App - appService.validPayApp(reqDTO.getAppId()); + PayAppDO payApp = appService.validPayApp(reqDTO.getAppId()); // 1.3 校验支付渠道是否有效 PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode()); PayClient client = channelService.getPayClient(channel.getId()); @@ -86,7 +91,7 @@ public Long createTransfer(PayTransferCreateReqDTO reqDTO) { PayTransferDO transfer = INSTANCE.convert(reqDTO) .setChannelId(channel.getId()) .setNo(no).setStatus(WAITING.getStatus()) - .setNotifyUrl("http://127.0.0.1:48080/admin-api/pay/todo"); // TODO 需要加个transfer Notify url + .setNotifyUrl(payApp.getTransferNotifyUrl()); transferMapper.insert(transfer); PayTransferRespDTO unifiedTransferResp = null; try { @@ -145,22 +150,13 @@ private void validateTransferCanCreate(Long appId, String merchantTransferId) { } private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { - // 1. 更新 PayTransferDO 转账成功 - Boolean transferred = updateTransferSuccess(channel, notify); - if (transferred) { - return; - } - // 2. TODO 插入转账通知记录 - } - - private Boolean updateTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { // 1.校验 PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); if (transfer == null) { throw exception(PAY_TRANSFER_NOT_FOUND); } if (isSuccess(transfer.getStatus())) { // 如果已成功,直接返回,不用重复更新 - return Boolean.TRUE; + return; } if (!isPendingStatus(transfer.getStatus())) { throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); @@ -176,10 +172,13 @@ private Boolean updateTransferSuccess(PayChannelDO channel, PayTransferRespDTO n throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); } log.info("[updateTransferSuccess][transfer({}) 更新为已转账]", transfer.getId()); - return Boolean.FALSE; + + // 3. 插入转账通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), + transfer.getId()); } - private void updateTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { + private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { // 1.校验 PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); if (transfer == null) { @@ -192,6 +191,7 @@ private void updateTransferClosed(PayChannelDO channel, PayTransferRespDTO notif if (!isPendingStatus(transfer.getStatus())) { throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); } + // 2.更新 int updateCount = transferMapper.updateByIdAndStatus(transfer.getId(), CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()), @@ -203,11 +203,11 @@ private void updateTransferClosed(PayChannelDO channel, PayTransferRespDTO notif throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING); } log.info("[updateTransferClosed][transfer({}) 更新为关闭状态]", transfer.getId()); - } - private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { - // 更新 PayTransferDO 转账关闭 - updateTransferClosed(channel, notify); + // 3. 插入转账通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), + transfer.getId()); + } /** From 15313c2992258c248433b73b6d921189ad775d4f Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Tue, 7 Nov 2023 23:11:07 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E8=BD=AC=E8=B4=A6=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=BD=AC=E8=B4=A6=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/pay/core/client/PayClient.java | 9 + .../dto/transfer/PayTransferRespDTO.java | 17 +- .../core/client/impl/AbstractPayClient.java | 22 ++- .../impl/alipay/AbstractAlipayPayClient.java | 108 ++++++++---- .../core/client/impl/mock/MockPayClient.java | 6 + .../impl/weixin/AbstractWxPayClient.java | 7 + .../transfer/PayTransferStatusRespEnum.java | 4 + .../module/pay/enums/ErrorCodeConstants.java | 6 +- .../enums/transfer/PayTransferStatusEnum.java | 4 + .../convert/transfer/PayTransferConvert.java | 2 +- .../dal/mysql/transfer/PayTransferMapper.java | 6 +- .../framework/pay/core/WalletPayClient.java | 6 + .../pay/job/transfer/PayTransferSyncJob.java | 30 ++++ .../service/transfer/PayTransferService.java | 6 + .../transfer/PayTransferServiceImpl.java | 162 +++++++++++++----- 15 files changed, 313 insertions(+), 82 deletions(-) create mode 100644 yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java index 18ae017d13..86e3566b2b 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; import java.util.Map; @@ -86,4 +87,12 @@ public interface PayClient { */ PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO); + /** + * 获得转账订单信息 + * + * @param outTradeNo 外部订单号 + * @param type 转账类型 + * @return 转账信息 + */ + PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type); } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java index da6f227744..0f9b48240c 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java @@ -53,11 +53,24 @@ public class PayTransferRespDTO { /** * 创建【WAITING】状态的转账返回 */ - public static PayTransferRespDTO waitingOf(String channelOrderNo, + public static PayTransferRespDTO waitingOf(String channelTransferNo, String outTransferNo, Object rawData) { PayTransferRespDTO respDTO = new PayTransferRespDTO(); respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus(); - respDTO.channelTransferNo = channelOrderNo; + respDTO.channelTransferNo = channelTransferNo; + respDTO.outTransferNo = outTransferNo; + respDTO.rawData = rawData; + return respDTO; + } + + /** + * 创建【IN_PROGRESS】状态的转账返回 + */ + public static PayTransferRespDTO dealingOf(String channelTransferNo, + String outTransferNo, Object rawData) { + PayTransferRespDTO respDTO = new PayTransferRespDTO(); + respDTO.status = PayTransferStatusRespEnum.IN_PROGRESS.getStatus(); + respDTO.channelTransferNo = channelTransferNo; respDTO.outTransferNo = outTransferNo; respDTO.rawData = rawData; return respDTO; diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java index f06dab22ee..82d68b58f6 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java @@ -188,11 +188,11 @@ protected abstract PayRefundRespDTO doGetRefund(String outTradeNo, String outRef @Override public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { + validatePayTransferReqDTO(reqDTO); PayTransferRespDTO resp; - try{ - validatePayTransferReqDTO(reqDTO); + try { resp = doUnifiedTransfer(reqDTO); - }catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 throw ex; } catch (Throwable ex) { // 系统异常,则包装成 PayException 异常抛出 @@ -219,9 +219,25 @@ private void validatePayTransferReqDTO(PayTransferUnifiedReqDTO reqDTO) { } } + @Override + public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) { + try { + return doGetTransfer(outTradeNo, type); + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 + throw ex; + } catch (Throwable ex) { + log.error("[getTransfer][客户端({}) outTradeNo({}) type({}) 查询转账单异常]", + getId(), outTradeNo, type, ex); + throw buildPayException(ex); + } + } + protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws Throwable; + protected abstract PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) + throws Throwable; + // ========== 各种工具方法 ========== private PayException buildPayException(Throwable ex) { diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java index fc9d658ac0..4dcf236755 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java @@ -23,14 +23,8 @@ import com.alipay.api.DefaultAlipayClient; import com.alipay.api.domain.*; import com.alipay.api.internal.util.AlipaySignature; -import com.alipay.api.request.AlipayFundTransUniTransferRequest; -import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; -import com.alipay.api.request.AlipayTradeQueryRequest; -import com.alipay.api.request.AlipayTradeRefundRequest; -import com.alipay.api.response.AlipayFundTransUniTransferResponse; -import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; -import com.alipay.api.response.AlipayTradeQueryResponse; -import com.alipay.api.response.AlipayTradeRefundResponse; +import com.alipay.api.request.*; +import com.alipay.api.response.*; import lombok.Getter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -126,7 +120,7 @@ protected PayOrderRespDTO doGetOrder(String outTradeNo) throws Throwable { } // 2.2 解析订单的状态 Integer status = parseStatus(response.getTradeStatus()); - Assert.notNull(status, () -> { + Assert.notNull(status, () -> { throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody())); }); return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()), @@ -228,7 +222,7 @@ protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) th protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException { // 1.1 校验公钥类型 必须使用公钥证书模式 if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) { - throw exception0(ERROR_CONFIGURATION.getCode(),"支付宝单笔转账必须使用公钥证书模式"); + throw exception0(ERROR_CONFIGURATION.getCode(), "支付宝单笔转账必须使用公钥证书模式"); } // 1.2 构建 AlipayFundTransUniTransferModel AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); @@ -238,44 +232,96 @@ protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) model.setOutBizNo(reqDTO.getOutTransferNo()); model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER - model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); + if (reqDTO.getChannelExtras() != null) { + model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); + } + // ② 个性化的参数 + Participant payeeInfo = new Participant(); PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType()); switch (transferType) { // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦? // @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试?? case ALIPAY_BALANCE: { - // ② 个性化的参数 - Participant payeeInfo = new Participant(); payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号 payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名 model.setPayeeInfo(payeeInfo); - // 1.3 构建 AlipayFundTransUniTransferRequest - AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); - request.setBizModel(model); - // 执行请求 - AlipayFundTransUniTransferResponse response = client.certificateExecute(request); - // 处理结果 - if (!response.isSuccess()) { - // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询 - if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { - return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response); - } - return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), - reqDTO.getOutTransferNo(), response); - } - return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()), - response.getOutBizNo(), response); + break; } case BANK_CARD: { - Participant payeeInfo = new Participant(); payeeInfo.setIdentityType("BANKCARD_ACCOUNT"); // TODO 待实现 throw exception(NOT_IMPLEMENTED); } default: { - throw exception0(BAD_REQUEST.getCode(),"不正确的转账类型: {}",transferType); + throw exception0(BAD_REQUEST.getCode(), "不正确的转账类型: {}", transferType); + } + } + // 1.3 构建 AlipayFundTransUniTransferRequest + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); + request.setBizModel(model); + // 执行请求 + AlipayFundTransUniTransferResponse response = client.certificateExecute(request); + // 处理结果 + if (!response.isSuccess()) { + // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询,或相同 outBizNo 重新发起转账 + // 发现 outBizNo 相同 两次请求参数相同. 会返回 "PAYMENT_INFO_INCONSISTENCY", 不知道哪里的问题. 暂时返回 WAIT. 后续job 会轮询 + if (ObjectUtils.equalsAny(response.getSubCode(),"PAYMENT_INFO_INCONSISTENCY", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { + return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response); + } + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + reqDTO.getOutTransferNo(), response); + } else { + if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL" + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + reqDTO.getOutTransferNo(), response); + } + if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中 + return PayTransferRespDTO.dealingOf(response.getOrderId(), reqDTO.getOutTransferNo(), response); + } + return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()), + response.getOutBizNo(), response); + } + + } + + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) throws Throwable { + // 1.1 构建 AlipayFundTransCommonQueryModel + AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel(); + model.setProductCode(type == PayTransferTypeEnum.BANK_CARD ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD"); + model.setBizScene("DIRECT_TRANSFER"); //业务场景 + model.setOutBizNo(outTradeNo); + // 1.2 构建 AlipayFundTransCommonQueryRequest + AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest(); + request.setBizModel(model); + + // 2.1 执行请求 + AlipayFundTransCommonQueryResponse response; + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式 + response = client.certificateExecute(request); + } else { + response = client.execute(request); + } + // 2.2 处理返回结果 + if (response.isSuccess()) { + if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL" + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + outTradeNo, response); + } + if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中 + return PayTransferRespDTO.dealingOf(response.getOrderId(), outTradeNo, response); } + return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getPayDate()), + response.getOutBizNo(), response); + } else { + // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账 + // 当出现 ORDER_NOT_EXIST 可能是转账还在处理中,也可能是转账处理失败. 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账 + if (ObjectUtils.equalsAny(response.getSubCode(), "ORDER_NOT_EXIST", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { + return PayTransferRespDTO.waitingOf(null, outTradeNo, response); + } + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + outTradeNo, response); } } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java index 3098136975..1ad1ad7134 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; import java.time.LocalDateTime; import java.util.Map; @@ -71,4 +72,9 @@ protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throw new UnsupportedOperationException("待实现"); } + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { + throw new UnsupportedOperationException("待实现"); + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java index f4f326a657..bb6feeb044 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -16,6 +16,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; @@ -431,6 +432,12 @@ private PayRefundRespDTO doGetRefundV3(String outTradeNo, String outRefundNo) th protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { throw new UnsupportedOperationException("待实现"); } + + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { + throw new UnsupportedOperationException("待实现"); + } + // ========== 各种工具方法 ========== static String formatDateV2(LocalDateTime time) { diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java index 63b3a96aa9..35ea344da2 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java @@ -38,4 +38,8 @@ public static boolean isSuccess(Integer status) { public static boolean isClosed(Integer status) { return Objects.equals(status, CLOSED.getStatus()); } + + public static boolean isInProgress(Integer status) { + return Objects.equals(status, IN_PROGRESS.getStatus()); + } } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java index 8fc38e61cc..8b7a38ecf6 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java @@ -66,9 +66,9 @@ public interface ErrorCodeConstants { // ========== 转账模块 1-007-009-000 ========== ErrorCode PAY_TRANSFER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1_007_009_000, "发起转账报错,错误码:{},错误提示:{}"); ErrorCode PAY_TRANSFER_NOT_FOUND = new ErrorCode(1_007_009_001, "转账单不存在"); - ErrorCode PAY_TRANSFER_STATUS_IS_SUCCESS = new ErrorCode(1_007_009_002, "转账单已成功转账"); - ErrorCode PAY_TRANSFER_EXISTS = new ErrorCode(1_007_009_003, "已经存在转账单"); - ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经存在,请查询转账订单相关状态"); + ErrorCode PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH = new ErrorCode(1_007_009_002, "两次相同转账请求的类型不匹配"); + ErrorCode PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH = new ErrorCode(1_007_009_003, "两次相同转账请求的金额不匹配"); + ErrorCode PAY_MERCHANT_TRANSFER_EXISTS = new ErrorCode(1_007_009_004, "该笔业务的转账已经发起,请查询转账订单相关状态"); ErrorCode PAY_TRANSFER_STATUS_IS_NOT_WAITING = new ErrorCode(1_007_009_005, "转账单不处于待转账"); ErrorCode PAY_TRANSFER_STATUS_IS_NOT_PENDING = new ErrorCode(1_007_009_006, "转账单不处于待转账或转账中"); diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java index 335a470f82..6f2f27c753 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayTransferStatusEnum.java @@ -40,9 +40,13 @@ public static boolean isSuccess(Integer status) { public static boolean isClosed(Integer status) { return Objects.equals(status, CLOSED.getStatus()); } + public static boolean isWaiting(Integer status) { return Objects.equals(status, WAITING.getStatus()); } + public static boolean isInProgress(Integer status) { + return Objects.equals(status, IN_PROGRESS.getStatus()); + } /** * 是否处于待转账或者转账中的状态 diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java index 4d5849dddd..4e79548d0d 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java @@ -18,7 +18,7 @@ public interface PayTransferConvert { PayTransferDO convert(PayTransferCreateReqDTO dto); - PayTransferUnifiedReqDTO convert2(PayTransferCreateReqDTO dto); + PayTransferUnifiedReqDTO convert2(PayTransferDO dto); PayTransferCreateReqDTO convert(PayTransferCreateReqVO vo); diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java index 0f73845267..af4f6debf7 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.pay.dal.mysql.transfer; 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.pay.controller.admin.transfer.vo.PayTransferPageReqVO; import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; @@ -40,6 +40,10 @@ default PageResult selectPage(PayTransferPageReqVO reqVO) { .betweenIfPresent(PayTransferDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(PayTransferDO::getId)); } + + default List selectListByStatus(Integer status){ + return selectList(PayTransferDO::getStatus, status); + } } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java index c1b72ef9eb..efd3d0ba18 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java @@ -14,6 +14,7 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; @@ -181,4 +182,9 @@ public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { throw new UnsupportedOperationException("待实现"); } + @Override + protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { + throw new UnsupportedOperationException("待实现"); + } + } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java new file mode 100644 index 0000000000..191071e102 --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/job/transfer/PayTransferSyncJob.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.pay.job.transfer; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 转账订单的同步 Job + * + * 由于转账订单的转账结果,有些渠道是异步通知进行同步的,考虑到异步通知可能会失败(小概率),所以需要定时进行同步。 + * + * @author jason + */ +@Component +public class PayTransferSyncJob implements JobHandler { + + @Resource + private PayTransferService transferService; + + @Override + @TenantJob + public String execute(String param) { + int count = transferService.syncTransfer(); + return StrUtil.format("同步转账订单 {} 个", count); + } +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java index 0848dc0ca0..9a58cf06a6 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java @@ -48,4 +48,10 @@ public interface PayTransferService { */ PageResult getTransferPage(PayTransferPageReqVO pageReqVO); + /** + * 同步渠道转账单状态 + * + * @return 同步到状态的转账数量,包括转账成功、转账失败、转账中的 + */ + int syncTransfer(); } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java index 27b9807bdf..73b726dcde 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java @@ -1,14 +1,16 @@ package cn.iocoder.yudao.module.pay.service.transfer; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; @@ -18,6 +20,7 @@ import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper; import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; import cn.iocoder.yudao.module.pay.service.app.PayAppService; import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; @@ -27,7 +30,7 @@ import javax.annotation.Resource; import javax.validation.Validator; -import java.util.Objects; +import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert.INSTANCE; @@ -75,56 +78,60 @@ public PayTransferDO createTransfer(PayTransferCreateReqVO reqVO, String userIp) @Override public Long createTransfer(PayTransferCreateReqDTO reqDTO) { - // 1.1 校验转账单是否可以提交 - validateTransferCanCreate(reqDTO.getAppId(), reqDTO.getMerchantTransferId()); - // 1.2 校验 App + // 1.1 校验 App PayAppDO payApp = appService.validPayApp(reqDTO.getAppId()); - // 1.3 校验支付渠道是否有效 + // 1.2 校验支付渠道是否有效 PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode()); PayClient client = channelService.getPayClient(channel.getId()); if (client == null) { log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); throw exception(CHANNEL_NOT_FOUND); } - // 2.创建转账单 - String no = noRedisDAO.generate(TRANSFER_NO_PREFIX); - PayTransferDO transfer = INSTANCE.convert(reqDTO) - .setChannelId(channel.getId()) - .setNo(no).setStatus(WAITING.getStatus()) - .setNotifyUrl(payApp.getTransferNotifyUrl()); - transferMapper.insert(transfer); - PayTransferRespDTO unifiedTransferResp = null; + // 1.3 校验转账单已经发起过转账。 + PayTransferDO transfer = validateTransferCanCreate(reqDTO); + + if (transfer == null) { + // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账 + String no = noRedisDAO.generate(TRANSFER_NO_PREFIX); + transfer = INSTANCE.convert(reqDTO) + .setChannelId(channel.getId()) + .setNo(no).setStatus(WAITING.getStatus()) + .setNotifyUrl(payApp.getTransferNotifyUrl()); + transferMapper.insert(transfer); + } try { // 3. 调用三方渠道发起转账 - PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(reqDTO) - .setOutTransferNo(no); - unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq); - } catch (ServiceException ex) { - // 业务异常.直接返回转账失败的结果 - log.error("[createTransfer][转账 id({}) requestDTO({}) 发生业务异常]", transfer.getId(), reqDTO, ex); - unifiedTransferResp = PayTransferRespDTO.closedOf("", "", no, ex); + PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer) + .setOutTransferNo(transfer.getNo()); + PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq); + // 4. 通知转账结果 + getSelf().notifyTransfer(channel, unifiedTransferResp); } catch (Throwable e) { // 注意这里仅打印异常,不进行抛出。 - // 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续通过转账回调、或者转账轮询可以拿到。 - // TODO 需要加转账回调业务接口 和 转账轮询未实现 - // 最终,在异常的情况下,支付中心会异步回调业务的转账回调接口,提供转账结果 + // 原因是:虽然调用支付渠道进行转账发生异常(网络请求超时),实际转账成功。这个结果,后续转账轮询可以拿到。 + // 或者使用相同 no 再次发起转账请求 log.error("[createTransfer][转账 id({}) requestDTO({}) 发生异常]", transfer.getId(), reqDTO, e); } - if (Objects.nonNull(unifiedTransferResp)) { - // 4. 通知转账结果 - getSelf().notifyTransfer(channel, unifiedTransferResp); - } - return transfer.getId(); - } - @Override - public PayTransferDO getTransfer(Long id) { - return transferMapper.selectById(id); + return transfer.getId(); } - @Override - public PageResult getTransferPage(PayTransferPageReqVO pageReqVO) { - return transferMapper.selectPage(pageReqVO); + private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto) { + PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(dto.getAppId(), dto.getMerchantTransferId()); + if (transfer != null) { + // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果. + if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) { + throw exception(PAY_MERCHANT_TRANSFER_EXISTS); + } + if (ObjectUtil.notEqual(dto.getPrice(), transfer.getPrice())) { + throw exception(PAY_SAME_MERCHANT_TRANSFER_PRICE_NOT_MATCH); + } + if (ObjectUtil.notEqual(dto.getType(), transfer.getType())) { + throw exception(PAY_SAME_MERCHANT_TRANSFER_TYPE_NOT_MATCH); + } + } + // 如果状态为等待状态。不知道渠道转账是否发起成功。 允许使用相同的 no 再次发起转账,渠道会保证幂等 + return transfer; } @Transactional(rollbackFor = Exception.class) @@ -138,17 +145,40 @@ public void notifyTransfer(PayChannelDO channel, PayTransferRespDTO notify) { if (PayTransferStatusRespEnum.isClosed(notify.getStatus())) { notifyTransferClosed(channel, notify); } + // 转账处理中的回调 + if (PayTransferStatusRespEnum.isInProgress(notify.getStatus())) { + notifyTransferInProgress(channel, notify); + } // WAITING 状态无需处理 - // TODO IN_PROGRESS 待处理 } - private void validateTransferCanCreate(Long appId, String merchantTransferId) { - PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, merchantTransferId); - if (transfer != null) { // 是否存在 - throw exception(PAY_MERCHANT_TRANSFER_EXISTS); + private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) { + // 1.校验 + PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); + if (transfer == null) { + throw exception(PAY_TRANSFER_NOT_FOUND); + } + if (isInProgress(transfer.getStatus())) { // 如果已经是转账中,直接返回,不用重复更新 + return; + } + if (!isWaiting(transfer.getStatus())) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); } + // 2.更新 + int updateCounts = transferMapper.updateByIdAndStatus(transfer.getId(), + CollUtil.newArrayList(WAITING.getStatus()), + new PayTransferDO().setStatus(IN_PROGRESS.getStatus())); + if (updateCounts == 0) { + throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); + } + log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId()); + + // 3. 插入转账通知记录 + notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), + transfer.getId()); } + private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { // 1.校验 PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); @@ -210,6 +240,56 @@ private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notif } + @Override + public PayTransferDO getTransfer(Long id) { + return transferMapper.selectById(id); + } + + @Override + public PageResult getTransferPage(PayTransferPageReqVO pageReqVO) { + return transferMapper.selectPage(pageReqVO); + } + + @Override + public int syncTransfer() { + List list = transferMapper.selectListByStatus(WAITING.getStatus()); + if (CollUtil.isEmpty(list)) { + return 0; + } + int count = 0; + for (PayTransferDO transfer : list) { + count += syncTransfer(transfer) ? 1 : 0; + } + return count; + } + + private boolean syncTransfer(PayTransferDO transfer) { + try { + // 1. 查询转账订单信息 + PayClient payClient = channelService.getPayClient(transfer.getChannelId()); + if (payClient == null) { + log.error("[syncTransfer][渠道编号({}) 找不到对应的支付客户端]", transfer.getChannelId()); + return false; + } + PayTransferRespDTO resp = payClient.getTransfer(transfer.getNo(), + PayTransferTypeEnum.typeOf(transfer.getType())); + + // 2. 回调转账结果 + notifyTransfer(transfer.getChannelId(), resp); + return true; + } catch (Throwable ex) { + log.error("[syncTransfer][transfer({}) 同步转账单状态异常]", transfer.getId(), ex); + return false; + } + } + + private void notifyTransfer(Long channelId, PayTransferRespDTO notify) { + // 校验渠道是否有效 + PayChannelDO channel = channelService.validPayChannel(channelId); + // 通知转账结果给对应的业务 + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyTransfer(channel, notify)); + } + /** * 获得自身的代理对象,解决 AOP 生效问题 * From daa7d14b092342b1bd7062873c9c9b7ec79cc2bc Mon Sep 17 00:00:00 2001 From: niou233 <2922564446@qq.com> Date: Wed, 8 Nov 2023 14:36:44 +0800 Subject: [PATCH 05/11] =?UTF-8?q?reafactor:=20=E4=BC=9A=E5=91=98=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/core/mapper/BaseMapperX.java | 4 +- .../favorite/ProductFavoriteController.java | 41 +++++-------------- .../favorite/ProductFavoriteConvert.java | 11 ++--- .../favorite/ProductFavoriteDetailDO.java | 1 - .../mysql/favorite/ProductFavoriteMapper.java | 33 ++------------- .../favorite/ProductFavoriteService.java | 3 +- .../favorite/ProductFavoriteServiceImpl.java | 5 +-- 7 files changed, 24 insertions(+), 74 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java index 2654bec52f..db054e9724 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java @@ -133,9 +133,9 @@ default void saveOrUpdateBatch(Collection collection) { Db.saveOrUpdateBatch(collection); } - default PageResult selectJoinPage(PageParam pageParam, @Param("resultTypeClass_Eg1sG") Class var2, @Param("ew") MPJBaseJoin queryWrapper) { + default PageResult selectJoinPage(PageParam pageParam, Class resultTypeClass, MPJBaseJoin joinQueryWrapper) { IPage mpPage = MyBatisUtils.buildPage(pageParam); - selectJoinPage(mpPage, var2, queryWrapper); + selectJoinPage(mpPage, resultTypeClass, joinQueryWrapper); // 转换返回 return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java index e59c108276..9157e8a055 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java @@ -4,16 +4,15 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; -import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteBatchReqVO; import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteReqVO; import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteRespVO; import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; -import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.service.favorite.ProductFavoriteService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -24,6 +23,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Tag(name = "管理后台 - 商品收藏") @RestController @@ -34,6 +34,9 @@ public class ProductFavoriteController { @Resource private ProductFavoriteService productFavoriteService; + @Resource + private ProductSpuService productSpuService; + @PostMapping("/create") @Operation(summary = "添加单个商品收藏") @PreAuthorize("@ss.hasPermission('product:favorite:create')") @@ -41,14 +44,6 @@ public CommonResult createFavorite(@Valid @RequestBody ProductFavoriteReqV return success(productFavoriteService.createFavorite(reqVO.getUserId(), reqVO.getSpuId())); } - @PostMapping("/create-list") - @Operation(summary = "添加多个商品收藏") - @PreAuthorize("@ss.hasPermission('product:favorite:create')") - public CommonResult createFavoriteList(@Valid @RequestBody ProductFavoriteBatchReqVO reqVO) { - // todo @jason:待实现;如果有已经收藏的,不用报错,忽略即可; - return success(Boolean.TRUE); - } - @DeleteMapping("/delete") @Operation(summary = "取消单个商品收藏") @PreAuthorize("@ss.hasPermission('product:favorite:delete')") @@ -57,26 +52,19 @@ public CommonResult deleteFavorite(@Valid @RequestBody ProductFavoriteR return success(Boolean.TRUE); } - @DeleteMapping("/delete-list") - @Operation(summary = "取消单个商品收藏") - @PreAuthorize("@ss.hasPermission('product:favorite:delete')") - public CommonResult deleteFavoriteList(@Valid @RequestBody ProductFavoriteBatchReqVO reqVO) { - // todo @jason:待实现 -// productFavoriteService.deleteFavorite(getLoginUserId(), reqVO.getSpuId()); - return success(Boolean.TRUE); - } - @GetMapping("/page") @Operation(summary = "获得商品收藏分页") @PreAuthorize("@ss.hasPermission('product:favorite:query')") public CommonResult> getFavoritePage(@Valid ProductFavoritePageReqVO pageVO) { - PageResult favoritePage = productFavoriteService.getFavoritePageByFilter(pageVO); + PageResult favoritePage = productFavoriteService.getFavoritePage(pageVO); if (CollUtil.isEmpty(favoritePage.getList())) { return success(PageResult.empty()); } + List list = productSpuService.getSpuList(convertSet(favoritePage.getList(), ProductFavoriteDO::getSpuId)); + // 得到商品 spu 信息 - List favorites = ProductFavoriteConvert.INSTANCE.convertList2admin(favoritePage.getList()); + List favorites = ProductFavoriteConvert.INSTANCE.convertList2admin(favoritePage.getList(), list); // 转换 VO 结果 PageResult pageResult = new PageResult<>(favoritePage.getTotal()); @@ -92,13 +80,4 @@ public CommonResult isFavoriteExists(@Valid @RequestBody ProductFavorit ProductFavoriteDO favorite = productFavoriteService.getFavorite(reqVO.getUserId(), reqVO.getSpuId()); return success(favorite != null); } - - @GetMapping(value = "/get-count") - @Operation(summary = "获得商品收藏数量") - @Parameter(name = "userId", description = "用户编号", required = true) - @PreAuthenticated - public CommonResult getFavoriteCount(@RequestParam("userId") Long userId) { - return success(productFavoriteService.getFavoriteCount(userId)); - } - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java index 22ffb85774..9adac8c869 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @@ -41,13 +42,13 @@ default List convertList(List favorites, L @Mapping(target = "userId", source = "favorite.userId") @Mapping(target = "spuId", source = "favorite.spuId") @Mapping(target = "createTime", source = "favorite.createTime") - @Mapping(target = "favoriteStatus", constant = "1") ProductFavoriteRespVO convert2admin(ProductSpuDO spu, ProductFavoriteDO favorite); - default List convertList2admin(List favorites) { - List resultList = new ArrayList<>(favorites.size()); - for (ProductFavoriteDetailDO favorite : favorites) { - resultList.add(convert2admin(favorite.getSpuDO(), favorite)); + default List convertList2admin(List favorites, List spus) { + List resultList = new ArrayList<>(spus.size()); + for (ProductFavoriteDO favorite : favorites) { + Optional spu = spus.stream().filter(e -> e.getId().equals(favorite.getSpuId())).findFirst(); + resultList.add(convert2admin(spu.get(), favorite)); } return resultList; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java index ba4d5b557c..60e401e11d 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java @@ -12,5 +12,4 @@ public class ProductFavoriteDetailDO extends ProductFavoriteDO { ProductSpuDO spuDO; - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java index 08a5c30638..e116a7c4a6 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java @@ -5,12 +5,8 @@ import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; -import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; -import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; -import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.annotations.Mapper; @Mapper @@ -27,34 +23,11 @@ default PageResult selectPageByUserAndType(Long userId, AppFa .orderByDesc(ProductFavoriteDO::getId)); } - default PageResult selectPageByUserAndFields(ProductFavoritePageReqVO reqVO) { - MPJLambdaWrapper wrapper = new MPJLambdaWrapper() + default PageResult selectPageByUserId(ProductFavoritePageReqVO reqVO) { + return selectPage(reqVO, new MPJLambdaWrapper() .selectAll(ProductFavoriteDO.class) .eq(ProductFavoriteDO::getUserId, reqVO.getUserId()) - .selectAssociation(ProductSpuDO.class, ProductFavoriteDetailDO::getSpuDO); - if(StringUtils.isNotEmpty(reqVO.getName())){ - wrapper.likeRight(ProductSpuDO::getName, reqVO.getName()); - } - if(StringUtils.isNotEmpty(reqVO.getName()) && StringUtils.isNotEmpty(reqVO.getKeyword())){ - wrapper.or(); - } - if(StringUtils.isNotEmpty(reqVO.getKeyword())){ - wrapper.likeRight(ProductSpuDO::getKeyword, reqVO.getKeyword()); - } - - if(reqVO.getCreateTime() != null){ - if (reqVO.getCreateTime()[0] != null && reqVO.getCreateTime()[1] != null) { - wrapper.between(ProductFavoriteDO::getCreateTime, reqVO.getCreateTime()[0], reqVO.getCreateTime()[1]); - } - if (reqVO.getCreateTime()[0] != null) { - wrapper.ge(ProductFavoriteDO::getCreateTime, reqVO.getCreateTime()[0]); - } - if (reqVO.getCreateTime()[1] != null) { - wrapper.le(ProductFavoriteDO::getCreateTime, reqVO.getCreateTime()[1]); - } - } - - return selectJoinPage(reqVO, ProductFavoriteDetailDO.class, wrapper); + .orderByDesc(ProductFavoriteDO::getCreateTime)); } default Long selectCountByUserId(Long userId) { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java index 87c9854a9a..295af4c947 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; -import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; import javax.validation.Valid; @@ -44,7 +43,7 @@ public interface ProductFavoriteService { * * @param reqVO 请求 vo */ - PageResult getFavoritePageByFilter(@Valid ProductFavoritePageReqVO reqVO); + PageResult getFavoritePage(@Valid ProductFavoritePageReqVO reqVO); /** * 获取收藏过商品 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java index 0f8d30ec02..945201286a 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; -import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; import cn.iocoder.yudao.module.product.dal.mysql.favorite.ProductFavoriteMapper; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -56,8 +55,8 @@ public PageResult getFavoritePage(Long userId, @Valid AppFavo } @Override - public PageResult getFavoritePageByFilter(@Valid ProductFavoritePageReqVO reqVO) { - return productFavoriteMapper.selectPageByUserAndFields(reqVO); + public PageResult getFavoritePage(@Valid ProductFavoritePageReqVO reqVO) { + return productFavoriteMapper.selectPageByUserId(reqVO); } @Override From 5facac733039e924c293ae892d289bd154187e9d Mon Sep 17 00:00:00 2001 From: niou233 <2922564446@qq.com> Date: Wed, 8 Nov 2023 14:37:18 +0800 Subject: [PATCH 06/11] =?UTF-8?q?refactor:=20=E4=BC=9A=E5=91=98=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../favorite/vo/ProductFavoriteBaseVO.java | 2 -- .../vo/ProductFavoriteBatchReqVO.java | 21 ------------------- .../favorite/vo/ProductFavoritePageReqVO.java | 18 ---------------- .../favorite/vo/ProductFavoriteRespVO.java | 4 ---- 4 files changed, 45 deletions(-) delete mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java index 72b2613d52..68b0a0a16d 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBaseVO.java @@ -16,6 +16,4 @@ public class ProductFavoriteBaseVO { @NotNull(message = "用户编号不能为空") private Long userId; - - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java deleted file mode 100644 index d779ff3a86..0000000000 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteBatchReqVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.product.controller.admin.favorite.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.ToString; - -import javax.validation.constraints.NotNull; -import java.util.List; - -import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; - -@Schema(description = "管理后台 - 商品收藏的批量 Request VO") -@Data -@ToString(callSuper = true) -public class ProductFavoriteBatchReqVO extends ProductFavoriteBaseVO{ - - @Schema(description = "商品 SPU 编号数组", requiredMode = REQUIRED, example = "29502") - @NotNull(message = "商品 SPU 编号数组不能为空") - private List spuIds; - -} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java index 37f8cecc38..9c0b330353 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java @@ -5,11 +5,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @Schema(description = "管理后台 - 商品收藏分页 Request VO") @Data @@ -19,17 +14,4 @@ public class ProductFavoritePageReqVO extends PageParam { @Schema(description = "用户编号", example = "5036") private Long userId; - - @Schema(description = "商品 SPU 编号", example = "32734") - private Long spuId; - - @Schema(description = "收藏时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - - @Schema(description = "商品名称", example = "5036") - private String name; - - @Schema(description = "关键字", example = "5036") - private String keyword; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java index 255fc631b1..bbf972181b 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java @@ -15,8 +15,4 @@ public class ProductFavoriteRespVO extends ProductSpuRespVO { @Schema(description = "spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") private Long spuId; - - @Schema(description = "收藏状态", example = "1") - private Integer favoriteStatus; - } From 670c0962a76fbf8e393d347c78ae66b2c4af1ee0 Mon Sep 17 00:00:00 2001 From: niou233 <2922564446@qq.com> Date: Wed, 8 Nov 2023 17:03:37 +0800 Subject: [PATCH 07/11] =?UTF-8?q?refactor:=20=E4=BC=9A=E5=91=98=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../favorite/ProductFavoriteController.java | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java index 9157e8a055..6f66c20623 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java @@ -3,9 +3,7 @@ import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoritePageReqVO; -import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteReqVO; import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteRespVO; import cn.iocoder.yudao.module.product.convert.favorite.ProductFavoriteConvert; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; @@ -16,7 +14,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; @@ -37,21 +37,6 @@ public class ProductFavoriteController { @Resource private ProductSpuService productSpuService; - @PostMapping("/create") - @Operation(summary = "添加单个商品收藏") - @PreAuthorize("@ss.hasPermission('product:favorite:create')") - public CommonResult createFavorite(@Valid @RequestBody ProductFavoriteReqVO reqVO) { - return success(productFavoriteService.createFavorite(reqVO.getUserId(), reqVO.getSpuId())); - } - - @DeleteMapping("/delete") - @Operation(summary = "取消单个商品收藏") - @PreAuthorize("@ss.hasPermission('product:favorite:delete')") - public CommonResult deleteFavorite(@Valid @RequestBody ProductFavoriteReqVO reqVO) { - productFavoriteService.deleteFavorite(reqVO.getUserId(), reqVO.getSpuId()); - return success(Boolean.TRUE); - } - @GetMapping("/page") @Operation(summary = "获得商品收藏分页") @PreAuthorize("@ss.hasPermission('product:favorite:query')") @@ -72,12 +57,4 @@ public CommonResult> getFavoritePage(@Valid Pr return success(pageResult); } - - @PostMapping(value = "/exits") - @Operation(summary = "检查是否收藏过商品") - @PreAuthenticated - public CommonResult isFavoriteExists(@Valid @RequestBody ProductFavoriteReqVO reqVO) { - ProductFavoriteDO favorite = productFavoriteService.getFavorite(reqVO.getUserId(), reqVO.getSpuId()); - return success(favorite != null); - } } From 92be763c6f35a1735d45e8fae8cce870c8808c10 Mon Sep 17 00:00:00 2001 From: niou233 <2922564446@qq.com> Date: Wed, 8 Nov 2023 17:18:28 +0800 Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20=E4=BC=9A=E5=91=98=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/product/service/favorite/ProductFavoriteService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java index 295af4c947..3dd3bd59e8 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteService.java @@ -60,4 +60,5 @@ public interface ProductFavoriteService { * @return 数量 */ Long getFavoriteCount(Long userId); + } From 5a5a42463bbfad1f95a32a6c8ee1c13094f633c3 Mon Sep 17 00:00:00 2001 From: niou233 <2922564446@qq.com> Date: Wed, 8 Nov 2023 17:22:00 +0800 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20=E4=BC=9A=E5=91=98=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/service/favorite/ProductFavoriteServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java index 945201286a..927d030d58 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/favorite/ProductFavoriteServiceImpl.java @@ -34,6 +34,7 @@ public Long createFavorite(Long userId, Long spuId) { if (favorite != null) { throw exception(FAVORITE_EXISTS); } + ProductFavoriteDO entity = ProductFavoriteConvert.INSTANCE.convert(userId, spuId); productFavoriteMapper.insert(entity); return entity.getId(); From 330380c2d0dd58af81af921e6b781d95395721c4 Mon Sep 17 00:00:00 2001 From: owen Date: Fri, 17 Nov 2023 09:56:52 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E8=90=A5=E9=94=80=EF=BC=9A=E9=80=82?= =?UTF-8?q?=E9=85=8D=E5=95=86=E5=9F=8E=E8=A3=85=E4=BF=AE=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E3=80=90=E5=95=86=E5=93=81=E5=8D=A1=E7=89=87=E3=80=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/spu/vo/ProductSpuDetailRespVO.java | 14 +------------ .../admin/spu/vo/ProductSpuRespVO.java | 2 +- .../app/spu/AppProductSpuController.java | 20 +++++++++++++++++++ .../app/spu/vo/AppProductSpuPageRespVO.java | 3 +++ 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java index 1be96632d1..336d44467a 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java @@ -12,19 +12,7 @@ @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class ProductSpuDetailRespVO extends ProductSpuBaseVO { - - @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1212") - private Long id; - - @Schema(description = "商品销量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000") - private Integer salesCount; - - @Schema(description = "浏览量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20000") - private Integer browseCount; - - @Schema(description = "商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer status; +public class ProductSpuDetailRespVO extends ProductSpuRespVO { // ========== SKU 相关字段 ========= diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java index 0148cb2a1b..faf8a55721 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java @@ -13,7 +13,7 @@ @ToString(callSuper = true) public class ProductSpuRespVO extends ProductSpuBaseVO { - @Schema(description = "spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") private Long id; @Schema(description = "商品价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "1999") 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 8f49e7f747..9d0a1fe9f8 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 @@ -30,6 +30,7 @@ import javax.validation.Valid; import java.util.Collections; import java.util.List; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -75,6 +76,25 @@ public CommonResult> getSpuList( return success(voList); } + @GetMapping("/list-by-ids") + @Operation(summary = "获得商品 SPU 列表") + @Parameters({ + @Parameter(name = "ids", description = "编号列表", required = true) + }) + public CommonResult> getSpuList(@RequestParam("ids") Set ids) { + List list = productSpuService.getSpuList(ids); + if (CollUtil.isEmpty(list)) { + return success(Collections.emptyList()); + } + + // 拼接返回 + List voList = ProductSpuConvert.INSTANCE.convertListForGetSpuList(list); + // 处理 vip 价格 + MemberLevelRespDTO memberLevel = getMemberLevel(); + voList.forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel))); + return success(voList); + } + @GetMapping("/page") @Operation(summary = "获得商品 SPU 分页") public CommonResult> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageRespVO.java index c4a66afd2a..07b0d8e952 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageRespVO.java @@ -15,6 +15,9 @@ public class AppProductSpuPageRespVO { @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; + @Schema(description = "商品简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉小短袖简介") + private String introduction; + @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED) private Long categoryId; From c7a21b2a6447a547c6470a26180cbee6a2bb39bf Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 19 Nov 2023 00:58:12 +0800 Subject: [PATCH 11/11] =?UTF-8?q?mall=EF=BC=9A=E4=BC=98=E5=8C=96=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=94=B6=E8=97=8F=E7=9A=84=E5=88=86=E9=A1=B5=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/core/mapper/BaseMapperX.java | 1 + .../favorite/ProductFavoriteController.java | 19 +++++---------- .../favorite/vo/ProductFavoritePageReqVO.java | 1 + .../favorite/vo/ProductFavoriteRespVO.java | 1 + .../favorite/ProductFavoriteConvert.java | 23 ++++++++----------- .../favorite/ProductFavoriteDetailDO.java | 15 ------------ .../mysql/favorite/ProductFavoriteMapper.java | 9 ++++---- 7 files changed, 23 insertions(+), 46 deletions(-) delete mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java index db054e9724..57e7133fbd 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java @@ -139,4 +139,5 @@ default PageResult selectJoinPage(PageParam pageParam, Class res // 转换返回 return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); } + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java index 6f66c20623..721cf19c09 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/ProductFavoriteController.java @@ -41,20 +41,13 @@ public class ProductFavoriteController { @Operation(summary = "获得商品收藏分页") @PreAuthorize("@ss.hasPermission('product:favorite:query')") public CommonResult> getFavoritePage(@Valid ProductFavoritePageReqVO pageVO) { - PageResult favoritePage = productFavoriteService.getFavoritePage(pageVO); - if (CollUtil.isEmpty(favoritePage.getList())) { + PageResult pageResult = productFavoriteService.getFavoritePage(pageVO); + if (CollUtil.isEmpty(pageResult.getList())) { return success(PageResult.empty()); } - - List list = productSpuService.getSpuList(convertSet(favoritePage.getList(), ProductFavoriteDO::getSpuId)); - - // 得到商品 spu 信息 - List favorites = ProductFavoriteConvert.INSTANCE.convertList2admin(favoritePage.getList(), list); - - // 转换 VO 结果 - PageResult pageResult = new PageResult<>(favoritePage.getTotal()); - pageResult.setList(favorites); - - return success(pageResult); + // 拼接数据 + List spuList = productSpuService.getSpuList(convertSet(pageResult.getList(), ProductFavoriteDO::getSpuId)); + return success(ProductFavoriteConvert.INSTANCE.convertPage(pageResult, spuList)); } + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java index 9c0b330353..3d78883ec9 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoritePageReqVO.java @@ -14,4 +14,5 @@ public class ProductFavoritePageReqVO extends PageParam { @Schema(description = "用户编号", example = "5036") private Long userId; + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java index bbf972181b..3c09aa8fc6 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/favorite/vo/ProductFavoriteRespVO.java @@ -15,4 +15,5 @@ public class ProductFavoriteRespVO extends ProductSpuRespVO { @Schema(description = "spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "111") private Long spuId; + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java index 9adac8c869..7b419b6a85 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/favorite/ProductFavoriteConvert.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.product.convert.favorite; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.product.controller.admin.favorite.vo.ProductFavoriteRespVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; -import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDetailDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -13,7 +13,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @@ -38,20 +37,18 @@ default List convertList(List favorites, L return resultList; } + default PageResult convertPage(PageResult pageResult, List spuList) { + Map spuMap = convertMap(spuList, ProductSpuDO::getId); + List voList = CollectionUtils.convertList(pageResult.getList(), favorite -> { + ProductSpuDO spu = spuMap.get(favorite.getSpuId()); + return convert02(spu, favorite); + }); + return new PageResult<>(voList, pageResult.getTotal()); + } @Mapping(target = "id", source = "favorite.id") @Mapping(target = "userId", source = "favorite.userId") @Mapping(target = "spuId", source = "favorite.spuId") @Mapping(target = "createTime", source = "favorite.createTime") - ProductFavoriteRespVO convert2admin(ProductSpuDO spu, ProductFavoriteDO favorite); - - default List convertList2admin(List favorites, List spus) { - List resultList = new ArrayList<>(spus.size()); - for (ProductFavoriteDO favorite : favorites) { - Optional spu = spus.stream().filter(e -> e.getId().equals(favorite.getSpuId())).findFirst(); - resultList.add(convert2admin(spu.get(), favorite)); - } - return resultList; - } + ProductFavoriteRespVO convert02(ProductSpuDO spu, ProductFavoriteDO favorite); - PageResult convertPage(PageResult page); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java deleted file mode 100644 index 60e401e11d..0000000000 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/favorite/ProductFavoriteDetailDO.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.iocoder.yudao.module.product.dal.dataobject.favorite; - -import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; -import lombok.Data; - -/** - * 商品收藏 DO - * - * @author 芋道源码 - */ -@Data -public class ProductFavoriteDetailDO extends ProductFavoriteDO { - - ProductSpuDO spuDO; -} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java index e116a7c4a6..a681d42a72 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/favorite/ProductFavoriteMapper.java @@ -2,11 +2,11 @@ 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.controller.admin.favorite.vo.ProductFavoritePageReqVO; import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.favorite.ProductFavoriteDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.github.yulichang.wrapper.MPJLambdaWrapper; import org.apache.ibatis.annotations.Mapper; @Mapper @@ -24,10 +24,9 @@ default PageResult selectPageByUserAndType(Long userId, AppFa } default PageResult selectPageByUserId(ProductFavoritePageReqVO reqVO) { - return selectPage(reqVO, new MPJLambdaWrapper() - .selectAll(ProductFavoriteDO.class) - .eq(ProductFavoriteDO::getUserId, reqVO.getUserId()) - .orderByDesc(ProductFavoriteDO::getCreateTime)); + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ProductFavoriteDO::getUserId, reqVO.getUserId()) + .orderByDesc(ProductFavoriteDO::getId)); } default Long selectCountByUserId(Long userId) {