Commit cddeb37289ec192fc7d912e697ddaf06b448522e
Merge remote-tracking branch 'origin/feature/mall_product' into brokerate
# Conflicts: # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
Showing
84 changed files
with
1006 additions
and
580 deletions
sql/mysql/pay_wallet.sql
| ... | ... | @@ -8,8 +8,8 @@ CREATE TABLE `pay_wallet` |
| 8 | 8 | `user_id` bigint NOT NULL COMMENT '用户编号', |
| 9 | 9 | `user_type` tinyint NOT NULL DEFAULT 0 COMMENT '用户类型', |
| 10 | 10 | `balance` int NOT NULL DEFAULT 0 COMMENT '余额,单位分', |
| 11 | - `total_expense` bigint NOT NULL DEFAULT 0 COMMENT '累计支出,单位分', | |
| 12 | - `total_recharge` bigint NOT NULL DEFAULT 0 COMMENT '累计充值,单位分', | |
| 11 | + `total_expense` int NOT NULL DEFAULT 0 COMMENT '累计支出,单位分', | |
| 12 | + `total_recharge` int NOT NULL DEFAULT 0 COMMENT '累计充值,单位分', | |
| 13 | 13 | `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', |
| 14 | 14 | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', |
| 15 | 15 | `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/CommonResult.java
| ... | ... | @@ -41,7 +41,7 @@ public class CommonResult<T> implements Serializable { |
| 41 | 41 | * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 |
| 42 | 42 | * |
| 43 | 43 | * @param result 传入的 result 对象 |
| 44 | - * @param <T> 返回的泛型 | |
| 44 | + * @param <T> 返回的泛型 | |
| 45 | 45 | * @return 新的 CommonResult 对象 |
| 46 | 46 | */ |
| 47 | 47 | public static <T> CommonResult<T> error(CommonResult<?> result) { | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.bargain; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 砍价活动 Api 接口 | |
| 5 | + * | |
| 6 | + * @author HUIHUI | |
| 7 | + */ | |
| 8 | +public interface BargainActivityApi { | |
| 9 | + | |
| 10 | + /** | |
| 11 | + * 更新砍价活动库存 | |
| 12 | + * | |
| 13 | + * @param activityId 砍价活动编号 | |
| 14 | + * @param count 购买数量 | |
| 15 | + */ | |
| 16 | + void updateBargainActivityStock(Long activityId, Integer count); | |
| 17 | + | |
| 18 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/dto/BargainRecordCreateReqDTO.java
| ... | ... | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.api.bargain.dto; |
| 2 | 2 | |
| 3 | 3 | import lombok.Data; |
| 4 | 4 | |
| 5 | -import javax.validation.constraints.NotEmpty; | |
| 6 | 5 | import javax.validation.constraints.NotNull; |
| 7 | 6 | |
| 8 | 7 | // TODO @芋艿:这块要在看看 |
| ... | ... | @@ -40,17 +39,7 @@ public class BargainRecordCreateReqDTO { |
| 40 | 39 | */ |
| 41 | 40 | @NotNull(message = "订单编号不能为空") |
| 42 | 41 | private Long orderId; |
| 43 | - // TODO @puhui999:spuName、picUrl、 之类字段不用传递; | |
| 44 | - /** | |
| 45 | - * 商品名字 | |
| 46 | - */ | |
| 47 | - @NotEmpty(message = "商品名字不能为空") | |
| 48 | - private String spuName; | |
| 49 | - /** | |
| 50 | - * 商品图片 | |
| 51 | - */ | |
| 52 | - @NotEmpty(message = "商品图片不能为空") | |
| 53 | - private String picUrl; | |
| 42 | + | |
| 54 | 43 | /** |
| 55 | 44 | * 砍价商品单价 |
| 56 | 45 | */ |
| ... | ... | @@ -61,17 +50,7 @@ public class BargainRecordCreateReqDTO { |
| 61 | 50 | */ |
| 62 | 51 | @NotNull(message = "商品原价不能为空") |
| 63 | 52 | private Integer price; |
| 64 | - // TODO @puhui999:nickname、avatar 不用传递,去查询; | |
| 65 | - /** | |
| 66 | - * 用户昵称 | |
| 67 | - */ | |
| 68 | - @NotEmpty(message = "用户昵称不能为空") | |
| 69 | - private String nickname; | |
| 70 | - /** | |
| 71 | - * 用户头像 | |
| 72 | - */ | |
| 73 | - @NotEmpty(message = "用户头像不能为空") | |
| 74 | - private String avatar; | |
| 53 | + | |
| 75 | 54 | /** |
| 76 | 55 | * 开团状态:进行中 砍价成功 砍价失败 |
| 77 | 56 | */ | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
| ... | ... | @@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.promotion.api.combination; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; |
| 4 | 4 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; |
| 5 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | |
| 6 | 5 | |
| 7 | 6 | import javax.validation.Valid; |
| 7 | +import java.time.LocalDateTime; | |
| 8 | 8 | import java.util.List; |
| 9 | 9 | |
| 10 | 10 | // TODO @芋艿:后面也再撸撸这几个接口 |
| ... | ... | @@ -51,13 +51,29 @@ public interface CombinationRecordApi { |
| 51 | 51 | */ |
| 52 | 52 | void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount); |
| 53 | 53 | |
| 54 | - // TODO @puhui999:是不是搞成具体的方法,拼团成功,拼团失败,这种方法; | |
| 54 | + /** | |
| 55 | + * 更新拼团状态为成功 | |
| 56 | + * | |
| 57 | + * @param userId 用户编号 | |
| 58 | + * @param orderId 订单编号 | |
| 59 | + */ | |
| 60 | + void updateRecordStatusToSuccess(Long userId, Long orderId); | |
| 55 | 61 | |
| 56 | 62 | /** |
| 57 | - * 更新开团记录状态 | |
| 63 | + * 更新拼团状态为失败 | |
| 58 | 64 | * |
| 59 | - * @param reqDTO 请求 DTO | |
| 65 | + * @param userId 用户编号 | |
| 66 | + * @param orderId 订单编号 | |
| 67 | + */ | |
| 68 | + void updateRecordStatusToFailed(Long userId, Long orderId); | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * 更新拼团状态为 进行中 | |
| 72 | + * | |
| 73 | + * @param userId 用户编号 | |
| 74 | + * @param orderId 订单编号 | |
| 75 | + * @param startTime 开始时间 | |
| 60 | 76 | */ |
| 61 | - void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO); | |
| 77 | + void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime); | |
| 62 | 78 | |
| 63 | 79 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordUpdateStatusReqDTO.java deleted
| 1 | -package cn.iocoder.yudao.module.promotion.api.combination.dto; | |
| 2 | - | |
| 3 | -import lombok.Data; | |
| 4 | - | |
| 5 | -import javax.validation.constraints.NotNull; | |
| 6 | -import java.time.LocalDateTime; | |
| 7 | - | |
| 8 | -/** | |
| 9 | - * 拼团记录的更新状态 Request DTO | |
| 10 | - * | |
| 11 | - * @author HUIHUI | |
| 12 | - */ | |
| 13 | -@Data | |
| 14 | -public class CombinationRecordUpdateStatusReqDTO { | |
| 15 | - | |
| 16 | - /** | |
| 17 | - * 用户编号 | |
| 18 | - */ | |
| 19 | - @NotNull(message = "用户编号不能为空") | |
| 20 | - private Long userId; | |
| 21 | - | |
| 22 | - /** | |
| 23 | - * 订单编号 | |
| 24 | - */ | |
| 25 | - @NotNull(message = "订单编号不能为空") | |
| 26 | - private Long orderId; | |
| 27 | - | |
| 28 | - /** | |
| 29 | - * 开团状态:正在开团 拼团成功 拼团失败 | |
| 30 | - */ | |
| 31 | - @NotNull(message = "开团状态不能为空") | |
| 32 | - private Integer status; | |
| 33 | - | |
| 34 | - /** | |
| 35 | - * 团开始时间 | |
| 36 | - */ | |
| 37 | - private LocalDateTime startTime; | |
| 38 | - | |
| 39 | -} |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.seckill; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 秒杀活动 API 接口 | |
| 7 | + * | |
| 8 | + * @author HUIHUI | |
| 9 | + */ | |
| 10 | +public interface SeckillActivityApi { | |
| 11 | + | |
| 12 | + /** | |
| 13 | + * 更新秒杀库存 | |
| 14 | + * | |
| 15 | + * @param updateStockReqDTO 请求 | |
| 16 | + */ | |
| 17 | + void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO); | |
| 18 | + | |
| 19 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/dto/SeckillActivityUpdateStockReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.seckill.dto; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +import java.util.List; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 更新秒杀库存 request DTO | |
| 9 | + * | |
| 10 | + * @author HUIHUI | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +public class SeckillActivityUpdateStockReqDTO { | |
| 14 | + | |
| 15 | + // TODO @puhui999:参数校验 | |
| 16 | + | |
| 17 | + // TODO @puhui999:秒杀的话,一次只能购买一种商品哈;不能多个哈; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 活动编号 | |
| 21 | + */ | |
| 22 | + private Long activityId; | |
| 23 | + /** | |
| 24 | + * 总购买数量 | |
| 25 | + */ | |
| 26 | + private Integer count; | |
| 27 | + /** | |
| 28 | + * 活动商品 | |
| 29 | + */ | |
| 30 | + private List<Item> items; | |
| 31 | + | |
| 32 | + @Data | |
| 33 | + public static class Item { | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * SPU 编号 | |
| 37 | + */ | |
| 38 | + private Long spuId; | |
| 39 | + /** | |
| 40 | + * SKU 编号 | |
| 41 | + */ | |
| 42 | + private Long skuId; | |
| 43 | + /** | |
| 44 | + * 购买数量 | |
| 45 | + */ | |
| 46 | + private Integer count; | |
| 47 | + | |
| 48 | + } | |
| 49 | + | |
| 50 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
| ... | ... | @@ -51,10 +51,11 @@ public interface ErrorCodeConstants { |
| 51 | 51 | |
| 52 | 52 | // ========== 秒杀活动 1013008000 ========== |
| 53 | 53 | ErrorCode SECKILL_ACTIVITY_NOT_EXISTS = new ErrorCode(1013008000, "秒杀活动不存在"); |
| 54 | - ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动"); | |
| 54 | + ErrorCode SECKILL_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013008002, "存在商品参加了其它秒杀活动,秒杀时段冲突"); | |
| 55 | 55 | ErrorCode SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1013008003, "秒杀活动已关闭,不能修改"); |
| 56 | 56 | ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除"); |
| 57 | 57 | ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); |
| 58 | + ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "更新秒杀活动库存失败,原因秒杀库存不足"); | |
| 58 | 59 | |
| 59 | 60 | // ========== 秒杀时段 1013009000 ========== |
| 60 | 61 | ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在"); | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/bargain/BargainActivityApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.bargain; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO; | |
| 4 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; | |
| 5 | +import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; | |
| 6 | +import org.springframework.stereotype.Service; | |
| 7 | + | |
| 8 | +import javax.annotation.Resource; | |
| 9 | + | |
| 10 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 11 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.BARGAIN_ACTIVITY_NOT_EXISTS; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 砍价活动 Api 接口实现类 | |
| 15 | + * | |
| 16 | + * @author HUIHUI | |
| 17 | + */ | |
| 18 | +@Service | |
| 19 | +public class BargainActivityApiImpl implements BargainActivityApi { | |
| 20 | + | |
| 21 | + @Resource | |
| 22 | + private BargainActivityService bargainActivityService; | |
| 23 | + | |
| 24 | + @Override | |
| 25 | + public void updateBargainActivityStock(Long activityId, Integer count) { | |
| 26 | + // TODO @puhui999:可以整个实现到 bargainActivityService 中 | |
| 27 | + // 查询砍价活动 | |
| 28 | + BargainActivityDO activity = bargainActivityService.getBargainActivity(activityId); | |
| 29 | + if (activity == null) { | |
| 30 | + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS); | |
| 31 | + } | |
| 32 | + | |
| 33 | + // 更新砍价库存 | |
| 34 | + // TODO @puhui999:考虑下并发更新问题 | |
| 35 | + BargainActivityUpdateReqVO reqVO = new BargainActivityUpdateReqVO(); | |
| 36 | + reqVO.setId(activityId); | |
| 37 | + reqVO.setStock(activity.getStock() - count); | |
| 38 | + bargainActivityService.updateBargainActivity(reqVO); | |
| 39 | + } | |
| 40 | + | |
| 41 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
| ... | ... | @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.promotion.api.combination; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; |
| 4 | 4 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; |
| 5 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | |
| 6 | 5 | import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; |
| 7 | 6 | import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; |
| 8 | 7 | import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; |
| 9 | 8 | import org.springframework.stereotype.Service; |
| 10 | 9 | |
| 11 | 10 | import javax.annotation.Resource; |
| 11 | +import java.time.LocalDateTime; | |
| 12 | 12 | import java.util.List; |
| 13 | 13 | |
| 14 | 14 | /** |
| ... | ... | @@ -43,12 +43,19 @@ public class CombinationRecordApiImpl implements CombinationRecordApi { |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | @Override |
| 46 | - public void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO) { | |
| 47 | - if (null == reqDTO.getStartTime()) { | |
| 48 | - recordService.updateCombinationRecordStatusByUserIdAndOrderId(reqDTO); | |
| 49 | - } else { | |
| 50 | - recordService.updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(reqDTO); | |
| 51 | - } | |
| 46 | + public void updateRecordStatusToSuccess(Long userId, Long orderId) { | |
| 47 | + recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId); | |
| 48 | + } | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + public void updateRecordStatusToFailed(Long userId, Long orderId) { | |
| 52 | + recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId); | |
| 53 | + } | |
| 54 | + | |
| 55 | + @Override | |
| 56 | + public void updateRecordStatusToInProgress(Long userId, Long orderId, LocalDateTime startTime) { | |
| 57 | + recordService.updateRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordStatusEnum.IN_PROGRESS.getStatus(), | |
| 58 | + userId, orderId, startTime); | |
| 52 | 59 | } |
| 53 | 60 | |
| 54 | 61 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/seckill/SeckillActivityApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.promotion.api.seckill; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 4 | +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO; | |
| 5 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; | |
| 6 | +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; | |
| 7 | +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; | |
| 8 | +import org.springframework.stereotype.Service; | |
| 9 | + | |
| 10 | +import javax.annotation.Resource; | |
| 11 | +import java.util.ArrayList; | |
| 12 | +import java.util.HashMap; | |
| 13 | +import java.util.List; | |
| 14 | +import java.util.Map; | |
| 15 | + | |
| 16 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 17 | +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_UPDATE_STOCK_FAIL; | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * 秒杀活动接口 Api 接口实现类 | |
| 21 | + * | |
| 22 | + * @author HUIHUI | |
| 23 | + */ | |
| 24 | +@Service | |
| 25 | +public class SeckillActivityApiImpl implements SeckillActivityApi { | |
| 26 | + | |
| 27 | + @Resource | |
| 28 | + private SeckillActivityService activityService; | |
| 29 | + | |
| 30 | + // TODO @puhui:建议这块弄到 activityService 实现哈; | |
| 31 | + // TODO @puhui:这个方法,要考虑事务性 | |
| 32 | + @Override | |
| 33 | + public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { | |
| 34 | + // TODO @puhui999:长方法,最好有 1.1 1.2 2.1 这种步骤哈; | |
| 35 | + SeckillActivityDO seckillActivity = activityService.getSeckillActivity(updateStockReqDTO.getActivityId()); | |
| 36 | + if (seckillActivity.getStock() < updateStockReqDTO.getCount()) { | |
| 37 | + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); | |
| 38 | + } | |
| 39 | + // 获取活动商品 | |
| 40 | + // TODO @puhui999:在一个方法里,dos 和 dolist 最好保持一致,要么用 s,要么用 list 哈; | |
| 41 | + List<SeckillProductDO> productDOs = activityService.getSeckillProductListByActivityId(updateStockReqDTO.getActivityId()); | |
| 42 | + // TODO @puhui999:这个是不是搞成 CollectionUtils.convertMultiMap() | |
| 43 | + List<SeckillActivityUpdateStockReqDTO.Item> items = updateStockReqDTO.getItems(); | |
| 44 | + Map<Long, List<Long>> map = new HashMap<>(); | |
| 45 | + items.forEach(item -> { | |
| 46 | + if (map.containsKey(item.getSpuId())) { | |
| 47 | + List<Long> skuIds = map.get(item.getSpuId()); | |
| 48 | + skuIds.add(item.getSkuId()); | |
| 49 | + map.put(item.getSpuId(), skuIds); | |
| 50 | + } else { | |
| 51 | + List<Long> list = new ArrayList<>(); | |
| 52 | + list.add(item.getSkuId()); | |
| 53 | + map.put(item.getSpuId(), list); | |
| 54 | + } | |
| 55 | + }); | |
| 56 | + // 过滤出购买的商品 | |
| 57 | + // TODO @puhui999:productDOList 可以简化成 productList;一般来说,do 之类不用带着哈,在变量里; | |
| 58 | + List<SeckillProductDO> productDOList = CollectionUtils.filterList(productDOs, item -> map.get(item.getSpuId()).contains(item.getSkuId())); | |
| 59 | + Map<Long, SeckillActivityUpdateStockReqDTO.Item> productDOMap = CollectionUtils.convertMap(items, SeckillActivityUpdateStockReqDTO.Item::getSkuId, p -> p); | |
| 60 | + // 检查活动商品库存是否充足 | |
| 61 | + // TODO @puhui999:避免 b 这种无业务含义的变量; | |
| 62 | + boolean b = CollectionUtils.anyMatch(productDOList, item -> { | |
| 63 | + SeckillActivityUpdateStockReqDTO.Item item1 = productDOMap.get(item.getSkuId()); | |
| 64 | + return (item.getStock() < item1.getCount()) || (item.getStock() - item1.getCount()) < 0; | |
| 65 | + }); | |
| 66 | + if (b) { | |
| 67 | + throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); | |
| 68 | + } | |
| 69 | + // TODO @puhui999:类似 doList,应该和下面的 update 逻辑粘的更紧密一点;so 在空行的时候,应该挪到 74 之后里去;甚至更合理,应该是 79 之后;说白了,逻辑要分块,每个模块涉及的代码要紧密在一起; | |
| 70 | + List<SeckillProductDO> doList = CollectionUtils.convertList(productDOList, item -> { | |
| 71 | + item.setStock(item.getStock() - productDOMap.get(item.getSkuId()).getCount()); | |
| 72 | + return item; | |
| 73 | + }); | |
| 74 | + | |
| 75 | + // 更新活动库存 | |
| 76 | + // TODO @puhui999:考虑下并发更新 | |
| 77 | + seckillActivity.setStock(seckillActivity.getStock() + updateStockReqDTO.getCount()); | |
| 78 | + seckillActivity.setTotalStock(seckillActivity.getTotalStock() - updateStockReqDTO.getCount()); | |
| 79 | + activityService.updateSeckillActivity(seckillActivity); | |
| 80 | + // 更新活动商品库存 | |
| 81 | + activityService.updateSeckillActivityProductList(doList); | |
| 82 | + } | |
| 83 | + | |
| 84 | +} | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
| ... | ... | @@ -9,6 +9,7 @@ import lombok.*; |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | 11 | |
| 12 | +// TODO 芋艿:把字段的顺序,和 do 顺序对齐下 | |
| 12 | 13 | /** |
| 13 | 14 | * 拼团记录 DO |
| 14 | 15 | * |
| ... | ... | @@ -27,34 +28,28 @@ import java.time.LocalDateTime; |
| 27 | 28 | @AllArgsConstructor |
| 28 | 29 | public class CombinationRecordDO extends BaseDO { |
| 29 | 30 | |
| 31 | + /** | |
| 32 | + * 编号,主键自增 | |
| 33 | + */ | |
| 30 | 34 | @TableId |
| 31 | 35 | private Long id; |
| 36 | + | |
| 32 | 37 | /** |
| 33 | 38 | * 拼团活动编号 |
| 39 | + * | |
| 40 | + * 关联 {@link CombinationActivityDO#getId()} | |
| 34 | 41 | */ |
| 35 | 42 | private Long activityId; |
| 36 | 43 | /** |
| 37 | - * SPU 编号 | |
| 38 | - */ | |
| 39 | - private Long spuId; | |
| 40 | - /** | |
| 41 | - * SKU 编号 | |
| 42 | - */ | |
| 43 | - private Long skuId; | |
| 44 | - /** | |
| 45 | - * 用户编号 | |
| 46 | - */ | |
| 47 | - private Long userId; | |
| 48 | - /** | |
| 49 | - * 订单编号 | |
| 44 | + * 拼团商品单价 | |
| 45 | + * | |
| 46 | + * 冗余 {@link CombinationProductDO#getCombinationPrice()} | |
| 50 | 47 | */ |
| 51 | - private Long orderId; | |
| 48 | + private Integer combinationPrice; | |
| 52 | 49 | /** |
| 53 | - * 团长编号 | |
| 54 | - * | |
| 55 | - * 关联 {@link CombinationRecordDO#getId()} | |
| 50 | + * SPU 编号 | |
| 56 | 51 | */ |
| 57 | - private Long headId; | |
| 52 | + private Long spuId; | |
| 58 | 53 | /** |
| 59 | 54 | * 商品名字 |
| 60 | 55 | */ |
| ... | ... | @@ -64,9 +59,14 @@ public class CombinationRecordDO extends BaseDO { |
| 64 | 59 | */ |
| 65 | 60 | private String picUrl; |
| 66 | 61 | /** |
| 67 | - * 拼团商品单价 | |
| 62 | + * SKU 编号 | |
| 68 | 63 | */ |
| 69 | - private Integer combinationPrice; | |
| 64 | + private Long skuId; | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * 用户编号 | |
| 68 | + */ | |
| 69 | + private Long userId; | |
| 70 | 70 | /** |
| 71 | 71 | * 用户昵称 |
| 72 | 72 | */ |
| ... | ... | @@ -75,6 +75,13 @@ public class CombinationRecordDO extends BaseDO { |
| 75 | 75 | * 用户头像 |
| 76 | 76 | */ |
| 77 | 77 | private String avatar; |
| 78 | + | |
| 79 | + /** | |
| 80 | + * 团长编号 | |
| 81 | + * | |
| 82 | + * 关联 {@link CombinationRecordDO#getId()} | |
| 83 | + */ | |
| 84 | + private Long headId; | |
| 78 | 85 | /** |
| 79 | 86 | * 开团状态 |
| 80 | 87 | * |
| ... | ... | @@ -82,15 +89,30 @@ public class CombinationRecordDO extends BaseDO { |
| 82 | 89 | */ |
| 83 | 90 | private Integer status; |
| 84 | 91 | /** |
| 92 | + * 订单编号 | |
| 93 | + */ | |
| 94 | + private Long orderId; | |
| 95 | + /** | |
| 96 | + * 开团需要人数 | |
| 97 | + * | |
| 98 | + * 关联 {@link CombinationActivityDO#getUserSize()} | |
| 99 | + */ | |
| 100 | + private Integer userSize; | |
| 101 | + /** | |
| 102 | + * 已加入拼团人数 | |
| 103 | + */ | |
| 104 | + private Integer userCount; | |
| 105 | + /** | |
| 85 | 106 | * 是否虚拟成团 |
| 86 | 107 | */ |
| 87 | 108 | private Boolean virtualGroup; |
| 109 | + | |
| 88 | 110 | /** |
| 89 | - * 过期时间,单位:小时 | |
| 111 | + * 过期时间 | |
| 90 | 112 | * |
| 91 | - * 关联 {@link CombinationActivityDO#getLimitDuration()} | |
| 113 | + * 基于 {@link CombinationRecordDO#getStartTime()} + {@link CombinationActivityDO#getLimitDuration()} 计算 | |
| 92 | 114 | */ |
| 93 | - private Integer expireTime; | |
| 115 | + private LocalDateTime expireTime; | |
| 94 | 116 | /** |
| 95 | 117 | * 开始时间 (订单付款后开始的时间) |
| 96 | 118 | */ |
| ... | ... | @@ -99,15 +121,5 @@ public class CombinationRecordDO extends BaseDO { |
| 99 | 121 | * 结束时间(成团时间/失败时间) |
| 100 | 122 | */ |
| 101 | 123 | private LocalDateTime endTime; |
| 102 | - /** | |
| 103 | - * 开团需要人数 | |
| 104 | - * | |
| 105 | - * 关联 {@link CombinationActivityDO#getUserSize()} | |
| 106 | - */ | |
| 107 | - private Integer userSize; | |
| 108 | - /** | |
| 109 | - * 已加入拼团人数 | |
| 110 | - */ | |
| 111 | - private Integer userCount; | |
| 112 | 124 | |
| 113 | 125 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.combination; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; |
| 4 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | |
| 5 | 4 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; |
| 6 | 5 | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | 7 | import java.util.List; |
| 8 | 8 | |
| 9 | 9 | /** |
| ... | ... | @@ -16,9 +16,11 @@ public interface CombinationRecordService { |
| 16 | 16 | /** |
| 17 | 17 | * 更新拼团状态 |
| 18 | 18 | * |
| 19 | - * @param reqDTO 请求 DTO | |
| 19 | + * @param status 状态 | |
| 20 | + * @param userId 用户编号 | |
| 21 | + * @param orderId 订单编号 | |
| 20 | 22 | */ |
| 21 | - void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO); | |
| 23 | + void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId); | |
| 22 | 24 | |
| 23 | 25 | /** |
| 24 | 26 | * 创建拼团记录 |
| ... | ... | @@ -30,9 +32,12 @@ public interface CombinationRecordService { |
| 30 | 32 | /** |
| 31 | 33 | * 更新拼团状态和开始时间 |
| 32 | 34 | * |
| 33 | - * @param reqDTO 请求 DTO | |
| 35 | + * @param status 状态 | |
| 36 | + * @param userId 用户编号 | |
| 37 | + * @param orderId 订单编号 | |
| 38 | + * @param startTime 开始时间 | |
| 34 | 39 | */ |
| 35 | - void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO); | |
| 40 | + void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime); | |
| 36 | 41 | |
| 37 | 42 | /** |
| 38 | 43 | * 获得拼团状态 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
| ... | ... | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.combination; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | 5 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; |
| 6 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | |
| 7 | 6 | import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; |
| 8 | 7 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; |
| 9 | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; |
| ... | ... | @@ -21,6 +20,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU |
| 21 | 20 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 22 | 21 | |
| 23 | 22 | // TODO 芋艿:等拼团记录做完,完整 review 下 |
| 23 | + | |
| 24 | 24 | /** |
| 25 | 25 | * 拼团记录 Service 实现类 |
| 26 | 26 | * |
| ... | ... | @@ -38,27 +38,27 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 38 | 38 | |
| 39 | 39 | @Override |
| 40 | 40 | @Transactional(rollbackFor = Exception.class) |
| 41 | - public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) { | |
| 41 | + public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) { | |
| 42 | 42 | // 校验拼团是否存在 |
| 43 | - CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId()); | |
| 43 | + CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId); | |
| 44 | 44 | |
| 45 | 45 | // 更新状态 |
| 46 | - recordDO.setStatus(reqDTO.getStatus()); | |
| 46 | + recordDO.setStatus(status); | |
| 47 | 47 | recordMapper.updateById(recordDO); |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | @Override |
| 51 | 51 | @Transactional(rollbackFor = Exception.class) |
| 52 | - public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) { | |
| 53 | - CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId()); | |
| 52 | + public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Integer status, Long userId, Long orderId, LocalDateTime startTime) { | |
| 53 | + CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId); | |
| 54 | 54 | // 更新状态 |
| 55 | - recordDO.setStatus(reqDTO.getStatus()); | |
| 55 | + recordDO.setStatus(status); | |
| 56 | 56 | // 更新开始时间 |
| 57 | - recordDO.setStartTime(reqDTO.getStartTime()); | |
| 57 | + recordDO.setStartTime(startTime); | |
| 58 | 58 | recordMapper.updateById(recordDO); |
| 59 | 59 | |
| 60 | 60 | // 更新拼团参入人数 |
| 61 | - List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), reqDTO.getStatus()); | |
| 61 | + List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), status); | |
| 62 | 62 | if (CollUtil.isNotEmpty(recordDOs)) { |
| 63 | 63 | recordDOs.forEach(item -> { |
| 64 | 64 | item.setUserCount(recordDOs.size()); |
| ... | ... | @@ -115,8 +115,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { |
| 115 | 115 | // 2. 创建拼团记录 |
| 116 | 116 | CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO); |
| 117 | 117 | record.setVirtualGroup(false); |
| 118 | - // TODO @puhui999:过期时间,应该是 Date 哈; | |
| 119 | - record.setExpireTime(activity.getLimitDuration()); | |
| 118 | + record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration())); | |
| 120 | 119 | record.setUserSize(activity.getUserSize()); |
| 121 | 120 | recordMapper.insert(record); |
| 122 | 121 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
| ... | ... | @@ -34,6 +34,20 @@ public interface SeckillActivityService { |
| 34 | 34 | void updateSeckillActivity(@Valid SeckillActivityUpdateReqVO updateReqVO); |
| 35 | 35 | |
| 36 | 36 | /** |
| 37 | + * 更新秒杀活动 | |
| 38 | + * | |
| 39 | + * @param activityDO 秒杀活动 | |
| 40 | + */ | |
| 41 | + void updateSeckillActivity(SeckillActivityDO activityDO); | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * 更新秒杀活动商品 | |
| 45 | + * | |
| 46 | + * @param productList 活动商品列表 | |
| 47 | + */ | |
| 48 | + void updateSeckillActivityProductList(List<SeckillProductDO> productList); | |
| 49 | + | |
| 50 | + /** | |
| 37 | 51 | * 关闭秒杀活动 |
| 38 | 52 | * |
| 39 | 53 | * @param id 编号 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
| ... | ... | @@ -79,8 +79,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 79 | 79 | * 1. 校验秒杀时段是否存在 |
| 80 | 80 | * 2. 秒杀商品是否参加其它活动 |
| 81 | 81 | * |
| 82 | - * @param configIds 秒杀时段数组 | |
| 83 | - * @param spuId 商品 SPU 编号 | |
| 82 | + * @param configIds 秒杀时段数组 | |
| 83 | + * @param spuId 商品 SPU 编号 | |
| 84 | 84 | * @param activityId 秒杀活动编号 |
| 85 | 85 | */ |
| 86 | 86 | private void validateProductConflict(List<Long> configIds, Long spuId, Long activityId) { |
| ... | ... | @@ -92,15 +92,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 92 | 92 | if (activityId != null) { // 排除自己 |
| 93 | 93 | activityList.removeIf(item -> ObjectUtil.equal(item.getId(), activityId)); |
| 94 | 94 | } |
| 95 | - // TODO @puhui999:一个 spu,参与两个活动应该没关系,关键是活动时间不充能重叠; | |
| 96 | - // 2.2 过滤出所有 spuId 有交集的活动,判断是否存在重叠 | |
| 97 | - List<SeckillActivityDO> activityDOs1 = filterList(activityList, s -> ObjectUtil.equal(s.getSpuId(), spuId)); | |
| 98 | - if (isNotEmpty(activityDOs1)) { | |
| 99 | - throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); | |
| 100 | - } | |
| 101 | - // 2.3 过滤出所有 configIds 有交集的活动,判断是否存在重叠 | |
| 102 | - List<SeckillActivityDO> activityDOs2 = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds)); | |
| 103 | - if (isNotEmpty(activityDOs2)) { | |
| 95 | + // 2.2 过滤出所有 configIds 有交集的活动,判断是否存在重叠 | |
| 96 | + List<SeckillActivityDO> conflictActivityList = filterList(activityList, s -> containsAny(s.getConfigIds(), configIds)); | |
| 97 | + if (isNotEmpty(conflictActivityList)) { | |
| 104 | 98 | throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); |
| 105 | 99 | } |
| 106 | 100 | } |
| ... | ... | @@ -108,7 +102,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 108 | 102 | /** |
| 109 | 103 | * 校验秒杀商品是否都存在 |
| 110 | 104 | * |
| 111 | - * @param spuId 商品 SPU 编号 | |
| 105 | + * @param spuId 商品 SPU 编号 | |
| 112 | 106 | * @param products 秒杀商品 |
| 113 | 107 | */ |
| 114 | 108 | private void validateProductExists(Long spuId, List<SeckillProductBaseVO> products) { |
| ... | ... | @@ -150,11 +144,21 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 150 | 144 | updateSeckillProduct(updateObj, updateReqVO.getProducts()); |
| 151 | 145 | } |
| 152 | 146 | |
| 147 | + @Override | |
| 148 | + public void updateSeckillActivity(SeckillActivityDO activityDO) { | |
| 149 | + seckillActivityMapper.updateById(activityDO); | |
| 150 | + } | |
| 151 | + | |
| 152 | + @Override | |
| 153 | + public void updateSeckillActivityProductList(List<SeckillProductDO> productList) { | |
| 154 | + seckillProductMapper.updateBatch(productList); | |
| 155 | + } | |
| 156 | + | |
| 153 | 157 | /** |
| 154 | 158 | * 更新秒杀商品 |
| 155 | 159 | * |
| 156 | 160 | * @param activity 秒杀活动 |
| 157 | - * @param products 该活动的最新商品配置 | |
| 161 | + * @param products 该活动的最新商品配置 | |
| 158 | 162 | */ |
| 159 | 163 | private void updateSeckillProduct(SeckillActivityDO activity, List<SeckillProductBaseVO> products) { |
| 160 | 164 | // 第一步,对比新老数据,获得添加、修改、删除的列表 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.util; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 6 | -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | |
| 7 | 5 | |
| 8 | 6 | import java.time.LocalDateTime; |
| 9 | -import java.util.List; | |
| 10 | -import java.util.Set; | |
| 11 | -import java.util.function.Function; | |
| 12 | - | |
| 13 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 14 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch; | |
| 15 | -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | |
| 16 | 7 | |
| 17 | 8 | /** |
| 18 | 9 | * 活动工具类 |
| ... | ... | @@ -31,21 +22,4 @@ public class PromotionUtils { |
| 31 | 22 | return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus(); |
| 32 | 23 | } |
| 33 | 24 | |
| 34 | - /** | |
| 35 | - * 校验商品 sku 是否都存在 | |
| 36 | - * | |
| 37 | - * @param skus 数据库中的商品 skus | |
| 38 | - * @param products 需要校验的商品 | |
| 39 | - * @param func 获取需要校验的商品的 skuId | |
| 40 | - */ | |
| 41 | - public static <T> void validateProductSkuAllExists(List<ProductSkuRespDTO> skus, List<T> products, Function<T, Long> func) { | |
| 42 | - // 校验 sku 个数是否一致 | |
| 43 | - Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func); | |
| 44 | - Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId); | |
| 45 | - // 校验 skuId 是否存在 | |
| 46 | - if (anyMatch(skuIdsSet, s -> !skuIdsSet1.contains(s))) { | |
| 47 | - throw exception(SKU_NOT_EXISTS); | |
| 48 | - } | |
| 49 | - } | |
| 50 | - | |
| 51 | 25 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/pom.xml
| ... | ... | @@ -86,6 +86,11 @@ |
| 86 | 86 | <artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
| 87 | 87 | </dependency> |
| 88 | 88 | |
| 89 | + <dependency> | |
| 90 | + <groupId>cn.iocoder.boot</groupId> | |
| 91 | + <artifactId>yudao-spring-boot-starter-redis</artifactId> | |
| 92 | + </dependency> | |
| 93 | + | |
| 89 | 94 | <!-- Test 测试相关 --> |
| 90 | 95 | <dependency> |
| 91 | 96 | <groupId>cn.iocoder.boot</groupId> | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApiImpl.java
| ... | ... | @@ -20,13 +20,14 @@ public class BrokerageApiImpl implements BrokerageApi { |
| 20 | 20 | @Resource |
| 21 | 21 | private BrokerageUserService brokerageUserService; |
| 22 | 22 | |
| 23 | + @Override | |
| 23 | 24 | public BrokerageUserDTO getBrokerageUser(Long userId) { |
| 24 | 25 | return BrokerageUserConvert.INSTANCE.convertDTO(brokerageUserService.getBrokerageUser(userId)); |
| 25 | 26 | } |
| 26 | 27 | |
| 27 | 28 | @Override |
| 28 | 29 | public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) { |
| 29 | - return brokerageUserService.bindUser(userId, bindUserId, isNewUser); | |
| 30 | + return brokerageUserService.bindBrokerageUser(userId, bindUserId, isNewUser); | |
| 30 | 31 | } |
| 31 | 32 | |
| 32 | 33 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
| ... | ... | @@ -76,6 +76,11 @@ public class TradeAfterSaleController { |
| 76 | 76 | public CommonResult<TradeAfterSaleDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { |
| 77 | 77 | // 查询订单 |
| 78 | 78 | TradeAfterSaleDO afterSale = afterSaleService.getAfterSale(id); |
| 79 | + // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理; | |
| 80 | +// if (afterSale == null) { | |
| 81 | +// return success(null, AFTER_SALE_NOT_FOUND.getMsg()); | |
| 82 | +// } | |
| 83 | + | |
| 79 | 84 | // 查询订单 |
| 80 | 85 | TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId()); |
| 81 | 86 | // 查询订单项 |
| ... | ... | @@ -92,7 +97,11 @@ public class TradeAfterSaleController { |
| 92 | 97 | TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO(); |
| 93 | 98 | respVO.setId((long) i); |
| 94 | 99 | respVO.setUserId((long) i); |
| 95 | - respVO.setUserType(1); | |
| 100 | + respVO.setUserType(i % 2 == 0 ? 2 : 1); | |
| 101 | + // 模拟系统操作 | |
| 102 | + if (i == 2) { | |
| 103 | + respVO.setUserType(3); | |
| 104 | + } | |
| 96 | 105 | respVO.setAfterSaleId(id); |
| 97 | 106 | respVO.setOrderId((long) i); |
| 98 | 107 | respVO.setOrderItemId((long) i); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDetailRespVO.java
| ... | ... | @@ -35,7 +35,7 @@ public class TradeAfterSaleDetailRespVO extends TradeAfterSaleBaseVO { |
| 35 | 35 | /** |
| 36 | 36 | * 售后日志 |
| 37 | 37 | */ |
| 38 | - private List<TradeAfterSaleLogRespVO> afterSaleLog; | |
| 38 | + private List<TradeAfterSaleLogRespVO> logs; | |
| 39 | 39 | |
| 40 | 40 | @Schema(description = "管理后台 - 交易订单的详情的订单项目") |
| 41 | 41 | @Data | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java
| ... | ... | @@ -62,7 +62,7 @@ public class BrokerageUserController { |
| 62 | 62 | @Operation(summary = "修改推广资格") |
| 63 | 63 | @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-enable')") |
| 64 | 64 | public CommonResult<Boolean> updateBrokerageEnabled(@Valid @RequestBody BrokerageUserUpdateBrokerageEnabledReqVO updateReqVO) { |
| 65 | - brokerageUserService.updateBrokerageEnabled(updateReqVO.getId(), updateReqVO.getEnabled()); | |
| 65 | + brokerageUserService.updateBrokerageUserEnabled(updateReqVO.getId(), updateReqVO.getEnabled()); | |
| 66 | 66 | return success(true); |
| 67 | 67 | } |
| 68 | 68 | |
| ... | ... | @@ -90,12 +90,12 @@ public class BrokerageUserController { |
| 90 | 90 | // 合计分佣订单 |
| 91 | 91 | Map<Long, UserBrokerageSummaryBO> userOrderSummaryMap = convertMap(userIds, |
| 92 | 92 | userId -> userId, |
| 93 | - userId -> brokerageRecordService.summaryByUserIdAndBizTypeAndStatus(userId, | |
| 93 | + userId -> brokerageRecordService.getUserBrokerageSummaryByUserId(userId, | |
| 94 | 94 | BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus())); |
| 95 | 95 | // 合计推广用户数量 |
| 96 | 96 | Map<Long, Long> brokerageUserCountMap = convertMap(userIds, |
| 97 | 97 | userId -> userId, |
| 98 | - userId -> brokerageUserService.getCountByBindUserId(userId)); | |
| 98 | + userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId)); | |
| 99 | 99 | |
| 100 | 100 | // todo 合计提现 |
| 101 | 101 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java
| ... | ... | @@ -19,7 +19,6 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO { |
| 19 | 19 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 20 | 20 | private LocalDateTime createTime; |
| 21 | 21 | |
| 22 | - | |
| 23 | 22 | // ========== 用户信息 ========== |
| 24 | 23 | |
| 25 | 24 | @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") |
| ... | ... | @@ -27,7 +26,6 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO { |
| 27 | 26 | @Schema(description = "用户昵称", example = "李四") |
| 28 | 27 | private String nickname; |
| 29 | 28 | |
| 30 | - | |
| 31 | 29 | // ========== 推广信息 ========== |
| 32 | 30 | |
| 33 | 31 | @Schema(description = "推广用户数量(一级)", example = "20019") |
| ... | ... | @@ -37,7 +35,6 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO { |
| 37 | 35 | @Schema(description = "推广订单金额", example = "20019") |
| 38 | 36 | private Integer brokerageOrderPrice; |
| 39 | 37 | |
| 40 | - | |
| 41 | 38 | // ========== 提现信息 ========== |
| 42 | 39 | |
| 43 | 40 | @Schema(description = "已提现金额", example = "20019") | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
| ... | ... | @@ -67,6 +67,11 @@ public class TradeOrderController { |
| 67 | 67 | public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) { |
| 68 | 68 | // 查询订单 |
| 69 | 69 | TradeOrderDO order = tradeOrderQueryService.getOrder(id); |
| 70 | + // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理; | |
| 71 | +// if (order == null) { | |
| 72 | +// return success(null, ORDER_NOT_FOUND.getMsg()); | |
| 73 | +// } | |
| 74 | + | |
| 70 | 75 | // 查询订单项 |
| 71 | 76 | List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); |
| 72 | 77 | // orderLog | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java
| ... | ... | @@ -26,24 +26,23 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO { |
| 26 | 26 | private MemberUserRespVO user; |
| 27 | 27 | |
| 28 | 28 | /** |
| 29 | - * TODO 订单操作日志, 先模拟一波;返回 logs,简洁,然后复数哈 | |
| 29 | + * TODO 订单操作日志, 先模拟一波 | |
| 30 | 30 | */ |
| 31 | - private List<OrderLog> orderLog; | |
| 31 | + private List<OrderLog> logs; | |
| 32 | 32 | |
| 33 | - // TODO @puhui999:swagger 注解 | |
| 33 | + @Schema(description = "管理后台 - 交易订单的操作日志") | |
| 34 | 34 | @Data |
| 35 | 35 | public static class OrderLog { |
| 36 | 36 | |
| 37 | - /** | |
| 38 | - * 内容 | |
| 39 | - */ | |
| 37 | + @Schema(description = "操作详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单发货") | |
| 40 | 38 | private String content; |
| 41 | 39 | |
| 42 | - /** | |
| 43 | - * 创建时间 | |
| 44 | - */ | |
| 40 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-06-01 10:50:20") | |
| 45 | 41 | private LocalDateTime createTime; |
| 46 | 42 | |
| 43 | + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 44 | + private Integer userType; | |
| 45 | + | |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | 48 | @Schema(description = "管理后台 - 交易订单的详情的订单项目") | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.controller.app.brokerage; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 6 | +import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO; | |
| 6 | 7 | import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO; |
| 8 | 9 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -11,6 +12,7 @@ import lombok.extern.slf4j.Slf4j; |
| 11 | 12 | import org.springframework.validation.annotation.Validated; |
| 12 | 13 | import org.springframework.web.bind.annotation.GetMapping; |
| 13 | 14 | import org.springframework.web.bind.annotation.RequestMapping; |
| 15 | +import org.springframework.web.bind.annotation.RequestParam; | |
| 14 | 16 | import org.springframework.web.bind.annotation.RestController; |
| 15 | 17 | |
| 16 | 18 | import javax.validation.Valid; |
| ... | ... | @@ -40,4 +42,14 @@ public class AppBrokerageRecordController { |
| 40 | 42 | return success(new PageResult<>(asList(vo1, vo2), 10L)); |
| 41 | 43 | } |
| 42 | 44 | |
| 45 | + @GetMapping("/get-product-brokerage-price") | |
| 46 | + @Operation(summary = "获得商品的分销金额") | |
| 47 | + public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) { | |
| 48 | + AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO(); | |
| 49 | + respVO.setEnabled(true); // TODO @疯狂:需要开启分销 + 人允许分销 | |
| 50 | + respVO.setBrokerageMinPrice(1); | |
| 51 | + respVO.setBrokerageMaxPrice(2); | |
| 52 | + return success(respVO); | |
| 53 | + } | |
| 54 | + | |
| 43 | 55 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java
| ... | ... | @@ -37,11 +37,19 @@ public class AppBrokerageUserController { |
| 37 | 37 | @PreAuthenticated |
| 38 | 38 | public CommonResult<AppBrokerageUserRespVO> getBrokerageUser() { |
| 39 | 39 | AppBrokerageUserRespVO respVO = new AppBrokerageUserRespVO() |
| 40 | + .setBrokerageEnabled(true) | |
| 40 | 41 | .setPrice(2000) |
| 41 | 42 | .setFrozenPrice(3000); |
| 42 | 43 | return success(respVO); |
| 43 | 44 | } |
| 44 | 45 | |
| 46 | + @PutMapping("/bind") | |
| 47 | + @Operation(summary = "绑定推广员") | |
| 48 | + @PreAuthenticated | |
| 49 | + public CommonResult<Boolean> bindBrokerageUser(@Valid @RequestBody AppBrokerageUserBindReqVO reqVO) { | |
| 50 | + return success(brokerageUserService.bindBrokerageUser(getLoginUserId(), reqVO.getBindUserId(), false)); | |
| 51 | + } | |
| 52 | + | |
| 45 | 53 | // TODO 芋艿:临时 mock => |
| 46 | 54 | @GetMapping("/get-summary") |
| 47 | 55 | @Operation(summary = "获得个人分销统计") |
| ... | ... | @@ -49,7 +57,7 @@ public class AppBrokerageUserController { |
| 49 | 57 | public CommonResult<AppBrokerageUserMySummaryRespVO> getBrokerageUserSummary() { |
| 50 | 58 | AppBrokerageUserMySummaryRespVO respVO = new AppBrokerageUserMySummaryRespVO() |
| 51 | 59 | .setYesterdayPrice(1) |
| 52 | - .setPrice(2) | |
| 60 | + .setBrokeragePrice(2) | |
| 53 | 61 | .setFrozenPrice(3) |
| 54 | 62 | .setWithdrawPrice(4) |
| 55 | 63 | .setFirstBrokerageUserCount(166) |
| ... | ... | @@ -84,16 +92,16 @@ public class AppBrokerageUserController { |
| 84 | 92 | public CommonResult<PageResult<AppBrokerageUserRankByPriceRespVO>> getBrokerageUserChildSummaryPageByPrice(AppBrokerageUserRankPageReqVO pageReqVO) { |
| 85 | 93 | AppBrokerageUserRankByPriceRespVO vo1 = new AppBrokerageUserRankByPriceRespVO() |
| 86 | 94 | .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") |
| 87 | - .setPrice(10); | |
| 95 | + .setBrokeragePrice(10); | |
| 88 | 96 | AppBrokerageUserRankByPriceRespVO vo2 = new AppBrokerageUserRankByPriceRespVO() |
| 89 | 97 | .setId(2L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") |
| 90 | - .setPrice(6); | |
| 98 | + .setBrokeragePrice(6); | |
| 91 | 99 | AppBrokerageUserRankByPriceRespVO vo3 = new AppBrokerageUserRankByPriceRespVO() |
| 92 | 100 | .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") |
| 93 | - .setPrice(4); | |
| 101 | + .setBrokeragePrice(4); | |
| 94 | 102 | AppBrokerageUserRankByPriceRespVO vo4 = new AppBrokerageUserRankByPriceRespVO() |
| 95 | 103 | .setId(3L).setNickname("芋3**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") |
| 96 | - .setPrice(4); | |
| 104 | + .setBrokeragePrice(4); | |
| 97 | 105 | return success(new PageResult<>(asList(vo1, vo2, vo3, vo4), 10L)); |
| 98 | 106 | } |
| 99 | 107 | |
| ... | ... | @@ -105,11 +113,11 @@ public class AppBrokerageUserController { |
| 105 | 113 | AppBrokerageUserChildSummaryPageReqVO pageReqVO) { |
| 106 | 114 | AppBrokerageUserChildSummaryRespVO vo1 = new AppBrokerageUserChildSummaryRespVO() |
| 107 | 115 | .setId(1L).setNickname("芋1**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") |
| 108 | - .setPrice(10).setPrice(20).setBrokerageOrderCount(30) | |
| 116 | + .setBrokeragePrice(10).setBrokeragePrice(20).setBrokerageOrderCount(30) | |
| 109 | 117 | .setBrokerageTime(LocalDateTime.now()); |
| 110 | 118 | AppBrokerageUserChildSummaryRespVO vo2 = new AppBrokerageUserChildSummaryRespVO() |
| 111 | 119 | .setId(1L).setNickname("芋2**艿").setAvatar("http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg") |
| 112 | - .setPrice(20).setPrice(30).setBrokerageOrderCount(40) | |
| 120 | + .setBrokeragePrice(20).setBrokeragePrice(30).setBrokerageOrderCount(40) | |
| 113 | 121 | .setBrokerageTime(LocalDateTime.now()); |
| 114 | 122 | return success(new PageResult<>(asList(vo1, vo2), 10L)); |
| 115 | 123 | } |
| ... | ... | @@ -118,15 +126,9 @@ public class AppBrokerageUserController { |
| 118 | 126 | @GetMapping("/get-rank-by-price") |
| 119 | 127 | @Operation(summary = "获得分销用户排行(基于佣金)") |
| 120 | 128 | @Parameter(name = "times", description = "时间段", required = true) |
| 121 | - public CommonResult<Integer> getBrokerageUserRankByPrice( | |
| 129 | + public CommonResult<Integer> bindBrokerageUser( | |
| 122 | 130 | @RequestParam("times") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) LocalDateTime[] times) { |
| 123 | 131 | return success(1); |
| 124 | 132 | } |
| 125 | 133 | |
| 126 | - @PutMapping("/bind-user") | |
| 127 | - @Operation(summary = "绑定推广员") | |
| 128 | - public CommonResult<Boolean> getBrokerageUserRankByPrice(@Valid AppBrokerageUserBindReqVO reqVO) { | |
| 129 | - return success(brokerageUserService.bindUser(getLoginUserId(), reqVO.getBindUserId(), false)); | |
| 130 | - } | |
| 131 | - | |
| 132 | 134 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/record/AppBrokerageProductPriceRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +@Schema(description = "用户 App - 商品的分销金额 Response VO") | |
| 7 | +@Data | |
| 8 | +public class AppBrokerageProductPriceRespVO { | |
| 9 | + | |
| 10 | + @Schema(description = "是否开启", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 11 | + private Boolean enabled; | |
| 12 | + | |
| 13 | + @Schema(description = "分销最小金额,单位:分", example = "100") | |
| 14 | + private Integer brokerageMinPrice; | |
| 15 | + | |
| 16 | + @Schema(description = "分销最大金额,单位:分", example = "100") | |
| 17 | + private Integer brokerageMaxPrice; | |
| 18 | + | |
| 19 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserChildSummaryRespVO.java
| ... | ... | @@ -19,7 +19,7 @@ public class AppBrokerageUserChildSummaryRespVO { |
| 19 | 19 | private String avatar; |
| 20 | 20 | |
| 21 | 21 | @Schema(description = "佣金金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
| 22 | - private Integer price; | |
| 22 | + private Integer brokeragePrice; | |
| 23 | 23 | |
| 24 | 24 | @Schema(description = "分销订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") |
| 25 | 25 | private Integer brokerageOrderCount; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java
| ... | ... | @@ -14,7 +14,7 @@ public class AppBrokerageUserMySummaryRespVO { |
| 14 | 14 | private Integer withdrawPrice; |
| 15 | 15 | |
| 16 | 16 | @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408") |
| 17 | - private Integer price; | |
| 17 | + private Integer brokeragePrice; | |
| 18 | 18 | |
| 19 | 19 | @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234") |
| 20 | 20 | private Integer frozenPrice; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRankByPriceRespVO.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserRespVO.java
| ... | ... | @@ -7,6 +7,9 @@ import lombok.Data; |
| 7 | 7 | @Data |
| 8 | 8 | public class AppBrokerageUserRespVO { |
| 9 | 9 | |
| 10 | + @Schema(description = "是否有分销资格", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | |
| 11 | + private Boolean brokerageEnabled; | |
| 12 | + | |
| 10 | 13 | @Schema(description = "可用的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2408") |
| 11 | 14 | private Integer price; |
| 12 | 15 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java
| ... | ... | @@ -23,21 +23,18 @@ public class AppBrokerageWithdrawCreateReqVO { |
| 23 | 23 | @Min(value = 1, message = "提现金额不能小于 1") |
| 24 | 24 | private Integer price; |
| 25 | 25 | |
| 26 | - | |
| 27 | 26 | // ========== 银行卡、微信、支付宝 提现相关字段 ========== |
| 28 | 27 | |
| 29 | 28 | @Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789") |
| 30 | 29 | @NotBlank(message = "提现账号不能为空", groups = {Bank.class, Wechat.class, Alipay.class}) |
| 31 | 30 | private String accountNo; |
| 32 | 31 | |
| 33 | - | |
| 34 | 32 | // ========== 微信、支付宝 提现相关字段 ========== |
| 35 | 33 | |
| 36 | 34 | @Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png") |
| 37 | 35 | @URL(message = "收款码的图片,必须是一个 URL") |
| 38 | 36 | private String accountQrCodeUrl; |
| 39 | 37 | |
| 40 | - | |
| 41 | 38 | // ========== 银行卡 提现相关字段 ========== |
| 42 | 39 | |
| 43 | 40 | @Schema(description = "持卡人姓名", example = "张三") | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
| ... | ... | @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 6 | 6 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; |
| 7 | -import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; | |
| 8 | 7 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; |
| 9 | 8 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; |
| 10 | 9 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; |
| ... | ... | @@ -82,9 +81,10 @@ public class AppTradeOrderController { |
| 82 | 81 | public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) { |
| 83 | 82 | // 查询订单 |
| 84 | 83 | TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id); |
| 85 | - if (order == null) { | |
| 86 | - return success(null); | |
| 87 | - } | |
| 84 | + // TODO @puhui999:这里建议改成,如果为 null,直接返回 success null;主要查询操作,尽量不要有非空的提示哈;交给前端处理; | |
| 85 | +// if (order == null) { | |
| 86 | +// return success(null, ORDER_NOT_FOUND.getMsg()); | |
| 87 | +// } | |
| 88 | 88 | |
| 89 | 89 | // 查询订单项 |
| 90 | 90 | List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId()); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
| ... | ... | @@ -50,12 +50,18 @@ public class AppTradeOrderSettlementReqVO { |
| 50 | 50 | private Long seckillActivityId; |
| 51 | 51 | |
| 52 | 52 | // ========== 拼团活动相关字段 ========== |
| 53 | + // TODO @puhui999:是不是拼团记录的编号哈? | |
| 53 | 54 | @Schema(description = "拼团活动编号", example = "1024") |
| 54 | 55 | private Long combinationActivityId; |
| 55 | 56 | |
| 56 | 57 | @Schema(description = "拼团团长编号", example = "2048") |
| 57 | 58 | private Long combinationHeadId; |
| 58 | 59 | |
| 60 | + // ========== 砍价活动相关字段 ========== | |
| 61 | + // TODO @puhui999:是不是砍价记录的编号哈? | |
| 62 | + @Schema(description = "砍价活动编号", example = "123") | |
| 63 | + private Long bargainActivityId; | |
| 64 | + | |
| 59 | 65 | @Data |
| 60 | 66 | @Schema(description = "用户 App - 商品项") |
| 61 | 67 | @Valid | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java
| ... | ... | @@ -78,7 +78,7 @@ public interface TradeAfterSaleConvert { |
| 78 | 78 | // 处理订单信息 |
| 79 | 79 | respVO.setOrder(convert(order)); |
| 80 | 80 | // 处理售后日志 |
| 81 | - respVO.setAfterSaleLog(convertList1(logs)); | |
| 81 | + respVO.setLogs(convertList1(logs)); | |
| 82 | 82 | return respVO; |
| 83 | 83 | } |
| 84 | 84 | List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespDTO> list); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java
| ... | ... | @@ -33,27 +33,22 @@ public interface BrokerageRecordConvert { |
| 33 | 33 | |
| 34 | 34 | PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page); |
| 35 | 35 | |
| 36 | + // TODO @疯狂:可能 title 不是很固化,会存在类似:沐晴成功购买《XXX JVM 实战》 | |
| 36 | 37 | default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId, |
| 37 | - Integer brokerageFrozenDays, int brokerage, LocalDateTime unfreezeTime, | |
| 38 | + Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime, | |
| 38 | 39 | String title, Long sourceUserId, Integer sourceUserType) { |
| 39 | 40 | brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0); |
| 40 | 41 | // 不冻结时,佣金直接就是结算状态 |
| 41 | 42 | Integer status = brokerageFrozenDays > 0 |
| 42 | 43 | ? BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus() |
| 43 | 44 | : BrokerageRecordStatusEnum.SETTLEMENT.getStatus(); |
| 44 | - return new BrokerageRecordDO() | |
| 45 | - .setUserId(user.getId()) | |
| 46 | - .setBizType(bizType.getType()) | |
| 47 | - .setBizId(bizId) | |
| 48 | - .setPrice(brokerage) | |
| 49 | - .setTotalPrice(user.getPrice()) | |
| 45 | + return new BrokerageRecordDO().setUserId(user.getId()) | |
| 46 | + .setBizType(bizType.getType()).setBizId(bizId) | |
| 47 | + .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice()) | |
| 50 | 48 | .setTitle(title) |
| 51 | - .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokerage / 100d))) | |
| 52 | - .setStatus(status) | |
| 53 | - .setFrozenDays(brokerageFrozenDays) | |
| 54 | - .setUnfreezeTime(unfreezeTime) | |
| 55 | - .setSourceUserType(sourceUserType) | |
| 56 | - .setSourceUserId(sourceUserId); | |
| 49 | + .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d))) | |
| 50 | + .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime) | |
| 51 | + .setSourceUserType(sourceUserType).setSourceUserId(sourceUserId); | |
| 57 | 52 | } |
| 58 | 53 | |
| 59 | 54 | default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) { | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java
| ... | ... | @@ -41,25 +41,19 @@ public interface BrokerageUserConvert { |
| 41 | 41 | |
| 42 | 42 | // 推广用户数量(一级) |
| 43 | 43 | vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0)); |
| 44 | - | |
| 44 | + // 推广订单数量、推广订单金额 | |
| 45 | 45 | Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId())); |
| 46 | - // 推广订单数量 | |
| 47 | - vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0)); | |
| 48 | - // 推广订单金额 | |
| 49 | - vo.setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0)); | |
| 50 | - | |
| 51 | - // todo 已提现次数 | |
| 52 | - vo.setWithdrawCount(0); | |
| 53 | - // todo 已提现金额 | |
| 54 | - vo.setWithdrawPrice(0); | |
| 46 | + vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0)) | |
| 47 | + .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0)); | |
| 48 | + // todo 已提现次数、已提现金额 | |
| 49 | + vo.setWithdrawCount(0).setWithdrawPrice(0); | |
| 55 | 50 | } |
| 56 | 51 | return result; |
| 57 | 52 | } |
| 58 | 53 | |
| 59 | 54 | default BrokerageUserRespVO copyTo(MemberUserRespDTO source, BrokerageUserRespVO target) { |
| 60 | - Optional.ofNullable(source) | |
| 61 | - .ifPresent(user -> target.setNickname(user.getNickname()) | |
| 62 | - .setAvatar(user.getAvatar())); | |
| 55 | + Optional.ofNullable(source).ifPresent( | |
| 56 | + user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar())); | |
| 63 | 57 | return target; |
| 64 | 58 | } |
| 65 | 59 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
| ... | ... | @@ -95,6 +95,7 @@ public interface TradeOrderConvert { |
| 95 | 95 | items.forEach(item -> item.setIncrCount(-item.getIncrCount())); |
| 96 | 96 | return new ProductSkuUpdateStockReqDTO(items); |
| 97 | 97 | } |
| 98 | + | |
| 98 | 99 | List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); |
| 99 | 100 | |
| 100 | 101 | @Mappings({ |
| ... | ... | @@ -153,9 +154,10 @@ public interface TradeOrderConvert { |
| 153 | 154 | TradeOrderDetailRespVO.OrderLog orderLog = new TradeOrderDetailRespVO.OrderLog(); |
| 154 | 155 | orderLog.setContent("订单操作" + i); |
| 155 | 156 | orderLog.setCreateTime(LocalDateTime.now()); |
| 157 | + orderLog.setUserType(i % 2 == 0 ? 2 : 1); | |
| 156 | 158 | orderLogs.add(orderLog); |
| 157 | 159 | } |
| 158 | - orderVO.setOrderLog(orderLogs); | |
| 160 | + orderVO.setLogs(orderLogs); | |
| 159 | 161 | return orderVO; |
| 160 | 162 | } |
| 161 | 163 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/user/BrokerageUserDO.java
| ... | ... | @@ -43,7 +43,7 @@ public class BrokerageUserDO extends BaseDO { |
| 43 | 43 | private LocalDateTime bindUserTime; |
| 44 | 44 | |
| 45 | 45 | /** |
| 46 | - * 推广资格 | |
| 46 | + * 是否有分销资格 | |
| 47 | 47 | */ |
| 48 | 48 | private Boolean brokerageEnabled; |
| 49 | 49 | /** |
| ... | ... | @@ -54,7 +54,7 @@ public class BrokerageUserDO extends BaseDO { |
| 54 | 54 | /** |
| 55 | 55 | * 可用佣金 |
| 56 | 56 | */ |
| 57 | - private Integer price; | |
| 57 | + private Integer brokeragePrice; | |
| 58 | 58 | /** |
| 59 | 59 | * 冻结佣金 |
| 60 | 60 | */ | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java
| ... | ... | @@ -53,6 +53,7 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> { |
| 53 | 53 | BrokerageRecordDO::getBizId, bizId); |
| 54 | 54 | } |
| 55 | 55 | |
| 56 | + // TODO @疯狂:mysql 关键字,大写哈;这样看起来清晰点;例如说 SELECT COUNT(1) | |
| 56 | 57 | @Select("select count(1), sum(price) from trade_brokerage_record where user_id = #{userId} and biz_type = #{bizType} and status = #{status}") |
| 57 | 58 | UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId, |
| 58 | 59 | @Param("bizType") Integer bizType, | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/redis/no/TradeOrderNoRedisDAO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.redis.no; | |
| 2 | + | |
| 3 | +import cn.hutool.core.date.DatePattern; | |
| 4 | +import cn.hutool.core.date.DateUtil; | |
| 5 | +import org.springframework.data.redis.core.StringRedisTemplate; | |
| 6 | +import org.springframework.stereotype.Repository; | |
| 7 | + | |
| 8 | +import javax.annotation.Resource; | |
| 9 | +import java.time.LocalDateTime; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 订单序号的 Redis DAO | |
| 13 | + * | |
| 14 | + * @author HUIHUI | |
| 15 | + */ | |
| 16 | +@Repository | |
| 17 | +public class TradeOrderNoRedisDAO { | |
| 18 | + | |
| 19 | + public static final String TRADE_ORDER_NO_PREFIX = "O"; | |
| 20 | + | |
| 21 | + @Resource | |
| 22 | + private StringRedisTemplate stringRedisTemplate; | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 生成序号 | |
| 26 | + * | |
| 27 | + * @param prefix 前缀 | |
| 28 | + * @return 序号 | |
| 29 | + */ | |
| 30 | + public String generate(String prefix) { | |
| 31 | + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN); | |
| 32 | + Long no = stringRedisTemplate.opsForValue().increment(noPrefix); | |
| 33 | + return noPrefix + no; | |
| 34 | + } | |
| 35 | + | |
| 36 | +} | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
| ... | ... | @@ -90,12 +90,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa |
| 90 | 90 | |
| 91 | 91 | @Override |
| 92 | 92 | public TradeAfterSaleDO getAfterSale(Long id) { |
| 93 | - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); | |
| 94 | - // TODO @puhui999;读不到,不要这里报错哈;交给前端报错;一般是读取信息不到,message 提示,然后 close tab; | |
| 95 | - if (afterSale == null) { | |
| 96 | - throw exception(AFTER_SALE_NOT_FOUND); | |
| 97 | - } | |
| 98 | - return afterSale; | |
| 93 | + return tradeAfterSaleMapper.selectById(id); | |
| 99 | 94 | } |
| 100 | 95 | |
| 101 | 96 | // TODO 芋艿:拼团失败,要不要发起售后的方式退款?还是走取消逻辑? | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java
| ... | ... | @@ -5,6 +5,7 @@ import lombok.Data; |
| 5 | 5 | import lombok.NoArgsConstructor; |
| 6 | 6 | |
| 7 | 7 | import javax.validation.constraints.NotBlank; |
| 8 | +import javax.validation.constraints.NotNull; | |
| 8 | 9 | |
| 9 | 10 | /** |
| 10 | 11 | * 佣金 增加 Request BO |
| ... | ... | @@ -24,6 +25,7 @@ public class BrokerageAddReqBO { |
| 24 | 25 | /** |
| 25 | 26 | * 佣金基数 |
| 26 | 27 | */ |
| 28 | + @NotNull(message = "佣金基数不能为空") | |
| 27 | 29 | private Integer basePrice; |
| 28 | 30 | /** |
| 29 | 31 | * 一级佣金(固定) | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/UserBrokerageSummaryBO.java
| ... | ... | @@ -13,6 +13,7 @@ import lombok.NoArgsConstructor; |
| 13 | 13 | @NoArgsConstructor |
| 14 | 14 | @AllArgsConstructor |
| 15 | 15 | public class UserBrokerageSummaryBO { |
| 16 | + | |
| 16 | 17 | /** |
| 17 | 18 | * 佣金数量 |
| 18 | 19 | */ |
| ... | ... | @@ -21,4 +22,5 @@ public class UserBrokerageSummaryBO { |
| 21 | 22 | * 佣金总额 |
| 22 | 23 | */ |
| 23 | 24 | private Integer price; |
| 25 | + | |
| 24 | 26 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordService.java
| ... | ... | @@ -66,5 +66,5 @@ public interface BrokerageRecordService { |
| 66 | 66 | * @param status 佣金状态 |
| 67 | 67 | * @return 用户佣金汇总 |
| 68 | 68 | */ |
| 69 | - UserBrokerageSummaryBO summaryByUserIdAndBizTypeAndStatus(Long userId, Integer bizType, Integer status); | |
| 69 | + UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status); | |
| 70 | 70 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java
| ... | ... | @@ -91,6 +91,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { |
| 91 | 91 | @Override |
| 92 | 92 | @Transactional(rollbackFor = Exception.class) |
| 93 | 93 | public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) { |
| 94 | + // TODO @疯狂:userId 加进去查询,会不会更好一点?万一穿错参数; | |
| 94 | 95 | BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizId(bizType.getType(), bizId); |
| 95 | 96 | if (record == null || ObjectUtil.notEqual(record.getUserId(), userId)) { |
| 96 | 97 | log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId); |
| ... | ... | @@ -209,9 +210,9 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { |
| 209 | 210 | } |
| 210 | 211 | |
| 211 | 212 | @Override |
| 212 | - public UserBrokerageSummaryBO summaryByUserIdAndBizTypeAndStatus(Long userId, Integer bizType, Integer status) { | |
| 213 | + public UserBrokerageSummaryBO getUserBrokerageSummaryByUserId(Long userId, Integer bizType, Integer status) { | |
| 213 | 214 | UserBrokerageSummaryBO summaryBO = brokerageRecordMapper.selectCountAndSumPriceByUserIdAndBizTypeAndStatus(userId, bizType, status); |
| 214 | - return summaryBO == null ? new UserBrokerageSummaryBO(0, 0) : summaryBO; | |
| 215 | + return summaryBO != null ? summaryBO : new UserBrokerageSummaryBO(0, 0); | |
| 215 | 216 | } |
| 216 | 217 | |
| 217 | 218 | @Transactional(rollbackFor = Exception.class) | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java
| ... | ... | @@ -52,7 +52,7 @@ public interface BrokerageUserService { |
| 52 | 52 | * @param id 用户编号 |
| 53 | 53 | * @param enabled 推广资格 |
| 54 | 54 | */ |
| 55 | - void updateBrokerageEnabled(Long id, Boolean enabled); | |
| 55 | + void updateBrokerageUserEnabled(Long id, Boolean enabled); | |
| 56 | 56 | |
| 57 | 57 | /** |
| 58 | 58 | * 获得用户的推广人 |
| ... | ... | @@ -79,20 +79,21 @@ public interface BrokerageUserService { |
| 79 | 79 | void updateUserFrozenPrice(Long id, Integer frozenPrice); |
| 80 | 80 | |
| 81 | 81 | /** |
| 82 | - * 更新用户冻结佣金(减少), 更新用户佣金(增加) | |
| 82 | + * 更新用户冻结佣金(减少),更新用户佣金(增加) | |
| 83 | 83 | * |
| 84 | 84 | * @param id 用户编号 |
| 85 | 85 | * @param frozenPrice 减少冻结佣金(负数) |
| 86 | 86 | */ |
| 87 | 87 | void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice); |
| 88 | 88 | |
| 89 | + // TODO @疯狂:这个后面可能要支持下,二级 | |
| 89 | 90 | /** |
| 90 | 91 | * 获得推广用户数量(一级) |
| 91 | 92 | * |
| 92 | 93 | * @param bindUserId 绑定的推广员编号 |
| 93 | 94 | * @return 推广用户数量 |
| 94 | 95 | */ |
| 95 | - Long getCountByBindUserId(Long bindUserId); | |
| 96 | + Long getBrokerageUserCountByBindUserId(Long bindUserId); | |
| 96 | 97 | |
| 97 | 98 | /** |
| 98 | 99 | * 【会员】绑定推广员 |
| ... | ... | @@ -102,5 +103,6 @@ public interface BrokerageUserService { |
| 102 | 103 | * @param isNewUser 是否为新用户 |
| 103 | 104 | * @return 是否绑定 |
| 104 | 105 | */ |
| 105 | - boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser); | |
| 106 | + boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser); | |
| 107 | + | |
| 106 | 108 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
| ... | ... | @@ -55,23 +55,24 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 55 | 55 | |
| 56 | 56 | @Override |
| 57 | 57 | public void updateBrokerageUserId(Long id, Long bindUserId) { |
| 58 | - // 0. 校验存在 | |
| 58 | + // 校验存在 | |
| 59 | 59 | BrokerageUserDO brokerageUser = validateBrokerageUserExists(id); |
| 60 | + | |
| 61 | + // 情况一:清除推广员 | |
| 60 | 62 | if (bindUserId == null) { |
| 61 | - // 1. 清除推广员 | |
| 63 | + // 清除推广员 | |
| 62 | 64 | brokerageUserMapper.updateBindUserIdAndBindUserTimeToNull(id); |
| 63 | 65 | return; |
| 64 | 66 | } |
| 65 | 67 | |
| 66 | - // 2.1 校验能否绑定 | |
| 68 | + // 情况二:修改推广员 | |
| 67 | 69 | validateCanBindUser(brokerageUser, bindUserId); |
| 68 | - // 2.2 修改推广员 | |
| 69 | 70 | brokerageUserMapper.updateById(new BrokerageUserDO().setId(id) |
| 70 | 71 | .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now())); |
| 71 | 72 | } |
| 72 | 73 | |
| 73 | 74 | @Override |
| 74 | - public void updateBrokerageEnabled(Long id, Boolean enabled) { | |
| 75 | + public void updateBrokerageUserEnabled(Long id, Boolean enabled) { | |
| 75 | 76 | // 校验存在 |
| 76 | 77 | validateBrokerageUserExists(id); |
| 77 | 78 | if (BooleanUtil.isTrue(enabled)) { |
| ... | ... | @@ -130,39 +131,42 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 130 | 131 | } |
| 131 | 132 | |
| 132 | 133 | @Override |
| 133 | - public Long getCountByBindUserId(Long bindUserId) { | |
| 134 | + public Long getBrokerageUserCountByBindUserId(Long bindUserId) { | |
| 135 | + // TODO @疯狂:mapper 封装下哈;不直接在 service 调用这种基础 mapper 的基础方法 | |
| 134 | 136 | return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId); |
| 135 | 137 | } |
| 136 | 138 | |
| 139 | + // TODO @疯狂:因为现在 user 会存在使用验证码直接注册,所以 isNewUser 不太好传递;我们是不是可以约定绑定的时间,createTime 在 30 秒内,就认为新用户; | |
| 137 | 140 | @Override |
| 138 | - public boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser) { | |
| 141 | + public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) { | |
| 142 | + // TODO @疯狂:userId 为空,搞到参数校验里哇; | |
| 139 | 143 | if (userId == null) { |
| 140 | 144 | throw exception(0); |
| 141 | 145 | } |
| 142 | 146 | |
| 143 | - boolean isInsert = false; | |
| 147 | + // 1. 获得分销用户 | |
| 148 | + boolean isNewBrokerageUser = false; | |
| 144 | 149 | BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId); |
| 145 | - // 分销用户不存在的情况:1.新注册 2.旧数据 3.分销功能关闭后又打开 | |
| 146 | - if (brokerageUser == null) { | |
| 147 | - isInsert = true; | |
| 148 | - brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setPrice(0).setFrozenPrice(0); | |
| 150 | + if (brokerageUser == null) { // 分销用户不存在的情况:1. 新注册;2. 旧数据;3. 分销功能关闭后又打开 | |
| 151 | + isNewBrokerageUser = true; | |
| 152 | + brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0); | |
| 149 | 153 | } |
| 150 | 154 | |
| 151 | - // 校验分配配置 | |
| 152 | - boolean validated = validateTradeConfig(brokerageUser, bindUserId, isNewUser); | |
| 155 | + // 2.1 校验是否能绑定用户 | |
| 156 | + boolean validated = isUserCanBind(brokerageUser, bindUserId, isNewUser); | |
| 153 | 157 | if (!validated) { |
| 154 | 158 | return false; |
| 155 | 159 | } |
| 156 | - | |
| 157 | - // 校验能否绑定 | |
| 160 | + // 2.3 校验能否绑定 | |
| 158 | 161 | validateCanBindUser(brokerageUser, bindUserId); |
| 159 | - | |
| 160 | - if (isInsert) { | |
| 162 | + // 2.3 绑定用户 | |
| 163 | + if (isNewBrokerageUser) { | |
| 161 | 164 | Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition(); |
| 162 | - if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { | |
| 163 | - // 人人分销:用户默认就有分销资格 | |
| 165 | + if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格 | |
| 166 | + // TODO @疯狂:应该设置下 brokerageTime,而不是 bindUserTime | |
| 164 | 167 | brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now()); |
| 165 | 168 | } |
| 169 | + // TODO @疯狂:这里是不是要设置 bindUserId、bindUserTime 字段哈; | |
| 166 | 170 | brokerageUserMapper.insert(brokerageUser); |
| 167 | 171 | } else { |
| 168 | 172 | brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId) |
| ... | ... | @@ -171,7 +175,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 171 | 175 | return true; |
| 172 | 176 | } |
| 173 | 177 | |
| 174 | - private boolean validateTradeConfig(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) { | |
| 178 | + private boolean isUserCanBind(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) { | |
| 175 | 179 | // 校验分销功能是否启用 |
| 176 | 180 | TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); |
| 177 | 181 | if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) { |
| ... | ... | @@ -194,7 +198,6 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 194 | 198 | } |
| 195 | 199 | } |
| 196 | 200 | |
| 197 | - validateCanBindUser(user, bindUserId); | |
| 198 | 201 | return true; |
| 199 | 202 | } |
| 200 | 203 | |
| ... | ... | @@ -210,6 +213,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService { |
| 210 | 213 | throw exception(BROKERAGE_BIND_SELF); |
| 211 | 214 | } |
| 212 | 215 | |
| 216 | + // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈 | |
| 213 | 217 | // A->B->A:下级不能绑定自己的上级, A->B->C->A可以!! |
| 214 | 218 | if (Objects.equals(user.getId(), bindUser.getBindUserId())) { |
| 215 | 219 | throw exception(BROKERAGE_BIND_LOOP); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
| ... | ... | @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.lang.Assert; |
| 5 | -import cn.hutool.core.util.IdUtil; | |
| 6 | 5 | import cn.hutool.core.util.ObjectUtil; |
| 7 | 6 | import cn.hutool.core.util.StrUtil; |
| 8 | 7 | import cn.hutool.extra.spring.SpringUtil; |
| ... | ... | @@ -25,12 +24,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 25 | 24 | import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; |
| 26 | 25 | import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; |
| 27 | 26 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 27 | +import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi; | |
| 28 | 28 | import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi; |
| 29 | 29 | import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; |
| 30 | 30 | import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; |
| 31 | -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO; | |
| 32 | 31 | import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; |
| 33 | 32 | import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; |
| 33 | +import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; | |
| 34 | +import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO; | |
| 34 | 35 | import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; |
| 35 | 36 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; |
| 36 | 37 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; |
| ... | ... | @@ -46,6 +47,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 46 | 47 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 47 | 48 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; |
| 48 | 49 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| 50 | +import cn.iocoder.yudao.module.trade.dal.redis.no.TradeOrderNoRedisDAO; | |
| 49 | 51 | import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; |
| 50 | 52 | import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; |
| 51 | 53 | import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; |
| ... | ... | @@ -74,7 +76,7 @@ import java.util.Set; |
| 74 | 76 | |
| 75 | 77 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 76 | 78 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 77 | -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND; | |
| 79 | +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL; | |
| 78 | 80 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID; |
| 79 | 81 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; |
| 80 | 82 | |
| ... | ... | @@ -92,6 +94,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 92 | 94 | private TradeOrderMapper tradeOrderMapper; |
| 93 | 95 | @Resource |
| 94 | 96 | private TradeOrderItemMapper tradeOrderItemMapper; |
| 97 | + @Resource | |
| 98 | + private TradeOrderNoRedisDAO orderNoRedisDAO; | |
| 95 | 99 | |
| 96 | 100 | @Resource |
| 97 | 101 | private CartService cartService; |
| ... | ... | @@ -115,6 +119,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 115 | 119 | @Resource |
| 116 | 120 | private BargainRecordApi bargainRecordApi; |
| 117 | 121 | @Resource |
| 122 | + private SeckillActivityApi seckillActivityApi; | |
| 123 | + @Resource | |
| 124 | + private BargainActivityApi bargainActivityApi; | |
| 125 | + @Resource | |
| 118 | 126 | private MemberUserApi memberUserApi; |
| 119 | 127 | @Resource |
| 120 | 128 | private MemberLevelApi memberLevelApi; |
| ... | ... | @@ -195,22 +203,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 195 | 203 | // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去 |
| 196 | 204 | // 拼团 |
| 197 | 205 | if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { |
| 198 | - MemberUserRespDTO user = memberUserApi.getUser(userId); | |
| 199 | - List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId()); | |
| 200 | - // TODO 拼团一次应该只能选择一种规格的商品 | |
| 201 | - TradeOrderItemDO orderItemDO = orderItems.get(0); | |
| 202 | - if (CollUtil.isNotEmpty(recordRespDTOS)) { | |
| 203 | - List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())); | |
| 204 | - List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS, | |
| 205 | - CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds); | |
| 206 | - combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(), | |
| 207 | - CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount()); | |
| 208 | - } | |
| 209 | - | |
| 210 | - combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user)); | |
| 206 | + createCombinationRecord(userId, createReqVO, orderItems, order); | |
| 211 | 207 | } |
| 212 | 208 | // 3.2 秒杀的特殊逻辑 |
| 213 | - // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除 | |
| 214 | 209 | if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) { |
| 215 | 210 | |
| 216 | 211 | } |
| ... | ... | @@ -220,6 +215,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 220 | 215 | return order; |
| 221 | 216 | } |
| 222 | 217 | |
| 218 | + private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) { | |
| 219 | + MemberUserRespDTO user = memberUserApi.getUser(userId); | |
| 220 | + List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId()); | |
| 221 | + // TODO 拼团一次应该只能选择一种规格的商品 | |
| 222 | + TradeOrderItemDO orderItemDO = orderItems.get(0); | |
| 223 | + if (CollUtil.isNotEmpty(recordRespDTOS)) { | |
| 224 | + List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())); | |
| 225 | + List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS, | |
| 226 | + CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds); | |
| 227 | + combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(), | |
| 228 | + CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount()); | |
| 229 | + } | |
| 230 | + | |
| 231 | + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user)); | |
| 232 | + } | |
| 233 | + | |
| 223 | 234 | // TODO @puhui999:订单超时,自动取消; |
| 224 | 235 | |
| 225 | 236 | /** |
| ... | ... | @@ -246,8 +257,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 246 | 257 | address = validateAddress(userId, createReqVO.getAddressId()); |
| 247 | 258 | } |
| 248 | 259 | TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address); |
| 260 | + String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX); | |
| 249 | 261 | order.setType(validateActivity(createReqVO)); |
| 250 | - order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈; | |
| 262 | + order.setNo(no); | |
| 251 | 263 | order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); |
| 252 | 264 | order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); |
| 253 | 265 | order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); |
| ... | ... | @@ -299,19 +311,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 299 | 311 | private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, |
| 300 | 312 | TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, |
| 301 | 313 | TradePriceCalculateRespBO calculateRespBO) { |
| 302 | - // 下单时扣减商品库存 | |
| 303 | - // TODO @puhui999:扣库存,需要前置; | |
| 314 | + Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum); | |
| 304 | 315 | // 1)如果是秒杀商品:额外扣减秒杀的库存; |
| 305 | - // 2)如果是拼团活动:额外扣减拼团的库存; | |
| 306 | - // 3)如果是砍价活动:额外扣减砍价的库存; | |
| 307 | - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); | |
| 308 | - | |
| 309 | - // 删除购物车商品 | |
| 310 | - Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); | |
| 311 | - if (CollUtil.isNotEmpty(cartIds)) { | |
| 312 | - cartService.deleteCart(userId, cartIds); | |
| 313 | - } | |
| 314 | - | |
| 316 | + if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) { | |
| 317 | + SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO(); | |
| 318 | + updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId()); | |
| 319 | + updateStockReqDTO.setCount(count); | |
| 320 | + updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> { | |
| 321 | + SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item(); | |
| 322 | + item1.setSpuId(item.getSpuId()); | |
| 323 | + item1.setSkuId(item.getSkuId()); | |
| 324 | + item1.setCount(item.getCount()); | |
| 325 | + return item1; | |
| 326 | + })); | |
| 327 | + seckillActivityApi.updateSeckillStock(updateStockReqDTO); | |
| 328 | + } | |
| 329 | + // 2)如果是砍价活动:额外扣减砍价的库存; | |
| 330 | + bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count); | |
| 315 | 331 | // 扣减积分 TODO 芋艿:待实现,需要前置; |
| 316 | 332 | // 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣 |
| 317 | 333 | |
| ... | ... | @@ -321,6 +337,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 321 | 337 | .setOrderId(tradeOrderDO.getId())); |
| 322 | 338 | } |
| 323 | 339 | |
| 340 | + // 下单时扣减商品库存 | |
| 341 | + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); | |
| 342 | + | |
| 343 | + // 删除购物车商品 | |
| 344 | + Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); | |
| 345 | + if (CollUtil.isNotEmpty(cartIds)) { | |
| 346 | + cartService.deleteCart(userId, cartIds); | |
| 347 | + } | |
| 348 | + | |
| 324 | 349 | // 生成预支付 |
| 325 | 350 | createPayOrder(tradeOrderDO, orderItems, calculateRespBO); |
| 326 | 351 | |
| ... | ... | @@ -357,8 +382,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 357 | 382 | // 1、拼团活动 |
| 358 | 383 | if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { |
| 359 | 384 | // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录 |
| 360 | - combinationRecordApi.updateCombinationRecordStatus(new CombinationRecordUpdateStatusReqDTO().setUserId(order.getUserId()) | |
| 361 | - .setOrderId(order.getId()).setStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus()).setStartTime(LocalDateTime.now())); | |
| 385 | + combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now()); | |
| 362 | 386 | } |
| 363 | 387 | // TODO 芋艿:发送订单变化的消息 |
| 364 | 388 | |
| ... | ... | @@ -371,7 +395,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 371 | 395 | // 增加用户经验 |
| 372 | 396 | getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId()); |
| 373 | 397 | // 增加用户佣金 |
| 374 | - getSelf().addBrokerageAsync(order.getUserId(), BrokerageRecordBizTypeEnum.ORDER, order.getId()); | |
| 398 | + getSelf().addBrokerageAsync(order.getUserId(), order.getId()); | |
| 375 | 399 | } |
| 376 | 400 | |
| 377 | 401 | /** |
| ... | ... | @@ -473,11 +497,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 473 | 497 | */ |
| 474 | 498 | private TradeOrderDO validateOrderDeliverable(Long id) { |
| 475 | 499 | TradeOrderDO order = validateOrderExists(id); |
| 476 | - // 校验订单是否是待发货状态 | |
| 477 | - // TODO @puhui999:已经发货,可以重新发货,修改信息; | |
| 478 | - if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) { | |
| 479 | - throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED); | |
| 480 | - } | |
| 481 | 500 | // 校验订单是否退款 |
| 482 | 501 | if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) { |
| 483 | 502 | throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE); |
| ... | ... | @@ -543,20 +562,35 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 543 | 562 | } |
| 544 | 563 | |
| 545 | 564 | @Override |
| 565 | + // TODO @puhui999:考虑事务性 | |
| 546 | 566 | public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) { |
| 547 | 567 | // 校验交易订单 |
| 548 | 568 | TradeOrderDO order = validateOrderExists(reqVO.getId()); |
| 549 | 569 | if (order.getPayStatus()) { |
| 550 | 570 | throw exception(ORDER_UPDATE_PRICE_FAIL_PAID); |
| 551 | 571 | } |
| 552 | - // TODO @puhui999:如果改价,需要校验下是否真的变化; | |
| 553 | - | |
| 554 | - // 更新 | |
| 555 | - // TODO @puhui999:TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下; | |
| 572 | + if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) { | |
| 573 | + throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL); | |
| 574 | + } | |
| 575 | + | |
| 576 | + // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的 | |
| 577 | + List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId()); | |
| 578 | + // TradeOrderItemDO 需要做 adjustPrice 的分摊 | |
| 579 | + int price = reqVO.getAdjustPrice() / itemDOs.size(); | |
| 580 | + itemDOs.forEach(item -> { | |
| 581 | + item.setAdjustPrice(price); | |
| 582 | + }); | |
| 583 | + // 更新 TradeOrderItem | |
| 584 | + // TODO @puhui999:不要整个对象去更新哈;应该 new 一下; | |
| 585 | + tradeOrderItemMapper.updateBatch(itemDOs); | |
| 586 | + // 更新订单 | |
| 587 | + // TODO @puhui999:要考虑多次修改价格,不能单单的 payPrice + 价格; | |
| 556 | 588 | TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO); |
| 557 | 589 | update.setPayPrice(update.getPayPrice() + update.getAdjustPrice()); |
| 558 | 590 | // TODO @芋艿:改价时,赠送的积分,要不要做改动??? |
| 559 | 591 | tradeOrderMapper.updateById(update); |
| 592 | + // 更新支付订单 | |
| 593 | + payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice()); | |
| 560 | 594 | } |
| 561 | 595 | |
| 562 | 596 | @Override |
| ... | ... | @@ -641,7 +675,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 641 | 675 | // 扣减用户经验 |
| 642 | 676 | getSelf().reduceUserExperienceAsync(order.getUserId(), orderRefundPrice, afterSaleId); |
| 643 | 677 | // 更新分佣记录为已失效 |
| 644 | - getSelf().cancelBrokerageAsync(order.getUserId(), BrokerageRecordBizTypeEnum.ORDER, id); | |
| 678 | + getSelf().cancelBrokerageAsync(order.getUserId(), id); | |
| 645 | 679 | } |
| 646 | 680 | |
| 647 | 681 | @Override |
| ... | ... | @@ -751,16 +785,16 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { |
| 751 | 785 | |
| 752 | 786 | |
| 753 | 787 | @Async |
| 754 | - protected void addBrokerageAsync(Long userId, BrokerageRecordBizTypeEnum bizType, Long orderId) { | |
| 788 | + protected void addBrokerageAsync(Long userId, Long orderId) { | |
| 755 | 789 | List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(orderId); |
| 756 | 790 | List<BrokerageAddReqBO> list = convertList(orderItems, |
| 757 | 791 | item -> TradeOrderConvert.INSTANCE.convert(item, productSkuApi.getSku(item.getSkuId()))); |
| 758 | - brokerageRecordService.addBrokerage(userId, bizType, list); | |
| 792 | + brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, list); | |
| 759 | 793 | } |
| 760 | 794 | |
| 761 | 795 | @Async |
| 762 | - protected void cancelBrokerageAsync(Long userId, BrokerageRecordBizTypeEnum bizType, Long orderItemId) { | |
| 763 | - brokerageRecordService.cancelBrokerage(userId, bizType, String.valueOf(orderItemId)); | |
| 796 | + protected void cancelBrokerageAsync(Long userId, Long orderItemId) { | |
| 797 | + brokerageRecordService.cancelBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, String.valueOf(orderItemId)); | |
| 764 | 798 | } |
| 765 | 799 | |
| 766 | 800 | /** | ... | ... |
yudao-module-member/yudao-module-member-biz/pom.xml
| ... | ... | @@ -33,11 +33,6 @@ |
| 33 | 33 | <artifactId>yudao-module-infra-api</artifactId> |
| 34 | 34 | <version>${revision}</version> |
| 35 | 35 | </dependency> |
| 36 | - <dependency> | |
| 37 | - <groupId>cn.iocoder.boot</groupId> | |
| 38 | - <artifactId>yudao-module-trade-api</artifactId> | |
| 39 | - <version>${revision}</version> | |
| 40 | - </dependency> | |
| 41 | 36 | |
| 42 | 37 | <!-- 业务组件 --> |
| 43 | 38 | <dependency> | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
| ... | ... | @@ -28,6 +28,17 @@ tenant-id: {{appTenentId}} |
| 28 | 28 | "code": 9999 |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | +### 请求 /social-login 接口 => 成功 | |
| 32 | +POST {{appApi}}/member/auth/social-login | |
| 33 | +Content-Type: application/json | |
| 34 | +tenant-id: {{appTenentId}} | |
| 35 | + | |
| 36 | +{ | |
| 37 | + "type": 34, | |
| 38 | + "code": "0e1oc9000CTjFQ1oim200bhtb61oc90g", | |
| 39 | + "state": "default" | |
| 40 | +} | |
| 41 | + | |
| 31 | 42 | ### 请求 /weixin-mini-app-login 接口 => 成功 |
| 32 | 43 | POST {{appApi}}/member/auth/weixin-mini-app-login |
| 33 | 44 | Content-Type: application/json |
| ... | ... | @@ -38,7 +49,6 @@ tenant-id: {{appTenentId}} |
| 38 | 49 | "loginCode": "001frTkl21JUf94VGxol2hSlff1frTkR" |
| 39 | 50 | } |
| 40 | 51 | |
| 41 | - | |
| 42 | 52 | ### 请求 /logout 接口 => 成功 |
| 43 | 53 | POST {{appApi}}/member/auth/logout |
| 44 | 54 | Content-Type: application/json | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthLoginRespVO.java
| ... | ... | @@ -27,4 +27,12 @@ public class AppAuthLoginRespVO { |
| 27 | 27 | @Schema(description = "过期时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 28 | 28 | private LocalDateTime expiresTime; |
| 29 | 29 | |
| 30 | + /** | |
| 31 | + * 仅社交登录、社交绑定时会返回 | |
| 32 | + * | |
| 33 | + * 为什么需要返回?微信公众号、微信小程序支付需要传递 openid 给支付接口 | |
| 34 | + */ | |
| 35 | + @Schema(description = "社交用户 openid", example = "qq768") | |
| 36 | + private String openid; | |
| 37 | + | |
| 30 | 38 | } | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java
| ... | ... | @@ -8,8 +8,6 @@ import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; |
| 8 | 8 | import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; |
| 9 | 9 | import cn.iocoder.yudao.module.member.service.level.MemberLevelService; |
| 10 | 10 | import cn.iocoder.yudao.module.member.service.user.MemberUserService; |
| 11 | -import cn.iocoder.yudao.module.trade.api.brokerage.BrokerageApi; | |
| 12 | -import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO; | |
| 13 | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 14 | 12 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 15 | 13 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -18,7 +16,6 @@ import org.springframework.web.bind.annotation.*; |
| 18 | 16 | |
| 19 | 17 | import javax.annotation.Resource; |
| 20 | 18 | import javax.validation.Valid; |
| 21 | -import java.util.Optional; | |
| 22 | 19 | |
| 23 | 20 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 24 | 21 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| ... | ... | @@ -32,23 +29,16 @@ public class AppMemberUserController { |
| 32 | 29 | |
| 33 | 30 | @Resource |
| 34 | 31 | private MemberUserService userService; |
| 35 | - | |
| 36 | 32 | @Resource |
| 37 | 33 | private MemberLevelService levelService; |
| 38 | 34 | |
| 39 | - @Resource | |
| 40 | - private BrokerageApi brokerageApi; | |
| 41 | - | |
| 42 | 35 | @GetMapping("/get") |
| 43 | 36 | @Operation(summary = "获得基本信息") |
| 44 | 37 | @PreAuthenticated |
| 45 | 38 | public CommonResult<AppMemberUserInfoRespVO> getUserInfo() { |
| 46 | 39 | MemberUserDO user = userService.getUser(getLoginUserId()); |
| 47 | 40 | MemberLevelDO level = levelService.getLevel(user.getLevelId()); |
| 48 | - BrokerageUserDTO brokerageUser = brokerageApi.getBrokerageUser(user.getId()); | |
| 49 | - return success(MemberUserConvert.INSTANCE.convert(user, level) | |
| 50 | - .setBrokerageEnabled(Optional.ofNullable(brokerageUser).map(BrokerageUserDTO::getBrokerageEnabled).orElse(false)) | |
| 51 | - ); | |
| 41 | + return success(MemberUserConvert.INSTANCE.convert(user, level)); | |
| 52 | 42 | } |
| 53 | 43 | |
| 54 | 44 | @PutMapping("/update") | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java
| ... | ... | @@ -25,7 +25,7 @@ public interface AuthConvert { |
| 25 | 25 | SmsCodeUseReqDTO convert(AppMemberUserResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); |
| 26 | 26 | SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String usedIp); |
| 27 | 27 | |
| 28 | - AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean); | |
| 28 | + AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean, String openid); | |
| 29 | 29 | |
| 30 | 30 | SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean); |
| 31 | 31 | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
| ... | ... | @@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; |
| 20 | 20 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 21 | 21 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; |
| 22 | 22 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 23 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 23 | 24 | import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; |
| 24 | 25 | import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; |
| 25 | 26 | import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants; |
| ... | ... | @@ -65,13 +66,14 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 65 | 66 | MemberUserDO user = login0(reqVO.getMobile(), reqVO.getPassword()); |
| 66 | 67 | |
| 67 | 68 | // 如果 socialType 非空,说明需要绑定社交用户 |
| 69 | + String openid = null; | |
| 68 | 70 | if (reqVO.getSocialType() != null) { |
| 69 | - socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | |
| 71 | + openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | |
| 70 | 72 | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); |
| 71 | 73 | } |
| 72 | 74 | |
| 73 | 75 | // 创建 Token 令牌,记录登录日志 |
| 74 | - return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE); | |
| 76 | + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, openid); | |
| 75 | 77 | } |
| 76 | 78 | |
| 77 | 79 | @Override |
| ... | ... | @@ -86,32 +88,33 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 86 | 88 | Assert.notNull(user, "获取用户失败,结果为空"); |
| 87 | 89 | |
| 88 | 90 | // 如果 socialType 非空,说明需要绑定社交用户 |
| 91 | + String openid = null; | |
| 89 | 92 | if (reqVO.getSocialType() != null) { |
| 90 | - socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | |
| 93 | + openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | |
| 91 | 94 | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); |
| 92 | 95 | } |
| 93 | 96 | |
| 94 | 97 | // 创建 Token 令牌,记录登录日志 |
| 95 | - return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS); | |
| 98 | + return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS, openid); | |
| 96 | 99 | } |
| 97 | 100 | |
| 98 | 101 | @Override |
| 99 | 102 | public AppAuthLoginRespVO socialLogin(AppAuthSocialLoginReqVO reqVO) { |
| 100 | 103 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 101 | - Long userId = socialUserApi.getBindUserId(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), | |
| 104 | + SocialUserRespDTO socialUser = socialUserApi.getSocialUser(UserTypeEnum.MEMBER.getValue(), reqVO.getType(), | |
| 102 | 105 | reqVO.getCode(), reqVO.getState()); |
| 103 | - if (userId == null) { | |
| 106 | + if (socialUser == null) { | |
| 104 | 107 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
| 105 | 108 | } |
| 106 | 109 | |
| 107 | 110 | // 自动登录 |
| 108 | - MemberUserDO user = userService.getUser(userId); | |
| 111 | + MemberUserDO user = userService.getUser(socialUser.getUserId()); | |
| 109 | 112 | if (user == null) { |
| 110 | 113 | throw exception(USER_NOT_EXISTS); |
| 111 | 114 | } |
| 112 | 115 | |
| 113 | 116 | // 创建 Token 令牌,记录登录日志 |
| 114 | - return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL); | |
| 117 | + return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, socialUser.getOpenid()); | |
| 115 | 118 | } |
| 116 | 119 | |
| 117 | 120 | @Override |
| ... | ... | @@ -129,14 +132,15 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 129 | 132 | Assert.notNull(user, "获取用户失败,结果为空"); |
| 130 | 133 | |
| 131 | 134 | // 绑定社交用户 |
| 132 | - socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | |
| 135 | + String openid = socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), | |
| 133 | 136 | SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), "")); |
| 134 | 137 | |
| 135 | 138 | // 创建 Token 令牌,记录登录日志 |
| 136 | - return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL); | |
| 139 | + return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL, openid); | |
| 137 | 140 | } |
| 138 | 141 | |
| 139 | - private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, LoginLogTypeEnum logType) { | |
| 142 | + private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, | |
| 143 | + LoginLogTypeEnum logType, String openid) { | |
| 140 | 144 | // 插入登陆日志 |
| 141 | 145 | createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS); |
| 142 | 146 | // 创建 Token 令牌 |
| ... | ... | @@ -144,7 +148,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 144 | 148 | .setUserId(user.getId()).setUserType(getUserType().getValue()) |
| 145 | 149 | .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT)); |
| 146 | 150 | // 构建返回结果 |
| 147 | - return AuthConvert.INSTANCE.convert(accessTokenRespDTO); | |
| 151 | + return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid); | |
| 148 | 152 | } |
| 149 | 153 | |
| 150 | 154 | @Override |
| ... | ... | @@ -231,7 +235,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { |
| 231 | 235 | public AppAuthLoginRespVO refreshToken(String refreshToken) { |
| 232 | 236 | OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, |
| 233 | 237 | OAuth2ClientConstants.CLIENT_ID_DEFAULT); |
| 234 | - return AuthConvert.INSTANCE.convert(accessTokenDO); | |
| 238 | + return AuthConvert.INSTANCE.convert(accessTokenDO, null); | |
| 235 | 239 | } |
| 236 | 240 | |
| 237 | 241 | private void createLogoutLog(Long userId) { | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java
| ... | ... | @@ -29,4 +29,13 @@ public interface PayOrderApi { |
| 29 | 29 | */ |
| 30 | 30 | PayOrderRespDTO getOrder(Long id); |
| 31 | 31 | |
| 32 | + // TODO @puhui999:可以去掉 byId;然后 payOrderId 参数改成 id; | |
| 33 | + /** | |
| 34 | + * 更新支付订单价格 | |
| 35 | + * | |
| 36 | + * @param payOrderId 支付单编号 | |
| 37 | + * @param payPrice 支付单价格 | |
| 38 | + */ | |
| 39 | + void updatePayOrderPriceById(Long payOrderId, Integer payPrice); | |
| 40 | + | |
| 32 | 41 | } | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
| ... | ... | @@ -28,6 +28,7 @@ public interface ErrorCodeConstants { |
| 28 | 28 | ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}"); |
| 29 | 29 | ErrorCode ORDER_REFUND_FAIL_STATUS_ERROR = new ErrorCode(1007002005, "支付订单退款失败,原因:状态不是已支付或已退款"); |
| 30 | 30 | ErrorCode ORDER_UPDATE_PRICE_FAIL_PAID = new ErrorCode(1007002006, "支付订单调价失败,原因:支付订单已付款,不能调价"); |
| 31 | + ErrorCode ORDER_UPDATE_PRICE_FAIL_EQUAL = new ErrorCode(1007002007, "支付订单调价失败,原因:价格没有变化"); | |
| 31 | 32 | |
| 32 | 33 | // ========== ORDER 模块(拓展单) 1007003000 ========== |
| 33 | 34 | ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在"); | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
| ... | ... | @@ -31,4 +31,9 @@ public class PayOrderApiImpl implements PayOrderApi { |
| 31 | 31 | return PayOrderConvert.INSTANCE.convert2(order); |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | + @Override | |
| 35 | + public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) { | |
| 36 | + payOrderService.updatePayOrderPriceById(payOrderId, payPrice); | |
| 37 | + } | |
| 38 | + | |
| 34 | 39 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
| ... | ... | @@ -6,14 +6,15 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 7 | 7 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 8 | 8 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 9 | -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; | |
| 10 | 9 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; |
| 11 | 10 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; |
| 12 | 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 13 | 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 14 | 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 14 | +import cn.iocoder.yudao.module.pay.framework.pay.wallet.WalletPayClient; | |
| 15 | 15 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 16 | 16 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 17 | +import com.google.common.collect.Maps; | |
| 17 | 18 | import io.swagger.v3.oas.annotations.Operation; |
| 18 | 19 | import io.swagger.v3.oas.annotations.Parameter; |
| 19 | 20 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | ... | @@ -25,12 +26,17 @@ import javax.annotation.Resource; |
| 25 | 26 | import javax.servlet.http.HttpServletResponse; |
| 26 | 27 | import javax.validation.Valid; |
| 27 | 28 | import java.io.IOException; |
| 28 | -import java.util.*; | |
| 29 | +import java.util.ArrayList; | |
| 30 | +import java.util.List; | |
| 31 | +import java.util.Map; | |
| 32 | +import java.util.Objects; | |
| 29 | 33 | |
| 30 | 34 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 31 | 35 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 32 | 36 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; |
| 33 | 37 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 38 | +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; | |
| 39 | +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; | |
| 34 | 40 | |
| 35 | 41 | @Tag(name = "管理后台 - 支付订单") |
| 36 | 42 | @RestController |
| ... | ... | @@ -70,13 +76,16 @@ public class PayOrderController { |
| 70 | 76 | @PostMapping("/submit") |
| 71 | 77 | @Operation(summary = "提交支付订单") |
| 72 | 78 | public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { |
| 73 | - // 钱包支付需要 额外传 user_id 和 user_type | |
| 79 | + // 1. 钱包支付事,需要额外传 user_id 和 user_type | |
| 74 | 80 | if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { |
| 75 | - Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? new HashMap<>(8) : reqVO.getChannelExtras(); | |
| 76 | - channelExtras.put("user_id", String.valueOf(WebFrameworkUtils.getLoginUserId())); | |
| 77 | - channelExtras.put("user_type", String.valueOf(WebFrameworkUtils.getLoginUserType())); | |
| 81 | + Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? | |
| 82 | + Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras(); | |
| 83 | + channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId())); | |
| 84 | + channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType())); | |
| 78 | 85 | reqVO.setChannelExtras(channelExtras); |
| 79 | 86 | } |
| 87 | + | |
| 88 | + // 2. 提交支付 | |
| 80 | 89 | PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP()); |
| 81 | 90 | return success(respVO); |
| 82 | 91 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java
| ... | ... | @@ -37,7 +37,7 @@ public class AppPayWalletController { |
| 37 | 37 | @Operation(summary = "获取钱包") |
| 38 | 38 | @PreAuthenticated |
| 39 | 39 | public CommonResult<AppPayWalletRespVO> getPayWallet() { |
| 40 | - PayWalletDO wallet = payWalletService.getOrCreatePayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue()); | |
| 40 | + PayWalletDO wallet = payWalletService.getOrCreateWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue()); | |
| 41 | 41 | return success(PayWalletConvert.INSTANCE.convert(wallet)); |
| 42 | 42 | } |
| 43 | 43 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/wallet/AppPayWalletRespVO.java
| ... | ... | @@ -11,9 +11,9 @@ public class AppPayWalletRespVO { |
| 11 | 11 | private Integer balance; |
| 12 | 12 | |
| 13 | 13 | @Schema(description = "累计支出, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") |
| 14 | - private Long totalExpense; | |
| 14 | + private Integer totalExpense; | |
| 15 | 15 | |
| 16 | 16 | @Schema(description = "累计充值, 单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000") |
| 17 | - private Long totalRecharge; | |
| 17 | + private Integer totalRecharge; | |
| 18 | 18 | |
| 19 | 19 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletTransactionConvert.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.wallet; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionRespVO; |
| 5 | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 6 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | |
| 6 | 7 | import org.mapstruct.Mapper; |
| 7 | 8 | import org.mapstruct.factory.Mappers; |
| 8 | 9 | |
| ... | ... | @@ -12,4 +13,7 @@ public interface PayWalletTransactionConvert { |
| 12 | 13 | PayWalletTransactionConvert INSTANCE = Mappers.getMapper(PayWalletTransactionConvert.class); |
| 13 | 14 | |
| 14 | 15 | PageResult<AppPayWalletTransactionRespVO> convertPage(PageResult<PayWalletTransactionDO> page); |
| 16 | + | |
| 17 | + PayWalletTransactionDO convert(CreateWalletTransactionBO bean); | |
| 18 | + | |
| 15 | 19 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java
| ... | ... | @@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.pay.dal.mysql.wallet; |
| 3 | 3 | |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 6 | -import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | |
| 7 | -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |
| 6 | +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | |
| 8 | 7 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 8 | |
| 10 | 9 | @Mapper |
| ... | ... | @@ -16,52 +15,32 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> { |
| 16 | 15 | } |
| 17 | 16 | |
| 18 | 17 | /** |
| 19 | - * 当余额减少时候更新 | |
| 18 | + * 当消费退款时候, 更新钱包 | |
| 20 | 19 | * |
| 21 | - * @param bizType 业务类型 | |
| 22 | - * @param balance 当前余额 | |
| 23 | - * @param totalRecharge 当前累计充值 | |
| 24 | - * @param totalExpense 当前累计支出 | |
| 25 | - * @param price 支出的金额 | |
| 20 | + * @param price 消费金额 | |
| 26 | 21 | * @param id 钱包 id |
| 27 | 22 | */ |
| 28 | - default int updateWhenDecBalance(PayWalletBizTypeEnum bizType, Integer balance, Long totalRecharge, | |
| 29 | - Long totalExpense, Integer price, Long id) { | |
| 30 | - PayWalletDO updateDO = new PayWalletDO().setBalance(balance - price); | |
| 31 | - if(bizType == PayWalletBizTypeEnum.PAYMENT){ | |
| 32 | - updateDO.setTotalExpense(totalExpense + price); | |
| 33 | - } | |
| 34 | - if (bizType == PayWalletBizTypeEnum.RECHARGE_REFUND) { | |
| 35 | - updateDO.setTotalRecharge(totalRecharge - price); | |
| 36 | - } | |
| 37 | - return update(updateDO, | |
| 38 | - new LambdaQueryWrapper<PayWalletDO>().eq(PayWalletDO::getId, id) | |
| 39 | - .eq(PayWalletDO::getBalance, balance) | |
| 40 | - .ge(PayWalletDO::getBalance, price)); | |
| 23 | + default int updateWhenConsumptionRefund(Integer price, Long id){ | |
| 24 | + LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>() | |
| 25 | + .setSql(" balance = balance + " + price | |
| 26 | + + ", total_expense = total_expense - " + price) | |
| 27 | + .eq(PayWalletDO::getId, id); | |
| 28 | + return update(null, lambdaUpdateWrapper); | |
| 41 | 29 | } |
| 42 | 30 | |
| 43 | 31 | /** |
| 44 | - * 当余额增加时候更新 | |
| 32 | + * 当消费时候, 更新钱包 | |
| 45 | 33 | * |
| 46 | - * @param bizType 业务类型 | |
| 47 | - * @param balance 当前余额 | |
| 48 | - * @param totalRecharge 当前累计充值 | |
| 49 | - * @param totalExpense 当前累计支出 | |
| 50 | - * @param price 金额 | |
| 34 | + * @param price 消费金额 | |
| 51 | 35 | * @param id 钱包 id |
| 52 | 36 | */ |
| 53 | - default int updateWhenIncBalance(PayWalletBizTypeEnum bizType, Integer balance, Long totalRecharge, | |
| 54 | - Long totalExpense, Integer price, Long id) { | |
| 55 | - PayWalletDO updateDO = new PayWalletDO().setBalance(balance + price); | |
| 56 | - if (bizType == PayWalletBizTypeEnum.PAYMENT_REFUND) { | |
| 57 | - updateDO.setTotalExpense(totalExpense - price); | |
| 58 | - } | |
| 59 | - if (bizType == PayWalletBizTypeEnum.RECHARGE) { | |
| 60 | - updateDO.setTotalExpense(totalRecharge + price); | |
| 61 | - } | |
| 62 | - return update(updateDO, | |
| 63 | - new LambdaQueryWrapper<PayWalletDO>().eq(PayWalletDO::getId, id) | |
| 64 | - .eq(PayWalletDO::getBalance, balance)); | |
| 37 | + default int updateWhenConsumption(Integer price, Long id){ | |
| 38 | + LambdaUpdateWrapper<PayWalletDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<PayWalletDO>() | |
| 39 | + .setSql(" balance = balance - " + price | |
| 40 | + + ", total_expense = total_expense + " + price) | |
| 41 | + .eq(PayWalletDO::getId, id) | |
| 42 | + .ge(PayWalletDO::getBalance, price); // cas 逻辑 | |
| 43 | + return update(null, lambdaUpdateWrapper); | |
| 65 | 44 | } |
| 66 | 45 | } |
| 67 | 46 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java
| ... | ... | @@ -37,13 +37,13 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FO |
| 37 | 37 | @Slf4j |
| 38 | 38 | public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 39 | 39 | |
| 40 | - private PayWalletService wallService; | |
| 40 | + public static final String USER_ID_KEY = "user_id"; | |
| 41 | + public static final String USER_TYPE_KEY = "user_type"; | |
| 41 | 42 | |
| 43 | + private PayWalletService wallService; | |
| 42 | 44 | private PayWalletTransactionService walletTransactionService; |
| 43 | - | |
| 44 | - private PayOrderService payOrderService; | |
| 45 | - | |
| 46 | - private PayRefundService payRefundService; | |
| 45 | + private PayOrderService orderService; | |
| 46 | + private PayRefundService refundService; | |
| 47 | 47 | |
| 48 | 48 | public WalletPayClient(Long channelId, NonePayClientConfig config) { |
| 49 | 49 | super(channelId, PayChannelEnum.WALLET.getCode(), config); |
| ... | ... | @@ -62,12 +62,12 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 62 | 62 | @Override |
| 63 | 63 | protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { |
| 64 | 64 | try { |
| 65 | - String userId = MapUtil.getStr(reqDTO.getChannelExtras(), "user_id"); | |
| 66 | - String userType = MapUtil.getStr(reqDTO.getChannelExtras(), "user_type"); | |
| 67 | - Assert.notEmpty(userId, "用户 id 不能为空"); | |
| 68 | - Assert.notEmpty(userType, "用户类型不能为空"); | |
| 69 | - PayWalletTransactionDO transaction = wallService.orderPay(Long.valueOf(userId), Integer.valueOf(userType), | |
| 70 | - reqDTO.getOutTradeNo(), reqDTO.getPrice()); | |
| 65 | + Long userId = MapUtil.getLong(reqDTO.getChannelExtras(), USER_ID_KEY); | |
| 66 | + Integer userType = MapUtil.getInt(reqDTO.getChannelExtras(), USER_TYPE_KEY); | |
| 67 | + Assert.notNull(userId, "用户 id 不能为空"); | |
| 68 | + Assert.notNull(userType, "用户类型不能为空"); | |
| 69 | + PayWalletTransactionDO transaction = wallService.orderPay(userId, userType, reqDTO.getOutTradeNo(), | |
| 70 | + reqDTO.getPrice()); | |
| 71 | 71 | return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(), |
| 72 | 72 | transaction.getCreateTime(), |
| 73 | 73 | reqDTO.getOutTradeNo(), transaction); |
| ... | ... | @@ -92,10 +92,10 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 92 | 92 | |
| 93 | 93 | @Override |
| 94 | 94 | protected PayOrderRespDTO doGetOrder(String outTradeNo) { |
| 95 | - if (payOrderService == null) { | |
| 96 | - payOrderService = SpringUtil.getBean(PayOrderService.class); | |
| 95 | + if (orderService == null) { | |
| 96 | + orderService = SpringUtil.getBean(PayOrderService.class); | |
| 97 | 97 | } |
| 98 | - PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo); | |
| 98 | + PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); | |
| 99 | 99 | // 支付交易拓展单不存在, 返回关闭状态 |
| 100 | 100 | if (orderExtension == null) { |
| 101 | 101 | return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()), |
| ... | ... | @@ -147,10 +147,10 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 147 | 147 | |
| 148 | 148 | @Override |
| 149 | 149 | protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { |
| 150 | - if (payRefundService == null) { | |
| 151 | - payRefundService = SpringUtil.getBean(PayRefundService.class); | |
| 150 | + if (refundService == null) { | |
| 151 | + refundService = SpringUtil.getBean(PayRefundService.class); | |
| 152 | 152 | } |
| 153 | - PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo); | |
| 153 | + PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo); | |
| 154 | 154 | // 支付退款单不存在, 返回退款失败状态 |
| 155 | 155 | if (payRefund == null) { |
| 156 | 156 | return PayRefundRespDTO.failureOf(String.valueOf(REFUND_NOT_FOUND), REFUND_NOT_FOUND.getMsg(), | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
| ... | ... | @@ -33,7 +33,7 @@ public interface PayOrderService { |
| 33 | 33 | /** |
| 34 | 34 | * 获得支付订单 |
| 35 | 35 | * |
| 36 | - * @param appId 应用编号 | |
| 36 | + * @param appId 应用编号 | |
| 37 | 37 | * @param merchantOrderId 商户订单编号 |
| 38 | 38 | * @return 支付订单 |
| 39 | 39 | */ |
| ... | ... | @@ -75,7 +75,7 @@ public interface PayOrderService { |
| 75 | 75 | * 提交支付 |
| 76 | 76 | * 此时,会发起支付渠道的调用 |
| 77 | 77 | * |
| 78 | - * @param reqVO 提交请求 | |
| 78 | + * @param reqVO 提交请求 | |
| 79 | 79 | * @param userIp 提交 IP |
| 80 | 80 | * @return 提交结果 |
| 81 | 81 | */ |
| ... | ... | @@ -93,12 +93,20 @@ public interface PayOrderService { |
| 93 | 93 | /** |
| 94 | 94 | * 更新支付订单的退款金额 |
| 95 | 95 | * |
| 96 | - * @param id 编号 | |
| 96 | + * @param id 编号 | |
| 97 | 97 | * @param incrRefundPrice 增加的退款金额 |
| 98 | 98 | */ |
| 99 | 99 | void updateOrderRefundPrice(Long id, Integer incrRefundPrice); |
| 100 | 100 | |
| 101 | 101 | /** |
| 102 | + * 更新支付订单价格 | |
| 103 | + * | |
| 104 | + * @param payOrderId 支付单编号 | |
| 105 | + * @param payPrice 支付单价格 | |
| 106 | + */ | |
| 107 | + void updatePayOrderPriceById(Long payOrderId, Integer payPrice); | |
| 108 | + | |
| 109 | + /** | |
| 102 | 110 | * 获得支付订单 |
| 103 | 111 | * |
| 104 | 112 | * @param id 编号 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
| ... | ... | @@ -412,6 +412,18 @@ public class PayOrderServiceImpl implements PayOrderService { |
| 412 | 412 | } |
| 413 | 413 | |
| 414 | 414 | @Override |
| 415 | + public void updatePayOrderPriceById(Long payOrderId, Integer payPrice) { | |
| 416 | + // TODO @puhui999:不能直接这样修改哈;应该只有未支付状态的订单才可以改;另外,如果价格如果没变,可以直接 return 哈; | |
| 417 | + PayOrderDO order = orderMapper.selectById(payOrderId); | |
| 418 | + if (order == null) { | |
| 419 | + throw exception(ORDER_NOT_FOUND); | |
| 420 | + } | |
| 421 | + | |
| 422 | + order.setPrice(payPrice); | |
| 423 | + orderMapper.updateById(order); | |
| 424 | + } | |
| 425 | + | |
| 426 | + @Override | |
| 415 | 427 | public PayOrderExtensionDO getOrderExtension(Long id) { |
| 416 | 428 | return orderExtensionMapper.selectById(id); |
| 417 | 429 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
| ... | ... | @@ -12,12 +12,14 @@ import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; |
| 12 | 12 | public interface PayWalletService { |
| 13 | 13 | |
| 14 | 14 | /** |
| 15 | - * 获取钱包信息,如果不存在创建钱包。由于用户注册时候不会创建钱包 | |
| 15 | + * 获取钱包信息 | |
| 16 | + * | |
| 17 | + * 如果不存在,则创建钱包。由于用户注册时候不会创建钱包 | |
| 16 | 18 | * |
| 17 | 19 | * @param userId 用户编号 |
| 18 | 20 | * @param userType 用户类型 |
| 19 | 21 | */ |
| 20 | - PayWalletDO getOrCreatePayWallet(Long userId, Integer userType); | |
| 22 | + PayWalletDO getOrCreateWallet(Long userId, Integer userType); | |
| 21 | 23 | |
| 22 | 24 | /** |
| 23 | 25 | * 钱包订单支付 |
| ... | ... | @@ -29,6 +31,14 @@ public interface PayWalletService { |
| 29 | 31 | */ |
| 30 | 32 | PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price); |
| 31 | 33 | |
| 34 | + /** | |
| 35 | + * 钱包订单支付退款 | |
| 36 | + * | |
| 37 | + * @param outRefundNo 外部退款号 | |
| 38 | + * @param refundPrice 退款金额 | |
| 39 | + * @param reason 退款原因 | |
| 40 | + */ | |
| 41 | + PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason); | |
| 32 | 42 | |
| 33 | 43 | /** |
| 34 | 44 | * 扣减钱包余额 |
| ... | ... | @@ -43,7 +53,6 @@ public interface PayWalletService { |
| 43 | 53 | PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType, |
| 44 | 54 | Long bizId, PayWalletBizTypeEnum bizType, Integer price); |
| 45 | 55 | |
| 46 | - | |
| 47 | 56 | /** |
| 48 | 57 | * 增加钱包余额 |
| 49 | 58 | * |
| ... | ... | @@ -57,13 +66,4 @@ public interface PayWalletService { |
| 57 | 66 | PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, |
| 58 | 67 | Long bizId, PayWalletBizTypeEnum bizType, Integer price); |
| 59 | 68 | |
| 60 | - /** | |
| 61 | - * 钱包订单支付退款 | |
| 62 | - * | |
| 63 | - * @param outRefundNo 外部退款号 | |
| 64 | - * @param refundPrice 退款金额 | |
| 65 | - * @param reason 退款原因 | |
| 66 | - */ | |
| 67 | - PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason); | |
| 68 | - | |
| 69 | 69 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
| ... | ... | @@ -6,10 +6,10 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 6 | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 7 | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 8 | 8 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper; |
| 9 | -import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | |
| 10 | 9 | import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; |
| 11 | 10 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 12 | 11 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 12 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | |
| 13 | 13 | import lombok.extern.slf4j.Slf4j; |
| 14 | 14 | import org.springframework.context.annotation.Lazy; |
| 15 | 15 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -18,7 +18,6 @@ import org.springframework.transaction.annotation.Transactional; |
| 18 | 18 | import javax.annotation.Resource; |
| 19 | 19 | import java.time.LocalDateTime; |
| 20 | 20 | |
| 21 | -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.TOO_MANY_REQUESTS; | |
| 22 | 21 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 23 | 22 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; |
| 24 | 23 | import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYMENT; |
| ... | ... | @@ -33,135 +32,55 @@ import static cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum.PAYM |
| 33 | 32 | @Slf4j |
| 34 | 33 | public class PayWalletServiceImpl implements PayWalletService { |
| 35 | 34 | |
| 36 | - /** | |
| 37 | - * 余额支付的 no 前缀 | |
| 38 | - */ | |
| 39 | - private static final String WALLET_PAY_NO_PREFIX = "WP"; | |
| 40 | - /** | |
| 41 | - * 余额退款的 no 前缀 | |
| 42 | - */ | |
| 43 | - private static final String WALLET_REFUND_NO_PREFIX = "WR"; | |
| 44 | - | |
| 45 | - @Resource | |
| 46 | - private PayWalletMapper payWalletMapper; | |
| 47 | 35 | @Resource |
| 48 | - private PayNoRedisDAO noRedisDAO; | |
| 49 | - | |
| 36 | + private PayWalletMapper walletMapper; | |
| 50 | 37 | @Resource |
| 51 | - private PayWalletTransactionService payWalletTransactionService; | |
| 38 | + private PayWalletTransactionService walletTransactionService; | |
| 52 | 39 | @Resource |
| 53 | 40 | @Lazy |
| 54 | - private PayOrderService payOrderService; | |
| 41 | + private PayOrderService orderService; | |
| 55 | 42 | @Resource |
| 56 | 43 | @Lazy |
| 57 | - private PayRefundService payRefundService; | |
| 44 | + private PayRefundService refundService; | |
| 58 | 45 | |
| 59 | 46 | @Override |
| 60 | - public PayWalletDO getOrCreatePayWallet(Long userId, Integer userType) { | |
| 61 | - PayWalletDO payWalletDO = payWalletMapper.selectByUserIdAndType(userId, userType); | |
| 62 | - if (payWalletDO == null) { | |
| 63 | - payWalletDO = new PayWalletDO(); | |
| 64 | - payWalletDO.setUserId(userId); | |
| 65 | - payWalletDO.setUserType(userType); | |
| 66 | - payWalletDO.setBalance(0); | |
| 67 | - payWalletDO.setTotalExpense(0L); | |
| 68 | - payWalletDO.setTotalRecharge(0L); | |
| 69 | - payWalletDO.setCreateTime(LocalDateTime.now()); | |
| 70 | - payWalletMapper.insert(payWalletDO); | |
| 47 | + public PayWalletDO getOrCreateWallet(Long userId, Integer userType) { | |
| 48 | + PayWalletDO wallet = walletMapper.selectByUserIdAndType(userId, userType); | |
| 49 | + if (wallet == null) { | |
| 50 | + wallet = new PayWalletDO().setUserId(userId).setUserType(userType) | |
| 51 | + .setBalance(0).setTotalExpense(0).setTotalRecharge(0); | |
| 52 | + wallet.setCreateTime(LocalDateTime.now()); | |
| 53 | + walletMapper.insert(wallet); | |
| 71 | 54 | } |
| 72 | - return payWalletDO; | |
| 55 | + return wallet; | |
| 73 | 56 | } |
| 74 | 57 | |
| 75 | - | |
| 76 | 58 | @Override |
| 77 | 59 | @Transactional(rollbackFor = Exception.class) |
| 78 | 60 | public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) { |
| 79 | - // 判断支付交易拓展单是否存 | |
| 80 | - PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo); | |
| 61 | + // 1. 判断支付交易拓展单是否存 | |
| 62 | + PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); | |
| 81 | 63 | if (orderExtension == null) { |
| 82 | 64 | throw exception(ORDER_EXTENSION_NOT_FOUND); |
| 83 | 65 | } |
| 66 | + // 2. 扣减余额 | |
| 84 | 67 | return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price); |
| 85 | 68 | } |
| 86 | 69 | |
| 87 | 70 | @Override |
| 88 | - public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType, | |
| 89 | - Long bizId, PayWalletBizTypeEnum bizType, Integer price) { | |
| 90 | - // 1.1 获取钱包 | |
| 91 | - PayWalletDO payWallet = getOrCreatePayWallet(userId, userType); | |
| 92 | - // 1.2 判断余额是否足够 | |
| 93 | - int afterBalance = payWallet.getBalance() - price; | |
| 94 | - if (afterBalance < 0) { | |
| 95 | - throw exception(WALLET_BALANCE_NOT_ENOUGH); | |
| 96 | - } | |
| 97 | - | |
| 98 | - // 2.1 扣除余额 | |
| 99 | - int number = payWalletMapper.updateWhenDecBalance(bizType,payWallet.getBalance(), payWallet.getTotalRecharge(), | |
| 100 | - payWallet.getTotalExpense(), price, payWallet.getId()); | |
| 101 | - if (number == 0) { | |
| 102 | - throw exception(TOO_MANY_REQUESTS); | |
| 103 | - } | |
| 104 | - // 2.2 生成钱包流水 | |
| 105 | - String walletNo = generateWalletNo(bizType); | |
| 106 | - PayWalletTransactionDO walletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) | |
| 107 | - .setNo(walletNo).setPrice(-price).setBalance(afterBalance) | |
| 108 | - .setBizId(String.valueOf(bizId)).setBizType(bizType.getType()).setTitle(bizType.getDescription()); | |
| 109 | - payWalletTransactionService.createWalletTransaction(walletTransaction); | |
| 110 | - return walletTransaction; | |
| 111 | - } | |
| 112 | - | |
| 113 | - @Override | |
| 114 | - public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, Long bizId, | |
| 115 | - PayWalletBizTypeEnum bizType, Integer price) { | |
| 116 | - // 1.1 获取钱包 | |
| 117 | - PayWalletDO payWallet = getOrCreatePayWallet(userId, userType); | |
| 118 | - | |
| 119 | - // 2.1 增加余额 | |
| 120 | - int number = payWalletMapper.updateWhenIncBalance(bizType, payWallet.getBalance(), payWallet.getTotalRecharge(), | |
| 121 | - payWallet.getTotalExpense(), price, payWallet.getId()); | |
| 122 | - if (number == 0) { | |
| 123 | - throw exception(TOO_MANY_REQUESTS); | |
| 124 | - } | |
| 125 | - | |
| 126 | - // 2.2 生成钱包流水 | |
| 127 | - String walletNo = generateWalletNo(bizType); | |
| 128 | - PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) | |
| 129 | - .setNo(walletNo).setPrice(price).setBalance(payWallet.getBalance()+price) | |
| 130 | - .setBizId(String.valueOf(bizId)).setBizType(bizType.getType()) | |
| 131 | - .setTitle(bizType.getDescription()); | |
| 132 | - payWalletTransactionService.createWalletTransaction(newWalletTransaction); | |
| 133 | - return newWalletTransaction; | |
| 134 | - } | |
| 135 | - | |
| 136 | - private String generateWalletNo(PayWalletBizTypeEnum bizType) { | |
| 137 | - String no = ""; | |
| 138 | - switch(bizType){ | |
| 139 | - case PAYMENT : | |
| 140 | - no = noRedisDAO.generate(WALLET_PAY_NO_PREFIX); | |
| 141 | - break; | |
| 142 | - case PAYMENT_REFUND : | |
| 143 | - no = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX); | |
| 144 | - break; | |
| 145 | - default : | |
| 146 | - // TODO 待增加 | |
| 147 | - } | |
| 148 | - return no; | |
| 149 | - } | |
| 150 | - | |
| 151 | - @Override | |
| 152 | 71 | @Transactional(rollbackFor = Exception.class) |
| 153 | 72 | public PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason) { |
| 154 | 73 | // 1.1 判断退款单是否存在 |
| 155 | - PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo); | |
| 74 | + PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo); | |
| 156 | 75 | if (payRefund == null) { |
| 157 | 76 | throw exception(REFUND_NOT_FOUND); |
| 158 | 77 | } |
| 159 | 78 | // 1.2 校验是否可以退款 |
| 160 | - Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), refundPrice); | |
| 161 | - | |
| 162 | - PayWalletDO payWallet = payWalletMapper.selectById(walletId); | |
| 163 | - Assert.notNull(payWallet, "钱包 {} 不存在", walletId); | |
| 164 | - return addWalletBalance(payWallet.getUserId(), payWallet.getUserType(),payRefund.getId(), PAYMENT_REFUND, refundPrice); | |
| 79 | + Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), refundPrice); | |
| 80 | + PayWalletDO wallet = walletMapper.selectById(walletId); | |
| 81 | + Assert.notNull(wallet, "钱包 {} 不存在", walletId); | |
| 82 | + // 2. 增加余额 | |
| 83 | + return addWalletBalance(wallet.getUserId(), wallet.getUserType(), payRefund.getId(), PAYMENT_REFUND, refundPrice); | |
| 165 | 84 | } |
| 166 | 85 | |
| 167 | 86 | /** |
| ... | ... | @@ -171,21 +90,76 @@ public class PayWalletServiceImpl implements PayWalletService { |
| 171 | 90 | * @param walletPayNo 钱包支付 no |
| 172 | 91 | */ |
| 173 | 92 | private Long validateWalletCanRefund(Long refundId, String walletPayNo, Integer refundPrice) { |
| 174 | - // 查询钱包支付交易 | |
| 175 | - PayWalletTransactionDO payWalletTransaction = payWalletTransactionService.getWalletTransactionByNo(walletPayNo); | |
| 176 | - if (payWalletTransaction == null) { | |
| 93 | + // 1. 校验钱包支付交易存在 | |
| 94 | + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransactionByNo(walletPayNo); | |
| 95 | + if (walletTransaction == null) { | |
| 177 | 96 | throw exception(WALLET_TRANSACTION_NOT_FOUND); |
| 178 | 97 | } |
| 179 | 98 | // 原来的支付金额 |
| 180 | - int amount = - payWalletTransaction.getPrice(); | |
| 99 | + // TODO @jason:应该允许多次退款哈; | |
| 100 | + int amount = - walletTransaction.getPrice(); | |
| 181 | 101 | if (refundPrice != amount) { |
| 182 | 102 | throw exception(WALLET_REFUND_AMOUNT_ERROR); |
| 183 | 103 | } |
| 184 | - PayWalletTransactionDO refundTransaction = payWalletTransactionService.getWalletTransaction( | |
| 104 | + PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction( | |
| 185 | 105 | String.valueOf(refundId), PAYMENT_REFUND); |
| 186 | 106 | if (refundTransaction != null) { |
| 187 | 107 | throw exception(WALLET_REFUND_EXIST); |
| 188 | 108 | } |
| 189 | - return payWalletTransaction.getWalletId(); | |
| 109 | + return walletTransaction.getWalletId(); | |
| 110 | + } | |
| 111 | + | |
| 112 | + @Override | |
| 113 | + public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType, | |
| 114 | + Long bizId, PayWalletBizTypeEnum bizType, Integer price) { | |
| 115 | + // 1. 获取钱包 | |
| 116 | + PayWalletDO payWallet = getOrCreateWallet(userId, userType); | |
| 117 | + | |
| 118 | + // 2.1 扣除余额 | |
| 119 | + int updateCounts = 0 ; | |
| 120 | + switch (bizType) { | |
| 121 | + case PAYMENT: { | |
| 122 | + updateCounts = walletMapper.updateWhenConsumption(price, payWallet.getId()); | |
| 123 | + break; | |
| 124 | + } | |
| 125 | + case RECHARGE_REFUND: { | |
| 126 | + // TODO | |
| 127 | + break; | |
| 128 | + } | |
| 129 | + } | |
| 130 | + if (updateCounts == 0) { | |
| 131 | + throw exception(WALLET_BALANCE_NOT_ENOUGH); | |
| 132 | + } | |
| 133 | + // 2.2 生成钱包流水 | |
| 134 | + Integer afterBalance = payWallet.getBalance() - price; | |
| 135 | + CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId()) | |
| 136 | + .setPrice(-price).setBalance(afterBalance).setBizId(String.valueOf(bizId)) | |
| 137 | + .setBizType(bizType.getType()).setTitle(bizType.getDescription()); | |
| 138 | + return walletTransactionService.createWalletTransaction(bo); | |
| 190 | 139 | } |
| 140 | + | |
| 141 | + @Override | |
| 142 | + public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, | |
| 143 | + Long bizId, PayWalletBizTypeEnum bizType, Integer price) { | |
| 144 | + // 1. 获取钱包 | |
| 145 | + PayWalletDO payWallet = getOrCreateWallet(userId, userType); | |
| 146 | + switch (bizType) { | |
| 147 | + case PAYMENT_REFUND: { | |
| 148 | + // 更新退款 | |
| 149 | + walletMapper.updateWhenConsumptionRefund(price, payWallet.getId()); | |
| 150 | + break; | |
| 151 | + } | |
| 152 | + case RECHARGE: { | |
| 153 | + //TODO | |
| 154 | + break; | |
| 155 | + } | |
| 156 | + } | |
| 157 | + | |
| 158 | + // 2. 生成钱包流水 | |
| 159 | + CreateWalletTransactionBO bo = new CreateWalletTransactionBO().setWalletId(payWallet.getId()) | |
| 160 | + .setPrice(price).setBalance(payWallet.getBalance()+price).setBizId(String.valueOf(bizId)) | |
| 161 | + .setBizType(bizType.getType()).setTitle(bizType.getDescription()); | |
| 162 | + return walletTransactionService.createWalletTransaction(bo); | |
| 163 | + } | |
| 164 | + | |
| 191 | 165 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java
| ... | ... | @@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; |
| 5 | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 6 | 6 | import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; |
| 7 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | |
| 8 | + | |
| 9 | +import javax.validation.Valid; | |
| 7 | 10 | |
| 8 | 11 | /** |
| 9 | 12 | * 钱包余额流水 Service 接口 |
| ... | ... | @@ -25,10 +28,10 @@ public interface PayWalletTransactionService { |
| 25 | 28 | /** |
| 26 | 29 | * 新增钱包余额流水 |
| 27 | 30 | * |
| 28 | - * @param payWalletTransaction 余额流水 | |
| 29 | - * @return id | |
| 31 | + * @param bo 创建钱包流水 bo | |
| 32 | + * @return 新建的钱包 do | |
| 30 | 33 | */ |
| 31 | - Long createWalletTransaction(PayWalletTransactionDO payWalletTransaction); | |
| 34 | + PayWalletTransactionDO createWalletTransaction(@Valid CreateWalletTransactionBO bo); | |
| 32 | 35 | |
| 33 | 36 | /** |
| 34 | 37 | * 根据 no,获取钱包余流水 |
| ... | ... | @@ -45,4 +48,5 @@ public interface PayWalletTransactionService { |
| 45 | 48 | * @return 钱包流水 |
| 46 | 49 | */ |
| 47 | 50 | PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type); |
| 51 | + | |
| 48 | 52 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java
| ... | ... | @@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.pay.service.wallet; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO; |
| 5 | +import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletTransactionConvert; | |
| 5 | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 6 | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 7 | 8 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper; |
| 9 | +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | |
| 8 | 10 | import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; |
| 11 | +import cn.iocoder.yudao.module.pay.service.wallet.bo.CreateWalletTransactionBO; | |
| 9 | 12 | import lombok.extern.slf4j.Slf4j; |
| 10 | 13 | import org.springframework.stereotype.Service; |
| 11 | 14 | |
| ... | ... | @@ -20,22 +23,31 @@ import javax.annotation.Resource; |
| 20 | 23 | @Slf4j |
| 21 | 24 | public class PayWalletTransactionServiceImpl implements PayWalletTransactionService { |
| 22 | 25 | |
| 26 | + /** | |
| 27 | + * 钱包流水的 no 前缀 | |
| 28 | + */ | |
| 29 | + private static final String WALLET_NO_PREFIX = "W"; | |
| 30 | + | |
| 23 | 31 | @Resource |
| 24 | 32 | private PayWalletService payWalletService; |
| 25 | 33 | @Resource |
| 26 | 34 | private PayWalletTransactionMapper payWalletTransactionMapper; |
| 35 | + @Resource | |
| 36 | + private PayNoRedisDAO noRedisDAO; | |
| 27 | 37 | |
| 28 | 38 | @Override |
| 29 | 39 | public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType, |
| 30 | 40 | AppPayWalletTransactionPageReqVO pageVO) { |
| 31 | - PayWalletDO wallet = payWalletService.getOrCreatePayWallet(userId, userType); | |
| 41 | + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); | |
| 32 | 42 | return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO); |
| 33 | 43 | } |
| 34 | 44 | |
| 35 | 45 | @Override |
| 36 | - public Long createWalletTransaction(PayWalletTransactionDO payWalletTransaction) { | |
| 37 | - payWalletTransactionMapper.insert(payWalletTransaction); | |
| 38 | - return payWalletTransaction.getId(); | |
| 46 | + public PayWalletTransactionDO createWalletTransaction(CreateWalletTransactionBO bo) { | |
| 47 | + PayWalletTransactionDO transaction = PayWalletTransactionConvert.INSTANCE.convert(bo) | |
| 48 | + .setNo(noRedisDAO.generate(WALLET_NO_PREFIX)); | |
| 49 | + payWalletTransactionMapper.insert(transaction); | |
| 50 | + return transaction; | |
| 39 | 51 | } |
| 40 | 52 | |
| 41 | 53 | @Override |
| ... | ... | @@ -47,4 +59,5 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ |
| 47 | 59 | public PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type) { |
| 48 | 60 | return payWalletTransactionMapper.selectByBiz(bizId, type.getType()); |
| 49 | 61 | } |
| 62 | + | |
| 50 | 63 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/bo/CreateWalletTransactionBO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.pay.service.wallet.bo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 创建钱包流水 BO | |
| 8 | + * | |
| 9 | + * @author jason | |
| 10 | + */ | |
| 11 | +@Data | |
| 12 | +public class CreateWalletTransactionBO { | |
| 13 | + | |
| 14 | + // TODO @jason:bo 的话,最好加个参数校验哈; | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 钱包编号 | |
| 18 | + * | |
| 19 | + */ | |
| 20 | + private Long walletId; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 交易金额,单位分 | |
| 24 | + * | |
| 25 | + * 正值表示余额增加,负值表示余额减少 | |
| 26 | + */ | |
| 27 | + private Integer price; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 交易后余额,单位分 | |
| 31 | + */ | |
| 32 | + private Integer balance; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 关联业务分类 | |
| 36 | + * | |
| 37 | + * 枚举 {@link PayWalletBizTypeEnum#getType()} | |
| 38 | + */ | |
| 39 | + private Integer bizType; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 关联业务编号 | |
| 43 | + */ | |
| 44 | + private String bizId; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * 流水说明 | |
| 48 | + */ | |
| 49 | + private String title; | |
| 50 | +} | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.social; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 5 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; |
| 6 | 7 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| 7 | 8 | |
| ... | ... | @@ -27,8 +28,9 @@ public interface SocialUserApi { |
| 27 | 28 | * 绑定社交用户 |
| 28 | 29 | * |
| 29 | 30 | * @param reqDTO 绑定信息 |
| 31 | + * @return 社交用户 openid | |
| 30 | 32 | */ |
| 31 | - void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); | |
| 33 | + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); | |
| 32 | 34 | |
| 33 | 35 | /** |
| 34 | 36 | * 取消绑定社交用户 |
| ... | ... | @@ -38,16 +40,17 @@ public interface SocialUserApi { |
| 38 | 40 | void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO); |
| 39 | 41 | |
| 40 | 42 | /** |
| 41 | - * 获得社交用户的绑定用户编号 | |
| 42 | - * 注意,返回的是 MemberUser 或者 AdminUser 的 id 编号! | |
| 43 | + * 获得社交用户 | |
| 44 | + * | |
| 43 | 45 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
| 44 | 46 | * |
| 45 | 47 | * @param userType 用户类型 |
| 46 | 48 | * @param type 社交平台的类型 |
| 47 | 49 | * @param code 授权码 |
| 48 | 50 | * @param state state |
| 49 | - * @return 绑定用户编号 | |
| 51 | + * @return 社交用户 | |
| 50 | 52 | */ |
| 51 | - Long getBindUserId(Integer userType, Integer type, String code, String state); | |
| 53 | + SocialUserRespDTO getSocialUser(Integer userType, Integer type, | |
| 54 | + String code, String state); | |
| 52 | 55 | |
| 53 | 56 | } | ... | ... |
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.api.social.dto; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.NoArgsConstructor; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 社交用户 Response DTO | |
| 9 | + * | |
| 10 | + * @author 芋道源码 | |
| 11 | + */ | |
| 12 | +@Data | |
| 13 | +@NoArgsConstructor | |
| 14 | +@AllArgsConstructor | |
| 15 | +public class SocialUserRespDTO { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 社交用户 openid | |
| 19 | + */ | |
| 20 | + private String openid; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 关联的用户编号 | |
| 24 | + */ | |
| 25 | + private Long userId; | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApiImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.system.api.social; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 4 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; |
| 5 | 6 | import cn.iocoder.yudao.module.system.service.social.SocialUserService; |
| 6 | 7 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -26,8 +27,8 @@ public class SocialUserApiImpl implements SocialUserApi { |
| 26 | 27 | } |
| 27 | 28 | |
| 28 | 29 | @Override |
| 29 | - public void bindSocialUser(SocialUserBindReqDTO reqDTO) { | |
| 30 | - socialUserService.bindSocialUser(reqDTO); | |
| 30 | + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { | |
| 31 | + return socialUserService.bindSocialUser(reqDTO); | |
| 31 | 32 | } |
| 32 | 33 | |
| 33 | 34 | @Override |
| ... | ... | @@ -37,8 +38,8 @@ public class SocialUserApiImpl implements SocialUserApi { |
| 37 | 38 | } |
| 38 | 39 | |
| 39 | 40 | @Override |
| 40 | - public Long getBindUserId(Integer userType, Integer type, String code, String state) { | |
| 41 | - return socialUserService.getBindUserId(userType, type, code, state); | |
| 41 | + public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { | |
| 42 | + return socialUserService.getSocialUser(userType, type, code, state); | |
| 42 | 43 | } |
| 43 | 44 | |
| 44 | 45 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
| ... | ... | @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; |
| 9 | 9 | import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 11 | 11 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 12 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 12 | 13 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; |
| 13 | 14 | import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; |
| 14 | 15 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; |
| ... | ... | @@ -155,14 +156,14 @@ public class AdminAuthServiceImpl implements AdminAuthService { |
| 155 | 156 | @Override |
| 156 | 157 | public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) { |
| 157 | 158 | // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 |
| 158 | - Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), | |
| 159 | + SocialUserRespDTO socialUser = socialUserService.getSocialUser(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), | |
| 159 | 160 | reqVO.getCode(), reqVO.getState()); |
| 160 | - if (userId == null) { | |
| 161 | + if (socialUser == null) { | |
| 161 | 162 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
| 162 | 163 | } |
| 163 | 164 | |
| 164 | 165 | // 获得用户 |
| 165 | - AdminUserDO user = userService.getUser(userId); | |
| 166 | + AdminUserDO user = userService.getUser(socialUser.getUserId()); | |
| 166 | 167 | if (user == null) { |
| 167 | 168 | throw exception(USER_NOT_EXISTS); |
| 168 | 169 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.social; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | 4 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 5 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 6 | 7 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| 7 | 8 | |
| ... | ... | @@ -50,8 +51,9 @@ public interface SocialUserService { |
| 50 | 51 | * 绑定社交用户 |
| 51 | 52 | * |
| 52 | 53 | * @param reqDTO 绑定信息 |
| 54 | + * @return 社交用户 openid | |
| 53 | 55 | */ |
| 54 | - void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); | |
| 56 | + String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); | |
| 55 | 57 | |
| 56 | 58 | /** |
| 57 | 59 | * 取消绑定社交用户 |
| ... | ... | @@ -64,15 +66,16 @@ public interface SocialUserService { |
| 64 | 66 | void unbindSocialUser(Long userId, Integer userType, Integer type, String openid); |
| 65 | 67 | |
| 66 | 68 | /** |
| 67 | - * 获得社交用户的绑定用户编号 | |
| 68 | - * 注意,返回的是 MemberUser 或者 AdminUser 的 id 编号! | |
| 69 | + * 获得社交用户 | |
| 70 | + * | |
| 69 | 71 | * 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
| 70 | 72 | * |
| 71 | 73 | * @param userType 用户类型 |
| 72 | 74 | * @param type 社交平台的类型 |
| 73 | 75 | * @param code 授权码 |
| 74 | 76 | * @param state state |
| 75 | - * @return 绑定用户编号 | |
| 77 | + * @return 社交用户 | |
| 76 | 78 | */ |
| 77 | - Long getBindUserId(Integer userType, Integer type, String code, String state); | |
| 79 | + SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state); | |
| 80 | + | |
| 78 | 81 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
| ... | ... | @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.util.http.HttpUtils; |
| 6 | 6 | import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; |
| 7 | 7 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 8 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 8 | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; |
| 9 | 10 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 10 | 11 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; |
| ... | ... | @@ -98,7 +99,7 @@ public class SocialUserServiceImpl implements SocialUserService { |
| 98 | 99 | |
| 99 | 100 | @Override |
| 100 | 101 | @Transactional |
| 101 | - public void bindSocialUser(SocialUserBindReqDTO reqDTO) { | |
| 102 | + public String bindSocialUser(SocialUserBindReqDTO reqDTO) { | |
| 102 | 103 | // 获得社交用户 |
| 103 | 104 | SocialUserDO socialUser = authSocialUser(reqDTO.getType(), reqDTO.getCode(), reqDTO.getState()); |
| 104 | 105 | Assert.notNull(socialUser, "社交用户不能为空"); |
| ... | ... | @@ -115,6 +116,7 @@ public class SocialUserServiceImpl implements SocialUserService { |
| 115 | 116 | .userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) |
| 116 | 117 | .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); |
| 117 | 118 | socialUserBindMapper.insert(socialUserBind); |
| 119 | + return socialUser.getOpenid(); | |
| 118 | 120 | } |
| 119 | 121 | |
| 120 | 122 | @Override |
| ... | ... | @@ -130,7 +132,7 @@ public class SocialUserServiceImpl implements SocialUserService { |
| 130 | 132 | } |
| 131 | 133 | |
| 132 | 134 | @Override |
| 133 | - public Long getBindUserId(Integer userType, Integer type, String code, String state) { | |
| 135 | + public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { | |
| 134 | 136 | // 获得社交用户 |
| 135 | 137 | SocialUserDO socialUser = authSocialUser(type, code, state); |
| 136 | 138 | Assert.notNull(socialUser, "社交用户不能为空"); |
| ... | ... | @@ -141,7 +143,7 @@ public class SocialUserServiceImpl implements SocialUserService { |
| 141 | 143 | if (socialUserBind == null) { |
| 142 | 144 | throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
| 143 | 145 | } |
| 144 | - return socialUserBind.getUserId(); | |
| 146 | + return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId()); | |
| 145 | 147 | } |
| 146 | 148 | |
| 147 | 149 | /** | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 7 | 7 | import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
| 8 | 8 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 9 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 9 | 10 | import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; |
| 10 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; |
| 11 | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; |
| ... | ... | @@ -235,8 +236,8 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { |
| 235 | 236 | AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class); |
| 236 | 237 | // mock 方法(绑定的用户编号) |
| 237 | 238 | Long userId = 1L; |
| 238 | - when(socialUserService.getBindUserId(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()), | |
| 239 | - eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(userId); | |
| 239 | + when(socialUserService.getSocialUser(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()), | |
| 240 | + eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), userId)); | |
| 240 | 241 | // mock(用户) |
| 241 | 242 | AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); |
| 242 | 243 | when(userService.getUser(eq(userId))).thenReturn(user); | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java
| ... | ... | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory; |
| 5 | 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 6 | 6 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 7 | +import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | |
| 7 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; |
| 8 | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; |
| 9 | 10 | import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; |
| ... | ... | @@ -195,10 +196,11 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { |
| 195 | 196 | .setSocialType(SocialTypeEnum.GITEE.getType()).setSocialUserId(socialUser.getId())); |
| 196 | 197 | |
| 197 | 198 | // 调用 |
| 198 | - socialUserService.bindSocialUser(reqDTO); | |
| 199 | + String openid = socialUserService.bindSocialUser(reqDTO); | |
| 199 | 200 | // 断言 |
| 200 | 201 | List<SocialUserBindDO> socialUserBinds = socialUserBindMapper.selectList(); |
| 201 | 202 | assertEquals(1, socialUserBinds.size()); |
| 203 | + assertEquals(socialUser.getOpenid(), openid); | |
| 202 | 204 | } |
| 203 | 205 | |
| 204 | 206 | @Test |
| ... | ... | @@ -232,25 +234,26 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { |
| 232 | 234 | } |
| 233 | 235 | |
| 234 | 236 | @Test |
| 235 | - public void testGetBindUserId() { | |
| 237 | + public void testGetSocialUser() { | |
| 236 | 238 | // 准备参数 |
| 237 | 239 | Integer userType = UserTypeEnum.ADMIN.getValue(); |
| 238 | 240 | Integer type = SocialTypeEnum.GITEE.getType(); |
| 239 | 241 | String code = "tudou"; |
| 240 | 242 | String state = "yuanma"; |
| 241 | 243 | // mock 社交用户 |
| 242 | - SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(type).setCode(code).setState(state); | |
| 243 | - socialUserMapper.insert(socialUser); | |
| 244 | + SocialUserDO socialUserDO = randomPojo(SocialUserDO.class).setType(type).setCode(code).setState(state); | |
| 245 | + socialUserMapper.insert(socialUserDO); | |
| 244 | 246 | // mock 社交用户的绑定 |
| 245 | 247 | Long userId = randomLong(); |
| 246 | 248 | SocialUserBindDO socialUserBind = randomPojo(SocialUserBindDO.class).setUserType(userType).setUserId(userId) |
| 247 | - .setSocialType(type).setSocialUserId(socialUser.getId()); | |
| 249 | + .setSocialType(type).setSocialUserId(socialUserDO.getId()); | |
| 248 | 250 | socialUserBindMapper.insert(socialUserBind); |
| 249 | 251 | |
| 250 | 252 | // 调用 |
| 251 | - Long result = socialUserService.getBindUserId(userType, type, code, state); | |
| 253 | + SocialUserRespDTO socialUser = socialUserService.getSocialUser(userType, type, code, state); | |
| 252 | 254 | // 断言 |
| 253 | - assertEquals(userId, result); | |
| 255 | + assertEquals(userId, socialUser.getUserId()); | |
| 256 | + assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid()); | |
| 254 | 257 | } |
| 255 | 258 | |
| 256 | 259 | } | ... | ... |
yudao-server/src/main/resources/application-local.yaml
| ... | ... | @@ -173,8 +173,10 @@ wx: |
| 173 | 173 | key-prefix: wx # Redis Key 的前缀 |
| 174 | 174 | http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 |
| 175 | 175 | miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 |
| 176 | - appid: wx62056c0d5e8db250 | |
| 177 | - secret: 333ae72f41552af1e998fe1f54e1584a | |
| 176 | +# appid: wx62056c0d5e8db250 | |
| 177 | +# secret: 333ae72f41552af1e998fe1f54e1584a | |
| 178 | + appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 | |
| 179 | + secret: 6f270509224a7ae1296bbf1c8cb97aed | |
| 178 | 180 | config-storage: |
| 179 | 181 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 180 | 182 | key-prefix: wa # Redis Key 的前缀 | ... | ... |