feat:【MALL 商城】商城分佣提现,初步对接成功微信支付

This commit is contained in:
YunaiV
2025-05-11 08:12:42 +08:00
parent b91a30dd3e
commit 4d25e810e3
22 changed files with 162 additions and 225 deletions

View File

@@ -7,6 +7,9 @@ package cn.iocoder.yudao.module.trade.enums;
*/
public interface DictTypeConstants {
String BROKERAGE_RECORD_STATUS = "brokerage_record_status"; // 佣金记录状态
String BROKERAGE_WITHDRAW_TYPE = "brokerage_withdraw_type"; // 佣金提现类型
String BROKERAGE_WITHDRAW_STATUS = "brokerage_withdraw_status"; // 佣金提现状态
}

View File

@@ -6,7 +6,6 @@ import lombok.Getter;
import java.util.Arrays;
// TODO 芋艿:提现的打通,在纠结下;
/**
* 佣金提现状态枚举
*

View File

@@ -3,11 +3,13 @@ package cn.iocoder.yudao.module.trade.controller.app.brokerage;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO;
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.AppBrokerageRecordRespVO;
import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageRecordConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO;
import cn.iocoder.yudao.module.trade.enums.DictTypeConstants;
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -36,8 +38,9 @@ public class AppBrokerageRecordController {
@Operation(summary = "获得分销记录分页")
public CommonResult<PageResult<AppBrokerageRecordRespVO>> getBrokerageRecordPage(@Valid AppBrokerageRecordPageReqVO pageReqVO) {
PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(
BrokerageRecordConvert.INSTANCE.convert(pageReqVO, getLoginUserId()));
return success(BeanUtils.toBean(pageResult, AppBrokerageRecordRespVO.class));
BeanUtils.toBean(pageReqVO, BrokerageRecordPageReqVO.class).setUserId(getLoginUserId()));
return success(BeanUtils.toBean(pageResult, AppBrokerageRecordRespVO.class, recordVO ->
recordVO.setStatusName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BROKERAGE_RECORD_STATUS, recordVO.getStatus()))));
}
@GetMapping("/get-product-brokerage-price")

View File

@@ -1,14 +1,23 @@
package cn.iocoder.yudao.module.trade.controller.app.brokerage;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO;
import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.enums.DictTypeConstants;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@@ -16,6 +25,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
@@ -29,12 +40,39 @@ public class AppBrokerageWithdrawController {
@Resource
private BrokerageWithdrawService brokerageWithdrawService;
@Resource
private PayTransferApi payTransferApi;
@GetMapping("/page")
@Operation(summary = "获得分销提现分页")
public CommonResult<PageResult<AppBrokerageWithdrawRespVO>> getBrokerageWithdrawPage(AppBrokerageWithdrawPageReqVO pageReqVO) {
PageResult<BrokerageWithdrawDO> pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(
BrokerageWithdrawConvert.INSTANCE.convert(pageReqVO, getLoginUserId()));
return success(BrokerageWithdrawConvert.INSTANCE.convertPage03(pageResult));
BeanUtils.toBean(pageReqVO, BrokerageWithdrawPageReqVO.class).setUserId(getLoginUserId()));
return success(BeanUtils.toBean(pageResult, AppBrokerageWithdrawRespVO.class, withdrawVO ->
withdrawVO.setTypeName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BROKERAGE_WITHDRAW_TYPE, withdrawVO.getType()))
.setStatusName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BROKERAGE_WITHDRAW_STATUS, withdrawVO.getStatus()))));
}
@GetMapping("/get")
@Operation(summary = "获得佣金提现")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<AppBrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Long id) {
BrokerageWithdrawDO withdraw = brokerageWithdrawService.getBrokerageWithdraw(id);
if (withdraw == null || ObjUtil.notEqual(withdraw.getUserId(), getLoginUserId())) {
return success(null);
}
// 审核中(转账中),并且是微信转账,需要返回 mchId 用于确认收款
AppBrokerageWithdrawRespVO withdrawVO = BeanUtils.toBean(withdraw, AppBrokerageWithdrawRespVO.class);
if (Objects.equals(withdraw.getStatus(), BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus())
&& Objects.equals(withdraw.getType(), BrokerageWithdrawTypeEnum.WECHAT_API.getType())
&& withdraw.getPayTransferId() != null) {
PayTransferRespDTO transfer = payTransferApi.getTransfer(withdraw.getPayTransferId());
if (transfer != null) {
withdrawVO.setTransferChannelPackageInfo(transfer.getChannelPackageInfo())
.setTransferChannelMchId(transfer.getChannelMchId());
}
}
return success(withdrawVO);
}
@PostMapping("/create")

View File

@@ -20,11 +20,11 @@ public class AppBrokerageRecordPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "业务类型", example = "1")
@InEnum(value = BrokerageRecordBizTypeEnum.class, message = "业务类型必须是 {value}")
private Integer bizType;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "状态", example = "1")
@InEnum(value = BrokerageRecordStatusEnum.class, message = "状态必须是 {value}")
private Integer status;

View File

@@ -24,6 +24,9 @@ public class AppBrokerageRecordRespVO {
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
@Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "待结算")
private String statusName;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;

View File

@@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.pay.enums.PayChannelEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
@@ -22,6 +24,7 @@ public class AppBrokerageWithdrawCreateReqVO {
@Schema(description = "提现金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
@PositiveOrZero(message = "提现金额不能小于 0")
@Min(value = 30, message = "微信提现金额不能小于 0.3", groups = {WechatApi.class})
@NotNull(message = "提现金额不能为空")
private Integer price;
@@ -43,6 +46,11 @@ public class AppBrokerageWithdrawCreateReqVO {
@Schema(description = "开户地址", example = "海淀支行")
private String bankAddress;
@Schema(description = "转账渠道", example = "wx_lite")
@NotNull(message = "转账渠道不能为空", groups = {WechatApi.class})
@InEnum(PayChannelEnum.class)
private String transferChannelCode;
public interface Wallet {
}

View File

@@ -1,22 +1,22 @@
package cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "应用 App - 分销提现分页 Request VO")
@Data
public class AppBrokerageWithdrawPageReqVO extends PageParam {
@Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@InEnum(value = BrokerageWithdrawTypeEnum.class, message = "类型必须是 {value}")
private Integer type;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@InEnum(value = BrokerageWithdrawStatusEnum.class, message = "状态必须是 {value}")
private Integer status;
}

View File

@@ -12,6 +12,12 @@ public class AppBrokerageWithdrawRespVO {
@Schema(description = "提现编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Long id;
@Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer type;
@Schema(description = "提现类型名", requiredMode = Schema.RequiredMode.REQUIRED, example = "微信")
private String typeName;
@Schema(description = "提现状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer status;
@@ -24,4 +30,15 @@ public class AppBrokerageWithdrawRespVO {
@Schema(description = "提现时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
// ========== 微信转账专属 ==========
@Schema(description = "转账单编号", example = "1024")
private Long payTransferId;
@Schema(description = "渠道 package 信息")
private String transferChannelPackageInfo;
@Schema(description = "渠道商户号")
private String transferChannelMchId;
}

View File

@@ -1,15 +1,11 @@
package cn.iocoder.yudao.module.trade.convert.brokerage;
import cn.hutool.core.math.Money;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordRespVO;
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.user.AppBrokerageUserRankByPriceRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
@@ -68,8 +64,6 @@ public interface BrokerageRecordConvert {
return result;
}
BrokerageRecordPageReqVO convert(AppBrokerageRecordPageReqVO pageReqVO, Long userId);
default PageResult<AppBrokerageUserRankByPriceRespVO> convertPage03(PageResult<AppBrokerageUserRankByPriceRespVO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
for (AppBrokerageUserRankByPriceRespVO vo : pageResult.getList()) {
copyTo(userMap.get(vo.getId()), vo);

View File

@@ -1,15 +1,9 @@
package cn.iocoder.yudao.module.trade.convert.brokerage;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawRespVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.enums.DictTypeConstants;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@@ -27,8 +21,6 @@ public interface BrokerageWithdrawConvert {
BrokerageWithdrawConvert INSTANCE = Mappers.getMapper(BrokerageWithdrawConvert.class);
BrokerageWithdrawDO convert(AppBrokerageWithdrawCreateReqVO createReqVO, Long userId, Integer feePrice);
BrokerageWithdrawRespVO convert(BrokerageWithdrawDO bean);
List<BrokerageWithdrawRespVO> convertList(List<BrokerageWithdrawDO> list);
@@ -43,15 +35,4 @@ public interface BrokerageWithdrawConvert {
return result;
}
PageResult<AppBrokerageWithdrawRespVO> convertPage02(PageResult<BrokerageWithdrawDO> pageResult);
default PageResult<AppBrokerageWithdrawRespVO> convertPage03(PageResult<BrokerageWithdrawDO> pageResult) {
PageResult<AppBrokerageWithdrawRespVO> result = convertPage02(pageResult);
for (AppBrokerageWithdrawRespVO vo : result.getList()) {
vo.setStatusName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BROKERAGE_WITHDRAW_STATUS, vo.getStatus()));
}
return result;
}
BrokerageWithdrawPageReqVO convert(AppBrokerageWithdrawPageReqVO pageReqVO, Long userId);
}

View File

@@ -126,12 +126,5 @@ public class BrokerageWithdrawDO extends BaseDO {
* 转账错误提示
*/
private String transferErrorMsg;
/**
* 渠道 package 信息
*
* 特殊:目前只有微信转账有这个东西!!!
* @see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716430">JSAPI 调起用户确认收款</a>
*/
private String transferChannelPackageInfo;
}

View File

@@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
@@ -18,7 +19,6 @@ import cn.iocoder.yudao.module.pay.enums.PayChannelEnum;
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO;
import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageWithdrawMapper;
@@ -157,8 +157,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
// 2. 更新提现记录
brokerageWithdrawMapper.updateById(new BrokerageWithdrawDO().setId(withdraw.getId())
.setPayTransferId(transferRespDTO.getId()).setTransferChannelCode(channelCode)
.setTransferChannelPackageInfo(transferRespDTO.getChannelPackageInfo()));
.setPayTransferId(transferRespDTO.getId()).setTransferChannelCode(channelCode));
}
private BrokerageWithdrawDO validateBrokerageWithdrawExists(Long id) {
@@ -190,7 +189,8 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
// 2.1 计算手续费
Integer feePrice = calculateFeePrice(createReqVO.getPrice(), tradeConfig.getBrokerageWithdrawFeePercent());
// 2.2 创建佣金提现记录
BrokerageWithdrawDO withdraw = BrokerageWithdrawConvert.INSTANCE.convert(createReqVO, userId, feePrice);
BrokerageWithdrawDO withdraw = BeanUtils.toBean(createReqVO, BrokerageWithdrawDO.class)
.setUserId(userId).setFeePrice(feePrice);
brokerageWithdrawMapper.insert(withdraw);
// 3. 创建用户佣金记录