by gateway: 支付应用的代码优化

This commit is contained in:
zhijiantianya@gmail.com 2023-07-12 12:52:48 +08:00
parent f1c4c7964a
commit 052e4689ee
22 changed files with 142 additions and 184 deletions

View File

@ -102,6 +102,10 @@ public class RandomUtils {
return randomString() + "@qq.com"; return randomString() + "@qq.com";
} }
public static String randomURL() {
return "https://www.iocoder.cn/" + randomString();
}
@SafeVarargs @SafeVarargs
public static <T> T randomPojo(Class<T> clazz, Consumer<T>... consumers) { public static <T> T randomPojo(Class<T> clazz, Consumer<T>... consumers) {
T pojo = PODAM_FACTORY.manufacturePojo(clazz); T pojo = PODAM_FACTORY.manufacturePojo(clazz);

View File

@ -12,7 +12,8 @@ public interface ErrorCodeConstants {
// ========== APP 模块 1007000000 ========== // ========== APP 模块 1007000000 ==========
ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在"); ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用"); ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
ErrorCode PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在交易中的订单,无法删除"); ErrorCode PAY_APP_EXIST_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在支付订单,无法删除");
ErrorCode PAY_APP_EXIST_REFUND_CANT_DELETE = new ErrorCode(1007000004, "支付应用存在退款订单,无法删除");
// ========== CHANNEL 模块 1007001000 ========== // ========== CHANNEL 模块 1007001000 ==========
ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在"); ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");

View File

@ -24,6 +24,7 @@ import javax.validation.Valid;
import java.util.*; import java.util.*;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Slf4j @Slf4j
@Tag(name = "管理后台 - 支付应用信息") @Tag(name = "管理后台 - 支付应用信息")
@ -78,15 +79,6 @@ public class PayAppController {
return success(PayAppConvert.INSTANCE.convert(app)); return success(PayAppConvert.INSTANCE.convert(app));
} }
@GetMapping("/list")
@Operation(summary = "获得支付应用信息列表")
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
@PreAuthorize("@ss.hasPermission('pay:app:query')")
public CommonResult<List<PayAppRespVO>> getAppList(@RequestParam("ids") Collection<Long> ids) {
List<PayAppDO> list = appService.getAppList(ids);
return success(PayAppConvert.INSTANCE.convertList(list));
}
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得支付应用信息分页") @Operation(summary = "获得支付应用信息分页")
@PreAuthorize("@ss.hasPermission('pay:app:query')") @PreAuthorize("@ss.hasPermission('pay:app:query')")
@ -94,34 +86,15 @@ public class PayAppController {
// 得到应用分页列表 // 得到应用分页列表
PageResult<PayAppDO> pageResult = appService.getAppPage(pageVO); PageResult<PayAppDO> pageResult = appService.getAppPage(pageVO);
if (CollUtil.isEmpty(pageResult.getList())) { if (CollUtil.isEmpty(pageResult.getList())) {
return success(new PageResult<>(pageResult.getTotal())); return success(PageResult.empty());
} }
// 得到所有的应用编号查出所有的渠道 // 得到所有的应用编号查出所有的渠道
Collection<Long> payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId); Collection<Long> appIds = convertList(pageResult.getList(), PayAppDO::getId);
List<PayChannelDO> channels = channelService.getChannelListByAppIds(payAppIds); List<PayChannelDO> channels = channelService.getChannelListByAppIds(appIds);
// TODO @aquan可以基于 appId 简历一个 multiMap这样下面直接 get 到之后CollUtil buildSet 即可
Iterator<PayChannelDO> iterator = channels.iterator();
// 利用反射将渠道数据复制到返回的数据结构中去 // 拼接后返回
List<PayAppPageItemRespVO> appList = new ArrayList<>(pageResult.getList().size()); return success(PayAppConvert.INSTANCE.convertPage(pageResult, channels));
pageResult.getList().forEach(app -> {
// 写入应用信息的数据
PayAppPageItemRespVO respVO = PayAppConvert.INSTANCE.pageConvert(app);
// 写入支付渠道信息的数据
Set<String> channelCodes = new HashSet<>(PayChannelEnum.values().length);
while (iterator.hasNext()) {
PayChannelDO channelDO = iterator.next();
if (channelDO.getAppId().equals(app.getId())) {
channelCodes.add(channelDO.getCode());
iterator.remove();
}
}
respVO.setChannelCodes(channelCodes);
appList.add(respVO);
});
return success(new PageResult<>(appList, pageResult.getTotal()));
} }
} }

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.pay.controller.admin.app.vo; package cn.iocoder.yudao.module.pay.controller.admin.app.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.*;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*; import javax.validation.constraints.*;
/** /**
@ -10,23 +12,25 @@ import javax.validation.constraints.*;
@Data @Data
public class PayAppBaseVO { public class PayAppBaseVO {
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "小豆")
@NotNull(message = "应用名不能为空") @NotNull(message = "应用名不能为空")
private String name; private String name;
@Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "开启状态不能为空") @NotNull(message = "开启状态不能为空")
private Integer status; private Integer status;
@Schema(description = "备注") @Schema(description = "备注", example = "我是一个测试应用")
private String remark; private String remark;
@Schema(description = "支付结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "支付结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/pay-callback")
@NotNull(message = "支付结果的回调地址不能为空") @NotNull(message = "支付结果的回调地址不能为空")
@URL(message = "支付结果的回调地址必须为 URL 格式")
private String payNotifyUrl; private String payNotifyUrl;
@Schema(description = "退款结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "退款结果的回调地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://127.0.0.1:48080/refund-callback")
@NotNull(message = "退款结果的回调地址不能为空") @NotNull(message = "退款结果的回调地址不能为空")
@URL(message = "退款结果的回调地址必须为 URL 格式")
private String refundNotifyUrl; private String refundNotifyUrl;
} }

View File

@ -14,13 +14,13 @@ import java.util.Set;
@ToString(callSuper = true) @ToString(callSuper = true)
public class PayAppPageItemRespVO extends PayAppBaseVO { public class PayAppPageItemRespVO extends PayAppBaseVO {
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id; private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "渠道编码集合", requiredMode = Schema.RequiredMode.REQUIRED, example = "[alipay_pc, alipay_wap]") @Schema(description = "已配置的支付渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "[alipay_pc, alipay_wap]")
private Set<String> channelCodes; private Set<String> channelCodes;
} }

View File

@ -17,21 +17,12 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@ToString(callSuper = true) @ToString(callSuper = true)
public class PayAppPageReqVO extends PageParam { public class PayAppPageReqVO extends PageParam {
@Schema(description = "应用名") @Schema(description = "应用名", example = "小豆")
private String name; private String name;
@Schema(description = "开启状态") @Schema(description = "开启状态", example = "0")
private Integer status; private Integer status;
@Schema(description = "备注")
private String remark;
@Schema(description = "支付结果的回调地址")
private String payNotifyUrl;
@Schema(description = "退款结果的回调地址")
private String refundNotifyUrl;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "创建时间") @Schema(description = "创建时间")
private LocalDateTime[] createTime; private LocalDateTime[] createTime;

View File

@ -10,7 +10,7 @@ import java.time.LocalDateTime;
@ToString(callSuper = true) @ToString(callSuper = true)
public class PayAppRespVO extends PayAppBaseVO { public class PayAppRespVO extends PayAppBaseVO {
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id; private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -9,7 +9,7 @@ import javax.validation.constraints.*;
@ToString(callSuper = true) @ToString(callSuper = true)
public class PayAppUpdateReqVO extends PayAppBaseVO { public class PayAppUpdateReqVO extends PayAppBaseVO {
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "应用编号不能为空") @NotNull(message = "应用编号不能为空")
private Long id; private Long id;

View File

@ -9,11 +9,11 @@ import javax.validation.constraints.NotNull;
@Data @Data
public class PayAppUpdateStatusReqVO { public class PayAppUpdateStatusReqVO {
@Schema(description = "商户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "商户编号不能为空") @NotNull(message = "应用编号不能为空")
private Long id; private Long id;
@Schema(description = "状态,见 SysCommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "状态见 SysCommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空") @NotNull(message = "状态不能为空")
private Integer status; private Integer status;

View File

@ -1,15 +1,20 @@
package cn.iocoder.yudao.module.pay.convert.app; package cn.iocoder.yudao.module.pay.convert.app;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
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.PayAppPageItemRespVO; import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageItemRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppRespVO; import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
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.dataobject.channel.PayChannelDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
/** /**
* 支付应用信息 Convert * 支付应用信息 Convert
@ -31,6 +36,14 @@ public interface PayAppConvert {
List<PayAppRespVO> convertList(List<PayAppDO> list); List<PayAppRespVO> convertList(List<PayAppDO> list);
PageResult<PayAppRespVO> convertPage(PageResult<PayAppDO> page); PageResult<PayAppPageItemRespVO> convertPage(PageResult<PayAppDO> page);
default PageResult<PayAppPageItemRespVO> convertPage(PageResult<PayAppDO> pageResult, List<PayChannelDO> channels) {
PageResult<PayAppPageItemRespVO> voPageResult = convertPage(pageResult);
// 处理 channel 关系
Map<Long, Set<String>> appIdChannelMap = CollectionUtils.convertMultiMap2(channels, PayChannelDO::getAppId, PayChannelDO::getCode);
voPageResult.getList().forEach(app -> app.setChannelCodes(appIdChannelMap.get(app.getId())));
return voPageResult;
}
} }

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.dal.mysql.app;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
@ -11,14 +12,11 @@ import org.apache.ibatis.annotations.Mapper;
public interface PayAppMapper extends BaseMapperX<PayAppDO> { public interface PayAppMapper extends BaseMapperX<PayAppDO> {
default PageResult<PayAppDO> selectPage(PayAppPageReqVO reqVO) { default PageResult<PayAppDO> selectPage(PayAppPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<PayAppDO>() return selectPage(reqVO, new LambdaQueryWrapperX<PayAppDO>()
.likeIfPresent("name", reqVO.getName()) .likeIfPresent(PayAppDO::getName, reqVO.getName())
.eqIfPresent("status", reqVO.getStatus()) .eqIfPresent(PayAppDO::getStatus, reqVO.getStatus())
.eqIfPresent("remark", reqVO.getRemark()) .betweenIfPresent(PayAppDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent("pay_notify_url", reqVO.getPayNotifyUrl()) .orderByDesc(PayAppDO::getId));
.eqIfPresent("refund_notify_url", reqVO.getRefundNotifyUrl())
.betweenIfPresent("create_time", reqVO.getCreateTime())
.orderByDesc("id"));
} }
} }

View File

@ -50,17 +50,8 @@ public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
.in(PayOrderDO::getId, idList)); .in(PayOrderDO::getId, idList));
} }
/** default Long selectCountByAppId(Long appId) {
* 查询符合的订单数量 return selectCount(PayOrderDO::getAppId, appId);
*
* @param appId 应用编号
* @param status 订单状态
* @return 条数
*/
default Long selectCount(Long appId, Integer status) {
return selectCount(new LambdaQueryWrapper<PayOrderDO>()
.eq(PayOrderDO::getAppId, appId)
.in(PayOrderDO::getStatus, status));
} }
default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) { default PayOrderDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) {

View File

@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List; import java.util.List;
@ -38,11 +37,8 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
.orderByDesc("id")); .orderByDesc("id"));
} }
default Long selectCount(Long appId, Integer status) { default Long selectCountByApp(Long appId) {
return selectCount(PayRefundDO::getAppId, appId);
return selectCount(new LambdaQueryWrapper<PayRefundDO>()
.eq(PayRefundDO::getAppId, appId)
.eq(PayRefundDO::getStatus, status));
} }
default PayRefundDO selectByReqNo(String reqNo) { default PayRefundDO selectByReqNo(String reqNo) {
@ -52,4 +48,5 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
default PayRefundDO selectByTradeNoAndMerchantRefundNo(String tradeNo, String merchantRefundNo){ default PayRefundDO selectByTradeNoAndMerchantRefundNo(String tradeNo, String merchantRefundNo){
return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo); return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo);
} }
} }

View File

@ -35,6 +35,14 @@ public interface PayAppService {
*/ */
void updateApp(@Valid PayAppUpdateReqVO updateReqVO); void updateApp(@Valid PayAppUpdateReqVO updateReqVO);
/**
* 修改应用信息状态
*
* @param id 应用编号
* @param status 状态
*/
void updateAppStatus(Long id, Integer status);
/** /**
* 删除支付应用信息 * 删除支付应用信息
* *
@ -66,14 +74,6 @@ public interface PayAppService {
*/ */
PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO); PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO);
/**
* 修改应用信息状态
*
* @param id 应用编号
* @param status 状态{@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
*/
void updateAppStatus(Long id, Integer status);
/** /**
* 获得指定编号的商户 Map * 获得指定编号的商户 Map
* *
@ -85,7 +85,6 @@ public interface PayAppService {
return CollectionUtils.convertMap(list, PayAppDO::getId); return CollectionUtils.convertMap(list, PayAppDO::getId);
} }
/** /**
* 支付应用的合法性 * 支付应用的合法性
* *

View File

@ -9,12 +9,13 @@ 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.order.PayOrderMapper;
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; 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.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
import com.google.common.annotations.VisibleForTesting; import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -23,11 +24,10 @@ import java.util.Collection;
import java.util.List; 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.module.pay.enums.ErrorCodeConstants.PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_APP_NOT_FOUND;
/** /**
* 支付应用信息 Service 实现类 * 支付应用 Service 实现类
* *
* @author aquan * @author aquan
*/ */
@ -37,11 +37,13 @@ public class PayAppServiceImpl implements PayAppService {
@Resource @Resource
private PayAppMapper appMapper; private PayAppMapper appMapper;
// TODO 芋艿不能调用对方的 mapper
@Resource @Resource
private PayOrderMapper orderMapper; @Lazy // 延迟加载避免循环依赖报错
private PayOrderService orderService;
@Resource @Resource
private PayRefundMapper refundMapper; @Lazy // 延迟加载避免循环依赖报错
private PayRefundService refundService;
@Override @Override
public Long createApp(PayAppCreateReqVO createReqVO) { public Long createApp(PayAppCreateReqVO createReqVO) {
@ -55,17 +57,34 @@ public class PayAppServiceImpl implements PayAppService {
@Override @Override
public void updateApp(PayAppUpdateReqVO updateReqVO) { public void updateApp(PayAppUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
this.validateAppExists(updateReqVO.getId()); validateAppExists(updateReqVO.getId());
// 更新 // 更新
PayAppDO updateObj = PayAppConvert.INSTANCE.convert(updateReqVO); PayAppDO updateObj = PayAppConvert.INSTANCE.convert(updateReqVO);
appMapper.updateById(updateObj); appMapper.updateById(updateObj);
} }
@Override
public void updateAppStatus(Long id, Integer status) {
// 校验商户存在
validateAppExists(id);
// 更新状态
PayAppDO app = new PayAppDO();
app.setId(id);
app.setStatus(status);
appMapper.updateById(app);
}
@Override @Override
public void deleteApp(Long id) { public void deleteApp(Long id) {
// 校验存在 // 校验存在
this.validateAppExists(id); validateAppExists(id);
this.validateOrderTransactionExist(id); // 校验关联数据是否存在
if (orderService.getOrderCountByAppId(id) > 0) {
throw exception(PAY_APP_EXIST_ORDER_CANT_DELETE);
}
if (refundService.getRefundCountByAppId(id) > 0) {
throw exception(PAY_APP_EXIST_REFUND_CANT_DELETE);
}
// 删除 // 删除
appMapper.deleteById(id); appMapper.deleteById(id);
@ -92,49 +111,6 @@ public class PayAppServiceImpl implements PayAppService {
return appMapper.selectPage(pageReqVO); return appMapper.selectPage(pageReqVO);
} }
@Override
public void updateAppStatus(Long id, Integer status) {
// 校验商户存在
this.checkAppExists(id);
// 更新状态
PayAppDO app = new PayAppDO();
app.setId(id);
app.setStatus(status);
appMapper.updateById(app);
}
/**
* 检查商户是否存在
*
* @param id 商户编号
*/
@VisibleForTesting
public void checkAppExists(Long id) {
if (id == null) {
return;
}
PayAppDO payApp = appMapper.selectById(id);
if (payApp == null) {
throw exception(PAY_APP_NOT_FOUND);
}
}
/**
* 验证是否存在交易中或者退款中等处理中状态的订单
*
* @param appId 应用 ID
*/
private void validateOrderTransactionExist(Long appId) {
// 查看交易订单
if (orderMapper.selectCount(appId, PayOrderStatusEnum.WAITING.getStatus()) > 0) {
throw exception(PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE);
}
// 查看退款订单
if (refundMapper.selectCount(appId, PayRefundStatusEnum.CREATE.getStatus()) > 0) {
throw exception(PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE);
}
}
@Override @Override
public PayAppDO validPayApp(Long id) { public PayAppDO validPayApp(Long id) {
PayAppDO app = appMapper.selectById(id); PayAppDO app = appMapper.selectById(id);

View File

@ -32,6 +32,14 @@ public interface PayOrderService {
*/ */
PayOrderDO getOrder(Long id); PayOrderDO getOrder(Long id);
/**
* 获得指定应用的订单数量
*
* @param appId 应用编号
* @return 订单数量
*/
Long getOrderCountByAppId(Long appId);
/** /**
* 获得支付订单 * 获得支付订单
* 分页 * 分页

View File

@ -82,6 +82,11 @@ public class PayOrderServiceImpl implements PayOrderService {
return orderMapper.selectById(id); return orderMapper.selectById(id);
} }
@Override
public Long getOrderCountByAppId(Long appId) {
return orderMapper.selectCountByAppId(appId);
}
@Override @Override
public PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO) { public PageResult<PayOrderDO> getOrderPage(PayOrderPageReqVO pageReqVO) {
return orderMapper.selectPage(pageReqVO); return orderMapper.selectPage(pageReqVO);

View File

@ -25,6 +25,14 @@ public interface PayRefundService {
*/ */
PayRefundDO getRefund(Long id); PayRefundDO getRefund(Long id);
/**
* 获得指定应用的退款数量
*
* @param appId 应用编号
* @return 退款数量
*/
Long getRefundCountByAppId(Long appId);
/** /**
* 获得退款订单分页 * 获得退款订单分页
* *

View File

@ -80,6 +80,11 @@ public class PayRefundServiceImpl implements PayRefundService {
return refundMapper.selectById(id); return refundMapper.selectById(id);
} }
@Override
public Long getRefundCountByAppId(Long appId) {
return refundMapper.selectCountByApp(appId);
}
@Override @Override
public PageResult<PayRefundDO> getRefundPage(PayRefundPageReqVO pageReqVO) { public PageResult<PayRefundDO> getRefundPage(PayRefundPageReqVO pageReqVO) {
return refundMapper.selectPage(pageReqVO); return refundMapper.selectPage(pageReqVO);

View File

@ -3,27 +3,37 @@ package cn.iocoder.yudao.module.pay.service.app;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
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;
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
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.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
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.LocalDateTime; import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
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.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.randomLongId; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_APP_NOT_FOUND; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_APP_NOT_FOUND;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
/**
* {@link PayAppServiceImpl} 的单元测试
*
* @author aquan
*/
@Import(PayAppServiceImpl.class) @Import(PayAppServiceImpl.class)
public class PayAppServiceTest extends BaseDbUnitTest { public class PayAppServiceTest extends BaseDbUnitTest {
@ -33,17 +43,23 @@ public class PayAppServiceTest extends BaseDbUnitTest {
@Resource @Resource
private PayAppMapper appMapper; private PayAppMapper appMapper;
@MockBean
private PayOrderService orderService;
@MockBean
private PayRefundService refundService;
@Test @Test
public void testCreateApp_success() { public void testCreateApp_success() {
// 准备参数 // 准备参数
PayAppCreateReqVO reqVO = randomPojo(PayAppCreateReqVO.class, o -> PayAppCreateReqVO reqVO = randomPojo(PayAppCreateReqVO.class, o ->
o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))); o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))
.setPayNotifyUrl(randomURL())
.setRefundNotifyUrl(randomURL()));
// 调用 // 调用
Long appId = appService.createApp(reqVO); Long appId = appService.createApp(reqVO);
// 断言 // 断言
assertNotNull(appId); assertNotNull(appId);
// 校验记录的属性是否正确
PayAppDO app = appMapper.selectById(appId); PayAppDO app = appMapper.selectById(appId);
assertPojoEquals(reqVO, app); assertPojoEquals(reqVO, app);
} }
@ -57,6 +73,7 @@ public class PayAppServiceTest extends BaseDbUnitTest {
// 准备参数 // 准备参数
PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> { PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setPayNotifyUrl(randomURL()).setRefundNotifyUrl(randomURL());
o.setId(dbApp.getId()); // 设置更新的 ID o.setId(dbApp.getId()); // 设置更新的 ID
}); });
@ -106,9 +123,6 @@ public class PayAppServiceTest extends BaseDbUnitTest {
PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到 PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到
o.setName("灿灿姐的杂货铺"); o.setName("灿灿姐的杂货铺");
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setRemark("敏敏姐的小卖铺");
o.setPayNotifyUrl("https://www.hc.com");
o.setRefundNotifyUrl("https://www.xm.com");
o.setCreateTime(buildTime(2021,11,20)); o.setCreateTime(buildTime(2021,11,20));
}); });
@ -117,22 +131,13 @@ public class PayAppServiceTest extends BaseDbUnitTest {
appMapper.insert(cloneIgnoreId(dbApp, o -> o.setName("敏敏姐的杂货铺"))); appMapper.insert(cloneIgnoreId(dbApp, o -> o.setName("敏敏姐的杂货铺")));
// 测试 status 不匹配 // 测试 status 不匹配
appMapper.insert(cloneIgnoreId(dbApp, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); appMapper.insert(cloneIgnoreId(dbApp, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 remark 不匹配
appMapper.insert(cloneIgnoreId(dbApp, o -> o.setRemark("灿灿姐的小卖部")));
// 测试 payNotifyUrl 不匹配
appMapper.insert(cloneIgnoreId(dbApp, o -> o.setPayNotifyUrl("xm.com")));
// 测试 refundNotifyUrl 不匹配
appMapper.insert(cloneIgnoreId(dbApp, o -> o.setRefundNotifyUrl("hc.com")));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
appMapper.insert(cloneIgnoreId(dbApp, o -> o.setCreateTime(buildTime(2021,12,21)))); appMapper.insert(cloneIgnoreId(dbApp, o -> o.setCreateTime(buildTime(2021,12,21))));
// 准备参数 // 准备参数
PayAppPageReqVO reqVO = new PayAppPageReqVO(); PayAppPageReqVO reqVO = new PayAppPageReqVO();
reqVO.setName("灿灿姐的杂货铺"); reqVO.setName("灿灿姐的杂货铺");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setRemark("敏敏姐的小卖铺"); reqVO.setCreateTime(buildBetweenTime(2021, 11, 19, 2021, 11, 21));
reqVO.setPayNotifyUrl("https://www.hc.com");
reqVO.setRefundNotifyUrl("https://www.xm.com");
reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021,11,19),buildTime(2021,11,21)}));
// 调用 // 调用
PageResult<PayAppDO> pageResult = appService.getAppPage(reqVO); PageResult<PayAppDO> pageResult = appService.getAppPage(reqVO);

View File

@ -1,4 +1,3 @@
DELETE FROM pay_merchant;
DELETE FROM pay_app; DELETE FROM pay_app;
DELETE FROM pay_channel; DELETE FROM pay_channel;
DELETE FROM pay_order; DELETE FROM pay_order;

View File

@ -1,18 +1,3 @@
CREATE TABLE IF NOT EXISTS "pay_merchant" (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"no" varchar(32) NOT NULL,
"name" varchar(64) NOT NULL,
"short_name" varchar(64) NOT NULL,
"status" tinyint NOT NULL,
"remark" varchar(255) DEFAULT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" datetime 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_app" ( CREATE TABLE IF NOT EXISTS "pay_app" (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(64) NOT NULL, "name" varchar(64) NOT NULL,
@ -20,14 +5,13 @@ CREATE TABLE IF NOT EXISTS "pay_app" (
"remark" varchar(255) DEFAULT NULL, "remark" varchar(255) DEFAULT NULL,
`pay_notify_url` varchar(1024) NOT NULL, `pay_notify_url` varchar(1024) NOT NULL,
`refund_notify_url` varchar(1024) NOT NULL, `refund_notify_url` varchar(1024) NOT NULL,
`merchant_id` bigint(20) NOT NULL,
"creator" varchar(64) DEFAULT '', "creator" varchar(64) DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '', "updater" varchar(64) DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit(1) NOT NULL DEFAULT FALSE, "deleted" bit(1) NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT = '支付应用信息'; ) COMMENT = '支付应用';
CREATE TABLE IF NOT EXISTS "pay_channel" ( CREATE TABLE IF NOT EXISTS "pay_channel" (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
@ -35,7 +19,6 @@ CREATE TABLE IF NOT EXISTS "pay_channel" (
"status" tinyint(4) NOT NULL, "status" tinyint(4) NOT NULL,
"remark" varchar(255) DEFAULT NULL, "remark" varchar(255) DEFAULT NULL,
"fee_rate" double NOT NULL DEFAULT 0, "fee_rate" double NOT NULL DEFAULT 0,
"merchant_id" bigint(20) NOT NULL,
"app_id" bigint(20) NOT NULL, "app_id" bigint(20) NOT NULL,
"config" varchar(10240) NOT NULL, "config" varchar(10240) NOT NULL,
"creator" varchar(64) NULL DEFAULT '', "creator" varchar(64) NULL DEFAULT '',
@ -49,7 +32,6 @@ CREATE TABLE IF NOT EXISTS "pay_channel" (
CREATE TABLE IF NOT EXISTS `pay_order` ( CREATE TABLE IF NOT EXISTS `pay_order` (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
`merchant_id` bigint(20) NOT NULL,
`app_id` bigint(20) NOT NULL, `app_id` bigint(20) NOT NULL,
`channel_id` bigint(20) DEFAULT NULL, `channel_id` bigint(20) DEFAULT NULL,
`channel_code` varchar(32) DEFAULT NULL, `channel_code` varchar(32) DEFAULT NULL,
@ -82,7 +64,6 @@ CREATE TABLE IF NOT EXISTS `pay_order` (
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,
`merchant_id` bigint(20) NOT NULL,
`app_id` bigint(20) NOT NULL, `app_id` bigint(20) NOT NULL,
`channel_id` bigint(20) NOT NULL, `channel_id` bigint(20) NOT NULL,
`channel_code` varchar(32) NOT NULL, `channel_code` varchar(32) NOT NULL,