mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 23:31:52 +08:00
完成支付单的单体轮廓
This commit is contained in:
parent
81126b2b4b
commit
24f4fd4fee
@ -1,15 +1,19 @@
|
||||
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.dal.dataobject.order.PayOrderExtensionDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderCreateReqDTO;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface PayOrderCoreServiceConvert {
|
||||
public interface PayOrderCoreConvert {
|
||||
|
||||
PayOrderCoreServiceConvert INSTANCE = Mappers.getMapper(PayOrderCoreServiceConvert.class);
|
||||
PayOrderCoreConvert INSTANCE = Mappers.getMapper(PayOrderCoreConvert.class);
|
||||
|
||||
PayOrderDO convert(PayOrderCreateReqDTO bean);
|
||||
|
||||
PayOrderExtensionDO convert(PayOrderSubmitReqDTO bean);
|
||||
|
||||
}
|
@ -28,12 +28,6 @@ public class PayOrderDO extends BaseDO {
|
||||
* 订单编号,数据库自增
|
||||
*/
|
||||
private Long id;
|
||||
// /**
|
||||
// * 订单号,根据规则生成
|
||||
// *
|
||||
// * 例如说,P202110132239124200055
|
||||
// */
|
||||
// private String no;
|
||||
/**
|
||||
* 商户编号
|
||||
*
|
||||
@ -53,7 +47,7 @@ public class PayOrderDO extends BaseDO {
|
||||
*/
|
||||
private Long channelId;
|
||||
/**
|
||||
* 商户编码
|
||||
* 渠道编码
|
||||
*
|
||||
* 枚举 {@link PayChannelCodeEnum}
|
||||
*/
|
||||
@ -132,6 +126,12 @@ public class PayOrderDO extends BaseDO {
|
||||
* 页面跳转地址
|
||||
*/
|
||||
private String returnUrl;
|
||||
/**
|
||||
* 支付成功的订单拓展单编号
|
||||
*
|
||||
* 关联 {@link PayOrderDO#getId()}
|
||||
*/
|
||||
private Long successExtensionId;
|
||||
|
||||
// TODO 芋艿:可能要优化
|
||||
/**
|
||||
|
@ -1,5 +1,7 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
|
||||
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;
|
||||
@ -7,48 +9,62 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 交易扩展表
|
||||
* 支付订单拓展 DO
|
||||
*
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("pay_transaction_extension")
|
||||
@TableName("pay_order_extension")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class PayOrderExtensionDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号,自增
|
||||
* 订单拓展编号,数据库自增
|
||||
*/
|
||||
private Integer id;
|
||||
private Long id;
|
||||
/**
|
||||
* 交易编号 {@link PayTransactionDO#getId()}
|
||||
*/
|
||||
private Integer transactionId;
|
||||
/**
|
||||
* 选择的支付渠道
|
||||
*/
|
||||
private Integer payChannel;
|
||||
/**
|
||||
* 生成传输给第三方的订单号
|
||||
* 订单号,根据规则生成
|
||||
* 调用支付渠道时,使用该字段作为对接的订单号。
|
||||
* 1. 调用微信支付 https://api.mch.weixin.qq.com/pay/unifiedorder 时,使用该字段作为 out_trade_no
|
||||
* 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no
|
||||
*
|
||||
* 唯一索引
|
||||
* 例如说,P202110132239124200055
|
||||
*/
|
||||
private String transactionCode;
|
||||
private String no;
|
||||
/**
|
||||
* 扩展内容
|
||||
* 订单号
|
||||
*
|
||||
* 异步通知的时候填充回调的数据
|
||||
* 关联 {@link PayOrderDO#getId()}
|
||||
*/
|
||||
private String extensionData;
|
||||
private Long orderId;
|
||||
/**
|
||||
* 发起交易的 IP
|
||||
*/
|
||||
private String createIp;
|
||||
/**
|
||||
* 状态
|
||||
* 渠道编号
|
||||
*
|
||||
* @see cn.iocoder.mall.payservice.enums.transaction.PayTransactionStatusEnum
|
||||
* 关联 {@link PayChannelDO#getId()}
|
||||
*/
|
||||
private Long channelId;
|
||||
/**
|
||||
* 渠道编码
|
||||
*/
|
||||
private Integer channelCode;
|
||||
/**
|
||||
* 客户端 IP
|
||||
*/
|
||||
private String clientIp;
|
||||
/**
|
||||
* 支付状态
|
||||
*
|
||||
* 枚举 {@link PayOrderStatusEnum}
|
||||
* 注意,只包含上述枚举的 WAITING 和 SUCCESS
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 支付渠道异步通知的内容
|
||||
*
|
||||
* 在支持成功后,会记录回调的数据
|
||||
*/
|
||||
private String channelCallbackData;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.merchant;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface PayChannelCoreMapper extends BaseMapperX<PayChannelDO> {
|
||||
|
||||
default PayChannelDO selectByAppIdAndCode(Long appId, String code) {
|
||||
return selectOne("app_id", appId, "code", code);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
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;
|
||||
|
||||
@Mapper
|
||||
public interface PayOrderExtensionCoreMapper extends BaseMapperX<PayOrderExtensionDO> {
|
||||
|
||||
}
|
@ -13,4 +13,18 @@ public interface PayErrorCodeConstants {
|
||||
ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
|
||||
ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
|
||||
|
||||
// ========== CHANNEL 模块 1-007-001-000 ==========
|
||||
ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
|
||||
ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001000, "支付渠道已经禁用");
|
||||
|
||||
// ========== 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, "支付订单不处于已支付");
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.pay.service.merchant;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
|
||||
/**
|
||||
* 支付渠道 Core Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface PayChannelCoreService {
|
||||
|
||||
/**
|
||||
* 支付渠道的合法性
|
||||
*
|
||||
* 如果不合法,抛出 {@link ServiceException} 业务异常
|
||||
*
|
||||
* @param appId 应用编号
|
||||
* @param code 支付渠道
|
||||
* @return 渠道信息
|
||||
*/
|
||||
PayChannelDO validPayChannel(Long appId, String code);
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.pay.service.merchant.impl;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.merchant.PayChannelCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService;
|
||||
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 PayChannelCoreServiceImpl implements PayChannelCoreService {
|
||||
|
||||
@Resource
|
||||
private PayChannelCoreMapper payChannelCoreMapper;
|
||||
|
||||
@Override
|
||||
public PayChannelDO validPayChannel(Long appId, String code) {
|
||||
PayChannelDO channel = payChannelCoreMapper.selectByAppIdAndCode(appId, code);
|
||||
if (channel == null) {
|
||||
throw exception(PAY_CHANNEL_NOT_FOUND);
|
||||
}
|
||||
if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) {
|
||||
throw exception(PayErrorCodeConstants.PAY_CHANNEL_IS_DISABLE);
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
}
|
@ -17,8 +17,8 @@ public class PayOrderSubmitReqDTO implements Serializable {
|
||||
/**
|
||||
* 应用编号
|
||||
*/
|
||||
@NotEmpty(message = "应用编号不能为空")
|
||||
private String appId;
|
||||
@NotNull(message = "应用编号不能为空")
|
||||
private Long appId;
|
||||
|
||||
/**
|
||||
* 支付单编号
|
||||
|
@ -1,11 +1,17 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.convert.order.PayOrderCoreServiceConvert;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.convert.order.PayOrderCoreConvert;
|
||||
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.order.PayOrderDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderExtensionCoreMapper;
|
||||
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.merchant.PayChannelCoreService;
|
||||
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;
|
||||
@ -17,9 +23,16 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants.PAY_ORDER_NOT_FOUND;
|
||||
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 支付订单 Core Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Valid
|
||||
@ -28,9 +41,13 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
|
||||
|
||||
@Resource
|
||||
private PayAppCoreService payAppCoreService;
|
||||
@Resource
|
||||
private PayChannelCoreService payChannelCoreService;
|
||||
|
||||
@Resource
|
||||
private PayOrderCoreMapper payOrderCoreMapper;
|
||||
@Resource
|
||||
private PayOrderExtensionCoreMapper payOrderExtensionCoreMapper;
|
||||
|
||||
@Override
|
||||
public Long createPayOrder(PayOrderCreateReqDTO reqDTO) {
|
||||
@ -47,7 +64,8 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
|
||||
}
|
||||
|
||||
// 创建支付交易单
|
||||
order = PayOrderCoreServiceConvert.INSTANCE.convert(reqDTO)
|
||||
// TODO 芋艿:需要看看,还有啥要补全的字段
|
||||
order = PayOrderCoreConvert.INSTANCE.convert(reqDTO)
|
||||
.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||
.setNotifyUrl(app.getPayNotifyUrl());
|
||||
payOrderCoreMapper.insert(order);
|
||||
@ -59,31 +77,50 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService {
|
||||
public PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO) {
|
||||
// 校验 App
|
||||
PayAppDO app = payAppCoreService.validPayApp(reqDTO.getId());
|
||||
// TODO 校验支付渠道是否有效
|
||||
// 校验支付渠道是否有效
|
||||
PayChannelDO channel = payChannelCoreService.validPayChannel(reqDTO.getId(), reqDTO.getChannelCode());
|
||||
|
||||
// 获得 PayOrderDO ,并校验其是否存在
|
||||
PayOrderDO order = payOrderCoreMapper.selectById(reqDTO.getId());
|
||||
if (order == null) { // 是否存在
|
||||
throw exception(PAY_TRANSACTION_NOT_FOUND);
|
||||
if (order == null || order.getAppId().equals(reqDTO.getAppId())) { // 是否存在
|
||||
throw exception(PAY_ORDER_NOT_FOUND);
|
||||
}
|
||||
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
|
||||
throw exception(PAY_TRANSACTION_STATUS_IS_NOT_WAITING);
|
||||
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
|
||||
// 插入 PayTransactionExtensionDO
|
||||
PayTransactionExtensionDO payTransactionExtensionDO = PayTransactionConvert.INSTANCE.convert(submitReqDTO)
|
||||
.setTransactionId(payTransaction.getId()).setTransactionCode(generateTransactionCode())
|
||||
.setStatus(PayTransactionStatusEnum.WAITING.getStatus());
|
||||
payTransactionExtensionMapper.insert(payTransactionExtensionDO);
|
||||
// 插入 PayOrderExtensionDO
|
||||
PayOrderExtensionDO orderExtension = PayOrderCoreConvert.INSTANCE.convert(reqDTO)
|
||||
.setOrderId(order.getId()).setNo(generateOrderExtensionNo())
|
||||
.setStatus(PayOrderStatusEnum.WAITING.getStatus());
|
||||
payOrderExtensionCoreMapper.insert(orderExtension);
|
||||
|
||||
// 调用三方接口
|
||||
AbstractThirdPayClient thirdPayClient = ThirdPayClientFactory.getThirdPayClient(submitReqDTO.getPayChannel());
|
||||
CommonResult<String> invokeResult = thirdPayClient.submitTransaction(payTransaction, payTransactionExtensionDO, null); // TODO 暂时传入 extra = null
|
||||
CommonResult<String> invokeResult = thirdPayClient.submitTransaction(payTransaction, orderExtension, null); // TODO 暂时传入 extra = null
|
||||
invokeResult.checkError();
|
||||
|
||||
// TODO 轮询三方接口,是否已经支付的任务
|
||||
// 返回成功
|
||||
return new PayTransactionSubmitRespDTO().setId(payTransactionExtensionDO.getId()).setInvokeResponse(invokeResult.getData());
|
||||
return new PayOrderSubmitRespDTO().setExtensionId(orderExtension.getId()).setInvokeResponse(invokeResult.getData());
|
||||
}
|
||||
|
||||
private String generateOrderExtensionNo() {
|
||||
// wx
|
||||
// 2014
|
||||
// 10
|
||||
// 27
|
||||
// 20
|
||||
// 09
|
||||
// 39
|
||||
// 5522657
|
||||
// a690389285100
|
||||
// 目前的算法
|
||||
// 时间序列,年月日时分秒 14 位
|
||||
// 纯随机,6 位 TODO 芋艿:此处估计是会有问题的,后续在调整
|
||||
return DateUtil.format(new Date(), "yyyyMMddHHmmss") + // 时间序列
|
||||
RandomUtil.randomInt(100000, 999999) // 随机。为什么是这个范围,因为偷懒
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
|
||||
return selectOne(new QueryWrapper<T>().eq(field, value));
|
||||
}
|
||||
|
||||
default T selectOne(String field1, Object value1, String field2, Object value2) {
|
||||
return selectOne(new QueryWrapper<T>().eq(field1, value1).eq(field2, value2));
|
||||
}
|
||||
|
||||
default Integer selectCount(String field, Object value) {
|
||||
return selectCount(new QueryWrapper<T>().eq(field, value));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user