Commit 423c0b7ea7ca2dcf938c80207c6a4a6a39f93a21
1 parent
d2b668a6
feat:【MALL 商城】佣金提现,优化字段,以及支持更多 API 自动打款
Showing
17 changed files
with
285 additions
and
111 deletions
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| @@ -101,5 +101,11 @@ public interface ErrorCodeConstants { | @@ -101,5 +101,11 @@ public interface ErrorCodeConstants { | ||
| 101 | ErrorCode BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING = new ErrorCode(1_011_008_001, "佣金提现记录状态不是审核中"); | 101 | ErrorCode BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING = new ErrorCode(1_011_008_001, "佣金提现记录状态不是审核中"); |
| 102 | ErrorCode BROKERAGE_WITHDRAW_MIN_PRICE = new ErrorCode(1_011_008_002, "提现金额不能低于 {} 元"); | 102 | ErrorCode BROKERAGE_WITHDRAW_MIN_PRICE = new ErrorCode(1_011_008_002, "提现金额不能低于 {} 元"); |
| 103 | ErrorCode BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH = new ErrorCode(1_011_008_003, "您当前最多可提现 {} 元"); | 103 | ErrorCode BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH = new ErrorCode(1_011_008_003, "您当前最多可提现 {} 元"); |
| 104 | + ErrorCode BROKERAGE_WITHDRAW_TRANSFER_FAIL_WECHAT_NOT_BIND = new ErrorCode(1_011_008_004, "提现失败,原因:用户未绑定微信"); | ||
| 105 | + ErrorCode BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_TRANSFER_ID_ERROR = new ErrorCode(1_011_008_005, "提现单更新转账状态失败,转账单不匹配"); | ||
| 106 | + ErrorCode BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_TRANSFER_STATUS_NOT_SUCCESS_OR_CLOSED = new ErrorCode(1_011_008_006, "提现单更新转账状态失败,转账单状态不是成功或关闭状态"); | ||
| 107 | + ErrorCode BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1_011_008_007, "提现单更新转账状态失败,转账单金额不匹配"); | ||
| 108 | + ErrorCode BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_MERCHANT_EXISTS = new ErrorCode(1_011_008_008, "提现单更新转账状态失败,转账单的商户订单不匹配"); | ||
| 109 | + ErrorCode BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_CHANNEL_NOT_MATCH = new ErrorCode(1_011_008_009, "提现单更新转账状态失败,转账渠道不匹配"); | ||
| 104 | 110 | ||
| 105 | } | 111 | } |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageWithdrawTypeEnum.java
| 1 | package cn.iocoder.yudao.module.trade.enums.brokerage; | 1 | package cn.iocoder.yudao.module.trade.enums.brokerage; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.core.ArrayValuable; | 3 | import cn.iocoder.yudao.framework.common.core.ArrayValuable; |
| 4 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||
| 4 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 5 | import lombok.Getter; | 6 | import lombok.Getter; |
| 6 | 7 | ||
| @@ -17,9 +18,10 @@ public enum BrokerageWithdrawTypeEnum implements ArrayValuable<Integer> { | @@ -17,9 +18,10 @@ public enum BrokerageWithdrawTypeEnum implements ArrayValuable<Integer> { | ||
| 17 | 18 | ||
| 18 | WALLET(1, "钱包"), | 19 | WALLET(1, "钱包"), |
| 19 | BANK(2, "银行卡"), | 20 | BANK(2, "银行卡"), |
| 20 | - WECHAT(3, "微信"), // 手动打款 | ||
| 21 | - ALIPAY(4, "支付宝"), | 21 | + WECHAT_QR(3, "微信收款码"), // 手动打款 |
| 22 | + ALIPAY_QR(4, "支付宝收款码"), // 手动打款 | ||
| 22 | WECHAT_API(5, "微信零钱"), // 自动打款,通过微信转账 API | 23 | WECHAT_API(5, "微信零钱"), // 自动打款,通过微信转账 API |
| 24 | + ALIPAY_API(6, "支付宝余额"), // 自动打款,通过支付宝转账 API | ||
| 23 | ; | 25 | ; |
| 24 | 26 | ||
| 25 | public static final Integer[] ARRAYS = Arrays.stream(values()).map(BrokerageWithdrawTypeEnum::getType).toArray(Integer[]::new); | 27 | public static final Integer[] ARRAYS = Arrays.stream(values()).map(BrokerageWithdrawTypeEnum::getType).toArray(Integer[]::new); |
| @@ -45,7 +47,7 @@ public enum BrokerageWithdrawTypeEnum implements ArrayValuable<Integer> { | @@ -45,7 +47,7 @@ public enum BrokerageWithdrawTypeEnum implements ArrayValuable<Integer> { | ||
| 45 | * @return 是否 | 47 | * @return 是否 |
| 46 | */ | 48 | */ |
| 47 | public static boolean isApi(Integer type) { | 49 | public static boolean isApi(Integer type) { |
| 48 | - return WECHAT_API.getType().equals(type); | 50 | + return ObjectUtils.equalsAny(type, WALLET.getType(), ALIPAY_API.getType(), WECHAT_API.getType()); |
| 49 | } | 51 | } |
| 50 | 52 | ||
| 51 | } | 53 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java
| @@ -82,10 +82,9 @@ public class BrokerageWithdrawController { | @@ -82,10 +82,9 @@ public class BrokerageWithdrawController { | ||
| 82 | return success(BrokerageWithdrawConvert.INSTANCE.convertPage(pageResult, userMap)); | 82 | return success(BrokerageWithdrawConvert.INSTANCE.convertPage(pageResult, userMap)); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | - // TODO @luchi:update-transferred,url 改成这个。和 update-paid 、update-refunded 保持一致 | ||
| 86 | - @PostMapping("/update-transfer") | ||
| 87 | - @Operation(summary = "更新转账订单为转账成功") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob | ||
| 88 | - @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现 | 85 | + @PostMapping("/update-transferred") |
| 86 | + @Operation(summary = "更新佣金提现的转账结果") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob | ||
| 87 | + @PermitAll // 无需登录,安全由 BrokerageWithdrawService 内部校验实现 | ||
| 89 | public CommonResult<Boolean> updateBrokerageWithdrawTransferred(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) { | 88 | public CommonResult<Boolean> updateBrokerageWithdrawTransferred(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) { |
| 90 | log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO); | 89 | log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO); |
| 91 | brokerageWithdrawService.updateBrokerageWithdrawTransferred( | 90 | brokerageWithdrawService.updateBrokerageWithdrawTransferred( |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawBaseVO.java
| @@ -37,10 +37,10 @@ public class BrokerageWithdrawBaseVO { | @@ -37,10 +37,10 @@ public class BrokerageWithdrawBaseVO { | ||
| 37 | private Integer type; | 37 | private Integer type; |
| 38 | 38 | ||
| 39 | @Schema(description = "真实姓名", example = "赵六") | 39 | @Schema(description = "真实姓名", example = "赵六") |
| 40 | - private String name; | 40 | + private String userName; |
| 41 | 41 | ||
| 42 | - @Schema(description = "账号", example = "88677912132") | ||
| 43 | - private String accountNo; | 42 | + @Schema(description = "收款账号", example = "88677912132") |
| 43 | + private String userAccount; | ||
| 44 | 44 | ||
| 45 | @Schema(description = "银行名称", example = "1") | 45 | @Schema(description = "银行名称", example = "1") |
| 46 | private String bankName; | 46 | private String bankName; |
| @@ -49,7 +49,7 @@ public class BrokerageWithdrawBaseVO { | @@ -49,7 +49,7 @@ public class BrokerageWithdrawBaseVO { | ||
| 49 | private String bankAddress; | 49 | private String bankAddress; |
| 50 | 50 | ||
| 51 | @Schema(description = "收款码", example = "https://www.iocoder.cn") | 51 | @Schema(description = "收款码", example = "https://www.iocoder.cn") |
| 52 | - private String accountQrCodeUrl; | 52 | + private String qrCodeUrl; |
| 53 | 53 | ||
| 54 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 54 | @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 55 | @NotNull(message = "状态不能为空") | 55 | @NotNull(message = "状态不能为空") |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawPageReqVO.java
| @@ -28,10 +28,10 @@ public class BrokerageWithdrawPageReqVO extends PageParam { | @@ -28,10 +28,10 @@ public class BrokerageWithdrawPageReqVO extends PageParam { | ||
| 28 | private Integer type; | 28 | private Integer type; |
| 29 | 29 | ||
| 30 | @Schema(description = "真实姓名", example = "赵六") | 30 | @Schema(description = "真实姓名", example = "赵六") |
| 31 | - private String name; | 31 | + private String userName; |
| 32 | 32 | ||
| 33 | @Schema(description = "账号", example = "886779132") | 33 | @Schema(description = "账号", example = "886779132") |
| 34 | - private String accountNo; | 34 | + private String userAccount; |
| 35 | 35 | ||
| 36 | @Schema(description = "银行名称", example = "1") | 36 | @Schema(description = "银行名称", example = "1") |
| 37 | private String bankName; | 37 | private String bankName; |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/withdraw/AppBrokerageWithdrawCreateReqVO.java
| @@ -25,23 +25,18 @@ public class AppBrokerageWithdrawCreateReqVO { | @@ -25,23 +25,18 @@ public class AppBrokerageWithdrawCreateReqVO { | ||
| 25 | @NotNull(message = "提现金额不能为空") | 25 | @NotNull(message = "提现金额不能为空") |
| 26 | private Integer price; | 26 | private Integer price; |
| 27 | 27 | ||
| 28 | - // ========== 银行卡、微信、支付宝 提现相关字段 ========== | ||
| 29 | - | ||
| 30 | @Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789") | 28 | @Schema(description = "提现账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456789") |
| 31 | - @NotBlank(message = "提现账号不能为空", groups = {Bank.class, Wechat.class, Alipay.class}) | ||
| 32 | - private String accountNo; | 29 | + @NotBlank(message = "提现账号不能为空", groups = {Bank.class, WechatApi.class, AlipayApi.class}) |
| 30 | + private String userAccount; | ||
| 33 | 31 | ||
| 34 | - // ========== 微信、支付宝 提现相关字段 ========== | 32 | + @Schema(description = "提现姓名", example = "张三") |
| 33 | + @NotBlank(message = "提现姓名不能为空", groups = {Bank.class, WechatApi.class, AlipayApi.class}) | ||
| 34 | + private String userName; | ||
| 35 | 35 | ||
| 36 | @Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png") | 36 | @Schema(description = "收款码的图片", example = "https://www.iocoder.cn/1.png") |
| 37 | - @URL(message = "收款码的图片,必须是一个 URL") | ||
| 38 | - private String accountQrCodeUrl; | ||
| 39 | - | ||
| 40 | - // ========== 银行卡 提现相关字段 ========== | 37 | + @URL(message = "收款码的图片,必须是一个 URL", groups = {WechatQR.class, AlipayQR.class}) |
| 38 | + private String qrCodeUrl; | ||
| 41 | 39 | ||
| 42 | - @Schema(description = "持卡人姓名", example = "张三") | ||
| 43 | - @NotBlank(message = "持卡人姓名不能为空", groups = {Bank.class}) | ||
| 44 | - private String name; | ||
| 45 | @Schema(description = "提现银行", example = "1") | 40 | @Schema(description = "提现银行", example = "1") |
| 46 | @NotNull(message = "提现银行不能为空", groups = {Bank.class}) | 41 | @NotNull(message = "提现银行不能为空", groups = {Bank.class}) |
| 47 | private String bankName; | 42 | private String bankName; |
| @@ -54,10 +49,16 @@ public class AppBrokerageWithdrawCreateReqVO { | @@ -54,10 +49,16 @@ public class AppBrokerageWithdrawCreateReqVO { | ||
| 54 | public interface Bank { | 49 | public interface Bank { |
| 55 | } | 50 | } |
| 56 | 51 | ||
| 57 | - public interface Wechat { | 52 | + public interface WechatQR { |
| 53 | + } | ||
| 54 | + | ||
| 55 | + public interface WechatApi { | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public interface AlipayQR { | ||
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | - public interface Alipay { | 61 | + public interface AlipayApi { |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | public void validate(Validator validator) { | 64 | public void validate(Validator validator) { |
| @@ -65,10 +66,14 @@ public class AppBrokerageWithdrawCreateReqVO { | @@ -65,10 +66,14 @@ public class AppBrokerageWithdrawCreateReqVO { | ||
| 65 | ValidationUtils.validate(validator, this, Wallet.class); | 66 | ValidationUtils.validate(validator, this, Wallet.class); |
| 66 | } else if (BrokerageWithdrawTypeEnum.BANK.getType().equals(type)) { | 67 | } else if (BrokerageWithdrawTypeEnum.BANK.getType().equals(type)) { |
| 67 | ValidationUtils.validate(validator, this, Bank.class); | 68 | ValidationUtils.validate(validator, this, Bank.class); |
| 68 | - } else if (BrokerageWithdrawTypeEnum.WECHAT.getType().equals(type)) { | ||
| 69 | - ValidationUtils.validate(validator, this, Wechat.class); | ||
| 70 | - } else if (BrokerageWithdrawTypeEnum.ALIPAY.getType().equals(type)) { | ||
| 71 | - ValidationUtils.validate(validator, this, Alipay.class); | 69 | + } else if (BrokerageWithdrawTypeEnum.WECHAT_QR.getType().equals(type)) { |
| 70 | + ValidationUtils.validate(validator, this, WechatQR.class); | ||
| 71 | + } else if (BrokerageWithdrawTypeEnum.WECHAT_API.getType().equals(type)) { | ||
| 72 | + ValidationUtils.validate(validator, this, WechatApi.class); | ||
| 73 | + } else if (BrokerageWithdrawTypeEnum.ALIPAY_QR.getType().equals(type)) { | ||
| 74 | + ValidationUtils.validate(validator, this, AlipayQR.class); | ||
| 75 | + } else if (BrokerageWithdrawTypeEnum.ALIPAY_API.getType().equals(type)) { | ||
| 76 | + ValidationUtils.validate(validator, this, AlipayApi.class); | ||
| 72 | } | 77 | } |
| 73 | } | 78 | } |
| 74 | 79 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/BrokerageWithdrawDO.java
| @@ -57,13 +57,25 @@ public class BrokerageWithdrawDO extends BaseDO { | @@ -57,13 +57,25 @@ public class BrokerageWithdrawDO extends BaseDO { | ||
| 57 | private Integer type; | 57 | private Integer type; |
| 58 | 58 | ||
| 59 | /** | 59 | /** |
| 60 | - * 真实姓名 | 60 | + * 提现姓名 |
| 61 | + * 1. {@link BrokerageWithdrawTypeEnum#BANK}:银行开户人 | ||
| 62 | + * 2. {@link BrokerageWithdrawTypeEnum#WECHAT_API}:微信真名 | ||
| 63 | + * 3. {@link BrokerageWithdrawTypeEnum#ALIPAY_API}:支付宝真名 | ||
| 61 | */ | 64 | */ |
| 62 | - private String name; | 65 | + private String userName; |
| 63 | /** | 66 | /** |
| 64 | - * 账号 | 67 | + * 提现账号 |
| 68 | + * 1. {@link BrokerageWithdrawTypeEnum#BANK}:银行账号 | ||
| 69 | + * 2. {@link BrokerageWithdrawTypeEnum#WECHAT_API}:微信 openid | ||
| 70 | + * 3. {@link BrokerageWithdrawTypeEnum#ALIPAY_API}:支付宝账号 | ||
| 65 | */ | 71 | */ |
| 66 | - private String accountNo; | 72 | + private String userAccount; |
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * 收款码 | ||
| 76 | + */ | ||
| 77 | + private String qrCodeUrl; | ||
| 78 | + | ||
| 67 | /** | 79 | /** |
| 68 | * 银行名称 | 80 | * 银行名称 |
| 69 | */ | 81 | */ |
| @@ -72,10 +84,7 @@ public class BrokerageWithdrawDO extends BaseDO { | @@ -72,10 +84,7 @@ public class BrokerageWithdrawDO extends BaseDO { | ||
| 72 | * 开户地址 | 84 | * 开户地址 |
| 73 | */ | 85 | */ |
| 74 | private String bankAddress; | 86 | private String bankAddress; |
| 75 | - /** | ||
| 76 | - * 收款码 | ||
| 77 | - */ | ||
| 78 | - private String accountQrCodeUrl; | 87 | + |
| 79 | /** | 88 | /** |
| 80 | * 状态 | 89 | * 状态 |
| 81 | * <p> | 90 | * <p> |
| @@ -95,4 +104,27 @@ public class BrokerageWithdrawDO extends BaseDO { | @@ -95,4 +104,27 @@ public class BrokerageWithdrawDO extends BaseDO { | ||
| 95 | */ | 104 | */ |
| 96 | private String remark; | 105 | private String remark; |
| 97 | 106 | ||
| 107 | + // ========== 转账相关字段 ========== | ||
| 108 | + | ||
| 109 | + /** | ||
| 110 | + * 转账单编号 | ||
| 111 | + * | ||
| 112 | + * 关联 {@link cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO#getId()} | ||
| 113 | + */ | ||
| 114 | + private Long payTransferId; | ||
| 115 | + /** | ||
| 116 | + * 转账渠道 | ||
| 117 | + * | ||
| 118 | + * 枚举 {@link cn.iocoder.yudao.module.pay.enums.PayChannelEnum} | ||
| 119 | + */ | ||
| 120 | + private String transferChannelCode; | ||
| 121 | + /** | ||
| 122 | + * 转账成功时间 | ||
| 123 | + */ | ||
| 124 | + private LocalDateTime transferTime; | ||
| 125 | + /** | ||
| 126 | + * 转账错误提示 | ||
| 127 | + */ | ||
| 128 | + private String transferErrorMsg; | ||
| 129 | + | ||
| 98 | } | 130 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java
| @@ -27,8 +27,8 @@ public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO | @@ -27,8 +27,8 @@ public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO | ||
| 27 | return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageWithdrawDO>() | 27 | return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageWithdrawDO>() |
| 28 | .eqIfPresent(BrokerageWithdrawDO::getUserId, reqVO.getUserId()) | 28 | .eqIfPresent(BrokerageWithdrawDO::getUserId, reqVO.getUserId()) |
| 29 | .eqIfPresent(BrokerageWithdrawDO::getType, reqVO.getType()) | 29 | .eqIfPresent(BrokerageWithdrawDO::getType, reqVO.getType()) |
| 30 | - .likeIfPresent(BrokerageWithdrawDO::getName, reqVO.getName()) | ||
| 31 | - .eqIfPresent(BrokerageWithdrawDO::getAccountNo, reqVO.getAccountNo()) | 30 | + .likeIfPresent(BrokerageWithdrawDO::getUserName, reqVO.getUserName()) |
| 31 | + .eqIfPresent(BrokerageWithdrawDO::getUserAccount, reqVO.getUserAccount()) | ||
| 32 | .likeIfPresent(BrokerageWithdrawDO::getBankName, reqVO.getBankName()) | 32 | .likeIfPresent(BrokerageWithdrawDO::getBankName, reqVO.getBankName()) |
| 33 | .eqIfPresent(BrokerageWithdrawDO::getStatus, reqVO.getStatus()) | 33 | .eqIfPresent(BrokerageWithdrawDO::getStatus, reqVO.getStatus()) |
| 34 | .betweenIfPresent(BrokerageWithdrawDO::getCreateTime, reqVO.getCreateTime()) | 34 | .betweenIfPresent(BrokerageWithdrawDO::getCreateTime, reqVO.getCreateTime()) |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java
| 1 | package cn.iocoder.yudao.module.trade.service.brokerage; | 1 | package cn.iocoder.yudao.module.trade.service.brokerage; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.lang.Assert; | ||
| 4 | import cn.hutool.core.util.ObjectUtil; | 5 | import cn.hutool.core.util.ObjectUtil; |
| 5 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | 6 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 7 | import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | 9 | import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; |
| 10 | +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||
| 8 | import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi; | 11 | import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi; |
| 9 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; | 12 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; |
| 10 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO; | 13 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO; |
| 11 | import cn.iocoder.yudao.module.pay.api.wallet.PayWalletApi; | 14 | import cn.iocoder.yudao.module.pay.api.wallet.PayWalletApi; |
| 12 | -import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletAddBalanceReqDTO; | 15 | +import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletRespDTO; |
| 16 | +import cn.iocoder.yudao.module.pay.enums.PayChannelEnum; | ||
| 13 | import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; | 17 | import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; |
| 14 | -//import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; | ||
| 15 | -import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; | ||
| 16 | -import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; | ||
| 17 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; | 18 | import cn.iocoder.yudao.module.system.api.social.SocialUserApi; |
| 18 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; | 19 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; |
| 19 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; | 20 | import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; |
| @@ -29,6 +30,7 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; | @@ -29,6 +30,7 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum; | ||
| 29 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; | 30 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; |
| 30 | import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; | 31 | import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO; |
| 31 | import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; | 32 | import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; |
| 33 | +import com.google.common.base.Objects; | ||
| 32 | import jakarta.annotation.Resource; | 34 | import jakarta.annotation.Resource; |
| 33 | import jakarta.validation.Validator; | 35 | import jakarta.validation.Validator; |
| 34 | import lombok.extern.slf4j.Slf4j; | 36 | import lombok.extern.slf4j.Slf4j; |
| @@ -40,10 +42,12 @@ import java.time.LocalDateTime; | @@ -40,10 +42,12 @@ import java.time.LocalDateTime; | ||
| 40 | import java.util.Collection; | 42 | import java.util.Collection; |
| 41 | import java.util.Collections; | 43 | import java.util.Collections; |
| 42 | import java.util.List; | 44 | import java.util.List; |
| 45 | +import java.util.Map; | ||
| 43 | 46 | ||
| 44 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 47 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 45 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 48 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 46 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | 49 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; |
| 50 | +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_TRANSFER_NOT_FOUND; | ||
| 47 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; | 51 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; |
| 48 | 52 | ||
| 49 | /** | 53 | /** |
| @@ -65,8 +69,6 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | @@ -65,8 +69,6 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | ||
| 65 | private TradeConfigService tradeConfigService; | 69 | private TradeConfigService tradeConfigService; |
| 66 | 70 | ||
| 67 | @Resource | 71 | @Resource |
| 68 | - private NotifyMessageSendApi notifyMessageSendApi; | ||
| 69 | - @Resource | ||
| 70 | private PayTransferApi payTransferApi; | 72 | private PayTransferApi payTransferApi; |
| 71 | @Resource | 73 | @Resource |
| 72 | private SocialUserApi socialUserApi; | 74 | private SocialUserApi socialUserApi; |
| @@ -109,44 +111,53 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | @@ -109,44 +111,53 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | ||
| 109 | } | 111 | } |
| 110 | 112 | ||
| 111 | private void auditBrokerageWithdrawSuccess(BrokerageWithdrawDO withdraw) { | 113 | private void auditBrokerageWithdrawSuccess(BrokerageWithdrawDO withdraw) { |
| 112 | - // 1.1 钱包 | ||
| 113 | - if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) { | ||
| 114 | - payWalletApi.addWalletBalance(new PayWalletAddBalanceReqDTO() | ||
| 115 | - .setUserId(withdraw.getUserId()).setUserType(UserTypeEnum.MEMBER.getValue()) | ||
| 116 | - .setBizType(PayWalletBizTypeEnum.TRANSFER.getType()).setBizId(withdraw.getId().toString()) | ||
| 117 | - .setPrice(withdraw.getPrice())); | ||
| 118 | - // 1.2 微信 API | ||
| 119 | - } else if (BrokerageWithdrawTypeEnum.WECHAT_API.getType().equals(withdraw.getType())) { | ||
| 120 | - // TODO @luchi:这里,要加个转账单号的记录;另外,调用 API 转账,是立马成功,还是有延迟的哈? | ||
| 121 | - Long payTransferId = createPayTransfer(withdraw); | ||
| 122 | - // 1.3 剩余类型,都是手动打款,所以不处理 | ||
| 123 | - } else { | ||
| 124 | - // TODO 可优化:未来可以考虑,接入支付宝、银联等 API 转账,实现自动打款 | ||
| 125 | - log.info("[auditBrokerageWithdrawSuccess][withdraw({}) 类型({}) 手动打款,无需处理]", withdraw.getId(), withdraw.getType()); | 114 | + // 情况一:通过 API 转账 |
| 115 | + if (BrokerageWithdrawTypeEnum.isApi(withdraw.getType())) { | ||
| 116 | + createPayTransfer(withdraw); | ||
| 117 | + return; | ||
| 126 | } | 118 | } |
| 127 | 119 | ||
| 128 | - // 2. 非支付 API,则直接体现成功 | ||
| 129 | - if (!BrokerageWithdrawTypeEnum.isApi(withdraw.getType())) { | ||
| 130 | - brokerageWithdrawMapper.updateByIdAndStatus(withdraw.getId(), BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus(), | ||
| 131 | - new BrokerageWithdrawDO().setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus())); | ||
| 132 | - } | 120 | + // 情况二:非 API 转账(手动打款) |
| 121 | + brokerageWithdrawMapper.updateByIdAndStatus(withdraw.getId(), BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus(), | ||
| 122 | + new BrokerageWithdrawDO().setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus())); | ||
| 133 | } | 123 | } |
| 134 | 124 | ||
| 135 | - private Long createPayTransfer(BrokerageWithdrawDO withdraw) { | ||
| 136 | - // 1.1 获取微信 openid | ||
| 137 | - SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId( | ||
| 138 | - UserTypeEnum.MEMBER.getValue(), withdraw.getUserId(), SocialTypeEnum.WECHAT_MINI_PROGRAM.getType()); | ||
| 139 | - // TODO @luchi:这里,需要校验非空。如果空的话,要有业务异常哈; | 125 | + private void createPayTransfer(BrokerageWithdrawDO withdraw) { |
| 126 | + // 1.1 获取基础信息 | ||
| 127 | + String userAccount = withdraw.getUserAccount(); | ||
| 128 | + String userName = withdraw.getUserName(); | ||
| 129 | + String channelCode = null; | ||
| 130 | + Map<String, String> channelExtras = null; | ||
| 131 | + if (Objects.equal(withdraw.getType(), BrokerageWithdrawTypeEnum.ALIPAY_API.getType())) { | ||
| 132 | + channelCode = PayChannelEnum.ALIPAY_PC.getCode(); | ||
| 133 | + } else if (Objects.equal(withdraw.getType(), BrokerageWithdrawTypeEnum.WECHAT_API.getType())) { | ||
| 134 | + SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId( | ||
| 135 | + UserTypeEnum.MEMBER.getValue(), withdraw.getUserId(), SocialTypeEnum.WECHAT_MINI_PROGRAM.getType()); | ||
| 136 | + if (socialUser == null) { | ||
| 137 | + throw exception(BROKERAGE_WITHDRAW_TRANSFER_FAIL_WECHAT_NOT_BIND); | ||
| 138 | + } | ||
| 139 | + channelCode = PayChannelEnum.WX_LITE.getCode(); | ||
| 140 | + userAccount = socialUser.getOpenid(); | ||
| 141 | + // 特殊:微信需要有报备信息 | ||
| 142 | + channelExtras = PayTransferCreateReqDTO.buildWeiXinChannelExtra1000("佣金提现", "佣金提现"); | ||
| 143 | + } else if (Objects.equal(withdraw.getType(), BrokerageWithdrawTypeEnum.WALLET.getType())) { | ||
| 144 | + PayWalletRespDTO wallet = payWalletApi.getOrCreateWallet(withdraw.getUserId(), UserTypeEnum.MEMBER.getValue()); | ||
| 145 | + Assert.notNull(wallet, "钱包不存在"); | ||
| 146 | + channelCode = PayChannelEnum.WALLET.getCode(); | ||
| 147 | + userAccount = wallet.getId().toString(); | ||
| 148 | + } | ||
| 140 | // 1.2 构建请求 | 149 | // 1.2 构建请求 |
| 141 | - PayTransferCreateReqDTO payTransferCreateReqDTO = new PayTransferCreateReqDTO() | ||
| 142 | - .setAppKey(tradeOrderProperties.getPayAppKey()) | ||
| 143 | - .setChannelCode("wx_lite") // TODO @芋艿:【转账】这里要处理下; | ||
| 144 | - .setMerchantOrderId(withdraw.getId().toString()) | ||
| 145 | - .setPrice(withdraw.getPrice()) | ||
| 146 | - .setSubject("佣金提现") | ||
| 147 | - .setUserAccount(socialUser.getOpenid()).setUserIp(getClientIP()); | ||
| 148 | - // 2. 发起请求 | ||
| 149 | - return payTransferApi.createTransfer(payTransferCreateReqDTO); | 150 | + PayTransferCreateReqDTO transferReqDTO = new PayTransferCreateReqDTO() |
| 151 | + .setAppKey(tradeOrderProperties.getPayAppKey()).setChannelCode(channelCode) | ||
| 152 | + .setMerchantOrderId(withdraw.getId().toString()).setSubject("佣金提现").setPrice(withdraw.getPrice()) | ||
| 153 | + .setUserAccount(userAccount).setUserName(userName).setUserIp(getClientIP()) | ||
| 154 | + .setChannelExtras(channelExtras); | ||
| 155 | + // 1.3 发起请求 | ||
| 156 | + Long payTransferId = payTransferApi.createTransfer(transferReqDTO); | ||
| 157 | + | ||
| 158 | + // 2. 更新提现记录 | ||
| 159 | + brokerageWithdrawMapper.updateById(new BrokerageWithdrawDO().setId(withdraw.getId()) | ||
| 160 | + .setPayTransferId(payTransferId).setTransferChannelCode(channelCode)); | ||
| 150 | } | 161 | } |
| 151 | 162 | ||
| 152 | private BrokerageWithdrawDO validateBrokerageWithdrawExists(Long id) { | 163 | private BrokerageWithdrawDO validateBrokerageWithdrawExists(Long id) { |
| @@ -220,22 +231,71 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | @@ -220,22 +231,71 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | ||
| 220 | @Override | 231 | @Override |
| 221 | @Transactional(rollbackFor = Exception.class) | 232 | @Transactional(rollbackFor = Exception.class) |
| 222 | public void updateBrokerageWithdrawTransferred(Long id, Long payTransferId) { | 233 | public void updateBrokerageWithdrawTransferred(Long id, Long payTransferId) { |
| 223 | - BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id); | ||
| 224 | - PayTransferRespDTO transfer = payTransferApi.getTransfer(payTransferId); | ||
| 225 | - // TODO @luchi:建议参考支付那,即使成功的情况下,也要各种校验;金额是否匹配、转账单号是否匹配、是否重复调用; | ||
| 226 | - if (PayTransferStatusEnum.isSuccess(transfer.getStatus())) { | ||
| 227 | - withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus()); | ||
| 228 | - // TODO @luchi:发送站内信 | ||
| 229 | - } else if (PayTransferStatusEnum.isWaitingOrProcessing(transfer.getStatus())) { | ||
| 230 | - // TODO @luchi:这里,是不是不用更新哈? | ||
| 231 | - withdraw.setStatus(BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus()); | ||
| 232 | - } else { | ||
| 233 | - withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_FAIL.getStatus()); | ||
| 234 | - // 3.2 驳回时需要退还用户佣金 | ||
| 235 | - brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT, | ||
| 236 | - String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle()); | 234 | + // 1.1 校验提现单是否存在 |
| 235 | + BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id); | ||
| 236 | + if (withdraw == null) { | ||
| 237 | + log.error("[updateBrokerageWithdrawTransferred][withdraw({}) payTransfer({}) 不存在提现单,请进行处理!]", id, payTransferId); | ||
| 238 | + throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS); | ||
| 239 | + } | ||
| 240 | + // 1.2 校验提现单已经结束(成功或失败) | ||
| 241 | + if (ObjectUtils.equalsAny(withdraw.getStatus(), BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus(), | ||
| 242 | + BrokerageWithdrawStatusEnum.WITHDRAW_FAIL.getStatus())) { | ||
| 243 | + // 特殊:转账单编号相同,直接返回,说明重复回调 | ||
| 244 | + if (ObjectUtil.equal(withdraw.getPayTransferId(), payTransferId)) { | ||
| 245 | + log.warn("[updateBrokerageWithdrawTransferred][withdraw({}) 已结束,且转账单编号相同({}),直接返回]", withdraw, payTransferId); | ||
| 246 | + return; | ||
| 247 | + } | ||
| 248 | + // 异常:转账单编号不同,说明转账单编号错误 | ||
| 249 | + log.error("[updateBrokerageWithdrawTransferred][withdraw({}) 转账单不匹配({}),请进行处理!]", withdraw, payTransferId); | ||
| 250 | + throw exception(BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_TRANSFER_ID_ERROR); | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + // 2. 校验转账单的合法性 | ||
| 254 | + PayTransferRespDTO payTransfer = validateBrokerageTransferStatusCanUpdate(withdraw, payTransferId); | ||
| 255 | + | ||
| 256 | + // 3. 更新提现单状态 | ||
| 257 | + Integer newStatus = PayTransferStatusEnum.isSuccess(payTransfer.getStatus()) ? BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus() : | ||
| 258 | + PayTransferStatusEnum.isClosed(payTransfer.getStatus()) ? BrokerageWithdrawStatusEnum.WITHDRAW_FAIL.getStatus() : null; | ||
| 259 | + Assert.notNull(newStatus, "转账单状态({}) 不合法", payTransfer.getStatus()); | ||
| 260 | + brokerageWithdrawMapper.updateByIdAndStatus(withdraw.getId(), withdraw.getStatus(), | ||
| 261 | + new BrokerageWithdrawDO().setStatus(newStatus) | ||
| 262 | + .setTransferTime(payTransfer.getSuccessTime()) | ||
| 263 | + .setTransferErrorMsg(payTransfer.getChannelErrorMsg())); | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + private PayTransferRespDTO validateBrokerageTransferStatusCanUpdate(BrokerageWithdrawDO withdraw, Long payTransferId) { | ||
| 267 | + // 1. 校验转账单是否存在 | ||
| 268 | + PayTransferRespDTO payTransfer = payTransferApi.getTransfer(payTransferId); | ||
| 269 | + if (payTransfer == null) { | ||
| 270 | + log.error("[validateBrokerageTransferStatusCanUpdate][withdraw({}) payTransfer({}) 不存在,请进行处理!]", withdraw.getId(), payTransferId); | ||
| 271 | + throw exception(PAY_TRANSFER_NOT_FOUND); | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + // 2.1 校验转账单已成功或关闭 | ||
| 275 | + if (!PayTransferStatusEnum.isSuccessOrClosed(payTransfer.getStatus())) { | ||
| 276 | + log.error("[validateBrokerageTransferStatusCanUpdate][withdraw({}) payTransfer({}) 未结束,请进行处理!payTransfer 数据是:{}]", | ||
| 277 | + withdraw.getId(), payTransferId, JsonUtils.toJsonString(payTransfer)); | ||
| 278 | + throw exception(BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_TRANSFER_STATUS_NOT_SUCCESS_OR_CLOSED); | ||
| 279 | + } | ||
| 280 | + // 2.2 校验转账金额一致 | ||
| 281 | + if (ObjectUtil.notEqual(payTransfer.getPrice(), withdraw.getPrice())) { | ||
| 282 | + log.error("[validateBrokerageTransferStatusCanUpdate][withdraw({}) payTransfer({}) 转账金额不匹配,请进行处理!withdraw 数据是:{},payTransfer 数据是:{}]", | ||
| 283 | + withdraw.getId(), payTransferId, JsonUtils.toJsonString(withdraw), JsonUtils.toJsonString(payTransfer)); | ||
| 284 | + throw exception(BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_PRICE_NOT_MATCH); | ||
| 285 | + } | ||
| 286 | + // 2.3 校验转账订单匹配 | ||
| 287 | + if (ObjectUtil.notEqual(payTransfer.getMerchantOrderId(), withdraw.getId().toString())) { | ||
| 288 | + log.error("[validateBrokerageTransferStatusCanUpdate][withdraw({}) 转账单不匹配({}),请进行处理!payTransfer 数据是:{}]", | ||
| 289 | + withdraw.getId(), payTransferId, JsonUtils.toJsonString(payTransfer)); | ||
| 290 | + throw exception(BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_MERCHANT_EXISTS); | ||
| 291 | + } | ||
| 292 | + // 2.4 校验转账渠道一致 | ||
| 293 | + if (ObjectUtil.notEqual(payTransfer.getChannelCode(), withdraw.getTransferChannelCode())) { | ||
| 294 | + log.error("[validateBrokerageTransferStatusCanUpdate][withdraw({}) payTransfer({}) 转账渠道不匹配,请进行处理!withdraw 数据是:{},payTransfer 数据是:{}]", | ||
| 295 | + withdraw.getId(), payTransferId, JsonUtils.toJsonString(withdraw), JsonUtils.toJsonString(payTransfer)); | ||
| 296 | + throw exception(BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_CHANNEL_NOT_MATCH); | ||
| 237 | } | 297 | } |
| 238 | - brokerageWithdrawMapper.updateById(withdraw); | 298 | + return payTransfer; |
| 239 | } | 299 | } |
| 240 | 300 | ||
| 241 | @Override | 301 | @Override |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImplTest.java
| @@ -56,8 +56,8 @@ public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest { | @@ -56,8 +56,8 @@ public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest { | ||
| 56 | BrokerageWithdrawDO dbBrokerageWithdraw = randomPojo(BrokerageWithdrawDO.class, o -> { // 等会查询到 | 56 | BrokerageWithdrawDO dbBrokerageWithdraw = randomPojo(BrokerageWithdrawDO.class, o -> { // 等会查询到 |
| 57 | o.setUserId(null); | 57 | o.setUserId(null); |
| 58 | o.setType(null); | 58 | o.setType(null); |
| 59 | - o.setName(null); | ||
| 60 | - o.setAccountNo(null); | 59 | + o.setUserName(null); |
| 60 | + o.setUserAccount(null); | ||
| 61 | o.setBankName(null); | 61 | o.setBankName(null); |
| 62 | o.setStatus(null); | 62 | o.setStatus(null); |
| 63 | o.setCreateTime(null); | 63 | o.setCreateTime(null); |
| @@ -68,9 +68,9 @@ public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest { | @@ -68,9 +68,9 @@ public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest { | ||
| 68 | // 测试 type 不匹配 | 68 | // 测试 type 不匹配 |
| 69 | brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setType(null))); | 69 | brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setType(null))); |
| 70 | // 测试 name 不匹配 | 70 | // 测试 name 不匹配 |
| 71 | - brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setName(null))); | 71 | + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setUserName(null))); |
| 72 | // 测试 accountNo 不匹配 | 72 | // 测试 accountNo 不匹配 |
| 73 | - brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setAccountNo(null))); | 73 | + brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setUserAccount(null))); |
| 74 | // 测试 bankName 不匹配 | 74 | // 测试 bankName 不匹配 |
| 75 | brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setBankName(null))); | 75 | brokerageWithdrawMapper.insert(cloneIgnoreId(dbBrokerageWithdraw, o -> o.setBankName(null))); |
| 76 | // 测试 status 不匹配 | 76 | // 测试 status 不匹配 |
| @@ -87,8 +87,8 @@ public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest { | @@ -87,8 +87,8 @@ public class BrokerageWithdrawServiceImplTest extends BaseDbUnitTest { | ||
| 87 | BrokerageWithdrawPageReqVO reqVO = new BrokerageWithdrawPageReqVO(); | 87 | BrokerageWithdrawPageReqVO reqVO = new BrokerageWithdrawPageReqVO(); |
| 88 | reqVO.setUserId(null); | 88 | reqVO.setUserId(null); |
| 89 | reqVO.setType(null); | 89 | reqVO.setType(null); |
| 90 | - reqVO.setName(null); | ||
| 91 | - reqVO.setAccountNo(null); | 90 | + reqVO.setUserName(null); |
| 91 | + reqVO.setUserAccount(null); | ||
| 92 | reqVO.setBankName(null); | 92 | reqVO.setBankName(null); |
| 93 | reqVO.setStatus(null); | 93 | reqVO.setStatus(null); |
| 94 | reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); | 94 | reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/wallet/PayWalletApi.java
| 1 | package cn.iocoder.yudao.module.pay.api.wallet; | 1 | package cn.iocoder.yudao.module.pay.api.wallet; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletAddBalanceReqDTO; | 3 | import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletAddBalanceReqDTO; |
| 4 | +import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletRespDTO; | ||
| 4 | 5 | ||
| 5 | /** | 6 | /** |
| 6 | * 钱包 API 接口 | 7 | * 钱包 API 接口 |
| @@ -16,4 +17,13 @@ public interface PayWalletApi { | @@ -16,4 +17,13 @@ public interface PayWalletApi { | ||
| 16 | */ | 17 | */ |
| 17 | void addWalletBalance(PayWalletAddBalanceReqDTO reqDTO); | 18 | void addWalletBalance(PayWalletAddBalanceReqDTO reqDTO); |
| 18 | 19 | ||
| 20 | + /** | ||
| 21 | + * 获取钱包信息 | ||
| 22 | + * | ||
| 23 | + * @param userId 用户编号 | ||
| 24 | + * @param userType 用户类型 | ||
| 25 | + * @return 钱包信息 | ||
| 26 | + */ | ||
| 27 | + PayWalletRespDTO getOrCreateWallet(Long userId, Integer userType); | ||
| 28 | + | ||
| 19 | } | 29 | } |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/wallet/dto/PayWalletRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.pay.api.wallet.dto; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 钱包 Response DTO | ||
| 8 | + * | ||
| 9 | + * @author jason | ||
| 10 | + */ | ||
| 11 | +@Data | ||
| 12 | +public class PayWalletRespDTO { | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 编号 | ||
| 16 | + */ | ||
| 17 | + private Long id; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 用户 id | ||
| 21 | + * | ||
| 22 | + * 关联 MemberUserDO 的 id 编号 | ||
| 23 | + * 关联 AdminUserDO 的 id 编号 | ||
| 24 | + */ | ||
| 25 | + private Long userId; | ||
| 26 | + /** | ||
| 27 | + * 用户类型, 预留 多商户转帐可能需要用到 | ||
| 28 | + * | ||
| 29 | + * 关联 {@link UserTypeEnum} | ||
| 30 | + */ | ||
| 31 | + private Integer userType; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 余额,单位分 | ||
| 35 | + */ | ||
| 36 | + private Integer balance; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 冻结金额,单位分 | ||
| 40 | + */ | ||
| 41 | + private Integer freezePrice; | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 累计支出,单位分 | ||
| 45 | + */ | ||
| 46 | + private Integer totalExpense; | ||
| 47 | + /** | ||
| 48 | + * 累计充值,单位分 | ||
| 49 | + */ | ||
| 50 | + private Integer totalRecharge; | ||
| 51 | + | ||
| 52 | +} |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/wallet/PayWalletApiImpl.java
| 1 | package cn.iocoder.yudao.module.pay.api.wallet; | 1 | package cn.iocoder.yudao.module.pay.api.wallet; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 4 | import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletAddBalanceReqDTO; | 5 | import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletAddBalanceReqDTO; |
| 6 | +import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletRespDTO; | ||
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | 7 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 6 | import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; | 8 | import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; |
| 7 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; | 9 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; |
| @@ -30,4 +32,10 @@ public class PayWalletApiImpl implements PayWalletApi { | @@ -30,4 +32,10 @@ public class PayWalletApiImpl implements PayWalletApi { | ||
| 30 | payWalletService.addWalletBalance(wallet.getId(), reqDTO.getBizId(), bizType, reqDTO.getPrice()); | 32 | payWalletService.addWalletBalance(wallet.getId(), reqDTO.getBizId(), bizType, reqDTO.getPrice()); |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 35 | + @Override | ||
| 36 | + public PayWalletRespDTO getOrCreateWallet(Long userId, Integer userType) { | ||
| 37 | + PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); | ||
| 38 | + return BeanUtils.toBean(wallet, PayWalletRespDTO.class); | ||
| 39 | + } | ||
| 40 | + | ||
| 33 | } | 41 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoWithdrawController.http
| 1 | -### 请求 /pay/demo-withdraw/create 接口(支付宝) => 成功 | 1 | +### 请求 /pay/demo-withdraw/create 接口(支付宝) |
| 2 | POST {{baseUrl}}/pay/demo-withdraw/create | 2 | POST {{baseUrl}}/pay/demo-withdraw/create |
| 3 | Authorization: Bearer {{token}} | 3 | Authorization: Bearer {{token}} |
| 4 | Content-Type: application/json | 4 | Content-Type: application/json |
| @@ -12,7 +12,7 @@ tenant-id: {{adminTenantId}} | @@ -12,7 +12,7 @@ tenant-id: {{adminTenantId}} | ||
| 12 | "userName": "oespxk7368" | 12 | "userName": "oespxk7368" |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | -### 请求 /pay/demo-withdraw/create 接口(微信余额) => 成功 | 15 | +### 请求 /pay/demo-withdraw/create 接口(微信余额) |
| 16 | POST {{baseUrl}}/pay/demo-withdraw/create | 16 | POST {{baseUrl}}/pay/demo-withdraw/create |
| 17 | Authorization: Bearer {{token}} | 17 | Authorization: Bearer {{token}} |
| 18 | Content-Type: application/json | 18 | Content-Type: application/json |
| @@ -26,7 +26,7 @@ tenant-id: {{adminTenantId}} | @@ -26,7 +26,7 @@ tenant-id: {{adminTenantId}} | ||
| 26 | "userName": "芋艿" | 26 | "userName": "芋艿" |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | -### 请求 /pay/demo-withdraw/create 接口(钱包余额) => 成功 | 29 | +### 请求 /pay/demo-withdraw/create 接口(钱包余额) |
| 30 | POST {{baseUrl}}/pay/demo-withdraw/create | 30 | POST {{baseUrl}}/pay/demo-withdraw/create |
| 31 | Authorization: Bearer {{token}} | 31 | Authorization: Bearer {{token}} |
| 32 | Content-Type: application/json | 32 | Content-Type: application/json |
| @@ -39,12 +39,12 @@ tenant-id: {{adminTenantId}} | @@ -39,12 +39,12 @@ tenant-id: {{adminTenantId}} | ||
| 39 | "userAccount": "1" | 39 | "userAccount": "1" |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | -### 请求 /pay/demo-withdraw/transfer 接口(发起转账) => 成功 | 42 | +### 请求 /pay/demo-withdraw/transfer 接口(发起转账) |
| 43 | POST {{baseUrl}}/pay/demo-withdraw/transfer?id=1 | 43 | POST {{baseUrl}}/pay/demo-withdraw/transfer?id=1 |
| 44 | Authorization: Bearer {{token}} | 44 | Authorization: Bearer {{token}} |
| 45 | tenant-id: {{adminTenantId}} | 45 | tenant-id: {{adminTenantId}} |
| 46 | 46 | ||
| 47 | -### 请求 /pay/demo-withdraw/page 接口(查询分页) => 成功 | 47 | +### 请求 /pay/demo-withdraw/page 接口(查询分页) |
| 48 | GET {{baseUrl}}/pay/demo-withdraw/page?pageNo=1&pageSize=10 | 48 | GET {{baseUrl}}/pay/demo-withdraw/page?pageNo=1&pageSize=10 |
| 49 | Authorization: Bearer {{token}} | 49 | Authorization: Bearer {{token}} |
| 50 | tenant-id: {{adminTenantId}} | 50 | tenant-id: {{adminTenantId}} |
| 51 | \ No newline at end of file | 51 | \ No newline at end of file |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoWithdrawController.java
| @@ -51,11 +51,11 @@ public class PayDemoWithdrawController { | @@ -51,11 +51,11 @@ public class PayDemoWithdrawController { | ||
| 51 | return success(BeanUtils.toBean(pageResult, PayDemoWithdrawRespVO.class)); | 51 | return success(BeanUtils.toBean(pageResult, PayDemoWithdrawRespVO.class)); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | - @PostMapping("/update-status") | 54 | + @PostMapping("/update-transferred") |
| 55 | @Operation(summary = "更新示例提现单的转账状态") // 由 pay-module 转账服务,进行回调 | 55 | @Operation(summary = "更新示例提现单的转账状态") // 由 pay-module 转账服务,进行回调 |
| 56 | @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现 | 56 | @PermitAll // 无需登录,安全由 PayDemoTransferService 内部校验实现 |
| 57 | - public CommonResult<Boolean> updateDemoWithdrawStatus(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) { | ||
| 58 | - demoWithdrawService.updateDemoWithdrawStatus(Long.valueOf(notifyReqDTO.getMerchantOrderId()), | 57 | + public CommonResult<Boolean> updateDemoWithdrawTransferred(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) { |
| 58 | + demoWithdrawService.updateDemoWithdrawTransferred(Long.valueOf(notifyReqDTO.getMerchantOrderId()), | ||
| 59 | notifyReqDTO.getPayTransferId()); | 59 | notifyReqDTO.getPayTransferId()); |
| 60 | return success(true); | 60 | return success(true); |
| 61 | } | 61 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
| @@ -124,7 +124,7 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService { | @@ -124,7 +124,7 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService { | ||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | @Override | 126 | @Override |
| 127 | - public void updateDemoWithdrawStatus(Long id, Long payTransferId) { | 127 | + public void updateDemoWithdrawTransferred(Long id, Long payTransferId) { |
| 128 | // 1.1 校验转账单是否存在 | 128 | // 1.1 校验转账单是否存在 |
| 129 | PayDemoWithdrawDO withdraw = demoTransferMapper.selectById(id); | 129 | PayDemoWithdrawDO withdraw = demoTransferMapper.selectById(id); |
| 130 | if (withdraw == null) { | 130 | if (withdraw == null) { |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoWithdrawService.java
| @@ -43,6 +43,6 @@ public interface PayDemoWithdrawService { | @@ -43,6 +43,6 @@ public interface PayDemoWithdrawService { | ||
| 43 | * @param id 编号 | 43 | * @param id 编号 |
| 44 | * @param payTransferId 转账单编号 | 44 | * @param payTransferId 转账单编号 |
| 45 | */ | 45 | */ |
| 46 | - void updateDemoWithdrawStatus(Long id, Long payTransferId); | 46 | + void updateDemoWithdrawTransferred(Long id, Long payTransferId); |
| 47 | 47 | ||
| 48 | } | 48 | } |