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