Commit 38c76806a3da36f8b97a5943c1410c94011623b0
1 parent
f81dc105
feat:【PAY 支付】微信支付的转账,接入新的 API(需要继续测试,= = 真麻烦)
feat:【PAY 支付】钱包支持转账功能
Showing
17 changed files
with
249 additions
and
205 deletions
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java
| @@ -113,7 +113,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | @@ -113,7 +113,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { | ||
| 113 | if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) { | 113 | if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) { |
| 114 | payWalletApi.addWalletBalance(new PayWalletAddBalanceReqDTO() | 114 | payWalletApi.addWalletBalance(new PayWalletAddBalanceReqDTO() |
| 115 | .setUserId(withdraw.getUserId()).setUserType(UserTypeEnum.MEMBER.getValue()) | 115 | .setUserId(withdraw.getUserId()).setUserType(UserTypeEnum.MEMBER.getValue()) |
| 116 | - .setBizType(PayWalletBizTypeEnum.BROKERAGE_WITHDRAW.getType()).setBizId(withdraw.getId().toString()) | 116 | + .setBizType(PayWalletBizTypeEnum.TRANSFER.getType()).setBizId(withdraw.getId().toString()) |
| 117 | .setPrice(withdraw.getPrice())); | 117 | .setPrice(withdraw.getPrice())); |
| 118 | // 1.2 微信 API | 118 | // 1.2 微信 API |
| 119 | } else if (BrokerageWithdrawTypeEnum.WECHAT_API.getType().equals(withdraw.getType())) { | 119 | } else if (BrokerageWithdrawTypeEnum.WECHAT_API.getType().equals(withdraw.getType())) { |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferCreateReqDTO.java
| 1 | package cn.iocoder.yudao.module.pay.api.transfer.dto; | 1 | package cn.iocoder.yudao.module.pay.api.transfer.dto; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 3 | import jakarta.validation.constraints.Min; | 5 | import jakarta.validation.constraints.Min; |
| 4 | import jakarta.validation.constraints.NotEmpty; | 6 | import jakarta.validation.constraints.NotEmpty; |
| 5 | import jakarta.validation.constraints.NotNull; | 7 | import jakarta.validation.constraints.NotNull; |
| 6 | import lombok.Data; | 8 | import lombok.Data; |
| 7 | 9 | ||
| 10 | +import java.util.ArrayList; | ||
| 11 | +import java.util.HashMap; | ||
| 12 | +import java.util.List; | ||
| 8 | import java.util.Map; | 13 | import java.util.Map; |
| 9 | 14 | ||
| 10 | /** | 15 | /** |
| @@ -70,4 +75,46 @@ public class PayTransferCreateReqDTO { | @@ -70,4 +75,46 @@ public class PayTransferCreateReqDTO { | ||
| 70 | */ | 75 | */ |
| 71 | private String userName; | 76 | private String userName; |
| 72 | 77 | ||
| 78 | + /** | ||
| 79 | + * 【微信】现金营销场景 | ||
| 80 | + * | ||
| 81 | + * @param activityName 活动名称 | ||
| 82 | + * @param rewardDescription 奖励说明 | ||
| 83 | + * @return channelExtras | ||
| 84 | + */ | ||
| 85 | + public static Map<String, String> buildWeiXinChannelExtra1000(String activityName, String rewardDescription) { | ||
| 86 | + return buildWeiXinChannelExtra(1000, | ||
| 87 | + "活动名称", activityName, | ||
| 88 | + "奖励说明", rewardDescription); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * 【微信】企业报销场景 | ||
| 93 | + * | ||
| 94 | + * @param expenseType 报销类型 | ||
| 95 | + * @param expenseDescription 报销说明 | ||
| 96 | + * @return channelExtras | ||
| 97 | + */ | ||
| 98 | + public static Map<String, String> buildWeiXinChannelExtra1006(String expenseType, String expenseDescription) { | ||
| 99 | + return buildWeiXinChannelExtra(1006, | ||
| 100 | + "报销类型", expenseType, | ||
| 101 | + "报销说明", expenseDescription); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + private static Map<String, String> buildWeiXinChannelExtra(Integer sceneId, String... values) { | ||
| 105 | + Map<String, String> channelExtras = new HashMap<>(); | ||
| 106 | + // 构建场景报备信息列表 | ||
| 107 | + List<Map<String, String>> sceneReportInfos = new ArrayList<>(); | ||
| 108 | + for (int i = 0; i < values.length; i += 2) { | ||
| 109 | + Map<String, String> info = new HashMap<>(); | ||
| 110 | + info.put("infoType", values[i]); | ||
| 111 | + info.put("infoContent", values[i + 1]); | ||
| 112 | + sceneReportInfos.add(info); | ||
| 113 | + } | ||
| 114 | + // 设置场景ID和场景报备信息 | ||
| 115 | + channelExtras.put("sceneId", StrUtil.toString(sceneId)); | ||
| 116 | + channelExtras.put("sceneReportInfos", JsonUtils.toJsonString(sceneReportInfos)); | ||
| 117 | + return channelExtras; | ||
| 118 | + } | ||
| 119 | + | ||
| 73 | } | 120 | } |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/wallet/PayWalletBizTypeEnum.java
| @@ -20,7 +20,7 @@ public enum PayWalletBizTypeEnum implements ArrayValuable<Integer> { | @@ -20,7 +20,7 @@ public enum PayWalletBizTypeEnum implements ArrayValuable<Integer> { | ||
| 20 | PAYMENT(3, "支付"), | 20 | PAYMENT(3, "支付"), |
| 21 | PAYMENT_REFUND(4, "支付退款"), | 21 | PAYMENT_REFUND(4, "支付退款"), |
| 22 | UPDATE_BALANCE(5, "更新余额"), | 22 | UPDATE_BALANCE(5, "更新余额"), |
| 23 | - BROKERAGE_WITHDRAW(6, "分佣提现"); | 23 | + TRANSFER(6, "转账"); |
| 24 | 24 | ||
| 25 | /** | 25 | /** |
| 26 | * 业务分类 | 26 | * 业务分类 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/PayDemoWithdrawController.http
| 1 | -### 请求 /pay/pay/demo-order 接口 => 成功 | 1 | +### 请求 /pay/pay/demo-order 接口(支付宝) => 成功 |
| 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 |
| @@ -10,4 +10,31 @@ tenant-id: {{adminTenantId}} | @@ -10,4 +10,31 @@ tenant-id: {{adminTenantId}} | ||
| 10 | "price": 10, | 10 | "price": 10, |
| 11 | "userAccount": "oespxk7368@sandbox.com", | 11 | "userAccount": "oespxk7368@sandbox.com", |
| 12 | "userName": "oespxk7368" | 12 | "userName": "oespxk7368" |
| 13 | +} | ||
| 14 | + | ||
| 15 | +### 请求 /pay/pay/demo-order 接口(微信余额) => 成功 | ||
| 16 | +POST {{baseUrl}}/pay/demo-withdraw/create | ||
| 17 | +Authorization: Bearer {{token}} | ||
| 18 | +Content-Type: application/json | ||
| 19 | +tenant-id: {{adminTenantId}} | ||
| 20 | + | ||
| 21 | +{ | ||
| 22 | + "type": 2, | ||
| 23 | + "subject": "测试转账", | ||
| 24 | + "price": 1, | ||
| 25 | + "userAccount": "oiSC85elO_OZogXODC5RoGyXamK4", | ||
| 26 | + "userName": "芋艿" | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +### 请求 /pay/pay/demo-order 接口(钱包余额) => 成功 | ||
| 30 | +POST {{baseUrl}}/pay/demo-withdraw/create | ||
| 31 | +Authorization: Bearer {{token}} | ||
| 32 | +Content-Type: application/json | ||
| 33 | +tenant-id: {{adminTenantId}} | ||
| 34 | + | ||
| 35 | +{ | ||
| 36 | + "type": 3, | ||
| 37 | + "subject": "测试转账", | ||
| 38 | + "price": 1, | ||
| 39 | + "userAccount": "1" | ||
| 13 | } | 40 | } |
| 14 | \ No newline at end of file | 41 | \ No newline at end of file |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/demo/vo/withdraw/PayDemoWithdrawCreateReqVO.java
| @@ -27,7 +27,6 @@ public class PayDemoWithdrawCreateReqVO { | @@ -27,7 +27,6 @@ public class PayDemoWithdrawCreateReqVO { | ||
| 27 | private String userAccount; | 27 | private String userAccount; |
| 28 | 28 | ||
| 29 | @Schema(description = "收款人姓名", example = "test1") | 29 | @Schema(description = "收款人姓名", example = "test1") |
| 30 | - @NotBlank(message = "收款人姓名不能为空") | ||
| 31 | private String userName; | 30 | private String userName; |
| 32 | 31 | ||
| 33 | @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 32 | @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
| @@ -12,10 +12,12 @@ import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; | @@ -12,10 +12,12 @@ import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; | ||
| 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 14 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | 14 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 15 | +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | ||
| 15 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | 16 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 16 | import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient; | 17 | import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient; |
| 17 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | 18 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 18 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 19 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 20 | +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; | ||
| 19 | import com.google.common.collect.Maps; | 21 | import com.google.common.collect.Maps; |
| 20 | import io.swagger.v3.oas.annotations.Operation; | 22 | import io.swagger.v3.oas.annotations.Operation; |
| 21 | import io.swagger.v3.oas.annotations.Parameter; | 23 | import io.swagger.v3.oas.annotations.Parameter; |
| @@ -51,6 +53,8 @@ public class PayOrderController { | @@ -51,6 +53,8 @@ public class PayOrderController { | ||
| 51 | private PayOrderService orderService; | 53 | private PayOrderService orderService; |
| 52 | @Resource | 54 | @Resource |
| 53 | private PayAppService appService; | 55 | private PayAppService appService; |
| 56 | + @Resource | ||
| 57 | + private PayWalletService payWalletService; | ||
| 54 | 58 | ||
| 55 | @GetMapping("/get") | 59 | @GetMapping("/get") |
| 56 | @Operation(summary = "获得支付订单") | 60 | @Operation(summary = "获得支付订单") |
| @@ -92,11 +96,11 @@ public class PayOrderController { | @@ -92,11 +96,11 @@ public class PayOrderController { | ||
| 92 | public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { | 96 | public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { |
| 93 | // 1. 钱包支付事,需要额外传 user_id 和 user_type | 97 | // 1. 钱包支付事,需要额外传 user_id 和 user_type |
| 94 | if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { | 98 | if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { |
| 95 | - Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? | ||
| 96 | - Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras(); | ||
| 97 | - channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId())); | ||
| 98 | - channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType())); | ||
| 99 | - reqVO.setChannelExtras(channelExtras); | 99 | + if (reqVO.getChannelExtras() == null) { |
| 100 | + reqVO.setChannelExtras(Maps.newHashMapWithExpectedSize(1)); | ||
| 101 | + } | ||
| 102 | + PayWalletDO wallet = payWalletService.getOrCreateWallet(getLoginUserId(), getLoginUserType()); | ||
| 103 | + reqVO.getChannelExtras().put(WalletPayClient.WALLET_ID_KEY, String.valueOf(wallet.getId())); | ||
| 100 | } | 104 | } |
| 101 | 105 | ||
| 102 | // 2. 提交支付 | 106 | // 2. 提交支付 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java
| @@ -9,9 +9,11 @@ import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqV | @@ -9,9 +9,11 @@ import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqV | ||
| 9 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; | 9 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; |
| 10 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; | 10 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; |
| 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 12 | +import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | ||
| 12 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | 13 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 13 | import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient; | 14 | import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient; |
| 14 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 15 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 16 | +import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; | ||
| 15 | import com.google.common.collect.Maps; | 17 | import com.google.common.collect.Maps; |
| 16 | import io.swagger.v3.oas.annotations.Operation; | 18 | import io.swagger.v3.oas.annotations.Operation; |
| 17 | import io.swagger.v3.oas.annotations.Parameter; | 19 | import io.swagger.v3.oas.annotations.Parameter; |
| @@ -22,7 +24,6 @@ import lombok.extern.slf4j.Slf4j; | @@ -22,7 +24,6 @@ import lombok.extern.slf4j.Slf4j; | ||
| 22 | import org.springframework.validation.annotation.Validated; | 24 | import org.springframework.validation.annotation.Validated; |
| 23 | import org.springframework.web.bind.annotation.*; | 25 | import org.springframework.web.bind.annotation.*; |
| 24 | 26 | ||
| 25 | -import java.util.Map; | ||
| 26 | import java.util.Objects; | 27 | import java.util.Objects; |
| 27 | 28 | ||
| 28 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 29 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| @@ -39,6 +40,8 @@ public class AppPayOrderController { | @@ -39,6 +40,8 @@ public class AppPayOrderController { | ||
| 39 | 40 | ||
| 40 | @Resource | 41 | @Resource |
| 41 | private PayOrderService payOrderService; | 42 | private PayOrderService payOrderService; |
| 43 | + @Resource | ||
| 44 | + private PayWalletService payWalletService; | ||
| 42 | 45 | ||
| 43 | @GetMapping("/get") | 46 | @GetMapping("/get") |
| 44 | @Operation(summary = "获得支付订单") | 47 | @Operation(summary = "获得支付订单") |
| @@ -63,11 +66,11 @@ public class AppPayOrderController { | @@ -63,11 +66,11 @@ public class AppPayOrderController { | ||
| 63 | public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) { | 66 | public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) { |
| 64 | // 1. 钱包支付事,需要额外传 user_id 和 user_type | 67 | // 1. 钱包支付事,需要额外传 user_id 和 user_type |
| 65 | if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { | 68 | if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) { |
| 66 | - Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? | ||
| 67 | - Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras(); | ||
| 68 | - channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId())); | ||
| 69 | - channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType())); | ||
| 70 | - reqVO.setChannelExtras(channelExtras); | 69 | + if (reqVO.getChannelExtras() == null) { |
| 70 | + reqVO.setChannelExtras(Maps.newHashMapWithExpectedSize(1)); | ||
| 71 | + } | ||
| 72 | + PayWalletDO wallet = payWalletService.getOrCreateWallet(getLoginUserId(), getLoginUserType()); | ||
| 73 | + reqVO.getChannelExtras().put(WalletPayClient.WALLET_ID_KEY, String.valueOf(wallet.getId())); | ||
| 71 | } | 74 | } |
| 72 | 75 | ||
| 73 | // 2. 提交支付 | 76 | // 2. 提交支付 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
| @@ -53,6 +53,10 @@ public interface PayTransferMapper extends BaseMapperX<PayTransferDO> { | @@ -53,6 +53,10 @@ public interface PayTransferMapper extends BaseMapperX<PayTransferDO> { | ||
| 53 | PayTransferDO::getNo, no); | 53 | PayTransferDO::getNo, no); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | + default PayTransferDO selectByNo(String no) { | ||
| 57 | + return selectOne(PayTransferDO::getNo, no); | ||
| 58 | + } | ||
| 59 | + | ||
| 56 | } | 60 | } |
| 57 | 61 | ||
| 58 | 62 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
| @@ -14,13 +14,16 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | @@ -14,13 +14,16 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | ||
| 14 | import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; | 14 | import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; |
| 15 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | 15 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 16 | import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | 16 | import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; |
| 17 | +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; | ||
| 17 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | 18 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 18 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | 19 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 20 | +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; | ||
| 19 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 21 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 20 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | 22 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 21 | import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; | 23 | import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; |
| 22 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 24 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 23 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | 25 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 26 | +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; | ||
| 24 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; | 27 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; |
| 25 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService; | 28 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletTransactionService; |
| 26 | import lombok.extern.slf4j.Slf4j; | 29 | import lombok.extern.slf4j.Slf4j; |
| @@ -39,13 +42,14 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FO | @@ -39,13 +42,14 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FO | ||
| 39 | @Slf4j | 42 | @Slf4j |
| 40 | public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | 43 | public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 41 | 44 | ||
| 42 | - public static final String USER_ID_KEY = "user_id"; | ||
| 43 | - public static final String USER_TYPE_KEY = "user_type"; | 45 | + public static final String WALLET_ID_KEY = "walletId"; |
| 44 | 46 | ||
| 45 | private PayWalletService wallService; | 47 | private PayWalletService wallService; |
| 46 | private PayWalletTransactionService walletTransactionService; | 48 | private PayWalletTransactionService walletTransactionService; |
| 49 | + | ||
| 47 | private PayOrderService orderService; | 50 | private PayOrderService orderService; |
| 48 | private PayRefundService refundService; | 51 | private PayRefundService refundService; |
| 52 | + private PayTransferService transferService; | ||
| 49 | 53 | ||
| 50 | public WalletPayClient(Long channelId, NonePayClientConfig config) { | 54 | public WalletPayClient(Long channelId, NonePayClientConfig config) { |
| 51 | super(channelId, PayChannelEnum.WALLET.getCode(), config); | 55 | super(channelId, PayChannelEnum.WALLET.getCode(), config); |
| @@ -62,19 +66,18 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | @@ -62,19 +66,18 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | ||
| 62 | } | 66 | } |
| 63 | 67 | ||
| 64 | @Override | 68 | @Override |
| 69 | + @SuppressWarnings("PatternVariableCanBeUsed") | ||
| 65 | protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | 70 | protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { |
| 66 | try { | 71 | try { |
| 67 | - Long userId = MapUtil.getLong(reqDTO.getChannelExtras(), USER_ID_KEY); | ||
| 68 | - Integer userType = MapUtil.getInt(reqDTO.getChannelExtras(), USER_TYPE_KEY); | ||
| 69 | - Assert.notNull(userId, "用户 id 不能为空"); | ||
| 70 | - Assert.notNull(userType, "用户类型不能为空"); | ||
| 71 | - PayWalletTransactionDO transaction = wallService.orderPay(userId, userType, reqDTO.getOutTradeNo(), | ||
| 72 | - reqDTO.getPrice()); | 72 | + Long walletId = MapUtil.getLong(reqDTO.getChannelExtras(), WALLET_ID_KEY); |
| 73 | + Assert.notNull(walletId, "钱包编号"); | ||
| 74 | + PayWalletTransactionDO transaction = wallService.orderPay(walletId, | ||
| 75 | + reqDTO.getOutTradeNo(), reqDTO.getPrice()); | ||
| 73 | return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(), | 76 | return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(), |
| 74 | transaction.getCreateTime(), | 77 | transaction.getCreateTime(), |
| 75 | reqDTO.getOutTradeNo(), transaction); | 78 | reqDTO.getOutTradeNo(), transaction); |
| 76 | } catch (Throwable ex) { | 79 | } catch (Throwable ex) { |
| 77 | - log.error("[doUnifiedOrder] 失败", ex); | 80 | + log.error("[doUnifiedOrder][reqDTO({}) 异常]", reqDTO, ex); |
| 78 | Integer errorCode = INTERNAL_SERVER_ERROR.getCode(); | 81 | Integer errorCode = INTERNAL_SERVER_ERROR.getCode(); |
| 79 | String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); | 82 | String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); |
| 80 | if (ex instanceof ServiceException) { | 83 | if (ex instanceof ServiceException) { |
| @@ -122,6 +125,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | @@ -122,6 +125,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | ||
| 122 | } | 125 | } |
| 123 | 126 | ||
| 124 | @Override | 127 | @Override |
| 128 | + @SuppressWarnings("PatternVariableCanBeUsed") | ||
| 125 | protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | 129 | protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { |
| 126 | try { | 130 | try { |
| 127 | PayWalletTransactionDO payWalletTransaction = wallService.orderRefund(reqDTO.getOutRefundNo(), | 131 | PayWalletTransactionDO payWalletTransaction = wallService.orderRefund(reqDTO.getOutRefundNo(), |
| @@ -129,7 +133,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | @@ -129,7 +133,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | ||
| 129 | return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreateTime(), | 133 | return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreateTime(), |
| 130 | reqDTO.getOutRefundNo(), payWalletTransaction); | 134 | reqDTO.getOutRefundNo(), payWalletTransaction); |
| 131 | } catch (Throwable ex) { | 135 | } catch (Throwable ex) { |
| 132 | - log.error("[doUnifiedRefund] 失败", ex); | 136 | + log.error("[doUnifiedRefund][reqDOT({}) 异常]", reqDTO, ex); |
| 133 | Integer errorCode = INTERNAL_SERVER_ERROR.getCode(); | 137 | Integer errorCode = INTERNAL_SERVER_ERROR.getCode(); |
| 134 | String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); | 138 | String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); |
| 135 | if (ex instanceof ServiceException) { | 139 | if (ex instanceof ServiceException) { |
| @@ -177,18 +181,71 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | @@ -177,18 +181,71 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { | ||
| 177 | } | 181 | } |
| 178 | 182 | ||
| 179 | @Override | 183 | @Override |
| 180 | - protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) { | ||
| 181 | - throw new UnsupportedOperationException("未实现"); | 184 | + @SuppressWarnings("PatternVariableCanBeUsed") |
| 185 | + public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { | ||
| 186 | + try { | ||
| 187 | + Long walletId = Long.parseLong(reqDTO.getUserAccount()); | ||
| 188 | + PayWalletTransactionDO transaction = wallService.addWalletBalance(walletId, String.valueOf(reqDTO.getOutTransferNo()), | ||
| 189 | + PayWalletBizTypeEnum.TRANSFER, reqDTO.getPrice()); | ||
| 190 | + return PayTransferRespDTO.successOf(transaction.getNo(), transaction.getCreateTime(), | ||
| 191 | + reqDTO.getOutTransferNo(), transaction); | ||
| 192 | + } catch (Throwable ex) { | ||
| 193 | + log.error("[doUnifiedTransfer][reqDTO({}) 异常]", reqDTO, ex); | ||
| 194 | + Integer errorCode = INTERNAL_SERVER_ERROR.getCode(); | ||
| 195 | + String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); | ||
| 196 | + if (ex instanceof ServiceException) { | ||
| 197 | + ServiceException serviceException = (ServiceException) ex; | ||
| 198 | + errorCode = serviceException.getCode(); | ||
| 199 | + errorMsg = serviceException.getMessage(); | ||
| 200 | + } | ||
| 201 | + return PayTransferRespDTO.closedOf(String.valueOf(errorCode), errorMsg, | ||
| 202 | + reqDTO.getOutTransferNo(), ""); | ||
| 203 | + } | ||
| 182 | } | 204 | } |
| 183 | 205 | ||
| 184 | @Override | 206 | @Override |
| 185 | - public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { | ||
| 186 | - throw new UnsupportedOperationException("待实现"); | 207 | + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) { |
| 208 | + throw new UnsupportedOperationException("钱包支付无转账回调"); | ||
| 187 | } | 209 | } |
| 188 | 210 | ||
| 189 | @Override | 211 | @Override |
| 190 | protected PayTransferRespDTO doGetTransfer(String outTradeNo) { | 212 | protected PayTransferRespDTO doGetTransfer(String outTradeNo) { |
| 191 | - throw new UnsupportedOperationException("待实现"); | 213 | + if (transferService == null) { |
| 214 | + transferService = SpringUtil.getBean(PayTransferService.class); | ||
| 215 | + } | ||
| 216 | + // 获取转账单 | ||
| 217 | + PayTransferDO transfer = transferService.getTransferByNo(outTradeNo); | ||
| 218 | + // 转账单不存在,返回关闭状态 | ||
| 219 | + if (transfer == null) { | ||
| 220 | + return PayTransferRespDTO.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getCode()), | ||
| 221 | + PAY_ORDER_EXTENSION_NOT_FOUND.getMsg(), outTradeNo, ""); | ||
| 222 | + } | ||
| 223 | + // 关闭状态 | ||
| 224 | + if (PayTransferStatusRespEnum.isClosed(transfer.getStatus())) { | ||
| 225 | + return PayTransferRespDTO.closedOf(transfer.getChannelErrorCode(), | ||
| 226 | + transfer.getChannelErrorMsg(), outTradeNo, ""); | ||
| 227 | + } | ||
| 228 | + // 成功状态 | ||
| 229 | + if (PayTransferStatusRespEnum.isSuccess(transfer.getStatus())) { | ||
| 230 | + PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransaction( | ||
| 231 | + String.valueOf(transfer.getId()), PayWalletBizTypeEnum.TRANSFER); | ||
| 232 | + Assert.notNull(walletTransaction, "转账单 {} 钱包流水不能为空", outTradeNo); | ||
| 233 | + return PayTransferRespDTO.successOf(walletTransaction.getNo(), walletTransaction.getCreateTime(), | ||
| 234 | + outTradeNo, walletTransaction); | ||
| 235 | + } | ||
| 236 | + // 处理中状态 | ||
| 237 | + if (PayTransferStatusRespEnum.isProcessing(transfer.getStatus())) { | ||
| 238 | + return PayTransferRespDTO.processingOf(transfer.getChannelTransferNo(), | ||
| 239 | + outTradeNo, transfer); | ||
| 240 | + } | ||
| 241 | + // 等待状态 | ||
| 242 | + if (transfer.getStatus().equals(PayTransferStatusRespEnum.WAITING.getStatus())) { | ||
| 243 | + return PayTransferRespDTO.waitingOf(transfer.getChannelTransferNo(), | ||
| 244 | + outTradeNo, transfer); | ||
| 245 | + } | ||
| 246 | + // 其它状态为无效状态 | ||
| 247 | + log.error("[doGetTransfer] 转账单 {} 的状态不正确", outTradeNo); | ||
| 248 | + throw new IllegalStateException(String.format("转账单[%s] 状态不正确", outTradeNo)); | ||
| 192 | } | 249 | } |
| 193 | 250 | ||
| 194 | } | 251 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
| @@ -57,11 +57,16 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService { | @@ -57,11 +57,16 @@ public class PayDemoTransferServiceImpl implements PayDemoWithdrawService { | ||
| 57 | demoTransferMapper.insert(withdraw); | 57 | demoTransferMapper.insert(withdraw); |
| 58 | 58 | ||
| 59 | // 2.1 创建支付单 | 59 | // 2.1 创建支付单 |
| 60 | - Long payTransferId = payTransferApi.createTransfer(new PayTransferCreateReqDTO() | 60 | + PayTransferCreateReqDTO transferReqDTO = new PayTransferCreateReqDTO() |
| 61 | .setAppKey(PAY_APP_KEY).setChannelCode(withdraw.getTransferChannelCode()).setUserIp(getClientIP()) // 支付应用 | 61 | .setAppKey(PAY_APP_KEY).setChannelCode(withdraw.getTransferChannelCode()).setUserIp(getClientIP()) // 支付应用 |
| 62 | .setMerchantOrderId(String.valueOf(withdraw.getId())) // 业务的订单编号 | 62 | .setMerchantOrderId(String.valueOf(withdraw.getId())) // 业务的订单编号 |
| 63 | .setSubject(reqVO.getSubject()).setPrice(withdraw.getPrice()) // 价格信息 | 63 | .setSubject(reqVO.getSubject()).setPrice(withdraw.getPrice()) // 价格信息 |
| 64 | - .setUserAccount(reqVO.getUserAccount()).setUserName(reqVO.getUserName())); // 收款信息 | 64 | + .setUserAccount(reqVO.getUserAccount()).setUserName(reqVO.getUserName()); // 收款信息 |
| 65 | + if (ObjectUtil.equal(reqVO.getType(), PayDemoWithdrawTypeEnum.WECHAT.getType())) { | ||
| 66 | + transferReqDTO.setChannelExtras(PayTransferCreateReqDTO.buildWeiXinChannelExtra1000( | ||
| 67 | + "测试活动", "测试奖励")); | ||
| 68 | + } | ||
| 69 | + Long payTransferId = payTransferApi.createTransfer(transferReqDTO); | ||
| 65 | // 2.2 更新转账单到 demo 示例提现单 | 70 | // 2.2 更新转账单到 demo 示例提现单 |
| 66 | demoTransferMapper.updateById(new PayDemoWithdrawDO().setId(withdraw.getId()) | 71 | demoTransferMapper.updateById(new PayDemoWithdrawDO().setId(withdraw.getId()) |
| 67 | .setPayTransferId(payTransferId)); | 72 | .setPayTransferId(payTransferId)); |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java
| @@ -29,6 +29,14 @@ public interface PayTransferService { | @@ -29,6 +29,14 @@ public interface PayTransferService { | ||
| 29 | PayTransferDO getTransfer(Long id); | 29 | PayTransferDO getTransfer(Long id); |
| 30 | 30 | ||
| 31 | /** | 31 | /** |
| 32 | + * 根据转账单号获取转账单 | ||
| 33 | + * | ||
| 34 | + * @param no 转账单号 | ||
| 35 | + * @return 转账单 | ||
| 36 | + */ | ||
| 37 | + PayTransferDO getTransferByNo(String no); | ||
| 38 | + | ||
| 39 | + /** | ||
| 32 | * 获得转账单分页 | 40 | * 获得转账单分页 |
| 33 | * | 41 | * |
| 34 | * @param pageReqVO 分页查询 | 42 | * @param pageReqVO 分页查询 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
| @@ -239,6 +239,11 @@ public class PayTransferServiceImpl implements PayTransferService { | @@ -239,6 +239,11 @@ public class PayTransferServiceImpl implements PayTransferService { | ||
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | @Override | 241 | @Override |
| 242 | + public PayTransferDO getTransferByNo(String no) { | ||
| 243 | + return transferMapper.selectByNo(no); | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + @Override | ||
| 242 | public PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO) { | 247 | public PageResult<PayTransferDO> getTransferPage(PayTransferPageReqVO pageReqVO) { |
| 243 | return transferMapper.selectPage(pageReqVO); | 248 | return transferMapper.selectPage(pageReqVO); |
| 244 | } | 249 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
| @@ -41,12 +41,11 @@ public interface PayWalletService { | @@ -41,12 +41,11 @@ public interface PayWalletService { | ||
| 41 | /** | 41 | /** |
| 42 | * 钱包订单支付 | 42 | * 钱包订单支付 |
| 43 | * | 43 | * |
| 44 | - * @param userId 用户 id | ||
| 45 | - * @param userType 用户类型 | 44 | + * @param walletId 钱包编号 |
| 46 | * @param outTradeNo 外部订单号 | 45 | * @param outTradeNo 外部订单号 |
| 47 | * @param price 金额 | 46 | * @param price 金额 |
| 48 | */ | 47 | */ |
| 49 | - PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price); | 48 | + PayWalletTransactionDO orderPay(Long walletId, String outTradeNo, Integer price); |
| 50 | 49 | ||
| 51 | /** | 50 | /** |
| 52 | * 钱包订单支付退款 | 51 | * 钱包订单支付退款 |
| @@ -60,8 +59,8 @@ public interface PayWalletService { | @@ -60,8 +59,8 @@ public interface PayWalletService { | ||
| 60 | /** | 59 | /** |
| 61 | * 扣减钱包余额 | 60 | * 扣减钱包余额 |
| 62 | * | 61 | * |
| 63 | - * @param walletId 钱包 id | ||
| 64 | - * @param bizId 业务关联 id | 62 | + * @param walletId 钱包编号 |
| 63 | + * @param bizId 业务关联编号 | ||
| 65 | * @param bizType 业务关联分类 | 64 | * @param bizType 业务关联分类 |
| 66 | * @param price 扣减金额 | 65 | * @param price 扣减金额 |
| 67 | * @return 钱包流水 | 66 | * @return 钱包流水 |
| @@ -72,8 +71,8 @@ public interface PayWalletService { | @@ -72,8 +71,8 @@ public interface PayWalletService { | ||
| 72 | /** | 71 | /** |
| 73 | * 增加钱包余额 | 72 | * 增加钱包余额 |
| 74 | * | 73 | * |
| 75 | - * @param walletId 钱包 id | ||
| 76 | - * @param bizId 业务关联 id | 74 | + * @param walletId 钱包编号 |
| 75 | + * @param bizId 业务关联编号 | ||
| 77 | * @param bizType 业务关联分类 | 76 | * @param bizType 业务关联分类 |
| 78 | * @param price 增加金额 | 77 | * @param price 增加金额 |
| 79 | * @return 钱包流水 | 78 | * @return 钱包流水 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
| @@ -81,13 +81,13 @@ public class PayWalletServiceImpl implements PayWalletService { | @@ -81,13 +81,13 @@ public class PayWalletServiceImpl implements PayWalletService { | ||
| 81 | 81 | ||
| 82 | @Override | 82 | @Override |
| 83 | @Transactional(rollbackFor = Exception.class) | 83 | @Transactional(rollbackFor = Exception.class) |
| 84 | - public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) { | 84 | + public PayWalletTransactionDO orderPay(Long walletId, String outTradeNo, Integer price) { |
| 85 | // 1. 判断支付交易拓展单是否存 | 85 | // 1. 判断支付交易拓展单是否存 |
| 86 | PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); | 86 | PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo); |
| 87 | if (orderExtension == null) { | 87 | if (orderExtension == null) { |
| 88 | throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); | 88 | throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); |
| 89 | } | 89 | } |
| 90 | - PayWalletDO wallet = getOrCreateWallet(userId, userType); | 90 | + PayWalletDO wallet = walletMapper.selectById(walletId); |
| 91 | // 2. 扣减余额 | 91 | // 2. 扣减余额 |
| 92 | return reduceWalletBalance(wallet.getId(), orderExtension.getOrderId(), PAYMENT, price); | 92 | return reduceWalletBalance(wallet.getId(), orderExtension.getOrderId(), PAYMENT, price); |
| 93 | } | 93 | } |
| @@ -198,7 +198,7 @@ public class PayWalletServiceImpl implements PayWalletService { | @@ -198,7 +198,7 @@ public class PayWalletServiceImpl implements PayWalletService { | ||
| 198 | break; | 198 | break; |
| 199 | } | 199 | } |
| 200 | case UPDATE_BALANCE: // 更新余额 | 200 | case UPDATE_BALANCE: // 更新余额 |
| 201 | - case BROKERAGE_WITHDRAW: // 分佣提现 | 201 | + case TRANSFER: // 分佣提现 |
| 202 | walletMapper.updateWhenAdd(payWallet.getId(), price); | 202 | walletMapper.updateWhenAdd(payWallet.getId(), price); |
| 203 | break; | 203 | break; |
| 204 | default: { | 204 | default: { |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java
| @@ -58,6 +58,8 @@ public class PayTransferUnifiedReqDTO { | @@ -58,6 +58,8 @@ public class PayTransferUnifiedReqDTO { | ||
| 58 | 58 | ||
| 59 | /** | 59 | /** |
| 60 | * 支付渠道的额外参数 | 60 | * 支付渠道的额外参数 |
| 61 | + * | ||
| 62 | + * 微信支付:sceneId 和 scene_report_infos 字段,必须传递;参考 <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012711988#%EF%BC%883%EF%BC%89%E6%8C%89%E8%BD%AC%E8%B4%A6%E5%9C%BA%E6%99%AF%E6%8A%A5%E5%A4%87%E8%83%8C%E6%99%AF%E4%BF%A1%E6%81%AF">按转账场景报备背景信息</> | ||
| 61 | */ | 63 | */ |
| 62 | private Map<String, String> channelExtras; | 64 | private Map<String, String> channelExtras; |
| 63 | 65 |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
| @@ -7,6 +7,7 @@ import cn.hutool.core.date.LocalDateTimeUtil; | @@ -7,6 +7,7 @@ import cn.hutool.core.date.LocalDateTimeUtil; | ||
| 7 | import cn.hutool.core.date.TemporalAccessorUtil; | 7 | import cn.hutool.core.date.TemporalAccessorUtil; |
| 8 | import cn.hutool.core.util.StrUtil; | 8 | import cn.hutool.core.util.StrUtil; |
| 9 | import cn.iocoder.yudao.framework.common.util.io.FileUtils; | 9 | import cn.iocoder.yudao.framework.common.util.io.FileUtils; |
| 10 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 10 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | 11 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | 13 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| @@ -20,10 +21,9 @@ import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | @@ -20,10 +21,9 @@ import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | ||
| 20 | import com.github.binarywang.wxpay.bean.notify.*; | 21 | import com.github.binarywang.wxpay.bean.notify.*; |
| 21 | import com.github.binarywang.wxpay.bean.request.*; | 22 | import com.github.binarywang.wxpay.bean.request.*; |
| 22 | import com.github.binarywang.wxpay.bean.result.*; | 23 | import com.github.binarywang.wxpay.bean.result.*; |
| 23 | -import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest; | ||
| 24 | -import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesResult; | ||
| 25 | -import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest; | ||
| 26 | -import com.github.binarywang.wxpay.bean.transfer.TransferBatchesResult; | 24 | +import com.github.binarywang.wxpay.bean.transfer.TransferBillsGetResult; |
| 25 | +import com.github.binarywang.wxpay.bean.transfer.TransferBillsRequest; | ||
| 26 | +import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult; | ||
| 27 | import com.github.binarywang.wxpay.config.WxPayConfig; | 27 | import com.github.binarywang.wxpay.config.WxPayConfig; |
| 28 | import com.github.binarywang.wxpay.exception.WxPayException; | 28 | import com.github.binarywang.wxpay.exception.WxPayException; |
| 29 | import com.github.binarywang.wxpay.service.WxPayService; | 29 | import com.github.binarywang.wxpay.service.WxPayService; |
| @@ -32,8 +32,6 @@ import lombok.extern.slf4j.Slf4j; | @@ -32,8 +32,6 @@ import lombok.extern.slf4j.Slf4j; | ||
| 32 | 32 | ||
| 33 | import java.time.LocalDateTime; | 33 | import java.time.LocalDateTime; |
| 34 | import java.time.ZoneId; | 34 | import java.time.ZoneId; |
| 35 | -import java.util.Collections; | ||
| 36 | -import java.util.List; | ||
| 37 | import java.util.Map; | 35 | import java.util.Map; |
| 38 | import java.util.Objects; | 36 | import java.util.Objects; |
| 39 | 37 | ||
| @@ -463,53 +461,57 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC | @@ -463,53 +461,57 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC | ||
| 463 | 461 | ||
| 464 | @Override | 462 | @Override |
| 465 | protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws WxPayException { | 463 | protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws WxPayException { |
| 466 | - // 1. 构建 TransferBatchesRequest 请求 | ||
| 467 | - List<TransferBatchesRequest.TransferDetail> transferDetailList = Collections.singletonList( | ||
| 468 | - TransferBatchesRequest.TransferDetail.newBuilder() | ||
| 469 | - .outDetailNo(reqDTO.getOutTransferNo()) | ||
| 470 | - .transferAmount(reqDTO.getPrice()) | ||
| 471 | - .transferRemark(reqDTO.getSubject()) | ||
| 472 | - .openid(reqDTO.getUserAccount()) | ||
| 473 | - .build()); | ||
| 474 | - // TODO @luchi:能不能我们搞个 TransferBatchesRequestX extends TransferBatchesRequest,这样更简洁一点。 | ||
| 475 | - TransferBatchesRequest transferBatches = TransferBatchesRequest.newBuilder() | 464 | + // 1. 构建 TransferBillsRequest 请求 |
| 465 | + TransferBillsRequest request = TransferBillsRequest.newBuilder() | ||
| 476 | .appid(this.config.getAppId()) | 466 | .appid(this.config.getAppId()) |
| 477 | - .outBatchNo(reqDTO.getOutTransferNo()) | ||
| 478 | - .batchName(reqDTO.getSubject()) | ||
| 479 | - .batchRemark(reqDTO.getSubject()) | ||
| 480 | - .totalAmount(reqDTO.getPrice()) | ||
| 481 | - .totalNum(transferDetailList.size()) | ||
| 482 | - .transferDetailList(transferDetailList).build() | ||
| 483 | - .setNotifyUrl(reqDTO.getNotifyUrl()); | 467 | + .outBillNo(reqDTO.getOutTransferNo()) |
| 468 | + .transferAmount(reqDTO.getPrice()) | ||
| 469 | + .transferRemark(reqDTO.getSubject()) | ||
| 470 | + .transferSceneId(reqDTO.getChannelExtras().get("sceneId")) | ||
| 471 | + .openid(reqDTO.getUserAccount()) | ||
| 472 | + .userName(reqDTO.getUserName()) | ||
| 473 | + .transferSceneReportInfos(JsonUtils.parseArray(reqDTO.getChannelExtras().get("sceneReportInfos"), | ||
| 474 | + TransferBillsRequest.TransferSceneReportInfo.class)) | ||
| 475 | + .notifyUrl(reqDTO.getNotifyUrl()) | ||
| 476 | + .build(); | ||
| 477 | + // 特殊:微信转账,必须 0.3 元起,才允许传入姓名 | ||
| 478 | + if (reqDTO.getPrice() < 30) { | ||
| 479 | + request.setUserName(null); | ||
| 480 | + } | ||
| 481 | + | ||
| 484 | // 2.1 执行请求 | 482 | // 2.1 执行请求 |
| 485 | - TransferBatchesResult transferBatchesResult = client.getTransferService().transferBatches(transferBatches); | ||
| 486 | - // 2.2 创建返回结果 | ||
| 487 | - return PayTransferRespDTO.processingOf(transferBatchesResult.getBatchId(), reqDTO.getOutTransferNo(), transferBatchesResult); | 483 | + try { |
| 484 | + TransferBillsResult response = client.getTransferService().transferBills(request); | ||
| 485 | + System.out.println(response); | ||
| 486 | + | ||
| 487 | + // 2.2 创建返回结果 | ||
| 488 | + // TODO @芋艿:这里要解析下; | ||
| 489 | + return PayTransferRespDTO.processingOf(response.getTransferBillNo(), reqDTO.getOutTransferNo(), response); | ||
| 490 | + } catch (WxPayException e) { | ||
| 491 | + log.error("[doUnifiedTransfer][转账({}) 发起微信支付异常", reqDTO, e); | ||
| 492 | + String errorCode = getErrorCode(e); | ||
| 493 | + String errorMessage = getErrorMessage(e); | ||
| 494 | + return PayTransferRespDTO.closedOf(errorCode, errorMessage, | ||
| 495 | + reqDTO.getOutTransferNo(), e.getXmlString()); | ||
| 496 | + } | ||
| 488 | } | 497 | } |
| 489 | 498 | ||
| 490 | @Override | 499 | @Override |
| 491 | protected PayTransferRespDTO doGetTransfer(String outTradeNo) throws WxPayException { | 500 | protected PayTransferRespDTO doGetTransfer(String outTradeNo) throws WxPayException { |
| 492 | - QueryTransferBatchesRequest request = QueryTransferBatchesRequest.newBuilder() | ||
| 493 | - .outBatchNo(outTradeNo).needQueryDetail(true).offset(0).limit(20).detailStatus("ALL") | ||
| 494 | - .build(); | ||
| 495 | - QueryTransferBatchesResult response = client.getTransferService().transferBatchesOutBatchNo(request); | ||
| 496 | - QueryTransferBatchesResult.TransferBatch transferBatch = response.getTransferBatch(); | ||
| 497 | - if (Objects.equals("FINISHED", transferBatch.getBatchStatus())) { | ||
| 498 | - // 明细中全部成功则成功,任一失败则失败 | ||
| 499 | - if (response.getTransferDetailList().stream().allMatch(detail -> Objects.equals("SUCCESS", detail.getDetailStatus()))) { | ||
| 500 | - return PayTransferRespDTO.successOf(transferBatch.getBatchId(), parseDateV3(transferBatch.getUpdateTime()), | ||
| 501 | - transferBatch.getOutBatchNo(), response); | ||
| 502 | - } | ||
| 503 | - if (response.getTransferDetailList().stream().anyMatch(detail -> Objects.equals("FAIL", detail.getDetailStatus()))) { | ||
| 504 | - return PayTransferRespDTO.closedOf(transferBatch.getBatchStatus(), transferBatch.getCloseReason(), | ||
| 505 | - transferBatch.getOutBatchNo(), response); | ||
| 506 | - } | 501 | + // 1. 执行请求 |
| 502 | + TransferBillsGetResult response = client.getTransferService().getBillsByTransferBillNo(outTradeNo); | ||
| 503 | + | ||
| 504 | + // 2. 创建返回结果 | ||
| 505 | + String state = response.getState(); | ||
| 506 | + if (ObjectUtils.equalsAny(state, "ACCEPTED", "PROCESSING", "WAIT_USER_CONFIRM", "TRANSFERING")) { | ||
| 507 | + return PayTransferRespDTO.processingOf(response.getTransferBillNo(), response.getOutBillNo(), response); | ||
| 507 | } | 508 | } |
| 508 | - if (Objects.equals("CLOSED", transferBatch.getBatchStatus())) { | ||
| 509 | - return PayTransferRespDTO.closedOf(transferBatch.getBatchStatus(), transferBatch.getCloseReason(), | ||
| 510 | - transferBatch.getOutBatchNo(), response); | 509 | + if (Objects.equals("SUCCESS", state)) { |
| 510 | + return PayTransferRespDTO.successOf(response.getTransferBillNo(), parseDateV3(response.getUpdateTime()), | ||
| 511 | + response.getOutBillNo(), response); | ||
| 511 | } | 512 | } |
| 512 | - return PayTransferRespDTO.processingOf(transferBatch.getBatchId(), transferBatch.getOutBatchNo(), response); | 513 | + return PayTransferRespDTO.closedOf(state, response.getFailReason(), |
| 514 | + response.getOutBillNo(), response); | ||
| 513 | } | 515 | } |
| 514 | 516 | ||
| 515 | // ========== 各种工具方法 ========== | 517 | // ========== 各种工具方法 ========== |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBatchesRequest.java deleted
| 1 | -package com.github.binarywang.wxpay.bean.transfer; | ||
| 2 | - | ||
| 3 | -import com.github.binarywang.wxpay.v3.SpecEncrypt; | ||
| 4 | -import com.google.gson.annotations.SerializedName; | ||
| 5 | -import lombok.AllArgsConstructor; | ||
| 6 | -import lombok.Builder; | ||
| 7 | -import lombok.Data; | ||
| 8 | -import lombok.NoArgsConstructor; | ||
| 9 | - | ||
| 10 | -import java.io.Serializable; | ||
| 11 | -import java.util.List; | ||
| 12 | - | ||
| 13 | -/** | ||
| 14 | - * 发起商家转账API参数 | ||
| 15 | - * | ||
| 16 | - * @author zhongjun | ||
| 17 | - * created on 2022/6/17 | ||
| 18 | - **/ | ||
| 19 | -@Data | ||
| 20 | -@Builder(builderMethodName = "newBuilder") | ||
| 21 | -@NoArgsConstructor | ||
| 22 | -@AllArgsConstructor | ||
| 23 | -public class TransferBatchesRequest implements Serializable { | ||
| 24 | - private static final long serialVersionUID = -2175582517588397426L; | ||
| 25 | - | ||
| 26 | - /** | ||
| 27 | - * 直连商户的appid | ||
| 28 | - */ | ||
| 29 | - @SerializedName("appid") | ||
| 30 | - private String appid; | ||
| 31 | - | ||
| 32 | - /** | ||
| 33 | - * 商家批次单号 | ||
| 34 | - */ | ||
| 35 | - @SerializedName("out_batch_no") | ||
| 36 | - private String outBatchNo; | ||
| 37 | - | ||
| 38 | - /** | ||
| 39 | - * 批次名称 | ||
| 40 | - */ | ||
| 41 | - @SerializedName("batch_name") | ||
| 42 | - private String batchName; | ||
| 43 | - | ||
| 44 | - /** | ||
| 45 | - * 批次备注 | ||
| 46 | - */ | ||
| 47 | - @SerializedName("batch_remark") | ||
| 48 | - private String batchRemark; | ||
| 49 | - | ||
| 50 | - /** | ||
| 51 | - * 转账总金额 | ||
| 52 | - */ | ||
| 53 | - @SerializedName("total_amount") | ||
| 54 | - private Integer totalAmount; | ||
| 55 | - | ||
| 56 | - /** | ||
| 57 | - * 转账总笔数 | ||
| 58 | - */ | ||
| 59 | - @SerializedName("total_num") | ||
| 60 | - private Integer totalNum; | ||
| 61 | - | ||
| 62 | - /** | ||
| 63 | - * 转账明细列表 | ||
| 64 | - */ | ||
| 65 | - @SpecEncrypt | ||
| 66 | - @SerializedName("transfer_detail_list") | ||
| 67 | - private List<TransferDetail> transferDetailList; | ||
| 68 | - | ||
| 69 | - /** | ||
| 70 | - * 转账场景ID | ||
| 71 | - */ | ||
| 72 | - @SerializedName("transfer_scene_id") | ||
| 73 | - private String transferSceneId; | ||
| 74 | - | ||
| 75 | - /** | ||
| 76 | - * 通知地址 说明:异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的url,必须为https,不能携带参数。 | ||
| 77 | - */ | ||
| 78 | - @SerializedName("notify_url") | ||
| 79 | - private String notifyUrl; | ||
| 80 | - | ||
| 81 | - @Data | ||
| 82 | - @Builder(builderMethodName = "newBuilder") | ||
| 83 | - @AllArgsConstructor | ||
| 84 | - @NoArgsConstructor | ||
| 85 | - public static class TransferDetail { | ||
| 86 | - | ||
| 87 | - /** | ||
| 88 | - * 商家明细单号 | ||
| 89 | - */ | ||
| 90 | - @SerializedName("out_detail_no") | ||
| 91 | - private String outDetailNo; | ||
| 92 | - | ||
| 93 | - /** | ||
| 94 | - * 转账金额 | ||
| 95 | - */ | ||
| 96 | - @SerializedName("transfer_amount") | ||
| 97 | - private Integer transferAmount; | ||
| 98 | - | ||
| 99 | - /** | ||
| 100 | - * 转账备注 | ||
| 101 | - */ | ||
| 102 | - @SerializedName("transfer_remark") | ||
| 103 | - private String transferRemark; | ||
| 104 | - | ||
| 105 | - /** | ||
| 106 | - * 用户在直连商户应用下的用户标示 | ||
| 107 | - */ | ||
| 108 | - @SerializedName("openid") | ||
| 109 | - private String openid; | ||
| 110 | - | ||
| 111 | - /** | ||
| 112 | - * 收款用户姓名 | ||
| 113 | - */ | ||
| 114 | - @SpecEncrypt | ||
| 115 | - @SerializedName("user_name") | ||
| 116 | - private String userName; | ||
| 117 | - } | ||
| 118 | -} |