增加微信公众号的支付回调接口
This commit is contained in:
parent
bac30d47b7
commit
75633aa84b
|
@ -120,6 +120,10 @@ public class PayOrderDO extends BaseDO {
|
|||
* 订单支付成功时间
|
||||
*/
|
||||
private Date successTime;
|
||||
/**
|
||||
* 订单支付通知时间,即支付渠道的通知时间
|
||||
*/
|
||||
private Date notifyTime;
|
||||
/**
|
||||
* 支付成功的订单拓展单编号
|
||||
*
|
||||
|
|
|
@ -77,6 +77,6 @@ public class PayOrderExtensionDO extends BaseDO {
|
|||
*
|
||||
* 在支持成功后,会记录回调的数据
|
||||
*/
|
||||
private String channelCallbackData;
|
||||
private String channelNotifyData;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
@ -13,4 +14,9 @@ public interface PayOrderCoreMapper extends BaseMapperX<PayOrderDO> {
|
|||
.eq("merchant_order_id", merchantOrderId));
|
||||
}
|
||||
|
||||
default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) {
|
||||
return update(update, new QueryWrapper<PayOrderDO>()
|
||||
.eq("id", id).eq("status", status));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
|
@ -9,4 +8,13 @@ import org.apache.ibatis.annotations.Mapper;
|
|||
@Mapper
|
||||
public interface PayOrderExtensionCoreMapper extends BaseMapperX<PayOrderExtensionDO> {
|
||||
|
||||
default PayOrderExtensionDO selectByOrderExtensionNo(String orderExtensionNo) {
|
||||
return selectOne("order_extension_no", orderExtensionNo);
|
||||
}
|
||||
|
||||
default int updateByIdAndStatus(Long id, Integer status, PayOrderExtensionDO update) {
|
||||
return update(update, new QueryWrapper<PayOrderExtensionDO>()
|
||||
.eq("id", id).eq("status", status));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,13 +19,13 @@ public interface PayErrorCodeCoreConstants {
|
|||
ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在");
|
||||
|
||||
// ========== ORDER 模块 1-007-002-000 ==========
|
||||
ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(100401000, "支付订单不存在");
|
||||
ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(100401001, "支付订单不处于待支付");
|
||||
ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(100401002, "支付订单不处于已支付");
|
||||
ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(100401003, "支付订单用户不正确");
|
||||
|
||||
ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(100401050, "支付交易拓展单不存在");
|
||||
ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(100401051, "支付交易拓展单不处于待支付");
|
||||
ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(100401052, "支付订单不处于已支付");
|
||||
ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
|
||||
ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
|
||||
ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
|
||||
ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(1007002003, "支付订单用户不正确");
|
||||
// ========== ORDER 模块(拓展单) 1-007-003-000 ==========
|
||||
ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
|
||||
ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
|
||||
ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007003002, "支付订单不处于已支付");
|
||||
|
||||
}
|
||||
|
|
|
@ -39,4 +39,13 @@ public interface PayOrderCoreService {
|
|||
*/
|
||||
PayOrderSubmitRespDTO submitPayOrder(@Valid PayOrderSubmitReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 通知支付单成功
|
||||
*
|
||||
* @param channelId 渠道编号
|
||||
* @param channelCode 渠道编码
|
||||
* @param notifyData 通知数据
|
||||
*/
|
||||
void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception;
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
|||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -99,7 +100,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
|
|||
@Override
|
||||
public PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO) {
|
||||
// 校验 App
|
||||
PayAppDO app = payAppCoreService.validPayApp(reqDTO.getAppId());
|
||||
payAppCoreService.validPayApp(reqDTO.getAppId());
|
||||
// 校验支付渠道是否有效
|
||||
PayChannelDO channel = payChannelCoreService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
|
||||
// 校验支付客户端是否正确初始化
|
||||
|
@ -172,4 +173,61 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
|
|||
;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception {
|
||||
// TODO 芋艿,记录回调日志
|
||||
log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData);
|
||||
|
||||
// 校验支付渠道是否有效
|
||||
PayChannelDO channel = payChannelCoreService.validPayChannel(channelId, channelCode);
|
||||
// 校验支付客户端是否正确初始化
|
||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
||||
if (client == null) {
|
||||
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||
}
|
||||
// 解析支付结果
|
||||
PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData);
|
||||
|
||||
// TODO 芋艿,先最严格的校验。即使调用方重复调用,实际哪个订单已经被重复回调的支付,也返回 false 。也没问题,因为实际已经回调成功了。
|
||||
// 1.1 查询 PayOrderExtensionDO
|
||||
PayOrderExtensionDO orderExtension = payOrderExtensionCoreMapper.selectByOrderExtensionNo(
|
||||
notifyRespDTO.getOrderExtensionNo());
|
||||
if (orderExtension == null) {
|
||||
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(orderExtension.getStatus())) { // 校验状态,必须是待支付
|
||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
// 1.2 更新 PayOrderExtensionDO
|
||||
int updateCounts = payOrderExtensionCoreMapper.updateByIdAndStatus(orderExtension.getOrderId(),
|
||||
PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId())
|
||||
.status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData).build());
|
||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
log.info("[notifyPayOrder][支付拓展单({}) 更新为已支付]", orderExtension.getId());
|
||||
|
||||
// 2.1 判断 PayOrderDO 是否处于待支付
|
||||
PayOrderDO order = payOrderCoreMapper.selectById(orderExtension.getOrderId());
|
||||
if (order == null) {
|
||||
throw exception(PAY_ORDER_NOT_FOUND);
|
||||
}
|
||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
||||
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
// 2.2 更新 PayOrderDO
|
||||
updateCounts = payOrderCoreMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
|
||||
PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelId(channelId).channelCode(channelCode)
|
||||
.successTime(notifyRespDTO.getSuccessTime()).notifyTime(new Date())
|
||||
.successExtensionId(orderExtension.getId()).build());
|
||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
log.info("[notifyPayOrder][支付订单({}) 更新为已支付]", order.getId());
|
||||
|
||||
// 3. 插入支付通知记录
|
||||
// payNotifyService.addPayTransactionNotifyTask(order, orderExtension);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cn.iocoder.yudao.framework.pay.core.client;
|
||||
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
|
||||
|
||||
/**
|
||||
|
@ -24,4 +25,13 @@ public interface PayClient {
|
|||
*/
|
||||
PayCommonResult<?> unifiedOrder(PayOrderUnifiedReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 解析支付单的通知结果
|
||||
*
|
||||
* @param data 通知结果
|
||||
* @return 解析结果
|
||||
* @throws Exception 解析失败,抛出异常
|
||||
*/
|
||||
PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package cn.iocoder.yudao.framework.pay.core.client.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 支付通知 Response DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PayOrderNotifyRespDTO {
|
||||
|
||||
/**
|
||||
* 支付订单号(支付模块的)
|
||||
*/
|
||||
private String orderExtensionNo;
|
||||
/**
|
||||
* 支付渠道
|
||||
*/
|
||||
private String channelOrderNo;
|
||||
/**
|
||||
* 支付渠道
|
||||
*/
|
||||
private Date successTime;
|
||||
|
||||
/**
|
||||
* 通知的原始数据
|
||||
*
|
||||
* 主要用于持久化,方便后续修复数据,或者排错
|
||||
*/
|
||||
private String data;
|
||||
|
||||
}
|
|
@ -12,6 +12,8 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* 统一下单 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class PayOrderUnifiedReqDTO {
|
||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
|||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
||||
|
@ -65,4 +66,9 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayClientConfig>
|
|||
return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception {
|
||||
// TODO 芋艿:待完成
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
|||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
||||
|
@ -61,4 +62,9 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig>
|
|||
return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception {
|
||||
// TODO 芋艿:待完成
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,17 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
|
|||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
||||
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
|
||||
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
|
||||
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
|
||||
|
@ -22,6 +25,8 @@ import com.github.binarywang.wxpay.service.WxPayService;
|
|||
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.CODE_SUCCESS;
|
||||
import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.MESSAGE_SUCCESS;
|
||||
|
@ -126,4 +131,13 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
|||
return openid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(String data) throws WxPayException {
|
||||
WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data);
|
||||
Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS");
|
||||
// 转换结果
|
||||
return new PayOrderNotifyRespDTO(notifyResult.getOutTradeNo(), notifyResult.getTransactionId(),
|
||||
DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"), data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue