【功能优化】完成转账回调接口

This commit is contained in:
痴货 2024-10-05 21:32:36 +08:00
parent ae1cf9e098
commit 325d5e6b12
33 changed files with 378 additions and 42 deletions

View File

@ -44,7 +44,7 @@ public class BrokerageRecordController {
@Operation(summary = "获得佣金记录") @Operation(summary = "获得佣金记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')") @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
public CommonResult<BrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Integer id) { public CommonResult<BrokerageRecordRespVO> getBrokerageRecord(@RequestParam("id") Long id) {
BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id); BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id);
return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord)); return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord));
} }

View File

@ -45,7 +45,7 @@ public class BrokerageWithdrawController {
@PutMapping("/approve") @PutMapping("/approve")
@Operation(summary = "通过申请") @Operation(summary = "通过申请")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')") @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Integer id) { public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Long id) {
brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "", getClientIP()); brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "", getClientIP());
return success(true); return success(true);
} }
@ -62,7 +62,7 @@ public class BrokerageWithdrawController {
@Operation(summary = "获得佣金提现") @Operation(summary = "获得佣金提现")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')") @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Integer id) { public CommonResult<BrokerageWithdrawRespVO> getBrokerageWithdraw(@RequestParam("id") Long id) {
BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id); BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id);
return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw)); return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw));
} }
@ -87,6 +87,7 @@ public class BrokerageWithdrawController {
// 目前业务逻辑不需要做任何事情 // 目前业务逻辑不需要做任何事情
// 当然退款会有小概率会失败的情况可以监控失败状态进行告警 // 当然退款会有小概率会失败的情况可以监控失败状态进行告警
log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO); log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO);
brokerageWithdrawService.updateTransfer(Long.parseLong(notifyReqDTO.getMerchantTransferId()), notifyReqDTO.getPayTransferId());
return success(true); return success(true);
} }

View File

@ -14,7 +14,7 @@ import java.time.LocalDateTime;
public class BrokerageRecordRespVO extends BrokerageRecordBaseVO { public class BrokerageRecordRespVO extends BrokerageRecordBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896") @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896")
private Integer id; private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@ -14,7 +14,7 @@ public class BrokerageWithdrawRejectReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
@NotNull(message = "编号不能为空") @NotNull(message = "编号不能为空")
private Integer id; private Long id;
@Schema(description = "审核驳回原因", example = "不对") @Schema(description = "审核驳回原因", example = "不对")
@NotEmpty(message = "审核驳回原因不能为空") @NotEmpty(message = "审核驳回原因不能为空")

View File

@ -14,7 +14,7 @@ import java.time.LocalDateTime;
public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO { public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161") @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
private Integer id; private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@ -35,7 +35,7 @@ public interface BrokerageWithdrawMapper extends BaseMapperX<BrokerageWithdrawDO
.orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId)); .orderByAsc(BrokerageWithdrawDO::getStatus).orderByDesc(BrokerageWithdrawDO::getId));
} }
default int updateByIdAndStatus(Integer id, Integer status, BrokerageWithdrawDO updateObj) { default int updateByIdAndStatus(Long id, Integer status, BrokerageWithdrawDO updateObj) {
return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>() return update(updateObj, new LambdaUpdateWrapper<BrokerageWithdrawDO>()
.eq(BrokerageWithdrawDO::getId, id) .eq(BrokerageWithdrawDO::getId, id)
.eq(BrokerageWithdrawDO::getStatus, status)); .eq(BrokerageWithdrawDO::getStatus, status));

View File

@ -32,7 +32,7 @@ public interface BrokerageRecordService {
* @param id 编号 * @param id 编号
* @return 佣金记录 * @return 佣金记录
*/ */
BrokerageRecordDO getBrokerageRecord(Integer id); BrokerageRecordDO getBrokerageRecord(Long id);
/** /**
* 获得佣金记录分页 * 获得佣金记录分页

View File

@ -64,7 +64,7 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
private ProductSkuApi productSkuApi; private ProductSkuApi productSkuApi;
@Override @Override
public BrokerageRecordDO getBrokerageRecord(Integer id) { public BrokerageRecordDO getBrokerageRecord(Long id) {
return brokerageRecordMapper.selectById(id); return brokerageRecordMapper.selectById(id);
} }

View File

@ -28,7 +28,7 @@ public interface BrokerageWithdrawService {
* @param status 审核状态 * @param status 审核状态
* @param auditReason 驳回原因 * @param auditReason 驳回原因
*/ */
void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp); void auditBrokerageWithdraw(Long id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp);
/** /**
* 获得佣金提现 * 获得佣金提现
@ -36,7 +36,7 @@ public interface BrokerageWithdrawService {
* @param id 编号 * @param id 编号
* @return 佣金提现 * @return 佣金提现
*/ */
BrokerageWithdrawDO getBrokerageWithdraw(Integer id); BrokerageWithdrawDO getBrokerageWithdraw(Long id);
/** /**
* 获得佣金提现分页 * 获得佣金提现分页
@ -77,4 +77,10 @@ public interface BrokerageWithdrawService {
return convertMap(getWithdrawSummaryListByUserId(userIds, status), BrokerageWithdrawSummaryRespBO::getUserId); return convertMap(getWithdrawSummaryListByUserId(userIds, status), BrokerageWithdrawSummaryRespBO::getUserId);
} }
/**
*
* @param merchantTransferId 提现编号
* @param payTransferId 转账订单编号
*/
void updateTransfer(Long merchantTransferId, Long payTransferId);
} }

View File

@ -9,6 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi; import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum; import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
@ -39,7 +41,6 @@ import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
/** /**
@ -76,7 +77,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp) { public void auditBrokerageWithdraw(Long id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp) {
// 1.1 校验存在 // 1.1 校验存在
BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id); BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id);
@ -105,7 +106,6 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
PayTransferCreateReqDTO payTransferCreateReqDTO = getPayTransferCreateReqDTO(userIp, withdraw, socialUser); PayTransferCreateReqDTO payTransferCreateReqDTO = getPayTransferCreateReqDTO(userIp, withdraw, socialUser);
payTransferApi.createTransfer(payTransferCreateReqDTO); payTransferApi.createTransfer(payTransferCreateReqDTO);
} }
// TODO 疯狂调用转账接口
} else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) { } else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT; templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT;
// 3.2 驳回时需要退还用户佣金 // 3.2 驳回时需要退还用户佣金
@ -116,13 +116,13 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
} }
// 4. 通知用户 // 4. 通知用户
Map<String, Object> templateParams = MapUtil.<String, Object>builder() // Map<String, Object> templateParams = MapUtil.<String, Object>builder()
.put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime())) // .put("createTime", LocalDateTimeUtil.formatNormal(withdraw.getCreateTime()))
.put("price", MoneyUtils.fenToYuanStr(withdraw.getPrice())) // .put("price", MoneyUtils.fenToYuanStr(withdraw.getPrice()))
.put("reason", auditReason) // .put("reason", auditReason)
.build(); // .build();
notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO() // notifyMessageSendApi.sendSingleMessageToMember(new NotifySendSingleToUserReqDTO()
.setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams)); // .setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams));
} }
private PayTransferCreateReqDTO getPayTransferCreateReqDTO(String userIp, BrokerageWithdrawDO withdraw, SocialUserRespDTO socialUser) { private PayTransferCreateReqDTO getPayTransferCreateReqDTO(String userIp, BrokerageWithdrawDO withdraw, SocialUserRespDTO socialUser) {
@ -138,7 +138,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
return payTransferCreateReqDTO; return payTransferCreateReqDTO;
} }
private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) { private BrokerageWithdrawDO validateBrokerageWithdrawExists(Long id) {
BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id); BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id);
if (withdraw == null) { if (withdraw == null) {
throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS); throw exception(BROKERAGE_WITHDRAW_NOT_EXISTS);
@ -147,7 +147,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
} }
@Override @Override
public BrokerageWithdrawDO getBrokerageWithdraw(Integer id) { public BrokerageWithdrawDO getBrokerageWithdraw(Long id) {
return brokerageWithdrawMapper.selectById(id); return brokerageWithdrawMapper.selectById(id);
} }
@ -186,6 +186,23 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus()); return brokerageWithdrawMapper.selectCountAndSumPriceByUserIdAndStatus(userIds, status.getStatus());
} }
@Override
public void updateTransfer(Long id, Long payTransferId) {
BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id);
PayTransferRespDTO transfer = payTransferApi.getTransfer(payTransferId);
if(PayTransferStatusEnum.isSuccess(transfer.getStatus())){
withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_SUCCESS.getStatus());
}else if(PayTransferStatusEnum.isPendingStatus(transfer.getStatus())){
withdraw.setStatus(BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.getStatus());
}else{
withdraw.setStatus(BrokerageWithdrawStatusEnum.WITHDRAW_FAIL.getStatus());
// 3.2 驳回时需要退还用户佣金
brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT,
String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle());
}
brokerageWithdrawMapper.updateById(withdraw);
}
/** /**
* 计算提现手续费 * 计算提现手续费
* *

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.api.transfer;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
import jakarta.validation.Valid; import jakarta.validation.Valid;
/** /**
@ -19,4 +20,10 @@ public interface PayTransferApi {
*/ */
Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO); Long createTransfer(@Valid PayTransferCreateReqDTO reqDTO);
/**
* 获取转账单详细
* @param id 转账单编号
* @return 转账单详细
*/
PayTransferRespDTO getTransfer(Long id);
} }

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.pay.api.transfer.dto;
import lombok.Data;
@Data
public class PayTransferRespDTO {
/**
* 编号
*/
private Long id;
/**
* 转账单号
*
*/
private String no;
/**
* 转账金额单位
*/
private Integer price;
/**
* 转账状态
*
* 枚举 {@link PayTransferStatusRespEnum}
*/
private Integer status;
}

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.pay.api.transfer; package cn.iocoder.yudao.module.pay.api.transfer;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
import cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert;
import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService; import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -24,4 +27,10 @@ public class PayTransferApiImpl implements PayTransferApi {
return payTransferService.createTransfer(reqDTO); return payTransferService.createTransfer(reqDTO);
} }
@Override
public PayTransferRespDTO getTransfer(Long id) {
PayTransferDO transfer = payTransferService.getTransfer(id);
return PayTransferConvert.INSTANCE.convert3(transfer);
}
} }

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.PayClient;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO; import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO;
@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -49,6 +51,8 @@ public class PayNotifyController {
@Resource @Resource
private PayRefundService refundService; private PayRefundService refundService;
@Resource @Resource
private PayTransferService payTransferService;
@Resource
private PayNotifyService notifyService; private PayNotifyService notifyService;
@Resource @Resource
private PayAppService appService; private PayAppService appService;
@ -95,6 +99,26 @@ public class PayNotifyController {
return "success"; return "success";
} }
@PostMapping(value = "/transfer/{channelId}")
@Operation(summary = "支付渠道的统一【转账】回调")
@PermitAll
public String notifyTransfer(@PathVariable("channelId") Long channelId,
@RequestParam(required = false) Map<String, String> params,
@RequestBody(required = false) String body) {
log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body);
// 1. 校验支付渠道是否存在
PayClient payClient = channelService.getPayClient(channelId);
if (payClient == null) {
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
throw exception(CHANNEL_NOT_FOUND);
}
// 2. 解析通知数据
PayTransferRespDTO notify = payClient.parseTransferNotify(params, body);
payTransferService.notifyTransfer(channelId, notify);
return "success";
}
@GetMapping("/get-detail") @GetMapping("/get-detail")
@Operation(summary = "获得回调通知的明细") @Operation(summary = "获得回调通知的明细")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.convert.transfer;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferRespDTO;
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageItemRespVO;
@ -24,7 +25,9 @@ public interface PayTransferConvert {
PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo); PayTransferCreateReqDTO convert(PayDemoTransferCreateReqVO vo);
PayTransferRespVO convert(PayTransferDO bean); PayTransferRespVO convert(PayTransferDO bean);
PayTransferRespDTO convert3(PayTransferDO bean);
PageResult<PayTransferPageItemRespVO> convertPage(PageResult<PayTransferDO> pageResult); PageResult<PayTransferPageItemRespVO> convertPage(PageResult<PayTransferDO> pageResult);
} }

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO; import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -44,6 +45,12 @@ public interface PayTransferMapper extends BaseMapperX<PayTransferDO> {
default List<PayTransferDO> selectListByStatus(Integer status){ default List<PayTransferDO> selectListByStatus(Integer status){
return selectList(PayTransferDO::getStatus, status); return selectList(PayTransferDO::getStatus, status);
} }
default PayTransferDO selectByAppIdAndNo(Long appId, String no){
return selectOne(new LambdaQueryWrapperX<PayTransferDO>()
.eq(PayTransferDO::getAppId, appId)
.eq(PayTransferDO::getNo, no));
}
} }

View File

@ -39,6 +39,15 @@ public class PayProperties {
@URL(message = "支付回调地址的格式必须是 URL") @URL(message = "支付回调地址的格式必须是 URL")
private String refundNotifyUrl; private String refundNotifyUrl;
/**
* 转账回调地址
*
* 实际上对应的 PayNotifyController notifyTransfer 方法的 URL
*
* 回调顺序支付渠道支付宝支付微信支付 => yudao-module-pay transferNotifyUrl 地址 => 业务的 PayAppDO.transferNotifyUrl 地址
*/
private String transferNotifyUrl;
/** /**
* 支付订单 no 的前缀 * 支付订单 no 的前缀
*/ */

View File

@ -177,6 +177,11 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo)); throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo));
} }
@Override
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
throw new UnsupportedOperationException("未实现");
}
@Override @Override
public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("待实现"); throw new UnsupportedOperationException("待实现");

View File

@ -78,5 +78,4 @@ public interface PayRefundService {
* @return 同步到状态的退款数量包括退款成功退款失败 * @return 同步到状态的退款数量包括退款成功退款失败
*/ */
int syncRefund(); int syncRefund();
} }

View File

@ -193,6 +193,8 @@ public class PayRefundServiceImpl implements PayRefundService {
TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyRefund(channel, notify)); TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyRefund(channel, notify));
} }
/** /**
* 通知并更新订单的退款结果 * 通知并更新订单的退款结果
* *

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.pay.service.transfer; package cn.iocoder.yudao.module.pay.service.transfer;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO; import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferCreateReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.transfer.vo.PayTransferPageReqVO;
@ -54,4 +55,12 @@ public interface PayTransferService {
* @return 同步到状态的转账数量包括转账成功转账失败转账中的 * @return 同步到状态的转账数量包括转账成功转账失败转账中的
*/ */
int syncTransfer(); int syncTransfer();
/**
* 渠道的转账通知
*
* @param channelId 渠道编号
* @param notify 通知
*/
void notifyTransfer(Long channelId, PayTransferRespDTO notify);
} }

View File

@ -21,6 +21,7 @@ import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum; import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
import cn.iocoder.yudao.module.pay.service.app.PayAppService; import cn.iocoder.yudao.module.pay.service.app.PayAppService;
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
@ -28,6 +29,7 @@ import jakarta.annotation.Resource;
import jakarta.validation.Validator; import jakarta.validation.Validator;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
@ -50,6 +52,9 @@ public class PayTransferServiceImpl implements PayTransferService {
private static final String TRANSFER_NO_PREFIX = "T"; private static final String TRANSFER_NO_PREFIX = "T";
@Resource
private PayProperties payProperties;
@Resource @Resource
private PayTransferMapper transferMapper; private PayTransferMapper transferMapper;
@Resource @Resource
@ -104,7 +109,7 @@ public class PayTransferServiceImpl implements PayTransferService {
// 3. 调用三方渠道发起转账 // 3. 调用三方渠道发起转账
PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer) PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer)
.setOutTransferNo(transfer.getNo()); .setOutTransferNo(transfer.getNo());
transferUnifiedReq.setNotifyUrl(payApp.getTransferNotifyUrl()); transferUnifiedReq.setNotifyUrl(genChannelTransferNotifyUrl(channel));
PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq); PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
// 4. 通知转账结果 // 4. 通知转账结果
getSelf().notifyTransfer(channel, unifiedTransferResp); getSelf().notifyTransfer(channel, unifiedTransferResp);
@ -118,6 +123,16 @@ public class PayTransferServiceImpl implements PayTransferService {
return transfer.getId(); return transfer.getId();
} }
/**
* 根据支付渠道的编码生成支付渠道的回调地址
*
* @param channel 支付渠道
* @return 支付渠道的回调地址 配置地址 + "/" + channel id
*/
private String genChannelTransferNotifyUrl(PayChannelDO channel) {
return payProperties.getTransferNotifyUrl() + "/" + channel.getId();
}
private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) { private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) {
PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId()); PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId());
if (transfer != null) { if (transfer != null) {
@ -156,7 +171,8 @@ public class PayTransferServiceImpl implements PayTransferService {
private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) { private void notifyTransferInProgress(PayChannelDO channel, PayTransferRespDTO notify) {
// 1.校验 // 1.校验
PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); PayTransferDO transfer = transferMapper.selectByAppIdAndNo(
channel.getAppId(), notify.getOutTransferNo());
if (transfer == null) { if (transfer == null) {
throw exception(PAY_TRANSFER_NOT_FOUND); throw exception(PAY_TRANSFER_NOT_FOUND);
} }
@ -174,16 +190,13 @@ public class PayTransferServiceImpl implements PayTransferService {
throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING); throw exception(PAY_TRANSFER_STATUS_IS_NOT_WAITING);
} }
log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId()); log.info("[notifyTransferInProgress][transfer({}) 更新为转账进行中状态]", transfer.getId());
// 3. 插入转账通知记录
notifyService.createPayNotifyTask(PayNotifyTypeEnum.TRANSFER.getType(),
transfer.getId());
} }
private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) { private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
// 1.校验 // 1.校验
PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); PayTransferDO transfer = transferMapper.selectByAppIdAndNo(
channel.getAppId(), notify.getOutTransferNo());
if (transfer == null) { if (transfer == null) {
throw exception(PAY_TRANSFER_NOT_FOUND); throw exception(PAY_TRANSFER_NOT_FOUND);
} }
@ -212,7 +225,8 @@ public class PayTransferServiceImpl implements PayTransferService {
private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) { private void notifyTransferClosed(PayChannelDO channel, PayTransferRespDTO notify) {
// 1.校验 // 1.校验
PayTransferDO transfer = transferMapper.selectByNo(notify.getOutTransferNo()); PayTransferDO transfer = transferMapper.selectByAppIdAndNo(
channel.getAppId(), notify.getOutTransferNo());
if (transfer == null) { if (transfer == null) {
throw exception(PAY_TRANSFER_NOT_FOUND); throw exception(PAY_TRANSFER_NOT_FOUND);
} }
@ -285,7 +299,7 @@ public class PayTransferServiceImpl implements PayTransferService {
} }
} }
private void notifyTransfer(Long channelId, PayTransferRespDTO notify) { public void notifyTransfer(Long channelId, PayTransferRespDTO notify) {
// 校验渠道是否有效 // 校验渠道是否有效
PayChannelDO channel = channelService.validPayChannel(channelId); PayChannelDO channel = channelService.validPayChannel(channelId);
// 通知转账结果给对应的业务 // 通知转账结果给对应的业务

View File

@ -79,6 +79,8 @@ public interface PayClient {
*/ */
PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo); PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo);
// ============ 转账相关 ==========
/** /**
* 调用渠道进行转账 * 调用渠道进行转账
* *
@ -95,4 +97,13 @@ public interface PayClient {
* @return 转账信息 * @return 转账信息
*/ */
PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type); PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type);
/**
* 解析 transfer 回调数据
*
* @param params HTTP 回调接口 content type application/x-www-form-urlencoded 的所有参数
* @param body HTTP 回调接口的 request body
* @return 转账信息
*/
PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body);
} }

View File

@ -0,0 +1,128 @@
package cn.iocoder.yudao.framework.pay.core.client.dto.transfer;
import com.github.binarywang.wxpay.bean.notify.OriginNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayBaseNotifyV3Result;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@NoArgsConstructor
public class WxPayTransferPartnerNotifyV3Result implements Serializable, WxPayBaseNotifyV3Result<WxPayTransferPartnerNotifyV3Result.TransferNotifyResult> {
private static final long serialVersionUID = -1L;
/**
* 源数据
*/
private OriginNotifyResponse rawData;
/**
* 解密后的数据
*/
private TransferNotifyResult result;
@Override
public void setRawData(OriginNotifyResponse rawData) {
this.rawData = rawData;
}
@Override
public void setResult(TransferNotifyResult data) {
this.result = data;
}
public TransferNotifyResult getResult() {
return result;
}
public OriginNotifyResponse getRawData() {
return rawData;
}
@Data
@NoArgsConstructor
public static class TransferNotifyResult implements Serializable {
private static final long serialVersionUID = 1L;
/*********************** 公共字段 ********************
/**
* 商家批次单号
*/
@SerializedName(value = "out_batch_no")
protected String outBatchNo;
/**
* 微信批次单号
*/
@SerializedName(value = "batch_id")
protected String batchId;
/**
* 批次状态
*/
@SerializedName(value = "batch_status")
protected String batchStatus;
/**
* 批次总笔数
*/
@SerializedName(value = "total_num")
protected Integer totalNum;
/**
* 批次总金额
*/
@SerializedName(value = "total_amount")
protected Integer totalAmount;
/**
* 批次更新时间
*/
@SerializedName(value = "update_time")
private String updateTime;
/*********************** FINISHED ********************
/**
* 转账成功金额
*/
@SerializedName(value = "success_amount")
protected Integer successAmount;
/**
* 转账成功笔数
*/
@SerializedName(value = "success_num")
protected Integer successNum;
/**
* 转账失败金额
*/
@SerializedName(value = "fail_amount")
protected Integer failAmount;
/**
* 转账失败笔数
*/
@SerializedName(value = "fail_num")
protected Integer failNum;
/*********************** CLOSED ********************
/**
* 商户号
*/
@SerializedName(value = "mchid")
protected String mchId;
/**
* 批次关闭原因
*/
@SerializedName(value = "close_reason")
protected String closeReason;
}
}

View File

@ -219,6 +219,22 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
} }
} }
@Override
public final PayTransferRespDTO parseTransferNotify(Map<String, String> params, String body) {
try {
return doParseTransferNotify(params, body);
} catch (ServiceException ex) { // 业务异常都是实现类已经翻译所以直接抛出即可
throw ex;
} catch (Throwable ex) {
log.error("[doParseTransferNotify][客户端({}) params({}) body({}) 解析失败]",
getId(), params, body, ex);
throw buildPayException(ex);
}
}
protected abstract PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body)
throws Throwable;
@Override @Override
public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) { public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) {
try { try {

View File

@ -325,6 +325,11 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
} }
} }
@Override
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
throw new UnsupportedOperationException("未实现");
}
// ========== 各种工具方法 ========== // ========== 各种工具方法 ==========
protected String formatAmount(Integer amount) { protected String formatAmount(Integer amount) {

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -56,4 +57,5 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
} }

View File

@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -82,4 +83,5 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, "", return PayOrderRespDTO.waitingOf(displayMode, "",
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.Method; import cn.hutool.http.Method;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -66,4 +67,5 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
} }

View File

@ -57,6 +57,11 @@ public class MockPayClient extends AbstractPayClient<NonePayClientConfig> {
outRefundNo, MOCK_RESP_SUCCESS_DATA); outRefundNo, MOCK_RESP_SUCCESS_DATA);
} }
@Override
protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws Throwable {
throw new UnsupportedOperationException("未实现");
}
@Override @Override
protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) { protected PayRefundRespDTO doParseRefundNotify(Map<String, String> params, String body) {
throw new UnsupportedOperationException("模拟支付无退款回调"); throw new UnsupportedOperationException("模拟支付无退款回调");

View File

@ -14,14 +14,11 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.WxPayTransferPartnerNotifyV3Result;
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest; import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
@ -31,7 +28,6 @@ import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.TransferService; import com.github.binarywang.wxpay.service.TransferService;
import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -355,6 +351,29 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response);
} }
@Override
public PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body) throws WxPayException {
switch (config.getApiVersion()) {
case API_VERSION_V3:
return parseTransferNotifyV3(body);
default:
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
}
}
private PayTransferRespDTO parseTransferNotifyV3(String body) throws WxPayException {
WxPayTransferPartnerNotifyV3Result response = client.baseParseOrderNotifyV3Result(body, null, WxPayTransferPartnerNotifyV3Result.class, WxPayTransferPartnerNotifyV3Result.TransferNotifyResult.class);
WxPayTransferPartnerNotifyV3Result.TransferNotifyResult result = response.getResult();
// 2. 构建结果
if (Objects.equals("FINISHED", result.getBatchStatus())) {
if(result.getFailNum() <= 0){
return PayTransferRespDTO.successOf(result.getBatchId(), parseDateV3(result.getUpdateTime()),
result.getOutBatchNo(), response);
}
}
return PayTransferRespDTO.closedOf(result.getBatchStatus(), result.getCloseReason(), result.getOutBatchNo(), response);
}
@Override @Override
protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException { protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException {
try { try {
@ -452,7 +471,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
.transferDetailList(transferDetailList).build(); .transferDetailList(transferDetailList).build();
transferBatches.setNotifyUrl(reqDTO.getNotifyUrl()); transferBatches.setNotifyUrl(reqDTO.getNotifyUrl());
TransferBatchesResult transferBatchesResult = transferService.transferBatches(transferBatches); TransferBatchesResult transferBatchesResult = transferService.transferBatches(transferBatches);
return PayTransferRespDTO.waitingOf(reqDTO.getOutTransferNo(), transferBatchesResult.getBatchId() ,transferBatchesResult); return PayTransferRespDTO.dealingOf(transferBatchesResult.getBatchId(), reqDTO.getOutTransferNo(), transferBatchesResult);
} }
@Override @Override

View File

@ -165,7 +165,8 @@ yudao:
pay: pay:
order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址
demo: true # 开启演示模式 transfer-notify-url: https://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址
demo: false # 开启演示模式
tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
justauth: justauth:

View File

@ -218,6 +218,7 @@ yudao:
pay: pay:
order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址
transfer-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/transfer # 支付渠道的【转账】回调地址
access-log: # 访问日志的配置项 access-log: # 访问日志的配置项
enable: false enable: false
demo: false # 关闭演示模式 demo: false # 关闭演示模式