by gateway:

1. 补全 channel 单元测试
2. 完善部分 order 单元测试
This commit is contained in:
zhijiantianya@gmail.com 2023-07-18 20:21:25 +08:00
parent 1c282bd3cb
commit 3f410c2735
16 changed files with 493 additions and 230 deletions

View File

@ -55,6 +55,9 @@ public class RandomUtils {
} }
return RandomUtil.randomInt(); return RandomUtil.randomInt();
}); });
// LocalDateTime
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(LocalDateTime.class,
(dataProviderStrategy, attributeMetadata, map) -> randomLocalDateTime());
// Boolean // Boolean
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> {
// 如果是 deleted 的字段返回非删除 // 如果是 deleted 的字段返回非删除
@ -82,7 +85,8 @@ public class RandomUtils {
} }
public static LocalDateTime randomLocalDateTime() { public static LocalDateTime randomLocalDateTime() {
return LocalDateTimeUtil.of(randomDate()); // 设置 Nano 为零的原因避免 MySQLH2 存储不到时间戳
return LocalDateTimeUtil.of(randomDate()).withNano(0);
} }
public static Short randomShort() { public static Short randomShort() {

View File

@ -57,7 +57,7 @@ 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.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
/** /**
@ -308,7 +308,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
if (payOrder == null) { if (payOrder == null) {
log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); log.error("[validateOrderPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
throw exception(PAY_ORDER_NOT_FOUND); throw exception(cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND);
} }
// 校验支付单已支付 // 校验支付单已支付
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {

View File

@ -10,48 +10,46 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
public interface ErrorCodeConstants { public interface ErrorCodeConstants {
// ========== APP 模块 1007000000 ========== // ========== APP 模块 1007000000 ==========
ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在"); ErrorCode APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用"); ErrorCode APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
ErrorCode PAY_APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在支付订单,无法删除"); ErrorCode APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");
ErrorCode PAY_APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1007000004, "支付应用存在退款订单,无法删除"); ErrorCode APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1007000004, "支付应用存在退款订单,无法删除");
// ========== CHANNEL 模块 1007001000 ========== // ========== CHANNEL 模块 1007001000 ==========
ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在"); ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用"); ErrorCode CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");
ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在"); ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001004, "已存在相同的渠道");
ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在");
ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道");
// ========== ORDER 模块 1007002000 ========== // ========== ORDER 模块 1007002000 ==========
ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在"); ErrorCode ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付"); ErrorCode ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付"); ErrorCode ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
ErrorCode PAY_ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期"); ErrorCode ORDER_IS_EXPIRED = new ErrorCode(1007002003, "支付订单已经过期");
ErrorCode PAY_ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}"); ErrorCode ORDER_SUBMIT_CHANNEL_ERROR = new ErrorCode(1007002004, "发起支付报错,错误码:{},错误提示:{}");
// ========== ORDER 模块(拓展单) 1007003000 ========== // ========== ORDER 模块(拓展单) 1007003000 ==========
ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在"); ErrorCode ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付"); ErrorCode ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
// ========== 支付模块(退款) 1007006000 ========== // ========== 支付模块(退款) 1007006000 ==========
ErrorCode PAY_REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额"); ErrorCode REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款"); ErrorCode REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
ErrorCode PAY_REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中"); ErrorCode REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");
ErrorCode PAY_REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单"); ErrorCode REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");
ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在"); ErrorCode REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
ErrorCode PAY_REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款"); ErrorCode REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款");
// ========== 示例订单 1007900000 ========== // ========== 示例订单 1007900000 ==========
ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在"); ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态"); ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配"); ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(1007900002, "示例订单更新支付状态失败,支付单编号不匹配");
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态"); ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007900003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配"); ErrorCode DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1007900004, "示例订单更新支付状态失败,支付单金额不匹配");
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付"); ErrorCode DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900005, "发起退款失败,示例订单未支付");
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款"); ErrorCode DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(1007900006, "发起退款失败,示例订单已退款");
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在"); ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900007, "发起退款失败,退款订单不存在");
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功"); ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(1007900008, "发起退款失败,退款订单未退款成功");
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配"); ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900009, "发起退款失败,退款单编号不匹配");
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配"); ErrorCode DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900010, "发起退款失败,退款单金额不匹配");
} }

View File

@ -17,8 +17,7 @@ import javax.annotation.Resource;
import javax.annotation.security.PermitAll; import javax.annotation.security.PermitAll;
import java.util.Map; import java.util.Map;
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.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
@Tag(name = "管理后台 - 支付通知") @Tag(name = "管理后台 - 支付通知")
@RestController @RestController
@ -47,7 +46,7 @@ public class PayNotifyController {
PayClient payClient = payClientFactory.getPayClient(channelId); PayClient payClient = payClientFactory.getPayClient(channelId);
if (payClient == null) { if (payClient == null) {
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); throw exception(CHANNEL_NOT_FOUND);
} }
// 2. 解析通知数据 // 2. 解析通知数据
@ -68,7 +67,7 @@ public class PayNotifyController {
PayClient payClient = payClientFactory.getPayClient(channelId); PayClient payClient = payClientFactory.getPayClient(channelId);
if (payClient == null) { if (payClient == null) {
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); throw exception(CHANNEL_NOT_FOUND);
} }
// 2. 解析通知数据 // 2. 解析通知数据

View File

@ -15,6 +15,7 @@ import java.util.Map;
/** /**
* 支付订单拓展 DO * 支付订单拓展 DO
* *
* 每次调用支付渠道都会生成一条对应记录
* *
* @author 芋道源码 * @author 芋道源码
*/ */

View File

@ -44,12 +44,6 @@ public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
.orderByDesc("id")); .orderByDesc("id"));
} }
default List<PayOrderDO> findByIdListQueryOrderSubject(Collection<Long> idList) {
return selectList(new LambdaQueryWrapper<PayOrderDO>()
.select(PayOrderDO::getId, PayOrderDO::getSubject)
.in(PayOrderDO::getId, idList));
}
default Long selectCountByAppId(Long appId) { default Long selectCountByAppId(Long appId) {
return selectCount(PayOrderDO::getAppId, appId); return selectCount(PayOrderDO::getAppId, appId);
} }

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.pay.service.app; package cn.iocoder.yudao.module.pay.service.app;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
@ -9,10 +8,7 @@ import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert; import cn.iocoder.yudao.module.pay.convert.app.PayAppConvert;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper; import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper;
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
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 org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -77,10 +73,10 @@ public class PayAppServiceImpl implements PayAppService {
validateAppExists(id); validateAppExists(id);
// 校验关联数据是否存在 // 校验关联数据是否存在
if (orderService.getOrderCountByAppId(id) > 0) { if (orderService.getOrderCountByAppId(id) > 0) {
throw exception(PAY_APP_EXIST_ORDER_CANT_DELETE); throw exception(APP_EXIST_ORDER_CANT_DELETE);
} }
if (refundService.getRefundCountByAppId(id) > 0) { if (refundService.getRefundCountByAppId(id) > 0) {
throw exception(PAY_APP_EXIST_REFUND_CANT_DELETE); throw exception(APP_EXIST_REFUND_CANT_DELETE);
} }
// 删除 // 删除
@ -89,7 +85,7 @@ public class PayAppServiceImpl implements PayAppService {
private void validateAppExists(Long id) { private void validateAppExists(Long id) {
if (appMapper.selectById(id) == null) { if (appMapper.selectById(id) == null) {
throw exception(PAY_APP_NOT_FOUND); throw exception(APP_NOT_FOUND);
} }
} }
@ -113,11 +109,11 @@ public class PayAppServiceImpl implements PayAppService {
PayAppDO app = appMapper.selectById(id); PayAppDO app = appMapper.selectById(id);
// 校验是否存在 // 校验是否存在
if (app == null) { if (app == null) {
throw exception(ErrorCodeConstants.PAY_APP_NOT_FOUND); throw exception(ErrorCodeConstants.APP_NOT_FOUND);
} }
// 校验是否禁用 // 校验是否禁用
if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) { if (CommonStatusEnum.DISABLE.getStatus().equals(app.getStatus())) {
throw exception(ErrorCodeConstants.PAY_APP_IS_DISABLE); throw exception(ErrorCodeConstants.APP_IS_DISABLE);
} }
return app; return app;
} }

View File

@ -32,8 +32,7 @@ import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
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.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS;
/** /**
* 支付渠道 Service 实现类 * 支付渠道 Service 实现类
@ -142,7 +141,7 @@ public class PayChannelServiceImpl implements PayChannelService {
// 解析配置 // 解析配置
Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass(); Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(code).getConfigClass();
if (ObjectUtil.isNull(payClass)) { if (ObjectUtil.isNull(payClass)) {
throw exception(CHANNEL_NOT_EXISTS); throw exception(CHANNEL_NOT_FOUND);
} }
PayClientConfig config = JsonUtils.parseObject2(configStr, payClass); PayClientConfig config = JsonUtils.parseObject2(configStr, payClass);
Assert.notNull(config); Assert.notNull(config);
@ -167,7 +166,7 @@ public class PayChannelServiceImpl implements PayChannelService {
private PayChannelDO validateChannelExists(Long id) { private PayChannelDO validateChannelExists(Long id) {
PayChannelDO channel = channelMapper.selectById(id); PayChannelDO channel = channelMapper.selectById(id);
if (channel == null) { if (channel == null) {
throw exception(CHANNEL_NOT_EXISTS); throw exception(CHANNEL_NOT_FOUND);
} }
return channel; return channel;
} }
@ -203,10 +202,10 @@ public class PayChannelServiceImpl implements PayChannelService {
private void validPayChannel(PayChannelDO channel) { private void validPayChannel(PayChannelDO channel) {
if (channel == null) { if (channel == null) {
throw exception(ErrorCodeConstants.PAY_CHANNEL_NOT_FOUND); throw exception(CHANNEL_NOT_FOUND);
} }
if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) { if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) {
throw exception(ErrorCodeConstants.PAY_CHANNEL_IS_DISABLE); throw exception(CHANNEL_IS_DISABLE);
} }
} }

View File

@ -119,7 +119,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now()) new PayDemoOrderDO().setPayStatus(true).setPayTime(LocalDateTime.now())
.setPayChannelCode(payOrder.getChannelCode())); .setPayChannelCode(payOrder.getChannelCode()));
if (updateCount == 0) { if (updateCount == 0) {
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
} }
} }
@ -137,44 +137,44 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
// 1.1 校验订单是否存在 // 1.1 校验订单是否存在
PayDemoOrderDO order = payDemoOrderMapper.selectById(id); PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
if (order == null) { if (order == null) {
throw exception(PAY_DEMO_ORDER_NOT_FOUND); throw exception(DEMO_ORDER_NOT_FOUND);
} }
// 1.2 校验订单未支付 // 1.2 校验订单未支付
if (order.getPayStatus()) { if (order.getPayStatus()) {
log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态请进行处理order 数据是:{}]", log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态请进行处理order 数据是:{}]",
id, toJsonString(order)); id, toJsonString(order));
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); throw exception(DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
} }
// 1.3 校验支付订单匹配 // 1.3 校验支付订单匹配
if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号 if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({})请进行处理order 数据是:{}]", log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({})请进行处理order 数据是:{}]",
id, payOrderId, toJsonString(order)); id, payOrderId, toJsonString(order));
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
} }
// 2.1 校验支付单是否存在 // 2.1 校验支付单是否存在
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId); PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
if (payOrder == null) { if (payOrder == null) {
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId); log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
throw exception(PAY_ORDER_NOT_FOUND); throw exception(ORDER_NOT_FOUND);
} }
// 2.2 校验支付单已支付 // 2.2 校验支付单已支付
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) { if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付请进行处理payOrder 数据是:{}]", log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付请进行处理payOrder 数据是:{}]",
id, payOrderId, toJsonString(payOrder)); id, payOrderId, toJsonString(payOrder));
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS); throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
} }
// 2.3 校验支付金额一致 // 2.3 校验支付金额一致
if (notEqual(payOrder.getPrice(), order.getPrice())) { if (notEqual(payOrder.getPrice(), order.getPrice())) {
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配请进行处理order 数据是:{}payOrder 数据是:{}]", log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配请进行处理order 数据是:{}payOrder 数据是:{}]",
id, payOrderId, toJsonString(order), toJsonString(payOrder)); id, payOrderId, toJsonString(order), toJsonString(payOrder));
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH); throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
} }
// 2.4 校验支付订单匹配二次 // 2.4 校验支付订单匹配二次
if (notEqual(payOrder.getMerchantOrderId(), id.toString())) { if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({})请进行处理payOrder 数据是:{}]", log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({})请进行处理payOrder 数据是:{}]",
id, payOrderId, toJsonString(payOrder)); id, payOrderId, toJsonString(payOrder));
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR); throw exception(DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
} }
return payOrder; return payOrder;
} }
@ -203,15 +203,15 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
// 校验订单是否存在 // 校验订单是否存在
PayDemoOrderDO order = payDemoOrderMapper.selectById(id); PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
if (order == null) { if (order == null) {
throw exception(PAY_DEMO_ORDER_NOT_FOUND); throw exception(DEMO_ORDER_NOT_FOUND);
} }
// 校验订单是否支付 // 校验订单是否支付
if (!order.getPayStatus()) { if (!order.getPayStatus()) {
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID); throw exception(DEMO_ORDER_REFUND_FAIL_NOT_PAID);
} }
// 校验订单是否已退款 // 校验订单是否已退款
if (order.getPayRefundId() != null) { if (order.getPayRefundId() != null) {
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED); throw exception(DEMO_ORDER_REFUND_FAIL_REFUNDED);
} }
return order; return order;
} }
@ -229,35 +229,35 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
// 1.1 校验示例订单 // 1.1 校验示例订单
PayDemoOrderDO order = payDemoOrderMapper.selectById(id); PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
if (order == null) { if (order == null) {
throw exception(PAY_DEMO_ORDER_NOT_FOUND); throw exception(DEMO_ORDER_NOT_FOUND);
} }
// 1.2 校验退款订单匹配 // 1.2 校验退款订单匹配
if (Objects.equals(order.getPayOrderId(), payRefundId)) { if (Objects.equals(order.getPayOrderId(), payRefundId)) {
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({})请进行处理order 数据是:{}]", log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({})请进行处理order 数据是:{}]",
id, payRefundId, toJsonString(order)); id, payRefundId, toJsonString(order));
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
} }
// 2.1 校验退款订单 // 2.1 校验退款订单
PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId); PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
if (payRefund == null) { if (payRefund == null) {
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND); throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
} }
// 2.2 // 2.2
if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) { if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS); throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
} }
// 2.3 校验退款金额一致 // 2.3 校验退款金额一致
if (notEqual(payRefund.getRefundPrice(), order.getPrice())) { if (notEqual(payRefund.getRefundPrice(), order.getPrice())) {
log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配请进行处理order 数据是:{}payRefund 数据是:{}]", log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配请进行处理order 数据是:{}payRefund 数据是:{}]",
id, payRefundId, toJsonString(order), toJsonString(payRefund)); id, payRefundId, toJsonString(order), toJsonString(payRefund));
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH); throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
} }
// 2.4 校验退款订单匹配二次 // 2.4 校验退款订单匹配二次
if (notEqual(payRefund.getMerchantOrderId(), id.toString())) { if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({})请进行处理payRefund 数据是:{}]", log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({})请进行处理payRefund 数据是:{}]",
id, payRefundId, toJsonString(payRefund)); id, payRefundId, toJsonString(payRefund));
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR); throw exception(DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
} }
return payRefund; return payRefund;
} }

View File

@ -49,41 +49,37 @@ public interface PayOrderService {
Long getOrderCountByAppId(Long appId); Long getOrderCountByAppId(Long appId);
/** /**
* 获得支付订单 * 获得支付订单分页
* 分页
* *
* @param pageReqVO 分页查询 * @param pageReqVO 分页查询
* @return 支付订单 * @return 支付订单分页
* 分页
*/ */
PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO); PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO);
/** /**
* 获得支付订单 * 获得支付订单列表, 用于 Excel 导出
* 列表, 用于 Excel 导出
* *
* @param exportReqVO 查询条件 * @param exportReqVO 查询条件
* @return 支付订单 * @return 支付订单列表
* 列表
*/ */
List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO); List<PayOrderDO> getOrderList(PayOrderExportReqVO exportReqVO);
/** /**
* 根据 ID 集合获取只包含商品名称的订单集合 * 获得支付订单列表
*
* @param idList 订单 ID 集合
* @return 只包含商品名称的订单集合
*/
List<PayOrderDO> getOrderSubjectList(Collection<Long> idList);
/**
* 根据订单 ID 集合获取订单商品名称Map集合
* *
* @param ids 订单 ID 集合 * @param ids 订单 ID 集合
* @return 订单商品 map 集合 * @return 支付订单列表
*/
List<PayOrderDO> getOrderList(Collection<Long> ids);
/**
* 获得支付订单 Map
*
* @param ids 订单 ID 集合
* @return 支付订单 Map 集合
*/ */
default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> ids) { default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> ids) {
List<PayOrderDO> list = getOrderSubjectList(ids); List<PayOrderDO> list = getOrderList(ids);
return CollectionUtils.convertMap(list, PayOrderDO::getId); return CollectionUtils.convertMap(list, PayOrderDO::getId);
} }

View File

@ -102,10 +102,9 @@ public class PayOrderServiceImpl implements PayOrderService {
return orderMapper.selectList(exportReqVO); return orderMapper.selectList(exportReqVO);
} }
// TODO @艿艿需要优化不确定这个方法的作用
@Override @Override
public List<PayOrderDO> getOrderSubjectList(Collection<Long> idList) { public List<PayOrderDO> getOrderList(Collection<Long> ids) {
return orderMapper.findByIdListQueryOrderSubject(idList); return orderMapper.selectBatchIds(ids);
} }
@Override @Override
@ -165,7 +164,7 @@ public class PayOrderServiceImpl implements PayOrderService {
notifyPayOrder(channel, unifiedOrderResp); notifyPayOrder(channel, unifiedOrderResp);
// 如有渠道错误码则抛出业务异常提示用户 // 如有渠道错误码则抛出业务异常提示用户
if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) { if (StrUtil.isNotEmpty(unifiedOrderResp.getChannelErrorCode())) {
throw exception(PAY_ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(), throw exception(ORDER_SUBMIT_CHANNEL_ERROR, unifiedOrderResp.getChannelErrorCode(),
unifiedOrderResp.getChannelErrorMsg()); unifiedOrderResp.getChannelErrorMsg());
} }
// 此处需要读取最新的状态 // 此处需要读取最新的状态
@ -177,13 +176,13 @@ public class PayOrderServiceImpl implements PayOrderService {
private PayOrderDO validateOrderCanSubmit(Long id) { private PayOrderDO validateOrderCanSubmit(Long id) {
PayOrderDO order = orderMapper.selectById(id); PayOrderDO order = orderMapper.selectById(id);
if (order == null) { // 是否存在 if (order == null) { // 是否存在
throw exception(PAY_ORDER_NOT_FOUND); throw exception(ORDER_NOT_FOUND);
} }
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态必须是待支付 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态必须是待支付
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); throw exception(ORDER_STATUS_IS_NOT_WAITING);
} }
if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期 if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
throw exception(PAY_ORDER_IS_EXPIRED); throw exception(ORDER_IS_EXPIRED);
} }
return order; return order;
} }
@ -196,7 +195,7 @@ public class PayOrderServiceImpl implements PayOrderService {
PayClient client = payClientFactory.getPayClient(channel.getId()); PayClient client = payClientFactory.getPayClient(channel.getId());
if (client == null) { if (client == null) {
log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); throw exception(CHANNEL_NOT_FOUND);
} }
return channel; return channel;
} }
@ -238,33 +237,6 @@ public class PayOrderServiceImpl implements PayOrderService {
TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify)); TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify));
} }
@Override
public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
PayOrderDO order = orderMapper.selectById(id);
if (order == null) {
throw exception(PAY_ORDER_NOT_FOUND);
}
if (!PayOrderStatusEnum.isSuccess(order.getStatus())) {
throw exception(PAY_REFUND_PRICE_EXCEED);
}
if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
throw exception(PAY_REFUND_PRICE_EXCEED);
}
// 更新订单
PayOrderDO updateObj = new PayOrderDO()
.setRefundPrice(order.getRefundPrice() + incrRefundPrice)
.setRefundTimes(order.getRefundTimes() + 1);
if (Objects.equals(updateObj.getRefundPrice(), order.getPrice())) {
updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus());
} else {
updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
.setRefundStatus(PayOrderRefundStatusEnum.PART.getStatus());
}
orderMapper.updateByIdAndStatus(id, PayOrderStatusEnum.SUCCESS.getStatus(), updateObj);
}
private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) { private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
// 情况一支付成功的回调 // 情况一支付成功的回调
if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) { if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
@ -301,21 +273,21 @@ public class PayOrderServiceImpl implements PayOrderService {
// 1. 查询 PayOrderExtensionDO // 1. 查询 PayOrderExtensionDO
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
if (orderExtension == null) { if (orderExtension == null) {
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); throw exception(ORDER_EXTENSION_NOT_FOUND);
} }
if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功直接返回不用重复更新 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功直接返回不用重复更新
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId()); log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新]", orderExtension.getId());
return orderExtension; return orderExtension;
} }
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态必须是待支付 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态必须是待支付
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
} }
// 2. 更新 PayOrderExtensionDO // 2. 更新 PayOrderExtensionDO
int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(), int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build()); PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
if (updateCounts == 0) { // 校验状态必须是待支付 if (updateCounts == 0) { // 校验状态必须是待支付
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
} }
log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId()); log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
return orderExtension; return orderExtension;
@ -335,7 +307,7 @@ public class PayOrderServiceImpl implements PayOrderService {
// 1. 判断 PayOrderDO 是否处于待支付 // 1. 判断 PayOrderDO 是否处于待支付
PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId()); PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
if (order == null) { if (order == null) {
throw exception(PAY_ORDER_NOT_FOUND); throw exception(ORDER_NOT_FOUND);
} }
if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功直接返回不用重复更新 if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功直接返回不用重复更新
&& Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) { && Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) {
@ -343,7 +315,7 @@ public class PayOrderServiceImpl implements PayOrderService {
return Pair.of(true, order); return Pair.of(true, order);
} }
if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态必须是待支付 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态必须是待支付
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); throw exception(ORDER_STATUS_IS_NOT_WAITING);
} }
// 2. 更新 PayOrderDO // 2. 更新 PayOrderDO
@ -354,7 +326,7 @@ public class PayOrderServiceImpl implements PayOrderService {
.channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId()) .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
.notifyTime(LocalDateTime.now()).build()); .notifyTime(LocalDateTime.now()).build());
if (updateCounts == 0) { // 校验状态必须是待支付 if (updateCounts == 0) { // 校验状态必须是待支付
throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING); throw exception(ORDER_STATUS_IS_NOT_WAITING);
} }
log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId()); log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId());
return Pair.of(false, order); return Pair.of(false, order);
@ -368,7 +340,7 @@ public class PayOrderServiceImpl implements PayOrderService {
// 1. 查询 PayOrderExtensionDO // 1. 查询 PayOrderExtensionDO
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo()); PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
if (orderExtension == null) { if (orderExtension == null) {
throw exception(PAY_ORDER_EXTENSION_NOT_FOUND); throw exception(ORDER_EXTENSION_NOT_FOUND);
} }
if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭直接返回不用重复更新 if (PayOrderStatusEnum.isClosed(orderExtension.getStatus())) { // 如果已经是关闭直接返回不用重复更新
log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId()); log.info("[updateOrderExtensionClosed][支付拓展单({}) 已经是支付关闭,无需更新]", orderExtension.getId());
@ -380,7 +352,7 @@ public class PayOrderServiceImpl implements PayOrderService {
return; return;
} }
if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态必须是待支付 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态必须是待支付
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
} }
// 2. 更新 PayOrderExtensionDO // 2. 更新 PayOrderExtensionDO
@ -388,9 +360,36 @@ public class PayOrderServiceImpl implements PayOrderService {
PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify)) PayOrderExtensionDO.builder().status(PayOrderStatusEnum.CLOSED.getStatus()).channelNotifyData(toJsonString(notify))
.channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build()); .channelErrorCode(notify.getChannelErrorCode()).channelErrorMsg(notify.getChannelErrorMsg()).build());
if (updateCounts == 0) { // 校验状态必须是待支付 if (updateCounts == 0) { // 校验状态必须是待支付
throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); throw exception(ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
} }
log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId()); log.info("[updateOrderExtensionClosed][支付拓展单({}) 更新为支付关闭]", orderExtension.getId());
} }
@Override
public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
PayOrderDO order = orderMapper.selectById(id);
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
if (!PayOrderStatusEnum.isSuccess(order.getStatus())) {
throw exception(REFUND_PRICE_EXCEED);
}
if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
throw exception(REFUND_PRICE_EXCEED);
}
// 更新订单
PayOrderDO updateObj = new PayOrderDO()
.setRefundPrice(order.getRefundPrice() + incrRefundPrice)
.setRefundTimes(order.getRefundTimes() + 1);
if (Objects.equals(updateObj.getRefundPrice(), order.getPrice())) {
updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus());
} else {
updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
.setRefundStatus(PayOrderRefundStatusEnum.PART.getStatus());
}
orderMapper.updateByIdAndStatus(id, PayOrderStatusEnum.SUCCESS.getStatus(), updateObj);
}
} }

View File

@ -43,6 +43,7 @@ import java.util.List;
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.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
/** /**
* 退款订单 Service 实现类 * 退款订单 Service 实现类
@ -106,13 +107,13 @@ public class PayRefundServiceImpl implements PayRefundService {
PayClient client = payClientFactory.getPayClient(channel.getId()); PayClient client = payClientFactory.getPayClient(channel.getId());
if (client == null) { if (client == null) {
log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND); throw exception(CHANNEL_NOT_FOUND);
} }
// 1.4 校验退款订单是否已经存在 // 1.4 校验退款订单是否已经存在
PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId( PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
app.getId(), reqDTO.getMerchantRefundId()); app.getId(), reqDTO.getMerchantRefundId());
if (refund != null) { if (refund != null) {
throw exception(ErrorCodeConstants.PAY_REFUND_EXISTS); throw exception(ErrorCodeConstants.REFUND_EXISTS);
} }
// 2.1 插入退款单 // 2.1 插入退款单
@ -153,25 +154,25 @@ public class PayRefundServiceImpl implements PayRefundService {
private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) { private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId()); PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
if (order == null) { if (order == null) {
throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND); throw exception(ErrorCodeConstants.ORDER_NOT_FOUND);
} }
// 校验状态必须是支付状态 // 校验状态必须是支付状态
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) { if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS); throw exception(ErrorCodeConstants.ORDER_STATUS_IS_NOT_SUCCESS);
} }
// 是否已经全额退款 // 是否已经全额退款
if (PayOrderRefundStatusEnum.ALL.getStatus().equals(order.getRefundStatus())) { if (PayOrderRefundStatusEnum.ALL.getStatus().equals(order.getRefundStatus())) {
throw exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED); throw exception(ErrorCodeConstants.REFUND_ALL_REFUNDED);
} }
// 校验金额 退款金额不能大于原定的金额 // 校验金额 退款金额不能大于原定的金额
if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){ if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
throw exception(ErrorCodeConstants.PAY_REFUND_PRICE_EXCEED); throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED);
} }
// 是否有退款中的订单 // 是否有退款中的订单
if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(), if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
PayRefundStatusEnum.WAITING.getStatus()) > 0) { PayRefundStatusEnum.WAITING.getStatus()) > 0) {
throw exception(ErrorCodeConstants.PAY_REFUND_HAS_REFUNDING); throw exception(ErrorCodeConstants.REFUND_HAS_REFUNDING);
} }
return order; return order;
} }
@ -230,13 +231,13 @@ public class PayRefundServiceImpl implements PayRefundService {
PayRefundDO refund = refundMapper.selectByAppIdAndNo( PayRefundDO refund = refundMapper.selectByAppIdAndNo(
channel.getAppId(), notify.getOutRefundNo()); channel.getAppId(), notify.getOutRefundNo());
if (refund == null) { if (refund == null) {
throw exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND); throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
} }
if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功直接返回不用重复更新 if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功直接返回不用重复更新
return; return;
} }
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING); throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
} }
// 1.2 更新 PayRefundDO // 1.2 更新 PayRefundDO
@ -247,7 +248,7 @@ public class PayRefundServiceImpl implements PayRefundService {
.setChannelNotifyData(toJsonString(notify)); .setChannelNotifyData(toJsonString(notify));
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
if (updateCounts == 0) { // 校验状态必须是等待状态 if (updateCounts == 0) { // 校验状态必须是等待状态
throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING); throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
} }
// 2. 更新订单 // 2. 更新订单

View File

@ -90,7 +90,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o ->
o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))); o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
// 调用, 并断言异常 // 调用, 并断言异常
assertServiceException(() -> appService.updateApp(reqVO), PAY_APP_NOT_FOUND); assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_FOUND);
} }
@Test @Test
@ -130,7 +130,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
Long id = randomLongId(); Long id = randomLongId();
// 调用, 并断言异常 // 调用, 并断言异常
assertServiceException(() -> appService.deleteApp(id), PAY_APP_NOT_FOUND); assertServiceException(() -> appService.deleteApp(id), APP_NOT_FOUND);
} }
@Test @Test
@ -144,7 +144,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L); when(orderService.getOrderCountByAppId(eq(id))).thenReturn(10L);
// 调用, 并断言异常 // 调用, 并断言异常
assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_ORDER_CANT_DELETE); assertServiceException(() -> appService.deleteApp(id), APP_EXIST_ORDER_CANT_DELETE);
} }
@Test @Test
@ -158,7 +158,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L); when(refundService.getRefundCountByAppId(eq(id))).thenReturn(10L);
// 调用, 并断言异常 // 调用, 并断言异常
assertServiceException(() -> appService.deleteApp(id), PAY_APP_EXIST_REFUND_CANT_DELETE); assertServiceException(() -> appService.deleteApp(id), APP_EXIST_REFUND_CANT_DELETE);
} }
@Test @Test
@ -239,7 +239,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
@Test @Test
public void testValidPayApp_notFound() { public void testValidPayApp_notFound() {
assertServiceException(() -> appService.validPayApp(randomLongId()), PAY_APP_NOT_FOUND); assertServiceException(() -> appService.validPayApp(randomLongId()), APP_NOT_FOUND);
} }
@Test @Test
@ -252,7 +252,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
Long id = dbApp.getId(); Long id = dbApp.getId();
// 调用并断言异常 // 调用并断言异常
assertServiceException(() -> appService.validPayApp(id), PAY_APP_IS_DISABLE); assertServiceException(() -> appService.validPayApp(id), APP_IS_DISABLE);
} }
} }

View File

@ -26,8 +26,7 @@ import java.util.List;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@Import({PayChannelServiceImpl.class}) @Import({PayChannelServiceImpl.class})
@ -51,6 +50,40 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
channelService.setChannelCache(null); channelService.setChannelCache(null);
} }
@Test
public void testInitLocalCache() {
// mock 数据
PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
o -> o.setConfig(randomWxPayClientConfig()));
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
// 调用
channelService.initLocalCache();
// 校验缓存
assertEquals(1, channelService.getChannelCache().size());
assertEquals(dbChannel, channelService.getChannelCache().get(0));
}
@Test
public void testRefreshLocalCache() {
// mock 数据 01
PayChannelDO dbChannel = randomPojo(PayChannelDO.class,
o -> o.setConfig(randomWxPayClientConfig()));
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
channelService.initLocalCache();
// mock 数据 02
PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class,
o -> o.setConfig(randomWxPayClientConfig()));
channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
// 调用
channelService.refreshLocalCache();
// 校验缓存
assertEquals(2, channelService.getChannelCache().size());
assertEquals(dbChannel, channelService.getChannelCache().get(0));
assertEquals(dbChannel02, channelService.getChannelCache().get(1));
}
@Test @Test
public void testCreateChannel_success() { public void testCreateChannel_success() {
// 准备参数 // 准备参数
@ -125,7 +158,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
}); });
// 调用, 并断言异常 // 调用, 并断言异常
assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS); assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_FOUND);
} }
@Test @Test
@ -153,7 +186,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
Long id = randomLongId(); Long id = randomLongId();
// 调用, 并断言异常 // 调用, 并断言异常
assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS); assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_FOUND);
} }
@Test @Test
@ -214,6 +247,101 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
assertPojoEquals(channel, dbChannel); assertPojoEquals(channel, dbChannel);
} }
@Test
public void testValidPayChannel_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_NOT_FOUND);
}
@Test
public void testValidPayChannel_isDisable() {
// mock 数据
PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
o.setConfig(randomAlipayPayClientConfig());
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
});
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbChannel.getId();
// 调用, 并断言异常
assertServiceException(() -> channelService.validPayChannel(id), CHANNEL_IS_DISABLE);
}
@Test
public void testValidPayChannel_success() {
// mock 数据
PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
o.setConfig(randomAlipayPayClientConfig());
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbChannel.getId();
// 调用
PayChannelDO channel = channelService.validPayChannel(id);
// 断言异常
assertPojoEquals(channel, dbChannel);
}
@Test
public void testValidPayChannel_appIdAndCode() {
// mock 数据
PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
o.setConfig(randomAlipayPayClientConfig());
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
// 准备参数
Long appId = dbChannel.getAppId();
String code = dbChannel.getCode();
// 调用
PayChannelDO channel = channelService.validPayChannel(appId, code);
// 断言异常
assertPojoEquals(channel, dbChannel);
}
@Test
public void testGetEnableChannelList() {
// 准备参数
Long appId = randomLongId();
// mock 数据 01enable 不匹配
PayChannelDO dbChannel01 = randomPojo(PayChannelDO.class, o -> {
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
o.setConfig(randomAlipayPayClientConfig());
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
});
channelMapper.insert(dbChannel01);// @Sql: 先插入出一条存在的数据
// mock 数据 02appId 不匹配
PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class, o -> {
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
o.setConfig(randomAlipayPayClientConfig());
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据
// mock 数据 03
PayChannelDO dbChannel03 = randomPojo(PayChannelDO.class, o -> {
o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
o.setConfig(randomAlipayPayClientConfig());
o.setAppId(appId);
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
channelMapper.insert(dbChannel03);// @Sql: 先插入出一条存在的数据
// 调用
List<PayChannelDO> channel = channelService.getEnableChannelList(appId);
// 断言异常
assertPojoEquals(channel, dbChannel03);
}
public WxPayClientConfig randomWxPayClientConfig() { public WxPayClientConfig randomWxPayClientConfig() {
return new WxPayClientConfig() return new WxPayClientConfig()
.setAppId(randomString()) .setAppId(randomString())

View File

@ -3,32 +3,53 @@ package cn.iocoder.yudao.module.pay.service.order;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.pay.config.PayProperties; 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.PayClientFactory;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
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.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper; import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum; import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum; import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
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;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.equalsAny;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/** /**
* {@link PayOrderServiceImpl} 的单元测试类 * {@link PayOrderServiceImpl} 的单元测试类
@ -43,6 +64,8 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
@Resource @Resource
private PayOrderMapper orderMapper; private PayOrderMapper orderMapper;
@Resource
private PayOrderExtensionMapper orderExtensionMapper;
@MockBean @MockBean
private PayClientFactory payClientFactory; private PayClientFactory payClientFactory;
@ -55,42 +78,18 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
@MockBean @MockBean
private PayNotifyService notifyService; private PayNotifyService notifyService;
public String generateNo() {
return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999);
}
@Test @Test
public void testGetOrderPage() { public void testGetOrderPage() {
String merchantOrderId = generateNo();
String channelOrderId = generateNo();
// mock 数据 // mock 数据
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
o.setAppId(1L); o.setAppId(1L);
o.setChannelId(1L); o.setChannelId(10L);
o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
o.setMerchantOrderId(merchantOrderId); o.setMerchantOrderId("110");
o.setSubject("灿灿子的炸弹猫");
o.setBody("斌斌子送给灿灿子的炸弹猫");
o.setNotifyUrl("https://hc.com/lbh");
o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
o.setPrice(10000);
o.setChannelFeeRate(0.01);
o.setChannelFeePrice(1L);
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
o.setUserIp("127.0.0.1"); o.setCreateTime(buildTime(2018, 1, 15));
o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));
o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));
o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
o.setSuccessExtensionId(1L);
o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()); o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
o.setRefundTimes(0);
o.setRefundPrice(0);
o.setChannelUserId("1008611");
o.setChannelOrderNo(channelOrderId);
o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
}); });
orderMapper.insert(dbOrder); orderMapper.insert(dbOrder);
// 测试 appId 不匹配 // 测试 appId 不匹配
@ -100,7 +99,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
// 测试 channelCode 不匹配 // 测试 channelCode 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
// 测试 merchantOrderId 不匹配 // 测试 merchantOrderId 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
// 测试 notifyStatus 不匹配 // 测试 notifyStatus 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
// 测试 status 不匹配 // 测试 status 不匹配
@ -108,58 +107,38 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
// 测试 refundStatus 不匹配 // 测试 refundStatus 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10, orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
1))));
// 准备参数 // 准备参数
PayOrderPageReqVO reqVO = new PayOrderPageReqVO(); PayOrderPageReqVO reqVO = new PayOrderPageReqVO();
reqVO.setAppId(1L); reqVO.setAppId(1L);
reqVO.setChannelId(1L); reqVO.setChannelId(10L);
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
reqVO.setMerchantOrderId(merchantOrderId); reqVO.setMerchantOrderId("110");
reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()); reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)})); reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
// 调用 // 调用
PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO); PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO);
// 断言 // 断言
assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size()); assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbOrder, pageResult.getList().get(0)); assertPojoEquals(dbOrder, pageResult.getList().get(0));
// assertEquals(0, dbOrder.getUpdateTime().compareTo(pageResult.getList().get(0).getUpdateTime()));
} }
@Test @Test
public void testGetOrderList() { public void testGetOrderList() {
// mock 数据 // mock 数据
String merchantOrderId = generateNo();
String channelOrderId = generateNo();
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到
o.setAppId(1L); o.setAppId(1L);
o.setChannelId(1L); o.setChannelId(10L);
o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
o.setMerchantOrderId(merchantOrderId); o.setMerchantOrderId("110");
o.setSubject("灿灿子的炸弹猫");
o.setBody("斌斌子送给灿灿子的炸弹猫");
o.setNotifyUrl("https://hc.com/lbh");
o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
o.setPrice(10000);
o.setChannelFeeRate(0.01);
o.setChannelFeePrice(1L);
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
o.setUserIp("127.0.0.1"); o.setCreateTime(buildTime(2018, 1, 15));
o.setCreateTime(LocalDateTime.of(2018, 1, 1, 10, 1, 0));
o.setExpireTime(LocalDateTime.of(2018, 1, 1, 10, 30, 0));
o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
o.setSuccessExtensionId(1L);
o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()); o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
o.setRefundTimes(0);
o.setRefundPrice(0);
o.setChannelUserId("1008611");
o.setChannelOrderNo(channelOrderId);
o.setUpdateTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
}); });
orderMapper.insert(dbOrder); orderMapper.insert(dbOrder);
// 测试 appId 不匹配 // 测试 appId 不匹配
@ -169,7 +148,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
// 测试 channelCode 不匹配 // 测试 channelCode 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
// 测试 merchantOrderId 不匹配 // 测试 merchantOrderId 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(generateNo()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setMerchantOrderId(randomString())));
// 测试 notifyStatus 不匹配 // 测试 notifyStatus 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
// 测试 status 不匹配 // 测试 status 不匹配
@ -177,18 +156,17 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
// 测试 refundStatus 不匹配 // 测试 refundStatus 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus()))); orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10, orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(buildTime(2019, 1, 1))));
1))));
// 准备参数 // 准备参数
PayOrderExportReqVO reqVO = new PayOrderExportReqVO(); PayOrderExportReqVO reqVO = new PayOrderExportReqVO();
reqVO.setAppId(1L); reqVO.setAppId(1L);
reqVO.setChannelId(1L); reqVO.setChannelId(10L);
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
reqVO.setMerchantOrderId(merchantOrderId); reqVO.setMerchantOrderId("110");
reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus()); reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()); reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)})); reqVO.setCreateTime(buildBetweenTime(2018, 1, 10, 2018, 1, 30));
// 调用 // 调用
List<PayOrderDO> list = orderService.getOrderList(reqVO); List<PayOrderDO> list = orderService.getOrderList(reqVO);
@ -197,4 +175,154 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
assertPojoEquals(dbOrder, list.get(0)); assertPojoEquals(dbOrder, list.get(0));
} }
@Test
public void testCreateOrder_success() {
// mock 参数
PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
o -> o.setAppId(1L).setMerchantOrderId("10")
.setSubject(randomString()).setBody(randomString()));
// mock 方法
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1"));
when(appService.validPayApp(eq(reqDTO.getAppId()))).thenReturn(app);
// 调用
Long orderId = orderService.createOrder(reqDTO);
// 断言
PayOrderDO order = orderMapper.selectById(orderId);
assertPojoEquals(order, reqDTO);
assertEquals(order.getAppId(), 1L);
assertEquals(order.getNotifyUrl(), "http://127.0.0.1");
assertEquals(order.getStatus(), PayOrderStatusEnum.WAITING.getStatus());
assertEquals(order.getRefundStatus(), PayOrderRefundStatusEnum.NO.getStatus());
assertEquals(order.getRefundTimes(), 0);
assertEquals(order.getRefundPrice(), 0);
}
@Test
public void testCreateOrder_exists() {
// mock 参数
PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
o -> o.setAppId(1L).setMerchantOrderId("10"));
// mock 数据
PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> o.setAppId(1L).setMerchantOrderId("10"));
orderMapper.insert(dbOrder);
// 调用
Long orderId = orderService.createOrder(reqDTO);
// 断言
PayOrderDO order = orderMapper.selectById(orderId);
assertPojoEquals(dbOrder, order);
}
@Test
public void testSubmitOrder_notFound() {
// 准备参数
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class);
String userIp = randomString();
// 调用, 并断言异常
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_NOT_FOUND);
}
@Test
public void testSubmitOrder_notWaiting() {
// mock 数据order
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()));
orderMapper.insert(order);
// 准备参数
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
String userIp = randomString();
// 调用, 并断言异常
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_STATUS_IS_NOT_WAITING);
}
@Test
public void testSubmitOrder_expired() {
// mock 数据order
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
.setExpireTime(addTime(Duration.ofDays(-1))));
orderMapper.insert(order);
// 准备参数
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId()));
String userIp = randomString();
// 调用, 并断言异常
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), ORDER_IS_EXPIRED);
}
@Test
public void testSubmitOrder_channelNotFound() {
// mock 数据order
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
.setAppId(1L));
orderMapper.insert(order);
// 准备参数
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
String userIp = randomString();
// mock 方法app
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
when(appService.validPayApp(eq(1L))).thenReturn(app);
// mock 方法channel
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
.thenReturn(channel);
// 调用, 并断言异常
assertServiceException(() -> orderService.submitOrder(reqVO, userIp), CHANNEL_NOT_FOUND);
}
@Test // 调用 unifiedOrder 接口返回存在渠道错误
public void testSubmitOrder_channelError() {
// mock 数据order
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
.setAppId(1L));
orderMapper.insert(order);
// 准备参数
PayOrderSubmitReqVO reqVO = randomPojo(PayOrderSubmitReqVO.class, o -> o.setId(order.getId())
.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
String userIp = randomString();
// mock 方法app
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
when(appService.validPayApp(eq(1L))).thenReturn(app);
// mock 方法channel
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
when(channelService.validPayChannel(eq(1L), eq(PayChannelEnum.ALIPAY_APP.getCode())))
.thenReturn(channel);
// mock 方法client
PayClient client = mock(PayClient.class);
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
when(client.unifiedOrder(any(PayOrderUnifiedReqDTO.class))).thenThrow(new NullPointerException());
// 调用并断言异常
assertThrows(NullPointerException.class, () -> orderService.submitOrder(reqVO, userIp));
// 断言数据记录PayOrderExtensionDO
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectOne(null);
assertNotNull(orderExtension);
assertThat(orderExtension).extracting("no", "orderId").isNotNull();
assertThat(orderExtension)
.extracting("channelId", "channelCode","userIp" ,"status", "channelExtras",
"channelErrorCode", "channelErrorMsg", "channelNotifyData")
.containsExactly(10L, PayChannelEnum.ALIPAY_APP.getCode(), userIp,
PayOrderStatusEnum.WAITING.getStatus(), reqVO.getChannelExtras(),
null, null, null);
}
@Test // 成功支付结果为等待中
public void testSubmitOrder_waitingResult() {
}
@Test // 成功支付结果为已完成
public void testSubmitOrder_successResult() {
}
@Test // 成功支付结果为已关闭
public void testSubmitOrder_closedResult() {
}
} }

View File

@ -40,9 +40,9 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
`body` varchar(128) NOT NULL, `body` varchar(128) NOT NULL,
`notify_url` varchar(1024) NOT NULL, `notify_url` varchar(1024) NOT NULL,
`notify_status` tinyint(4) NOT NULL, `notify_status` tinyint(4) NOT NULL,
`amount` bigint(20) NOT NULL, `price` bigint(20) NOT NULL,
`channel_fee_rate` double DEFAULT 0, `channel_fee_rate` double DEFAULT 0,
`channel_fee_amount` bigint(20) DEFAULT 0, `channel_fee_price` bigint(20) DEFAULT 0,
`status` tinyint(4) NOT NULL, `status` tinyint(4) NOT NULL,
`user_ip` varchar(50) NOT NULL, `user_ip` varchar(50) NOT NULL,
`expire_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, `expire_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
@ -50,8 +50,8 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
`notify_time` datetime(0) DEFAULT CURRENT_TIMESTAMP, `notify_time` datetime(0) DEFAULT CURRENT_TIMESTAMP,
`success_extension_id` bigint(20) DEFAULT NULL COMMENT '支付成功的订单拓展单编号', `success_extension_id` bigint(20) DEFAULT NULL COMMENT '支付成功的订单拓展单编号',
`refund_status` tinyint(4) NOT NULL, `refund_status` tinyint(4) NOT NULL,
`refund_times` tinyint(4) NOT NULL, `refund_times` int NOT NULL,
`refund_amount` bigint(20) NOT NULL, `refund_price` bigint(20) NOT NULL,
`channel_user_id` varchar(255) DEFAULT NULL, `channel_user_id` varchar(255) DEFAULT NULL,
`channel_order_no` varchar(64) DEFAULT NULL, `channel_order_no` varchar(64) DEFAULT NULL,
`creator` varchar(64) DEFAULT '', `creator` varchar(64) DEFAULT '',
@ -62,6 +62,26 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT = '支付订单'; ) COMMENT = '支付订单';
CREATE TABLE IF NOT EXISTS `pay_order_extension` (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
`no` varchar(64) NOT NULL,
`order_id` bigint(20) NOT NULL,
`channel_id` bigint(20) NOT NULL,
`channel_code` varchar(32) NOT NULL,
`user_ip` varchar(50) NULL DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`channel_extras` varchar(1024) NULL DEFAULT NULL,
`channel_error_code` varchar(64) NULL,
`channel_error_msg` varchar(64) NULL,
`channel_notify_data` varchar(64) NULL,
`creator` varchar(64) NULL DEFAULT '',
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updater` varchar(64) NULL DEFAULT '',
`update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted` bit(1) NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT = '支付订单拓展';
CREATE TABLE IF NOT EXISTS `pay_refund` ( CREATE TABLE IF NOT EXISTS `pay_refund` (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
`app_id` bigint(20) NOT NULL, `app_id` bigint(20) NOT NULL,