Commit 325d5e6b121cb95420bc96ccfd0b69050d7bf26a
1 parent
ae1cf9e0
【功能优化】完成转账回调接口
Showing
33 changed files
with
378 additions
and
42 deletions
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java
| ... | ... | @@ -44,7 +44,7 @@ public class BrokerageRecordController { |
| 44 | 44 | @Operation(summary = "获得佣金记录") |
| 45 | 45 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 46 | 46 | @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") |
| 47 | - public CommonResult<BrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Integer id) { | |
| 47 | + public CommonResult<BrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Long id) { | |
| 48 | 48 | BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id); |
| 49 | 49 | return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord)); |
| 50 | 50 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java
| ... | ... | @@ -45,7 +45,7 @@ public class BrokerageWithdrawController { |
| 45 | 45 | @PutMapping("/approve") |
| 46 | 46 | @Operation(summary = "通过申请") |
| 47 | 47 | @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')") |
| 48 | - public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Integer id) { | |
| 48 | + public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Long id) { | |
| 49 | 49 | brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "", getClientIP()); |
| 50 | 50 | return success(true); |
| 51 | 51 | } |
| ... | ... | @@ -62,7 +62,7 @@ public class BrokerageWithdrawController { |
| 62 | 62 | @Operation(summary = "获得佣金提现") |
| 63 | 63 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 64 | 64 | @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')") |
| 65 | - public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Integer id) { | |
| 65 | + public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Long id) { | |
| 66 | 66 | BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id); |
| 67 | 67 | return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw)); |
| 68 | 68 | } |
| ... | ... | @@ -87,6 +87,7 @@ public class BrokerageWithdrawController { |
| 87 | 87 | // 目前业务逻辑,不需要做任何事情 |
| 88 | 88 | // 当然,退款会有小概率会失败的情况,可以监控失败状态,进行告警 |
| 89 | 89 | log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO); |
| 90 | + brokerageWithdrawService.updateTransfer(Long.parseLong(notifyReqDTO.getMerchantTransferId()), notifyReqDTO.getPayTransferId()); | |
| 90 | 91 | return success(true); |
| 91 | 92 | } |
| 92 | 93 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java
| ... | ... | @@ -14,7 +14,7 @@ import java.time.LocalDateTime; |
| 14 | 14 | public class BrokerageRecordRespVO extends BrokerageRecordBaseVO { |
| 15 | 15 | |
| 16 | 16 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896") |
| 17 | - private Integer id; | |
| 17 | + private Long id; | |
| 18 | 18 | |
| 19 | 19 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 20 | 20 | private LocalDateTime createTime; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java
| ... | ... | @@ -14,7 +14,7 @@ public class BrokerageWithdrawRejectReqVO { |
| 14 | 14 | |
| 15 | 15 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") |
| 16 | 16 | @NotNull(message = "编号不能为空") |
| 17 | - private Integer id; | |
| 17 | + private Long id; | |
| 18 | 18 | |
| 19 | 19 | @Schema(description = "审核驳回原因", example = "不对") |
| 20 | 20 | @NotEmpty(message = "审核驳回原因不能为空") | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java
| ... | ... | @@ -14,7 +14,7 @@ import java.time.LocalDateTime; |
| 14 | 14 | public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO { |
| 15 | 15 | |
| 16 | 16 | @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") |
| 17 | - private Integer id; | |
| 17 | + private Long id; | |
| 18 | 18 | |
| 19 | 19 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 20 | 20 | private LocalDateTime createTime; | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageWithdrawMapper.java
| ... | ... | @@ -35,7 +35,7 @@ public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO |
| 35 | 35 | .orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId)); |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | - default int updateByIdAndStatus(Integer id, Integer status, BrokerageWithdrawDO updateObj) { | |
| 38 | + default int updateByIdAndStatus(Long id, Integer status, BrokerageWithdrawDO updateObj) { | |
| 39 | 39 | return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>() |
| 40 | 40 | .eq(BrokerageWithdrawDO::getId, id) |
| 41 | 41 | .eq(BrokerageWithdrawDO::getStatus, status)); | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordService.java
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
| ... | ... | @@ -64,7 +64,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService { |
| 64 | 64 | private ProductSkuApi productSkuApi; |
| 65 | 65 | |
| 66 | 66 | @Override |
| 67 | - public BrokerageRecordDO getBrokerageRecord(Integer id) { | |
| 67 | + public BrokerageRecordDO getBrokerageRecord(Long id) { | |
| 68 | 68 | return brokerageRecordMapper.selectById(id); |
| 69 | 69 | } |
| 70 | 70 | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java
| ... | ... | @@ -28,7 +28,7 @@ public interface BrokerageWithdrawService { |
| 28 | 28 | * @param status 审核状态 |
| 29 | 29 | * @param auditReason 驳回原因 |
| 30 | 30 | */ |
| 31 | - void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp); | |
| 31 | + void auditBrokerageWithdraw(Long id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp); | |
| 32 | 32 | |
| 33 | 33 | /** |
| 34 | 34 | * 获得佣金提现 |
| ... | ... | @@ -36,7 +36,7 @@ public interface BrokerageWithdrawService { |
| 36 | 36 | * @param id 编号 |
| 37 | 37 | * @return 佣金提现 |
| 38 | 38 | */ |
| 39 | - BrokerageWithdrawDO getBrokerageWithdraw(Integer id); | |
| 39 | + BrokerageWithdrawDO getBrokerageWithdraw(Long id); | |
| 40 | 40 | |
| 41 | 41 | /** |
| 42 | 42 | * 获得佣金提现分页 |
| ... | ... | @@ -77,4 +77,10 @@ public interface BrokerageWithdrawService { |
| 77 | 77 | return convertMap(getWithdrawSummaryListByUserId(userIds, status), BrokerageWithdrawSummaryRespBO::getUserId); |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | + /** | |
| 81 | + * | |
| 82 | + * @param merchantTransferId 提现编号 | |
| 83 | + * @param payTransferId 转账订单编号 | |
| 84 | + */ | |
| 85 | + void updateTransfer(Long merchantTransferId, Long payTransferId); | |
| 80 | 86 | } | ... | ... |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java
| ... | ... | @@ -9,6 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | 9 | import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; |
| 10 | 10 | import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi; |
| 11 | 11 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; |
| 12 | +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO; | |
| 13 | +import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; | |
| 12 | 14 | import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; |
| 13 | 15 | import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; |
| 14 | 16 | import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; |
| ... | ... | @@ -39,7 +41,6 @@ import java.time.LocalDateTime; |
| 39 | 41 | import java.util.*; |
| 40 | 42 | |
| 41 | 43 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 42 | -import static cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX; | |
| 43 | 44 | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; |
| 44 | 45 | |
| 45 | 46 | /** |
| ... | ... | @@ -76,7 +77,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { |
| 76 | 77 | |
| 77 | 78 | @Override |
| 78 | 79 | @Transactional(rollbackFor = Exception.class) |
| 79 | - public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp) { | |
| 80 | + public void auditBrokerageWithdraw(Long id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp) { | |
| 80 | 81 | // 1.1 校验存在 |
| 81 | 82 | BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id); |
| 82 | 83 | |
| ... | ... | @@ -105,7 +106,6 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { |
| 105 | 106 | PayTransferCreateReqDTO payTransferCreateReqDTO = getPayTransferCreateReqDTO(userIp, withdraw, socialUser); |
| 106 | 107 | payTransferApi.createTransfer(payTransferCreateReqDTO); |
| 107 | 108 | } |
| 108 | - // TODO 疯狂:调用转账接口 | |
| 109 | 109 | } else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) { |
| 110 | 110 | templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT; |
| 111 | 111 | // 3.2 驳回时需要退还用户佣金 |
| ... | ... | @@ -116,13 +116,13 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 118 | // 4. 通知用户 |
| 119 | - Map<String, Object> templateParams = MapUtil.<String, Object>builder() | |
| 120 | - .put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime())) | |
| 121 | - .put("price", MoneyUtils.fenToYuanStr(withdraw.getPrice())) | |
| 122 | - .put("reason", auditReason) | |
| 123 | - .build(); | |
| 124 | - notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO() | |
| 125 | - .setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams)); | |
| 119 | +// Map<String, Object> templateParams = MapUtil.<String, Object>builder() | |
| 120 | +// .put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime())) | |
| 121 | +// .put("price", MoneyUtils.fenToYuanStr(withdraw.getPrice())) | |
| 122 | +// .put("reason", auditReason) | |
| 123 | +// .build(); | |
| 124 | +// notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO() | |
| 125 | +// .setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams)); | |
| 126 | 126 | } |
| 127 | 127 | |
| 128 | 128 | private PayTransferCreateReqDTO getPayTransferCreateReqDTO(String userIp, BrokerageWithdrawDO withdraw, SocialUserRespDTO socialUser) { |
| ... | ... | @@ -138,7 +138,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { |
| 138 | 138 | return payTransferCreateReqDTO; |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | - private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) { | |
| 141 | + private BrokerageWithdrawDO validateBrokerageWithdrawExists(Long id) { | |
| 142 | 142 | BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id); |
| 143 | 143 | if (withdraw == null) { |
| 144 | 144 | throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS); |
| ... | ... | @@ -147,7 +147,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | 149 | @Override |
| 150 | - public BrokerageWithdrawDO getBrokerageWithdraw(Integer id) { | |
| 150 | + public BrokerageWithdrawDO getBrokerageWithdraw(Long id) { | |
| 151 | 151 | return brokerageWithdrawMapper.selectById(id); |
| 152 | 152 | } |
| 153 | 153 | |
| ... | ... | @@ -186,6 +186,23 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { |
| 186 | 186 | return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus()); |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | + @Override | |
| 190 | + public void updateTransfer(Long id, Long payTransferId) { | |
| 191 | + BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id); | |
| 192 | + PayTransferRespDTO transfer = payTransferApi.getTransfer(payTransferId); | |
| 193 | + if(PayTransferStatusEnum.isSuccess(transfer.getStatus())){ | |
| 194 | + withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus()); | |
| 195 | + }else if(PayTransferStatusEnum.isPendingStatus(transfer.getStatus())){ | |
| 196 | + withdraw.setStatus(BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus()); | |
| 197 | + }else{ | |
| 198 | + withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_FAIL.getStatus()); | |
| 199 | + // 3.2 驳回时需要退还用户佣金 | |
| 200 | + brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT, | |
| 201 | + String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle()); | |
| 202 | + } | |
| 203 | + brokerageWithdrawMapper.updateById(withdraw); | |
| 204 | + } | |
| 205 | + | |
| 189 | 206 | /** |
| 190 | 207 | * 计算提现手续费 |
| 191 | 208 | * | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApi.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.api.transfer; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; |
| 4 | 4 | |
| 5 | +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO; | |
| 5 | 6 | import jakarta.validation.Valid; |
| 6 | 7 | |
| 7 | 8 | /** |
| ... | ... | @@ -19,4 +20,10 @@ public interface PayTransferApi { |
| 19 | 20 | */ |
| 20 | 21 | Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO); |
| 21 | 22 | |
| 23 | + /** | |
| 24 | + * 获取转账单详细 | |
| 25 | + * @param id 转账单编号 | |
| 26 | + * @return 转账单详细 | |
| 27 | + */ | |
| 28 | + PayTransferRespDTO getTransfer(Long id); | |
| 22 | 29 | } | ... | ... |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/dto/PayTransferRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.pay.api.transfer.dto; | |
| 2 | + | |
| 3 | +import lombok.Data; | |
| 4 | + | |
| 5 | +@Data | |
| 6 | +public class PayTransferRespDTO { | |
| 7 | + | |
| 8 | + /** | |
| 9 | + * 编号 | |
| 10 | + */ | |
| 11 | + private Long id; | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * 转账单号 | |
| 15 | + * | |
| 16 | + */ | |
| 17 | + private String no; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 转账金额,单位:分 | |
| 21 | + */ | |
| 22 | + private Integer price; | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 转账状态 | |
| 26 | + * | |
| 27 | + * 枚举 {@link PayTransferStatusRespEnum} | |
| 28 | + */ | |
| 29 | + private Integer status; | |
| 30 | + | |
| 31 | + | |
| 32 | +} | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/transfer/PayTransferApiImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.pay.api.transfer; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; |
| 4 | +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO; | |
| 5 | +import cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert; | |
| 6 | +import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; | |
| 4 | 7 | import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; |
| 5 | 8 | import org.springframework.stereotype.Service; |
| 6 | 9 | import org.springframework.validation.annotation.Validated; |
| ... | ... | @@ -24,4 +27,10 @@ public class PayTransferApiImpl implements PayTransferApi { |
| 24 | 27 | return payTransferService.createTransfer(reqDTO); |
| 25 | 28 | } |
| 26 | 29 | |
| 30 | + @Override | |
| 31 | + public PayTransferRespDTO getTransfer(Long id) { | |
| 32 | + PayTransferDO transfer = payTransferService.getTransfer(id); | |
| 33 | + return PayTransferConvert.INSTANCE.convert3(transfer); | |
| 34 | + } | |
| 35 | + | |
| 27 | 36 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 8 | 8 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 9 | +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; | |
| 9 | 10 | import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; |
| 10 | 11 | import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; |
| 11 | 12 | import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO; |
| ... | ... | @@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 18 | 19 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 19 | 20 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 20 | 21 | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; |
| 22 | +import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; | |
| 21 | 23 | import io.swagger.v3.oas.annotations.Operation; |
| 22 | 24 | import io.swagger.v3.oas.annotations.Parameter; |
| 23 | 25 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | ... | @@ -49,6 +51,8 @@ public class PayNotifyController { |
| 49 | 51 | @Resource |
| 50 | 52 | private PayRefundService refundService; |
| 51 | 53 | @Resource |
| 54 | + private PayTransferService payTransferService; | |
| 55 | + @Resource | |
| 52 | 56 | private PayNotifyService notifyService; |
| 53 | 57 | @Resource |
| 54 | 58 | private PayAppService appService; |
| ... | ... | @@ -95,6 +99,26 @@ public class PayNotifyController { |
| 95 | 99 | return "success"; |
| 96 | 100 | } |
| 97 | 101 | |
| 102 | + @PostMapping(value = "/transfer/{channelId}") | |
| 103 | + @Operation(summary = "支付渠道的统一【转账】回调") | |
| 104 | + @PermitAll | |
| 105 | + public String notifyTransfer(@PathVariable("channelId") Long channelId, | |
| 106 | + @RequestParam(required = false) Map<String, String> params, | |
| 107 | + @RequestBody(required = false) String body) { | |
| 108 | + log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body); | |
| 109 | + // 1. 校验支付渠道是否存在 | |
| 110 | + PayClient payClient = channelService.getPayClient(channelId); | |
| 111 | + if (payClient == null) { | |
| 112 | + log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); | |
| 113 | + throw exception(CHANNEL_NOT_FOUND); | |
| 114 | + } | |
| 115 | + | |
| 116 | + // 2. 解析通知数据 | |
| 117 | + PayTransferRespDTO notify = payClient.parseTransferNotify(params, body); | |
| 118 | + payTransferService.notifyTransfer(channelId, notify); | |
| 119 | + return "success"; | |
| 120 | + } | |
| 121 | + | |
| 98 | 122 | @GetMapping("/get-detail") |
| 99 | 123 | @Operation(summary = "获得回调通知的明细") |
| 100 | 124 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/transfer/PayTransferConvert.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.transfer; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; |
| 6 | +import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO; | |
| 6 | 7 | import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; |
| 8 | 9 | import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO; |
| ... | ... | @@ -24,7 +25,9 @@ public interface PayTransferConvert { |
| 24 | 25 | |
| 25 | 26 | PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo); |
| 26 | 27 | |
| 27 | - PayTransferRespVO convert(PayTransferDO bean); | |
| 28 | + PayTransferRespVO convert(PayTransferDO bean); | |
| 29 | + | |
| 30 | + PayTransferRespDTO convert3(PayTransferDO bean); | |
| 28 | 31 | |
| 29 | 32 | PageResult<PayTransferPageItemRespVO> convertPage(PageResult<PayTransferDO> pageResult); |
| 30 | 33 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
| ... | ... | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | 6 | import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; |
| 7 | +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | |
| 7 | 8 | import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; |
| 8 | 9 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 9 | 10 | import org.apache.ibatis.annotations.Mapper; |
| ... | ... | @@ -44,6 +45,12 @@ public interface PayTransferMapper extends BaseMapperX<PayTransferDO> { |
| 44 | 45 | default List<PayTransferDO> selectListByStatus(Integer status){ |
| 45 | 46 | return selectList(PayTransferDO::getStatus, status); |
| 46 | 47 | } |
| 48 | + | |
| 49 | + default PayTransferDO selectByAppIdAndNo(Long appId, String no){ | |
| 50 | + return selectOne(new LambdaQueryWrapperX<PayTransferDO>() | |
| 51 | + .eq(PayTransferDO::getAppId, appId) | |
| 52 | + .eq(PayTransferDO::getNo, no)); | |
| 53 | + } | |
| 47 | 54 | } |
| 48 | 55 | |
| 49 | 56 | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/config/PayProperties.java
| ... | ... | @@ -40,6 +40,15 @@ public class PayProperties { |
| 40 | 40 | private String refundNotifyUrl; |
| 41 | 41 | |
| 42 | 42 | /** |
| 43 | + * 转账回调地址 | |
| 44 | + * | |
| 45 | + * 实际上,对应的 PayNotifyController 的 notifyTransfer 方法的 URL | |
| 46 | + * | |
| 47 | + * 回调顺序:支付渠道(支付宝支付、微信支付) => yudao-module-pay 的 transferNotifyUrl 地址 => 业务的 PayAppDO.transferNotifyUrl 地址 | |
| 48 | + */ | |
| 49 | + private String transferNotifyUrl; | |
| 50 | + | |
| 51 | + /** | |
| 43 | 52 | * 支付订单 no 的前缀 |
| 44 | 53 | */ |
| 45 | 54 | @NotEmpty(message = "支付订单 no 的前缀不能为空") | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/WalletPayClient.java
| ... | ... | @@ -178,6 +178,11 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 178 | 178 | } |
| 179 | 179 | |
| 180 | 180 | @Override |
| 181 | + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable { | |
| 182 | + throw new UnsupportedOperationException("未实现"); | |
| 183 | + } | |
| 184 | + | |
| 185 | + @Override | |
| 181 | 186 | public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { |
| 182 | 187 | throw new UnsupportedOperationException("待实现"); |
| 183 | 188 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferService.java
| 1 | 1 | package cn.iocoder.yudao.module.pay.service.transfer; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; |
| 5 | 6 | import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; |
| 6 | 7 | import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; |
| ... | ... | @@ -54,4 +55,12 @@ public interface PayTransferService { |
| 54 | 55 | * @return 同步到状态的转账数量,包括转账成功、转账失败、转账中的 |
| 55 | 56 | */ |
| 56 | 57 | int syncTransfer(); |
| 58 | + | |
| 59 | + /** | |
| 60 | + * 渠道的转账通知 | |
| 61 | + * | |
| 62 | + * @param channelId 渠道编号 | |
| 63 | + * @param notify 通知 | |
| 64 | + */ | |
| 65 | + void notifyTransfer(Long channelId, PayTransferRespDTO notify); | |
| 57 | 66 | } | ... | ... |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
| ... | ... | @@ -21,6 +21,7 @@ import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper; |
| 21 | 21 | import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; |
| 22 | 22 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; |
| 23 | 23 | import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; |
| 24 | +import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | |
| 24 | 25 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 25 | 26 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 26 | 27 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| ... | ... | @@ -28,6 +29,7 @@ import jakarta.annotation.Resource; |
| 28 | 29 | import jakarta.validation.Validator; |
| 29 | 30 | import lombok.extern.slf4j.Slf4j; |
| 30 | 31 | import org.springframework.stereotype.Service; |
| 32 | +import org.springframework.transaction.annotation.Propagation; | |
| 31 | 33 | import org.springframework.transaction.annotation.Transactional; |
| 32 | 34 | |
| 33 | 35 | import java.util.List; |
| ... | ... | @@ -51,6 +53,9 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 51 | 53 | private static final String TRANSFER_NO_PREFIX = "T"; |
| 52 | 54 | |
| 53 | 55 | @Resource |
| 56 | + private PayProperties payProperties; | |
| 57 | + | |
| 58 | + @Resource | |
| 54 | 59 | private PayTransferMapper transferMapper; |
| 55 | 60 | @Resource |
| 56 | 61 | private PayAppService appService; |
| ... | ... | @@ -104,7 +109,7 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 104 | 109 | // 3. 调用三方渠道发起转账 |
| 105 | 110 | PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer) |
| 106 | 111 | .setOutTransferNo(transfer.getNo()); |
| 107 | - transferUnifiedReq.setNotifyUrl(payApp.getTransferNotifyUrl()); | |
| 112 | + transferUnifiedReq.setNotifyUrl(genChannelTransferNotifyUrl(channel)); | |
| 108 | 113 | PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq); |
| 109 | 114 | // 4. 通知转账结果 |
| 110 | 115 | getSelf().notifyTransfer(channel, unifiedTransferResp); |
| ... | ... | @@ -118,6 +123,16 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 118 | 123 | return transfer.getId(); |
| 119 | 124 | } |
| 120 | 125 | |
| 126 | + /** | |
| 127 | + * 根据支付渠道的编码,生成支付渠道的回调地址 | |
| 128 | + * | |
| 129 | + * @param channel 支付渠道 | |
| 130 | + * @return 支付渠道的回调地址 配置地址 + "/" + channel id | |
| 131 | + */ | |
| 132 | + private String genChannelTransferNotifyUrl(PayChannelDO channel) { | |
| 133 | + return payProperties.getTransferNotifyUrl() + "/" + channel.getId(); | |
| 134 | + } | |
| 135 | + | |
| 121 | 136 | private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) { |
| 122 | 137 | PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId()); |
| 123 | 138 | if (transfer != null) { |
| ... | ... | @@ -156,7 +171,8 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 156 | 171 | |
| 157 | 172 | private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) { |
| 158 | 173 | // 1.校验 |
| 159 | - PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); | |
| 174 | + PayTransferDO transfer = transferMapper.selectByAppIdAndNo( | |
| 175 | + channel.getAppId(), notify.getOutTransferNo()); | |
| 160 | 176 | if (transfer == null) { |
| 161 | 177 | throw exception(PAY_TRANSFER_NOT_FOUND); |
| 162 | 178 | } |
| ... | ... | @@ -174,16 +190,13 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 174 | 190 | throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); |
| 175 | 191 | } |
| 176 | 192 | log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId()); |
| 177 | - | |
| 178 | - // 3. 插入转账通知记录 | |
| 179 | - notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(), | |
| 180 | - transfer.getId()); | |
| 181 | 193 | } |
| 182 | 194 | |
| 183 | 195 | |
| 184 | 196 | private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { |
| 185 | 197 | // 1.校验 |
| 186 | - PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); | |
| 198 | + PayTransferDO transfer = transferMapper.selectByAppIdAndNo( | |
| 199 | + channel.getAppId(), notify.getOutTransferNo()); | |
| 187 | 200 | if (transfer == null) { |
| 188 | 201 | throw exception(PAY_TRANSFER_NOT_FOUND); |
| 189 | 202 | } |
| ... | ... | @@ -212,7 +225,8 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 212 | 225 | |
| 213 | 226 | private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { |
| 214 | 227 | // 1.校验 |
| 215 | - PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); | |
| 228 | + PayTransferDO transfer = transferMapper.selectByAppIdAndNo( | |
| 229 | + channel.getAppId(), notify.getOutTransferNo()); | |
| 216 | 230 | if (transfer == null) { |
| 217 | 231 | throw exception(PAY_TRANSFER_NOT_FOUND); |
| 218 | 232 | } |
| ... | ... | @@ -285,7 +299,7 @@ public class PayTransferServiceImpl implements PayTransferService { |
| 285 | 299 | } |
| 286 | 300 | } |
| 287 | 301 | |
| 288 | - private void notifyTransfer(Long channelId, PayTransferRespDTO notify) { | |
| 302 | + public void notifyTransfer(Long channelId, PayTransferRespDTO notify) { | |
| 289 | 303 | // 校验渠道是否有效 |
| 290 | 304 | PayChannelDO channel = channelService.validPayChannel(channelId); |
| 291 | 305 | // 通知转账结果给对应的业务 | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
| ... | ... | @@ -79,6 +79,8 @@ public interface PayClient { |
| 79 | 79 | */ |
| 80 | 80 | PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo); |
| 81 | 81 | |
| 82 | + // ============ 转账相关 ========== | |
| 83 | + | |
| 82 | 84 | /** |
| 83 | 85 | * 调用渠道,进行转账 |
| 84 | 86 | * |
| ... | ... | @@ -95,4 +97,13 @@ public interface PayClient { |
| 95 | 97 | * @return 转账信息 |
| 96 | 98 | */ |
| 97 | 99 | PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type); |
| 100 | + | |
| 101 | + /** | |
| 102 | + * 解析 transfer 回调数据 | |
| 103 | + * | |
| 104 | + * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 | |
| 105 | + * @param body HTTP 回调接口的 request body | |
| 106 | + * @return 转账信息 | |
| 107 | + */ | |
| 108 | + PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body); | |
| 98 | 109 | } | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/WxPayTransferPartnerNotifyV3Result.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.pay.core.client.dto.transfer; | |
| 2 | + | |
| 3 | +import com.github.binarywang.wxpay.bean.notify.OriginNotifyResponse; | |
| 4 | +import com.github.binarywang.wxpay.bean.notify.WxPayBaseNotifyV3Result; | |
| 5 | +import com.google.gson.annotations.SerializedName; | |
| 6 | +import lombok.Data; | |
| 7 | +import lombok.NoArgsConstructor; | |
| 8 | + | |
| 9 | +import java.io.Serializable; | |
| 10 | + | |
| 11 | +@NoArgsConstructor | |
| 12 | +public class WxPayTransferPartnerNotifyV3Result implements Serializable, WxPayBaseNotifyV3Result<WxPayTransferPartnerNotifyV3Result.TransferNotifyResult> { | |
| 13 | + | |
| 14 | + private static final long serialVersionUID = -1L; | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 源数据 | |
| 18 | + */ | |
| 19 | + private OriginNotifyResponse rawData; | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 解密后的数据 | |
| 23 | + */ | |
| 24 | + private TransferNotifyResult result; | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public void setRawData(OriginNotifyResponse rawData) { | |
| 28 | + this.rawData = rawData; | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Override | |
| 32 | + public void setResult(TransferNotifyResult data) { | |
| 33 | + this.result = data; | |
| 34 | + } | |
| 35 | + | |
| 36 | + public TransferNotifyResult getResult() { | |
| 37 | + return result; | |
| 38 | + } | |
| 39 | + | |
| 40 | + public OriginNotifyResponse getRawData() { | |
| 41 | + return rawData; | |
| 42 | + } | |
| 43 | + | |
| 44 | + @Data | |
| 45 | + @NoArgsConstructor | |
| 46 | + public static class TransferNotifyResult implements Serializable { | |
| 47 | + private static final long serialVersionUID = 1L; | |
| 48 | + | |
| 49 | + /*********************** 公共字段 ******************** | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * 商家批次单号 | |
| 53 | + */ | |
| 54 | + @SerializedName(value = "out_batch_no") | |
| 55 | + protected String outBatchNo; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * 微信批次单号 | |
| 59 | + */ | |
| 60 | + @SerializedName(value = "batch_id") | |
| 61 | + protected String batchId; | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * 批次状态 | |
| 65 | + */ | |
| 66 | + @SerializedName(value = "batch_status") | |
| 67 | + protected String batchStatus; | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * 批次总笔数 | |
| 71 | + */ | |
| 72 | + @SerializedName(value = "total_num") | |
| 73 | + protected Integer totalNum; | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * 批次总金额 | |
| 77 | + */ | |
| 78 | + @SerializedName(value = "total_amount") | |
| 79 | + protected Integer totalAmount; | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * 批次更新时间 | |
| 83 | + */ | |
| 84 | + @SerializedName(value = "update_time") | |
| 85 | + private String updateTime; | |
| 86 | + | |
| 87 | + /*********************** FINISHED ******************** | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * 转账成功金额 | |
| 91 | + */ | |
| 92 | + @SerializedName(value = "success_amount") | |
| 93 | + protected Integer successAmount; | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * 转账成功笔数 | |
| 97 | + */ | |
| 98 | + @SerializedName(value = "success_num") | |
| 99 | + protected Integer successNum; | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * 转账失败金额 | |
| 103 | + */ | |
| 104 | + @SerializedName(value = "fail_amount") | |
| 105 | + protected Integer failAmount; | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * 转账失败笔数 | |
| 109 | + */ | |
| 110 | + @SerializedName(value = "fail_num") | |
| 111 | + protected Integer failNum; | |
| 112 | + | |
| 113 | + /*********************** CLOSED ******************** | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * 商户号 | |
| 117 | + */ | |
| 118 | + @SerializedName(value = "mchid") | |
| 119 | + protected String mchId; | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * 批次关闭原因 | |
| 123 | + */ | |
| 124 | + @SerializedName(value = "close_reason") | |
| 125 | + protected String closeReason; | |
| 126 | + | |
| 127 | + } | |
| 128 | +} | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
| ... | ... | @@ -220,6 +220,22 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 220 | 220 | } |
| 221 | 221 | |
| 222 | 222 | @Override |
| 223 | + public final PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body) { | |
| 224 | + try { | |
| 225 | + return doParseTransferNotify(params, body); | |
| 226 | + } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 | |
| 227 | + throw ex; | |
| 228 | + } catch (Throwable ex) { | |
| 229 | + log.error("[doParseTransferNotify][客户端({}) params({}) body({}) 解析失败]", | |
| 230 | + getId(), params, body, ex); | |
| 231 | + throw buildPayException(ex); | |
| 232 | + } | |
| 233 | + } | |
| 234 | + | |
| 235 | + protected abstract PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) | |
| 236 | + throws Throwable; | |
| 237 | + | |
| 238 | + @Override | |
| 223 | 239 | public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) { |
| 224 | 240 | try { |
| 225 | 241 | return doGetTransfer(outTradeNo, type); | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
| ... | ... | @@ -325,6 +325,11 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 325 | 325 | } |
| 326 | 326 | } |
| 327 | 327 | |
| 328 | + @Override | |
| 329 | + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable { | |
| 330 | + throw new UnsupportedOperationException("未实现"); | |
| 331 | + } | |
| 332 | + | |
| 328 | 333 | // ========== 各种工具方法 ========== |
| 329 | 334 | |
| 330 | 335 | protected String formatAmount(Integer amount) { | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; | |
| 5 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 7 | 8 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -56,4 +57,5 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { |
| 56 | 57 | return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), |
| 57 | 58 | reqDTO.getOutTradeNo(), response); |
| 58 | 59 | } |
| 60 | + | |
| 59 | 61 | } | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java
| ... | ... | @@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil; |
| 5 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 7 | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 8 | +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; | |
| 8 | 9 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 9 | 10 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 10 | 11 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -82,4 +83,5 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { |
| 82 | 83 | return PayOrderRespDTO.waitingOf(displayMode, "", |
| 83 | 84 | reqDTO.getOutTradeNo(), response); |
| 84 | 85 | } |
| 86 | + | |
| 85 | 87 | } | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
| ... | ... | @@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil; |
| 4 | 4 | import cn.hutool.http.Method; |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 7 | +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; | |
| 7 | 8 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | 9 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 9 | 10 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -66,4 +67,5 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { |
| 66 | 67 | return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), |
| 67 | 68 | reqDTO.getOutTradeNo(), response); |
| 68 | 69 | } |
| 70 | + | |
| 69 | 71 | } | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
| ... | ... | @@ -58,6 +58,11 @@ public class MockPayClient extends AbstractPayClient<NonePayClientConfig> { |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | 60 | @Override |
| 61 | + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable { | |
| 62 | + throw new UnsupportedOperationException("未实现"); | |
| 63 | + } | |
| 64 | + | |
| 65 | + @Override | |
| 61 | 66 | protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) { |
| 62 | 67 | throw new UnsupportedOperationException("模拟支付无退款回调"); |
| 63 | 68 | } | ... | ... |
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
| ... | ... | @@ -14,14 +14,11 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 14 | 14 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 15 | 15 | import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; |
| 16 | 16 | import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; |
| 17 | +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.WxPayTransferPartnerNotifyV3Result; | |
| 17 | 18 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| 18 | 19 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; |
| 19 | 20 | import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; |
| 20 | -import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; | |
| 21 | -import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result; | |
| 22 | -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; | |
| 23 | -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; | |
| 24 | -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result; | |
| 21 | +import com.github.binarywang.wxpay.bean.notify.*; | |
| 25 | 22 | import com.github.binarywang.wxpay.bean.request.*; |
| 26 | 23 | import com.github.binarywang.wxpay.bean.result.*; |
| 27 | 24 | import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest; |
| ... | ... | @@ -31,7 +28,6 @@ import com.github.binarywang.wxpay.exception.WxPayException; |
| 31 | 28 | import com.github.binarywang.wxpay.service.TransferService; |
| 32 | 29 | import com.github.binarywang.wxpay.service.WxPayService; |
| 33 | 30 | import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; |
| 34 | -import jakarta.annotation.Resource; | |
| 35 | 31 | import lombok.extern.slf4j.Slf4j; |
| 36 | 32 | |
| 37 | 33 | import java.time.LocalDateTime; |
| ... | ... | @@ -356,6 +352,29 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 356 | 352 | } |
| 357 | 353 | |
| 358 | 354 | @Override |
| 355 | + public PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws WxPayException { | |
| 356 | + switch (config.getApiVersion()) { | |
| 357 | + case API_VERSION_V3: | |
| 358 | + return parseTransferNotifyV3(body); | |
| 359 | + default: | |
| 360 | + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); | |
| 361 | + } | |
| 362 | + } | |
| 363 | + | |
| 364 | + private PayTransferRespDTO parseTransferNotifyV3(String body) throws WxPayException { | |
| 365 | + WxPayTransferPartnerNotifyV3Result response = client.baseParseOrderNotifyV3Result(body, null, WxPayTransferPartnerNotifyV3Result.class, WxPayTransferPartnerNotifyV3Result.TransferNotifyResult.class); | |
| 366 | + WxPayTransferPartnerNotifyV3Result.TransferNotifyResult result = response.getResult(); | |
| 367 | + // 2. 构建结果 | |
| 368 | + if (Objects.equals("FINISHED", result.getBatchStatus())) { | |
| 369 | + if(result.getFailNum() <= 0){ | |
| 370 | + return PayTransferRespDTO.successOf(result.getBatchId(), parseDateV3(result.getUpdateTime()), | |
| 371 | + result.getOutBatchNo(), response); | |
| 372 | + } | |
| 373 | + } | |
| 374 | + return PayTransferRespDTO.closedOf(result.getBatchStatus(), result.getCloseReason(), result.getOutBatchNo(), response); | |
| 375 | + } | |
| 376 | + | |
| 377 | + @Override | |
| 359 | 378 | protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException { |
| 360 | 379 | try { |
| 361 | 380 | switch (config.getApiVersion()) { |
| ... | ... | @@ -452,7 +471,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 452 | 471 | .transferDetailList(transferDetailList).build(); |
| 453 | 472 | transferBatches.setNotifyUrl(reqDTO.getNotifyUrl()); |
| 454 | 473 | TransferBatchesResult transferBatchesResult = transferService.transferBatches(transferBatches); |
| 455 | - return PayTransferRespDTO.waitingOf(reqDTO.getOutTransferNo(), transferBatchesResult.getBatchId() ,transferBatchesResult); | |
| 474 | + return PayTransferRespDTO.dealingOf(transferBatchesResult.getBatchId(), reqDTO.getOutTransferNo(), transferBatchesResult); | |
| 456 | 475 | } |
| 457 | 476 | |
| 458 | 477 | @Override | ... | ... |
yudao-server/src/main/resources/application-dev.yaml
| ... | ... | @@ -165,7 +165,8 @@ yudao: |
| 165 | 165 | pay: |
| 166 | 166 | order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 |
| 167 | 167 | refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 |
| 168 | - demo: true # 开启演示模式 | |
| 168 | + transfer-notify-url: https://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 | |
| 169 | + demo: false # 开启演示模式 | |
| 169 | 170 | tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc |
| 170 | 171 | |
| 171 | 172 | justauth: | ... | ... |
yudao-server/src/main/resources/application-local.yaml
| ... | ... | @@ -218,6 +218,7 @@ yudao: |
| 218 | 218 | pay: |
| 219 | 219 | order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 |
| 220 | 220 | refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 |
| 221 | + transfer-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址 | |
| 221 | 222 | access-log: # 访问日志的配置项 |
| 222 | 223 | enable: false |
| 223 | 224 | demo: false # 关闭演示模式 | ... | ... |