1. 引入 IJPay 组件

2. 增加创建支付单的 Service 实现
This commit is contained in:
YunaiV
2021-10-18 09:41:38 +08:00
parent 711a074059
commit 81126b2b4b
36 changed files with 587 additions and 85 deletions

View File

@ -11,7 +11,7 @@ import lombok.ToString;
/**
* 参数配置表
*
* @author ruoyi
* @author 芋道源码
*/
@TableName("inf_config")
@Data

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.coreservice.modules.pay.convert.order;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderCreateReqDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface PayOrderCoreServiceConvert {
PayOrderCoreServiceConvert INSTANCE = Mappers.getMapper(PayOrderCoreServiceConvert.class);
PayOrderDO convert(PayOrderCreateReqDTO bean);
}

View File

@ -0,0 +1,6 @@
/**
* 提供 POJO 类的实体转换
*
* 目前使用 MapStruct 框架
*/
package cn.iocoder.yudao.coreservice.modules.pay.convert;

View File

@ -0,0 +1 @@
<http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao>

View File

@ -0,0 +1,60 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
/**
* 支付应用 DO
* 一个商户下,可能会有多个支付应用。例如说,京东有京东商城、京东到家等等
* 不过一般来说,一个商户,只有一个应用哈~
*
* 即 PayMerchantDO : PayAppDO = 1 : n
*
* @author 芋道源码
*/
@Data
public class PayAppDO extends BaseDO {
/**
* 应用编号,数据库自增
*/
@TableId
private Long id;
/**
* 应用名
*/
private String name;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 备注
*/
private String remark;
/**
* 应用私钥
* TODO 芋艿:用途
*/
private String secret;
/**
* 支付结果的回调地址
*/
private String payNotifyUrl;
/**
* 退款结果的回调地址
*/
private String refundNotifyUrl;
/**
* 商户编号
*
* 关联 {@link PayMerchantDO#getId()}
*/
private Long merchantId;
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant;
import cn.iocoder.yudao.coreservice.modules.pay.enums.merchant.PayChannelCodeEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
/**
* 支付渠道 DO
* 一个应用下,会有多种支付渠道,例如说微信支付、支付宝支付等等
*
* 即 PayAppDO : PayChannelDO = 1 : n
*
* @author 芋道源码
*/
@Data
public class PayChannelDO extends BaseDO {
/**
* 渠道编号,数据库自增
*/
private Long id;
/**
* 渠道编码
*
* 枚举 {@link PayChannelCodeEnum}
*/
private String code;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 渠道费率,单位:百分比
*/
private Double feeRate;
/**
* 商户编号
*
* 关联 {@link PayMerchantDO#getId()}
*/
private Long merchantId;
/**
* 应用编号
*
* 关联 {@link PayAppDO#getId()}
*/
private String appId;
// TODO 芋艿:不同渠道的配置。暂时考虑硬编码
}

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
/**
* 商户信息 DO
* 目前暂时没有特别的用途,主要为未来多商户提供基础。
*
* @author 芋道源码
*/
@Data
public class PayMerchantDO extends BaseDO {
/**
* 商户编号,数据库自增
*/
@TableId
private Long id;
/**
* 商户号
* 例如说M233666999
*/
private String no;
/**
* 商户全称
*/
private String name;
/**
* 商户简称
*/
private String shortName;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
/**
* 商户支付、退款等的通知
* 在支付系统收到支付渠道的支付、退款的结果后,需要不断的通知到业务系统,直到成功。
* TODO 芋艿:待完善
*
* @author 芋道源码
*/
@Data
public class PayNotifyDO extends BaseDO {
}

View File

@ -0,0 +1,174 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
import cn.iocoder.yudao.coreservice.modules.pay.enums.merchant.PayChannelCodeEnum;
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
/**
* 支付订单 DO
*
* @author 芋道源码
*/
@TableName("pay_order")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayOrderDO extends BaseDO {
/**
* 订单编号,数据库自增
*/
private Long id;
// /**
// * 订单号,根据规则生成
// *
// * 例如说P202110132239124200055
// */
// private String no;
/**
* 商户编号
*
* 关联 {@link PayMerchantDO#getId()}
*/
private Long merchantId;
/**
* 应用编号
*
* 关联 {@link PayAppDO#getId()}
*/
private Long appId;
/**
* 渠道编号
*
* 关联 {@link PayChannelDO#getId()}
*/
private Long channelId;
/**
* 商户编码
*
* 枚举 {@link PayChannelCodeEnum}
*/
private String channelCode;
// ========== 商户相关字段 ==========
/**
* 商户订单编号
* 例如说,内部系统 A 的订单号。需要保证每个 PayMerchantDO 唯一 TODO 芋艿:需要在测试下
*/
private String merchantOrderId;
/**
* 商品标题
*/
private String subject;
/**
* 商品描述信息
*/
private String body;
/**
* 商户拓展参数
*/
private String merchantExtra;
// ========== 订单相关字段 ==========
/**
* 支付金额,单位:分
*/
private Long amount;
/**
* 渠道手续费
*
* 冗余 {@link PayChannelDO#getFeeRate()}
*/
private Double channelFeeRate;
/**
* 渠道手续金额
*/
private Long channelFeeAmount;
/**
* 支付状态
*
* 枚举 {@link PayOrderStatusEnum}
*/
private Integer status;
/**
* 通知商户支付结果的回调状态
* TODO 芋艿0 未发送 1 已发送
*/
private Integer notifyStatus;
/**
* 客户端 IP
*/
private String clientIp;
/**
* 订单支付成功时间
*/
private Date successTime;
/**
* 订单失效时间
*/
private Date expireTime;
/**
* 支付渠道的额外参数
*
* 参见 https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html
*/
private String channelExtra;
/**
* 异步通知地址
*/
private String notifyUrl;
/**
* 页面跳转地址
*/
private String returnUrl;
// TODO 芋艿:可能要优化
/**
* 渠道支付错误码
*/
private String errorCode;
/**
* 渠道支付错误消息
*/
private String errorMessage;
// ========== 退款相关字段 ==========
/**
* 退款状态
*
* TODO 芋艿0 - 未退款1 - 部分退款; 2 - 全额退款
*/
private Integer refundStatus;
/**
* 退款次数
*/
private Integer refundTimes;
/**
* 退款总金额,单位:分
*/
private Long refundAmount;
// ========== 渠道相关字段 ==========
/**
* 渠道用户编号
*
* 例如说,微信 openid、支付宝账号
*/
private String channelUserId;
/**
* 渠道订单号
*/
private String channelOrderNo;
}

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 交易扩展表
*/
@TableName("pay_transaction_extension")
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class PayOrderExtensionDO extends BaseDO {
/**
* 编号,自增
*/
private Integer id;
/**
* 交易编号 {@link PayTransactionDO#getId()}
*/
private Integer transactionId;
/**
* 选择的支付渠道
*/
private Integer payChannel;
/**
* 生成传输给第三方的订单号
*
* 唯一索引
*/
private String transactionCode;
/**
* 扩展内容
*
* 异步通知的时候填充回调的数据
*/
private String extensionData;
/**
* 发起交易的 IP
*/
private String createIp;
/**
* 状态
*
* @see cn.iocoder.mall.payservice.enums.transaction.PayTransactionStatusEnum
* 注意,只包含上述枚举的 WAITING 和 SUCCESS
*/
private Integer status;
}

View File

@ -0,0 +1,138 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
import cn.iocoder.yudao.coreservice.modules.pay.enums.merchant.PayChannelCodeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import lombok.Data;
import java.util.Date;
/**
* 支付退款单 DO
* 一个支付订单,可以拥有多个支付退款单
*
* 即 PayOrderDO : PayRefundDO = 1 : n
*
* @author 芋道源码
*/
@Data
public class PayRefundDO extends BaseDO {
/**
* 退款单编号,数据库自增
*/
private Long id;
/**
* 退款单号,根据规则生成
*
* 例如说R202109181134287570000
*/
private String no;
/**
* 商户编号
*
* 关联 {@link PayMerchantDO#getId()}
*/
private Long merchantId;
/**
* 应用编号
*
* 关联 {@link PayAppDO#getId()}
*/
private Long appId;
/**
* 渠道编号
*
* 关联 {@link PayChannelDO#getId()}
*/
private Long channelId;
/**
* 商户编码
*
* 枚举 {@link PayChannelCodeEnum}
*/
private String channelCode;
/**
* 订单编号
*
* 关联 {@link PayOrderDO#getId()}
*/
private Long orderId;
// ========== 商户相关字段 ==========
/**
* 商户退款订单号
* 例如说,内部系统 A 的退款订单号。需要保证每个 PayMerchantDO 唯一 TODO 芋艿:需要在测试下
*/
private String merchantRefundNo;
/**
* 商户拓展参数
*/
private String merchantExtra;
// ========== 退款相关字段 ==========
/**
* 退款状态
*
* TODO 芋艿:状态枚举
*/
private Integer status;
/**
* 通知商户退款结果的回调状态
* TODO 芋艿0 未发送 1 已发送
*/
private Integer notifyStatus;
/**
* 客户端 IP
*/
private String clientIp;
/**
* 退款金额,单位:分
*/
private Long amount;
/**
* 退款原因
*/
private String reason;
/**
* 订单退款成功时间
*/
private Date successTime;
/**
* 退款失效时间
*/
private Date expireTime;
/**
* 支付渠道的额外参数
*
* 参见 https://www.pingxx.com/api/Refunds%20退款概述.html
*/
private String channelExtra;
/**
* 异步通知地址
*/
private String notifyUrl;
// TODO 芋艿:可能要优化
/**
* 渠道支付错误码
*/
private String errorCode;
/**
* 渠道支付错误消息
*/
private String errorMessage;
// ========== 渠道相关字段 ==========
/**
* 渠道订单号
*/
private String channelOrderNo;
/**
* 渠道退款号
*/
private String channelRefundNo;
}

View File

@ -0,0 +1 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject;

View File

@ -0,0 +1,9 @@
package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.merchant;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PayAppCoreMapper extends BaseMapperX<PayAppDO> {
}

View File

@ -0,0 +1,16 @@
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.framework.mybatis.core.mapper.BaseMapperX;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PayOrderCoreMapper extends BaseMapperX<PayOrderDO> {
default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) {
return selectOne(new QueryWrapper<PayOrderDO>().eq("app_id", appId)
.eq("merchant_order_id", merchantOrderId));
}
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.coreservice.modules.pay.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* Pay 错误码枚举类
*
* pay 系统,使用 1-007-000-000 段
*/
public interface PayErrorCodeConstants {
// ========== APP 模块 1-007-000-000 ==========
ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.coreservice.modules.pay.enums.merchant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付渠道的编码的枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum PayChannelCodeEnum {
wx_pub("wx_pub", "微信 JSAPI 支付");
/**
* 编码
*
* 参考 https://www.pingxx.com/api/支付渠道属性值.html
*/
private String code;
/**
* 名字
*/
private String name;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.coreservice.modules.pay.enums.order;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付订单的状态枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum PayOrderStatusEnum implements IntArrayValuable {
WAITING(0, "未支付"),
SUCCESS(10, "支付成功"),
CLOSED(20, "支付关闭"), // 未付款交易超时关闭,或支付完成后全额退款 TODO 芋艿:需要优化下
;
private final Integer status;
private final String name;
@Override
public int[] array() {
return new int[0];
}
}

View File

@ -0,0 +1,7 @@
/**
* pay 包下,我们放支付业务,提供业务的支付能力。
* 例如说:商户、应用、支付、退款等等
*
* 缩写pay
*/
package cn.iocoder.yudao.coreservice.modules.pay;

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.coreservice.modules.pay.service.merchant;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
/**
* 支付应用 Core Service 接口
*
* @author 芋道源码
*/
public interface PayAppCoreService {
/**
* 支付应用的合法性
*
* 如果不合法,抛出 {@link ServiceException} 业务异常
*
* @param id 应用编号
* @return 应用信息
*/
PayAppDO validPayApp(Long id);
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.coreservice.modules.pay.service.merchant.impl;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.merchant.PayAppCoreMapper;
import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* 支付应用 Core Service 实现类
*
* @author 芋道源码
*/
@Service
@Valid
@Slf4j
public class PayAppCoreServiceImpl implements PayAppCoreService {
@Resource
private PayAppCoreMapper payAppCoreMapper;
@Override
public PayAppDO validPayApp(Long id) {
PayAppDO app = payAppCoreMapper.selectById(id);
// 校验是否存在
if (app == null) {
throw exception(PAY_APP_NOT_FOUND);
}
// 校验是否禁用
if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) {
throw exception(PAY_APP_IS_DISABLE);
}
return app;
}
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.coreservice.modules.pay.service.order;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO;
import javax.validation.Valid;
/**
* 支付订单 Core Service
*
* @author 芋道源码
*/
public interface PayOrderCoreService {
/**
* 创建支付单
*
* @param reqDTO 创建请求
* @return 支付单编号
*/
Long createPayOrder(@Valid PayOrderCreateReqDTO reqDTO);
/**
* 提交支付
* 此时,会发起支付渠道的调用
*
* @param reqDTO 提交请求
* @return 提交结果
*/
PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO);
}

View File

@ -0,0 +1,64 @@
package cn.iocoder.yudao.coreservice.modules.pay.service.order.dto;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
/**
* 支付单创建 Request DTO
*/
@Data
public class PayOrderCreateReqDTO implements Serializable {
/**
* 应用编号
*/
@NotEmpty(message = "应用编号不能为空")
private Long appId;
/**
* 客户端 IP
*/
@NotEmpty(message = "客户端 IP 不能为空")
private String clientIp;
// ========== 商户相关字段 ==========
/**
* 商户订单编号
*/
@NotEmpty(message = "商户订单编号不能为空")
private String merchantOrderId;
/**
* 商品标题
*/
@NotEmpty(message = "商品标题不能为空")
@Length(max = 32, message = "商品标题不能超过 32")
private String subject;
/**
* 商品描述信息
*/
@NotEmpty(message = "商品描述信息不能为空")
@Length(max = 128, message = "商品描述信息长度不能超过128")
private String body;
// ========== 订单相关字段 ==========
/**
* 支付金额,单位:分
*/
@NotNull(message = "支付金额不能为空")
@DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零")
private Integer amount;
/**
* 支付过期时间
*/
@NotNull(message = "支付过期时间不能为空")
private Date expireTime;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.coreservice.modules.pay.service.order.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 支付单提交 Request DTO
*/
@Data
@Accessors(chain = true)
public class PayOrderSubmitReqDTO implements Serializable {
/**
* 应用编号
*/
@NotEmpty(message = "应用编号不能为空")
private String appId;
/**
* 支付单编号
*/
@NotNull(message = "支付单编号不能为空")
private Long id;
/**
* 支付渠道
*/
@NotNull(message = "支付渠道")
private String channelCode;
/**
* 客户端 IP
*/
@NotEmpty(message = "客户端 IP 不能为空")
private String clientIp;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.coreservice.modules.pay.service.order.dto;
import lombok.Data;
import java.io.Serializable;
/**
* 支付单提交 Response DTO
*/
@Data
public class PayOrderSubmitRespDTO implements Serializable {
/**
* 支付拓展单的编号
*/
private Long extensionId;
/**
* 调用支付渠道的响应结果
*/
private String invokeResponse;
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
import cn.iocoder.yudao.coreservice.modules.pay.convert.order.PayOrderCoreServiceConvert;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreService;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO;
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.Valid;
/**
* 支付订单 Core Service 实现类
*/
@Service
@Valid
@Slf4j
public class PayOrderCoreServiceImpl implements PayOrderCoreService {
@Resource
private PayAppCoreService payAppCoreService;
@Resource
private PayOrderCoreMapper payOrderCoreMapper;
@Override
public Long createPayOrder(PayOrderCreateReqDTO reqDTO) {
// 校验 App
PayAppDO app = payAppCoreService.validPayApp(reqDTO.getAppId());
// 查询对应的支付交易单是否已经存在。如果是,则直接返回
PayOrderDO order = payOrderCoreMapper.selectByAppIdAndMerchantOrderId(
reqDTO.getAppId(), reqDTO.getMerchantOrderId());
if (order != null) {
log.warn("[createPayOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(),
order.getMerchantOrderId(), JsonUtils.toJsonString(order)); // 理论来说,不会出现这个情况
return app.getId();
}
// 创建支付交易单
order = PayOrderCoreServiceConvert.INSTANCE.convert(reqDTO)
.setStatus(PayOrderStatusEnum.WAITING.getStatus())
.setNotifyUrl(app.getPayNotifyUrl());
payOrderCoreMapper.insert(order);
// 最终返回
return order.getId();
}
@Override
public PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO) {
// 校验 App
PayAppDO app = payAppCoreService.validPayApp(reqDTO.getId());
// TODO 校验支付渠道是否有效
// 获得 PayOrderDO ,并校验其是否存在
PayOrderDO order = payOrderCoreMapper.selectById(reqDTO.getId());
if (order == null) { // 是否存在
throw exception(PAY_TRANSACTION_NOT_FOUND);
}
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
throw exception(PAY_TRANSACTION_STATUS_IS_NOT_WAITING);
}
// 插入 PayTransactionExtensionDO
PayTransactionExtensionDO payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(submitReqDTO)
.setTransactionId(payTransaction.getId()).setTransactionCode(generateTransactionCode())
.setStatus(PayTransactionStatusEnum.WAITING.getStatus());
payTransactionExtensionMapper.insert(payTransactionExtensionDO);
// 调用三方接口
AbstractThirdPayClient thirdPayClient = ThirdPayClientFactory.getThirdPayClient(submitReqDTO.getPayChannel());
CommonResult<String> invokeResult = thirdPayClient.submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
invokeResult.checkError();
// TODO 轮询三方接口,是否已经支付的任务
// 返回成功
return new PayTransactionSubmitRespDTO().setId(payTransactionExtensionDO.getId()).setInvokeResponse(invokeResult.getData());
}
}

View File

@ -0,0 +1 @@
package cn.iocoder.yudao.coreservice.modules.pay.service;