Commit d556eae5569ad2faedd74e82f8973dd5c61ccf0d

Authored by chen quan
1 parent 08103685

优化 支付配置校验方式,优化业务层异常抛出类型,优化支付应用渲染逻辑,添加删除支付商户 支付应用的校验,退款订单去除reqNo字段,支付订单去除 channelExtras 参数展示

Showing 34 changed files with 267 additions and 300 deletions
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/PayAppController.java
1 1 package cn.iocoder.yudao.adminserver.modules.pay.controller.app;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.util.StrUtil;
5 4 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.*;
6 5 import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert;
7 6 import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService;
... ... @@ -10,12 +9,12 @@ import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantServ
10 9 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
11 10 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
12 11 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
13   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
14 12 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
15 13 import cn.iocoder.yudao.framework.common.pojo.PageResult;
16 14 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
17 15 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
18 16 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  17 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
19 18 import io.swagger.annotations.Api;
20 19 import io.swagger.annotations.ApiImplicitParam;
21 20 import io.swagger.annotations.ApiOperation;
... ... @@ -28,20 +27,11 @@ import javax.annotation.Resource;
28 27 import javax.servlet.http.HttpServletResponse;
29 28 import javax.validation.Valid;
30 29 import java.io.IOException;
31   -import java.lang.reflect.InvocationTargetException;
32   -import java.util.ArrayList;
33   -import java.util.Collection;
34   -import java.util.List;
35   -import java.util.Map;
  30 +import java.util.*;
36 31  
37 32 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
38 33 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
39 34  
40   -/**
41   - * 支付应用信息 controller 组件
42   - *
43   - * @author aquan
44   - */ // TODO @aquan:一般 controller 上就不写注释了,因为有 swagger 注解,不然就重复啦
45 35 @Slf4j
46 36 @Api(tags = "支付应用信息")
47 37 @RestController
... ... @@ -119,6 +109,7 @@ public class PayAppController {
119 109 // 得到所有的应用编号,查出所有的通道
120 110 Collection<Long> payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId);
121 111 List<PayChannelDO> channels = channelService.getChannelListByAppIds(payAppIds);
  112 + Iterator<PayChannelDO> iterator = channels.iterator();
122 113  
123 114 // 得到所有的商户信息
124 115 Collection<Long> merchantIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getMerchantId);
... ... @@ -132,22 +123,15 @@ public class PayAppController {
132 123 // 写入商户的数据
133 124 respVO.setPayMerchant(PayAppConvert.INSTANCE.convert(deptMap.get(app.getMerchantId())));
134 125 // 写入支付渠道信息的数据
135   - // TODO @aquan:VO 里返回的 payChannel,是不是用一个 Set 集合就好了,里面是渠道的枚举值
136   - PayAppPageItemRespVO.PayChannel payChannel = new PayAppPageItemRespVO.PayChannel();
137   - channels.forEach(c -> {
138   - if (c.getAppId().equals(app.getId())) {
139   - // 获取 set 方法
140   - String methodName = StrUtil.toCamelCase("set_" + c.getCode());
141   - try {
142   - // 根据 set 方法将值写入
143   - payChannel.getClass().getMethod(methodName, Integer.class)
144   - .invoke(payChannel, CommonStatusEnum.ENABLE.getStatus());
145   - } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
146   - log.error("[getAppPage]调用方法[{}]设置参数[{}]异常", c.getCode(), methodName);
147   - }
  126 + Set<String> channelCodes = new HashSet<>(PayChannelEnum.values().length);
  127 + while (iterator.hasNext()) {
  128 + PayChannelDO channelDO = iterator.next();
  129 + if (channelDO.getAppId().equals(app.getId())) {
  130 + channelCodes.add(channelDO.getCode());
  131 + iterator.remove();
148 132 }
149   - });
150   - respVO.setPayChannel(payChannel);
  133 + }
  134 + respVO.setChannelCodes(channelCodes);
151 135 appList.add(respVO);
152 136 });
153 137  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/vo/PayAppPageItemRespVO.java
1 1 package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
2 2  
3   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 3 import io.swagger.annotations.ApiModel;
5 4 import io.swagger.annotations.ApiModelProperty;
6 5 import lombok.Data;
... ... @@ -8,7 +7,13 @@ import lombok.EqualsAndHashCode;
8 7 import lombok.ToString;
9 8  
10 9 import java.util.Date;
  10 +import java.util.Set;
11 11  
  12 +/**
  13 + * 支付应用信息分页查询 Response VO
  14 + *
  15 + * @author aquan
  16 + */
12 17 @ApiModel(value = "支付应用信息分页查询 Response VO", description = "相比于支付信息,还会多出应用渠道的开关信息")
13 18 @Data
14 19 @EqualsAndHashCode(callSuper = true)
... ... @@ -38,39 +43,8 @@ public class PayAppPageItemRespVO extends PayAppBaseVO {
38 43  
39 44 }
40 45  
41   - /**
42   - * 支付渠道
43   - */
44   - private PayChannel payChannel;
45   -
46   - /**
47   - * 支付渠道开通情况
48   - * 1默认为未开通当前支付渠道,0为已开通支付渠道
49   - */
50   - @Data
51   - @ApiModel("支付渠道")
52   - public static class PayChannel {
53   -
54   - @ApiModelProperty(value = "微信 JSAPI 支付", required = true, example = "1")
55   - private Integer wxPub = CommonStatusEnum.DISABLE.getStatus();
  46 + @ApiModelProperty(value = "渠道编码集合", required = true, example = "alipay_pc,alipay_wap...")
  47 + private Set<String> channelCodes;
56 48  
57   - @ApiModelProperty(value = "微信小程序支付", required = true, example = "1")
58   - private Integer wxLite = CommonStatusEnum.DISABLE.getStatus();
59   -
60   - @ApiModelProperty(value = "微信 App 支付", required = true, example = "1")
61   - private Integer wxApp = CommonStatusEnum.DISABLE.getStatus();
62   -
63   - @ApiModelProperty(value = "支付宝 PC 网站支付", required = true, example = "1")
64   - private Integer alipayPc = CommonStatusEnum.DISABLE.getStatus();
65   -
66   - @ApiModelProperty(value = "支付宝 Wap 网站支付", required = true, example = "1")
67   - private Integer alipayWap = CommonStatusEnum.DISABLE.getStatus();
68   -
69   - @ApiModelProperty(value = "支付宝App 支付", required = true, example = "1")
70   - private Integer alipayApp = CommonStatusEnum.DISABLE.getStatus();
71   -
72   - @ApiModelProperty(value = "支付宝扫码支付", required = true, example = "1")
73   - private Integer alipayQr = CommonStatusEnum.DISABLE.getStatus();
74   - }
75 49  
76 50 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/merchant/PayMerchantController.java
... ... @@ -75,7 +75,7 @@ public class PayMerchantController {
75 75 return success(PayMerchantConvert.INSTANCE.convert(merchant));
76 76 }
77 77  
78   - @GetMapping("/list-name") // TODO @aquan:/list-name =》/list-by-name
  78 + @GetMapping("/list-by-name")
79 79 @ApiOperation("根据商户名称获得支付商户信息列表")
80 80 @ApiImplicitParam(name = "name", value = "商户名称", example = "芋道", dataTypeClass = Long.class)
81 81 @PreAuthorize("@ss.hasPermission('pay:merchant:query')")
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/merchant/vo/PayMerchantExcelVO.java
... ... @@ -2,11 +2,10 @@ package cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
4 4 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
5   -import lombok.*;
6   -import java.util.*;
7   -import io.swagger.annotations.*;
8   -
9 5 import com.alibaba.excel.annotation.ExcelProperty;
  6 +import lombok.Data;
  7 +
  8 +import java.util.Date;
10 9  
11 10 /**
12 11 * 支付商户信息 Excel VO
... ... @@ -29,7 +28,7 @@ public class PayMerchantExcelVO {
29 28 private String shortName;
30 29  
31 30 @ExcelProperty(value = "开启状态",converter = DictConvert.class)
32   - @DictFormat("pay_merchant_status")
  31 + @DictFormat("sys_common_status")
33 32 private Integer status;
34 33  
35 34 @ExcelProperty("备注")
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/order/vo/order/PayOrderDetailsRespVO.java
... ... @@ -46,9 +46,6 @@ public class PayOrderDetailsRespVO extends PayOrderBaseVO {
46 46 @ApiModelProperty(value = "支付订单号")
47 47 private String no;
48 48  
49   - @ApiModelProperty(value = "支付渠道的额外参数")
50   - private String channelExtras;
51   -
52 49 @ApiModelProperty(value = "支付异步通知的内容")
53 50 private String channelNotifyData;
54 51 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/order/vo/refund/vo/PayRefundBaseVO.java
... ... @@ -16,10 +16,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
16 16 @Data
17 17 public class PayRefundBaseVO {
18 18  
19   - @ApiModelProperty(value = "退款单请求号", required = true)
20   - @NotNull(message = "退款单请求号不能为空")
21   - private String reqNo;
22   -
23 19 @ApiModelProperty(value = "商户编号", required = true)
24 20 @NotNull(message = "商户编号不能为空")
25 21 private Long merchantId;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/order/vo/refund/vo/PayRefundExcelVO.java
... ... @@ -22,9 +22,6 @@ public class PayRefundExcelVO {
22 22 @ExcelProperty("商品名称")
23 23 private String subject;
24 24  
25   - @ExcelProperty("退款单请求号")
26   - private String reqNo;
27   -
28 25 @ExcelProperty(value = "商户名称")
29 26 private String merchantName;
30 27  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/order/vo/refund/vo/PayRefundExportReqVO.java
... ... @@ -13,9 +13,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
13 13 @Data
14 14 public class PayRefundExportReqVO {
15 15  
16   - @ApiModelProperty(value = "退款单请求号")
17   - private String reqNo;
18   -
19 16 @ApiModelProperty(value = "商户编号")
20 17 private Long merchantId;
21 18  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/order/vo/refund/vo/PayRefundPageReqVO.java
... ... @@ -18,9 +18,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
18 18 @ToString(callSuper = true)
19 19 public class PayRefundPageReqVO extends PageParam {
20 20  
21   - @ApiModelProperty(value = "退款单请求号")
22   - private String reqNo;
23   -
24 21 @ApiModelProperty(value = "商户编号")
25 22 private Long merchantId;
26 23  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/convert/order/PayOrderConvert.java
... ... @@ -8,8 +8,6 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
8 8 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
9 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 10 import org.mapstruct.Mapper;
11   -import org.mapstruct.Mapping;
12   -import org.mapstruct.Mappings;
13 11 import org.mapstruct.factory.Mappers;
14 12  
15 13 import java.math.BigDecimal;
... ... @@ -44,10 +42,6 @@ public interface PayOrderConvert {
44 42 * @param bean 订单扩展DO
45 43 * @return 详细订单扩展 RespVO
46 44 */
47   - @Mappings({
48   - @Mapping(target = "channelExtras"
49   - , expression = "java(bean.getChannelExtras() != null ? bean.getChannelExtras().toString():null)")
50   - })
51 45 PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
52 46  
53 47 List<PayOrderRespVO> convertList(List<PayOrderDO> list);
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/convert/refund/PayRefundConvert.java
... ... @@ -62,7 +62,6 @@ public interface PayRefundConvert {
62 62 PayRefundExcelVO payRefundExcelVO = new PayRefundExcelVO();
63 63  
64 64 payRefundExcelVO.setId(bean.getId());
65   - payRefundExcelVO.setReqNo(bean.getReqNo());
66 65 payRefundExcelVO.setTradeNo(bean.getTradeNo());
67 66 payRefundExcelVO.setMerchantOrderId(bean.getMerchantOrderId());
68 67 payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo());
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/app/PayAppMapper.java
... ... @@ -60,12 +60,24 @@ public interface PayAppMapper extends BaseMapperX&lt;PayAppDO&gt; {
60 60  
61 61 /**
62 62 * 根据 商户 ID 查询支付应用信息
  63 + *
63 64 * @param merchantId 商户 ID
64 65 * @return 支付应用信息列表
65 66 */
66   - default List<PayAppDO> getListByMerchantId(String merchantId){
  67 + default List<PayAppDO> getListByMerchantId(String merchantId) {
67 68 return selectList(new LambdaQueryWrapper<PayAppDO>()
68 69 .select(PayAppDO::getId, PayAppDO::getName)
69 70 .eq(PayAppDO::getMerchantId, merchantId));
70 71 }
  72 +
  73 + /**
  74 + * 根据商户号统计存在的支付应用数量
  75 + *
  76 + * @param merchantId 商户 ID
  77 + * @return 支付应用数量
  78 + */
  79 + default Long selectCount(Long merchantId) {
  80 + return selectCount(new LambdaQueryWrapper<PayAppDO>().eq(PayAppDO::getMerchantId, merchantId));
  81 + }
  82 +
71 83 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/channel/PayChannelMapper.java
... ... @@ -55,8 +55,7 @@ public interface PayChannelMapper extends BaseMapperX&lt;PayChannelDO&gt; {
55 55 * @param code 通道编码
56 56 * @return 数量
57 57 */
58   - // TODO @aquan:Mapper 的操作,和 db 保持一致
59   - default Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
  58 + default Integer selectCount(Long merchantId, Long appid, String code) {
60 59 return this.selectCount(new QueryWrapper<PayChannelDO>().lambda()
61 60 .eq(PayChannelDO::getMerchantId, merchantId)
62 61 .eq(PayChannelDO::getAppId, appid)
... ... @@ -71,7 +70,7 @@ public interface PayChannelMapper extends BaseMapperX&lt;PayChannelDO&gt; {
71 70 * @param code 通道编码
72 71 * @return 数量
73 72 */
74   - default PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
  73 + default PayChannelDO selectOne(Long merchantId, Long appid, String code) {
75 74 return this.selectOne((new QueryWrapper<PayChannelDO>().lambda()
76 75 .eq(PayChannelDO::getMerchantId, merchantId)
77 76 .eq(PayChannelDO::getAppId, appid)
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/order/PayOrderMapper.java
... ... @@ -62,4 +62,18 @@ public interface PayOrderMapper extends BaseMapperX&lt;PayOrderDO&gt; {
62 62 .in(PayOrderDO::getId, idList));
63 63 }
64 64  
  65 + /**
  66 + * 查询符合的订单数量
  67 + *
  68 + * @param appId 应用编号
  69 + * @param status 订单状态
  70 + * @return 条数
  71 + */
  72 + default Long selectCount(Long appId, Integer status) {
  73 +
  74 + return selectCount(new LambdaQueryWrapper<PayOrderDO>()
  75 + .eq(PayOrderDO::getAppId, appId)
  76 + .in(PayOrderDO::getStatus, status));
  77 + }
  78 +
65 79 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/order/PayRefundMapper.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
8 8 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
  9 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
9 10 import org.apache.ibatis.annotations.Mapper;
10 11  
11 12 import java.util.List;
... ... @@ -20,7 +21,6 @@ public interface PayRefundMapper extends BaseMapperX&lt;PayRefundDO&gt; {
20 21  
21 22 default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
22 23 return selectPage(reqVO, new QueryWrapperX<PayRefundDO>()
23   - .likeIfPresent("req_no", reqVO.getReqNo())
24 24 .eqIfPresent("merchant_id", reqVO.getMerchantId())
25 25 .eqIfPresent("app_id", reqVO.getAppId())
26 26 .eqIfPresent("channel_code", reqVO.getChannelCode())
... ... @@ -37,7 +37,6 @@ public interface PayRefundMapper extends BaseMapperX&lt;PayRefundDO&gt; {
37 37 .eqIfPresent("merchant_id", reqVO.getMerchantId())
38 38 .eqIfPresent("app_id", reqVO.getAppId())
39 39 .eqIfPresent("channel_code", reqVO.getChannelCode())
40   - .likeIfPresent("req_no", reqVO.getReqNo())
41 40 .likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())
42 41 .eqIfPresent("type", reqVO.getType())
43 42 .eqIfPresent("status", reqVO.getStatus())
... ... @@ -46,4 +45,17 @@ public interface PayRefundMapper extends BaseMapperX&lt;PayRefundDO&gt; {
46 45 .orderByDesc("id"));
47 46 }
48 47  
  48 + /**
  49 + * 查询符合的订单数量
  50 + *
  51 + * @param appId 应用编号
  52 + * @param status 订单状态
  53 + * @return 条数
  54 + */
  55 + default Long selectCount(Long appId, Integer status) {
  56 +
  57 + return selectCount(new LambdaQueryWrapper<PayRefundDO>()
  58 + .eq(PayRefundDO::getAppId, appId)
  59 + .eq(PayRefundDO::getStatus, status));
  60 + }
49 61 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/impl/PayAppServiceImpl.java
... ... @@ -9,9 +9,13 @@ import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateRe
9 9 import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert;
10 10 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper;
11 11 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
  12 +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.order.PayOrderMapper;
  13 +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.order.PayRefundMapper;
12 14 import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService;
13 15 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
14 16 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
  17 +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
  18 +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
15 19 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
16 20 import cn.iocoder.yudao.framework.common.pojo.PageResult;
17 21 import com.google.common.annotations.VisibleForTesting;
... ... @@ -21,7 +25,7 @@ import org.springframework.validation.annotation.Validated;
21 25 import javax.annotation.Resource;
22 26 import java.util.*;
23 27  
24   -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_APP_NOT_FOUND;
  28 +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
25 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26 30 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
27 31  
... ... @@ -36,9 +40,17 @@ public class PayAppServiceImpl implements PayAppService {
36 40  
37 41 @Resource
38 42 private PayAppMapper appMapper;
  43 +
39 44 @Resource
40 45 private PayMerchantMapper merchantMapper;
41 46  
  47 + @Resource
  48 + private PayOrderMapper orderMapper;
  49 +
  50 + @Resource
  51 + private PayRefundMapper refundMapper;
  52 +
  53 +
42 54 @Override
43 55 public Long createApp(PayAppCreateReqVO createReqVO) {
44 56 // 插入
... ... @@ -61,7 +73,8 @@ public class PayAppServiceImpl implements PayAppService {
61 73 public void deleteApp(Long id) {
62 74 // 校验存在
63 75 this.validateAppExists(id);
64   - // TODO aquan:校验是否存在进行中的支付单、退款单,如果是,则不允许删除。
  76 + this.validateOrderTransactionExist(id);
  77 +
65 78 // 删除
66 79 appMapper.deleteById(id);
67 80 }
... ... @@ -157,4 +170,21 @@ public class PayAppServiceImpl implements PayAppService {
157 170 }
158 171 }
159 172  
  173 + /**
  174 + * 验证是否存在交易中或者退款中等处理中状态的订单
  175 + *
  176 + * @param appId 应用 ID
  177 + */
  178 + private void validateOrderTransactionExist(Long appId) {
  179 + // 查看交易订单
  180 + if (orderMapper.selectCount(appId, PayOrderStatusEnum.WAITING.getStatus()) > 0) {
  181 + throw exception(PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE);
  182 + }
  183 + // 查看退款订单
  184 + if (refundMapper.selectCount(appId, PayRefundStatusEnum.CREATE.getStatus()) > 0) {
  185 + throw exception(PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE);
  186 + }
  187 +
  188 + }
  189 +
160 190 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/impl/PayChannelServiceImpl.java
1 1 package cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl;
2 2  
  3 +import cn.hutool.core.util.ObjectUtil;
3 4 import cn.hutool.json.JSONUtil;
4 5 import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelCreateReqVO;
5 6 import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelExportReqVO;
... ... @@ -14,7 +15,6 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
14 15 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
15 16 import lombok.extern.slf4j.Slf4j;
16 17 import org.springframework.stereotype.Service;
17   -import org.springframework.util.Assert;
18 18 import org.springframework.validation.annotation.Validated;
19 19  
20 20 import javax.annotation.Resource;
... ... @@ -46,8 +46,9 @@ public class PayChannelServiceImpl implements PayChannelService {
46 46 public Long createChannel(PayChannelCreateReqVO reqVO) {
47 47 // 断言是否有重复的
48 48 PayChannelDO channelDO = this.getChannelByConditions(reqVO.getMerchantId(), reqVO.getAppId(), reqVO.getCode());
49   - // TODO @aquan:这里会抛出系统异常,不会抛出 ServiceException
50   - Assert.isNull(channelDO, CHANNEL_EXIST_SAME_CHANNEL_ERROR.getMsg());
  49 + if (ObjectUtil.isNotNull(channelDO)) {
  50 + throw exception(CHANNEL_EXIST_SAME_CHANNEL_ERROR);
  51 + }
51 52  
52 53 // 新增渠道
53 54 PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO);
... ... @@ -122,7 +123,7 @@ public class PayChannelServiceImpl implements PayChannelService {
122 123 */
123 124 @Override
124 125 public Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
125   - return this.channelMapper.getChannelCountByConditions(merchantId, appid, code);
  126 + return this.channelMapper.selectCount(merchantId, appid, code);
126 127 }
127 128  
128 129 /**
... ... @@ -135,7 +136,7 @@ public class PayChannelServiceImpl implements PayChannelService {
135 136 */
136 137 @Override
137 138 public PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
138   - return this.channelMapper.getChannelByConditions(merchantId, appid, code);
  139 + return this.channelMapper.selectOne(merchantId, appid, code);
139 140 }
140 141  
141 142 /**
... ... @@ -146,11 +147,14 @@ public class PayChannelServiceImpl implements PayChannelService {
146 147 */
147 148 private void settingConfigAndCheckParam(PayChannelDO channel, String configStr) {
148 149 // 得到这个渠道是微信的还是支付宝的
149   - Class<? extends PayClientConfig> payClass = PayChannelEnum.findByCodeGetClass(channel.getCode());
150   - Assert.notNull(payClass, CHANNEL_NOT_EXISTS.getMsg());
  150 + Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(channel.getCode()).getConfigClass();
  151 + if (ObjectUtil.isNull(payClass)) {
  152 + throw exception(CHANNEL_NOT_EXISTS);
  153 + }
151 154 PayClientConfig config = JSONUtil.toBean(configStr, payClass);
  155 +
152 156 // 验证参数
153   - config.verifyParam(validator);
  157 + config.validate(validator);
154 158 channel.setConfig(config);
155 159 }
156 160  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantService.java
... ... @@ -16,7 +16,7 @@ import java.util.Map;
16 16 /**
17 17 * 支付商户信息 Service 接口
18 18 *
19   - * @author 芋艿 TODO @aquan:作者是你哈
  19 + * @author aquan
20 20 */
21 21 public interface PayMerchantService {
22 22  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/impl/PayMerchantServiceImpl.java
1 1 package cn.iocoder.yudao.adminserver.modules.pay.service.merchant.impl;
2 2  
3 3 import cn.hutool.core.date.DateUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
4 5 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantCreateReqVO;
5 6 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantExportReqVO;
6 7 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantPageReqVO;
7 8 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantUpdateReqVO;
8 9 import cn.iocoder.yudao.adminserver.modules.pay.convert.merchant.PayMerchantConvert;
  10 +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper;
9 11 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
10 12 import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService;
11 13 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
... ... @@ -19,6 +21,7 @@ import java.time.LocalDateTime;
19 21 import java.util.Collection;
20 22 import java.util.List;
21 23  
  24 +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_MERCHANT_EXIST_APP_CANT_DELETE;
22 25 import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_MERCHANT_NOT_EXISTS;
23 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 27  
... ... @@ -34,6 +37,9 @@ public class PayMerchantServiceImpl implements PayMerchantService {
34 37 @Resource
35 38 private PayMerchantMapper merchantMapper;
36 39  
  40 + @Resource
  41 + private PayAppMapper appMapper;
  42 +
37 43 @Override
38 44 public Long createMerchant(PayMerchantCreateReqVO createReqVO) {
39 45 // 插入
... ... @@ -55,19 +61,13 @@ public class PayMerchantServiceImpl implements PayMerchantService {
55 61  
56 62 @Override
57 63 public void deleteMerchant(Long id) {
58   - // 校验存在
  64 + // 校验
59 65 this.validateMerchantExists(id);
60   - // TODO @aquan:需要校验 PayApp 是否都在。如果在的情况下,不允许删除
  66 + this.validateAppExists(id);
61 67 // 删除
62 68 merchantMapper.deleteById(id);
63 69 }
64 70  
65   - private void validateMerchantExists(Long id) {
66   - if (merchantMapper.selectById(id) == null) {
67   - throw exception(PAY_MERCHANT_NOT_EXISTS);
68   - }
69   - }
70   -
71 71 @Override
72 72 public PayMerchantDO getMerchant(Long id) {
73 73 return merchantMapper.selectById(id);
... ... @@ -88,13 +88,6 @@ public class PayMerchantServiceImpl implements PayMerchantService {
88 88 return merchantMapper.selectList(exportReqVO);
89 89 }
90 90  
91   - // TODO @aquan:接口上已经有注释,这里不用在有啦
92   - /**
93   - * 修改商户状态
94   - *
95   - * @param id 商户编号
96   - * @param status 状态
97   - */
98 91 @Override
99 92 public void updateMerchantStatus(Long id, Integer status) {
100 93 // 校验商户存在
... ... @@ -106,21 +99,11 @@ public class PayMerchantServiceImpl implements PayMerchantService {
106 99 merchantMapper.updateById(merchant);
107 100 }
108 101  
109   - /**
110   - * 根据商户名称模糊查询商户集合
111   - *
112   - * @param merchantName 商户名称
113   - * @return 商户集合
114   - */
115 102 @Override
116 103 public List<PayMerchantDO> getMerchantListByName(String merchantName) {
117 104 return this.merchantMapper.getMerchantListByName(merchantName);
118 105 }
119 106  
120   - /**
121   - * 检查商户是否存在
122   - * @param id 商户编号
123   - */
124 107 @VisibleForTesting
125 108 public void checkMerchantExists(Long id) {
126 109 if (id == null) {
... ... @@ -132,6 +115,27 @@ public class PayMerchantServiceImpl implements PayMerchantService {
132 115 }
133 116 }
134 117  
  118 + /**
  119 + * 校验商户是否存在
  120 + *
  121 + * @param id 商户 ID
  122 + */
  123 + private void validateMerchantExists(Long id) {
  124 + if (ObjectUtil.isNull(merchantMapper.selectById(id))) {
  125 + throw exception(PAY_MERCHANT_NOT_EXISTS);
  126 + }
  127 + }
  128 +
  129 + /**
  130 + * 校验商户是否还存在支付应用
  131 + *
  132 + * @param id 商户ID
  133 + */
  134 + private void validateAppExists(Long id) {
  135 + if (appMapper.selectCount(id) > 0) {
  136 + throw exception(PAY_MERCHANT_EXIST_APP_CANT_DELETE);
  137 + }
  138 + }
135 139  
136 140 // TODO @芋艿:后续增加下合适的算法
137 141 /**
... ... @@ -139,8 +143,8 @@ public class PayMerchantServiceImpl implements PayMerchantService {
139 143 *
140 144 * @return 商户号
141 145 */
142   - private String generateMerchantNo(){
143   - return "M" + DateUtil.format(LocalDateTime.now(),"yyyyMMddHHmmssSSS");
  146 + private String generateMerchantNo() {
  147 + return "M" + DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmssSSS");
144 148 }
145 149  
146 150 }
... ...
yudao-admin-server/src/main/resources/application.yaml
... ... @@ -75,6 +75,4 @@ yudao:
75 75 - cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
76 76 tenant: # 多租户相关配置项
77 77 tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置
78   - pay:
79   - payReturnUrl: http://127.0.0.1 # TODO @aquan:这个变量,配置到 dev 或者 local 里,不同环境有差别哈
80 78 debug: false
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/refund/PayRefundServiceTest.java
... ... @@ -72,8 +72,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
72 72 o.setUpdateTime(DateUtils.buildTime(2021, 1, 1, 10, 10, 35));
73 73 });
74 74 refundMapper.insert(dbRefund);
75   - // 测试 reqNo 不匹配
76   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setReqNo("RF1111112")));
77 75 // 测试 merchantId 不匹配
78 76 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantId(2L)));
79 77 // 测试 appId 不匹配
... ... @@ -94,7 +92,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
94 92 o.setCreateTime(DateUtils.buildTime(2022, 1, 1, 10, 10, 10))));
95 93 // 准备参数
96 94 PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
97   - reqVO.setReqNo("RF0000001");
98 95 reqVO.setMerchantId(1L);
99 96 reqVO.setAppId(1L);
100 97 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
... ... @@ -147,8 +144,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
147 144 o.setUpdateTime(DateUtils.buildTime(2021, 1, 1, 10, 10, 35));
148 145 });
149 146 refundMapper.insert(dbRefund);
150   - // 测试 reqNo 不匹配
151   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setReqNo("RF1111112")));
152 147 // 测试 merchantId 不匹配
153 148 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantId(2L)));
154 149 // 测试 appId 不匹配
... ... @@ -170,7 +165,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
170 165  
171 166 // 准备参数
172 167 PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
173   - reqVO.setReqNo("RF0000001");
174 168 reqVO.setMerchantId(1L);
175 169 reqVO.setAppId(1L);
176 170 reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
... ...
yudao-admin-ui/src/api/pay/merchant.js
... ... @@ -49,7 +49,7 @@ export function getMerchant(id) {
49 49 // 根据商户名称搜索商户列表
50 50 export function getMerchantListByName(name) {
51 51 return request({
52   - url: '/pay/merchant/list-name',
  52 + url: '/pay/merchant/list-by-name',
53 53 params:{
54 54 name:name
55 55 },
... ...
yudao-admin-ui/src/utils/dict.js
... ... @@ -34,12 +34,6 @@ export const DICT_TYPE = {
34 34 OA_LEAVE_STATUS: 'oa_leave_status',
35 35 OA_LEAVE_TYPE: 'oa_leave_type',
36 36  
37   - // 商户状态
38   - PAY_MERCHANT_STATUS: 'pay_merchant_status', // TODO @aquan:一般使用 COMMON_RESULT 即可。保持数值一致,以后加更多状态的时候,在单独数据字典
39   - // 应用状态
40   - PAY_APP_STATUS: 'pay_app_status',
41   - // 渠道状态
42   - PAY_CHANNEL_STATUS: 'pay_channel_status',
43 37 // 微信渠道版本
44 38 PAY_CHANNEL_WECHAT_VERSION:'pay_channel_wechat_version',
45 39 // 支付渠道支付宝算法类型
... ...
yudao-admin-ui/src/views/pay/app/components/aliPayChannelForm.vue
1 1 <template>
2 2 <div>
3   - <el-dialog :visible.sync="transferParam.aliPayOpen" @closed="close" append-to-body width="800px">
  3 + <el-dialog :visible.sync="transferParam.aliPayOpen" :title="title" @closed="close" append-to-body width="800px">
4 4 <el-form ref="aliPayForm" :model="form" :rules="rules" size="medium" label-width="100px"
5 5 v-loading="transferParam.loading">
6 6 <el-form-item label-width="180px" label="渠道费率" prop="feeRate">
... ... @@ -172,6 +172,7 @@ export default {
172 172 },
173 173 data() {
174 174 return {
  175 + title:'',
175 176 form: JSON.parse(JSON.stringify(defaultForm)),
176 177 rules: {
177 178 feeRate: [{
... ... @@ -232,7 +233,7 @@ export default {
232 233 },
233 234 fileAccept: ".crt",
234 235 // 渠道状态 数据字典
235   - statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS),
  236 + statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
236 237 // 支付宝加密方式
237 238 aliPaySignTypeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SIGN_TYPE),
238 239 // 版本状态 数据字典
... ... @@ -251,7 +252,10 @@ export default {
251 252 this.form.merchantId = newVal.payMerchant.id;
252 253 // 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
253 254 if (newVal.edit === true && newVal.loading) {
  255 + this.title = "编辑支付渠道";
254 256 this.init();
  257 + } else {
  258 + this.title = "创建支付渠道";
255 259 }
256 260 }
257 261 }
... ...
yudao-admin-ui/src/views/pay/app/components/wechatChannelForm.vue
1 1 <template>
2 2 <div>
3   - <el-dialog :visible.sync="transferParam.wechatOpen" @close="close" append-to-body width="800px">
  3 + <el-dialog :visible.sync="transferParam.wechatOpen" :title="title" @close="close" append-to-body width="800px">
4 4 <el-form ref="wechatJsApiForm" :model="form" :rules="rules" size="medium" label-width="100px"
5 5 v-loading="transferParam.loading">
6 6 <el-form-item label-width="180px" label="渠道费率" prop="feeRate">
... ... @@ -134,6 +134,7 @@ export default {
134 134 },
135 135 data() {
136 136 return {
  137 + title:'',
137 138 form: JSON.parse(JSON.stringify(defaultForm)),
138 139 rules: {
139 140 feeRate: [{
... ... @@ -188,7 +189,7 @@ export default {
188 189 },
189 190 fileAccept: ".pem",
190 191 // 渠道状态 数据字典
191   - statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS),
  192 + statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
192 193 versionDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_WECHAT_VERSION),
193 194 }
194 195 },
... ... @@ -202,7 +203,10 @@ export default {
202 203 this.form.merchantId = newVal.payMerchant.id;
203 204 // 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
204 205 if (newVal.edit && newVal.loading) {
  206 + this.title = "编辑支付渠道";
205 207 this.init();
  208 + } else {
  209 + this.title = "创建支付渠道";
206 210 }
207 211 }
208 212 }
... ...
yudao-admin-ui/src/views/pay/app/index.vue
... ... @@ -57,59 +57,49 @@
57 57 <el-table-column label="支付宝配置" align="center">
58 58 <el-table-column :label="payChannelEnum.ALIPAY_APP.name" align="center">
59 59 <template slot-scope="scope">
60   - <el-button
61   - type="success" icon="el-icon-check" circle
62   - @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)"
63   - v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.ENABLE">
  60 + <el-button type="success" icon="el-icon-check" circle
  61 + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_APP.code)"
  62 + @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
64 63 </el-button>
65   - <el-button
66   - type="danger" icon="el-icon-close" circle
67   - @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)"
68   - v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.DISABLE">
  64 + <el-button v-else
  65 + type="danger" icon="el-icon-close" circle
  66 + @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
69 67 </el-button>
70 68 </template>
71 69 </el-table-column>
72 70 <el-table-column :label="payChannelEnum.ALIPAY_PC.name" align="center">
73 71 <template slot-scope="scope">
74   - <el-button
75   - type="success" icon="el-icon-check" circle
76   - @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_PC.code,payType.ALIPAY)"
77   - v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.ENABLE">
  72 + <el-button type="success" icon="el-icon-check" circle
  73 + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_PC.code)"
  74 + @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
78 75 </el-button>
79   - <el-button
80   - type="danger" icon="el-icon-close" circle
81   - @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_PC.code,payType.ALIPAY)"
82   - v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.DISABLE">
  76 + <el-button v-else
  77 + type="danger" icon="el-icon-close" circle
  78 + @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_PC.code,payType.ALIPAY)">
83 79 </el-button>
84 80 </template>
85 81 </el-table-column>
86 82 <el-table-column :label="payChannelEnum.ALIPAY_WAP.name" align="center">
87 83 <template slot-scope="scope">
88   - <el-button
89   - type="success" icon="el-icon-check" circle
90   - @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_WAP.code,payType.ALIPAY)"
91   - v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.ENABLE">
  84 + <el-button type="success" icon="el-icon-check" circle
  85 + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_WAP.code)"
  86 + @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
92 87 </el-button>
93   - <el-button
94   - type="danger" icon="el-icon-close" circle
95   - @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_WAP.code,payType.ALIPAY)"
96   - v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.DISABLE">
  88 + <el-button v-else
  89 + type="danger" icon="el-icon-close" circle
  90 + @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_WAP.code,payType.ALIPAY)">
97 91 </el-button>
98 92 </template>
99 93 </el-table-column>
100 94 <el-table-column :label="payChannelEnum.ALIPAY_QR.name" align="center">
101 95 <template slot-scope="scope">
102   - <el-button
103   - type="success" icon="el-icon-check" circle
104   - @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_QR.code,payType.ALIPAY)"
105   - v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.ENABLE">
106   -
  96 + <el-button type="success" icon="el-icon-check" circle
  97 + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_QR.code)"
  98 + @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
107 99 </el-button>
108   - <el-button
109   - type="danger" icon="el-icon-close" circle
110   - @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_QR.code,payType.ALIPAY)"
111   - v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.DISABLE">
112   -
  100 + <el-button v-else
  101 + type="danger" icon="el-icon-close" circle
  102 + @click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_QR.code,payType.ALIPAY)">
113 103 </el-button>
114 104 </template>
115 105 </el-table-column>
... ... @@ -117,43 +107,37 @@
117 107 <el-table-column label="微信配置" align="center">
118 108 <el-table-column :label="payChannelEnum.WX_LITE.name" align="center">
119 109 <template slot-scope="scope">
120   - <el-button
121   - type="success" icon="el-icon-check" circle
122   - @click="handleUpdateChannel(scope.row,payChannelEnum.WX_LITE.code,payType.WECHAT)"
123   - v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.ENABLE">
  110 + <el-button type="success" icon="el-icon-check" circle
  111 + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_LITE.code)"
  112 + @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.WECHAT)">
124 113 </el-button>
125   - <el-button
126   - type="danger" icon="el-icon-close" circle
127   - @click="handleCreateChannel(scope.row,payChannelEnum.WX_LITE.code,payType.WECHAT)"
128   - v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.DISABLE">
  114 + <el-button v-else
  115 + type="danger" icon="el-icon-close" circle
  116 + @click="handleCreateChannel(scope.row,payChannelEnum.WX_LITE.code,payType.WECHAT)">
129 117 </el-button>
130 118 </template>
131 119 </el-table-column>
132 120 <el-table-column :label="payChannelEnum.WX_PUB.name" align="center">
133 121 <template slot-scope="scope">
134   - <el-button
135   - type="success" icon="el-icon-check" circle
136   - @click="handleUpdateChannel(scope.row,payChannelEnum.WX_PUB.code,payType.WECHAT)"
137   - v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.ENABLE">
  122 + <el-button type="success" icon="el-icon-check" circle
  123 + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_PUB.code)"
  124 + @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.WECHAT)">
138 125 </el-button>
139   - <el-button
140   - type="danger" icon="el-icon-close" circle
141   - @click="handleCreateChannel(scope.row,payChannelEnum.WX_PUB.code,payType.WECHAT)"
142   - v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.DISABLE">
  126 + <el-button v-else
  127 + type="danger" icon="el-icon-close" circle
  128 + @click="handleCreateChannel(scope.row,payChannelEnum.WX_PUB.code,payType.WECHAT)">
143 129 </el-button>
144 130 </template>
145 131 </el-table-column>
146 132 <el-table-column :label="payChannelEnum.WX_APP.name" align="center">
147 133 <template slot-scope="scope">
148   - <el-button
149   - type="success" icon="el-icon-check" circle
150   - @click="handleUpdateChannel(scope.row,payChannelEnum.WX_APP.code,payType.WECHAT)"
151   - v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.ENABLE">
  134 + <el-button type="success" icon="el-icon-check" circle
  135 + v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_APP.code)"
  136 + @click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.WECHAT)">
152 137 </el-button>
153   - <el-button
154   - type="danger" icon="el-icon-close" circle
155   - @click="handleCreateChannel(scope.row,payChannelEnum.WX_APP.code,payType.WECHAT)"
156   - v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.DISABLE">
  138 + <el-button v-else
  139 + type="danger" icon="el-icon-close" circle
  140 + @click="handleCreateChannel(scope.row,payChannelEnum.WX_APP.code,payType.WECHAT)">
157 141 </el-button>
158 142 </template>
159 143 </el-table-column>
... ... @@ -276,7 +260,7 @@ export default {
276 260 merchantId: [{required: true, message: "商户编号不能为空", trigger: "blur"}],
277 261 },
278 262 // 数据字典
279   - statusDictDatas: getDictDatas(DICT_TYPE.PAY_APP_STATUS),
  263 + statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
280 264 sysCommonStatusEnum: SysCommonStatusEnum,
281 265 // 支付渠道枚举
282 266 payChannelEnum: PayChannelEnum,
... ... @@ -322,6 +306,7 @@ export default {
322 306 // 执行查询
323 307 getAppPage(params).then(response => {
324 308 this.list = response.data.list;
  309 + console.log(this.list);
325 310 this.total = response.data.total;
326 311 this.loading = false;
327 312 });
... ... @@ -422,7 +407,12 @@ export default {
422 407 }).then(() => {
423 408 this.getList();
424 409 this.msgSuccess("删除成功");
425   - })
  410 + }).catch(() => {
  411 + this.$message({
  412 + type: 'info',
  413 + message: '已取消删除'
  414 + });
  415 + });
426 416 },
427 417 /** 导出按钮操作 */
428 418 handleExport() {
... ... @@ -486,6 +476,14 @@ export default {
486 476 this.channelParam.payCode = payCode;
487 477 this.channelParam.payMerchant = row.payMerchant;
488 478 },
  479 + /**
  480 + * 根据渠道编码判断渠道列表中是否存在
  481 + * @param channels 渠道列表
  482 + * @param channelCode 渠道编码
  483 + */
  484 + judgeChannelExist(channels, channelCode) {
  485 + return channels.indexOf(channelCode) !== -1;
  486 + },
489 487 refreshTable() {
490 488 this.getList();
491 489 }
... ...
yudao-admin-ui/src/views/pay/merchant/index.vue
... ... @@ -154,8 +154,8 @@ export default {
154 154 shortName: [{ required: true, message: "商户简称不能为空", trigger: "blur" }],
155 155 status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }],
156 156 },
157   - // 数据字典
158   - statusDictDatas: getDictDatas(DICT_TYPE.PAY_MERCHANT_STATUS)
  157 + // 商户状态数据字典
  158 + statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)
159 159 };
160 160 },
161 161 created() {
... ...
yudao-admin-ui/src/views/pay/order/index.vue
... ... @@ -236,9 +236,6 @@
236 236 <el-descriptions-item label="商品描述">
237 237 {{ orderDetail.body }}
238 238 </el-descriptions-item>
239   - <el-descriptions-item label="支付通道额外扩展参数">
240   - {{ orderDetail.payOrderExtension.channelExtras }}
241   - </el-descriptions-item>
242 239 <el-descriptions-item label="支付通道异步回调内容">
243 240 {{ orderDetail.payOrderExtension.channelNotifyData }}
244 241 </el-descriptions-item>
... ... @@ -278,7 +275,6 @@ const defaultOrderDetail = {
278 275 notifyTime: '',
279 276 expireTime: '',
280 277 payOrderExtension: {
281   - channelExtras: '',
282 278 channelNotifyData: '',
283 279 no: ''
284 280 }
... ...
yudao-admin-ui/src/views/pay/refund/index.vue
... ... @@ -43,20 +43,17 @@
43 43 <el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
44 44 </el-select>
45 45 </el-form-item>
46   - <el-form-item label="退款单号" prop="reqNo">
47   - <el-input v-model="queryParams.reqNo" placeholder="请输入退款单请求号" clearable size="small"
48   - @keyup.enter.native="handleQuery"/>
49   - </el-form-item>
50   - <el-form-item label="商户退款订单号" prop="merchantRefundNo">
51   - <el-input v-model="queryParams.merchantRefundNo" placeholder="请输入商户退款订单号" clearable size="small"
52   - @keyup.enter.native="handleQuery"/>
53   - </el-form-item>
54 46 <el-form-item label="退款类型" prop="type">
55 47 <el-select v-model="queryParams.type" placeholder="请选择退款类型" clearable size="small">
56 48 <el-option v-for="dict in payRefundOrderTypeDictDatum" :key="parseInt(dict.value)"
57 49 :label="dict.label" :value="parseInt(dict.value)"/>
58 50 </el-select>
59 51 </el-form-item>
  52 + <el-form-item label="商户退款订单号" prop="merchantRefundNo">
  53 + <el-input v-model="queryParams.merchantRefundNo" placeholder="请输入商户退款订单号" clearable size="small"
  54 + @keyup.enter.native="handleQuery"/>
  55 + </el-form-item>
  56 +
60 57 <el-form-item label="退款状态" prop="status">
61 58 <el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable size="small">
62 59 <el-option v-for="dict in payRefundOrderDictDatum" :key="parseInt(dict.value)"
... ... @@ -112,15 +109,15 @@
112 109 </el-table-column>
113 110 <!-- <el-table-column label="交易订单号" align="center" prop="tradeNo" width="140"/>-->
114 111 <!-- <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" width="140"/>-->
115   - <el-table-column label="退款订单号" align="left" width="230">
  112 + <el-table-column label="商户订单号" align="left" width="230">
116 113 <template v-slot="scope">
117 114 <p class="order-font">
118 115 <el-tag size="mini">退款</el-tag>
119   - {{ scope.row.reqNo }}
  116 + {{ scope.row.merchantRefundNo }}
120 117 </p>
121 118 <p class="order-font">
122   - <el-tag size="mini" type="success">商户</el-tag>
123   - {{ scope.row.merchantRefundNo }}
  119 + <el-tag type="success">交易</el-tag>
  120 + {{ scope.row.merchantOrderId }}
124 121 </p>
125 122 </template>
126 123 </el-table-column>
... ... @@ -202,9 +199,6 @@
202 199 <el-descriptions-item label="商户退款单号">
203 200 <el-tag size="mini">{{ refundDetail.merchantRefundNo }}</el-tag>
204 201 </el-descriptions-item>
205   - <el-descriptions-item label="商户退款请求单号" size="mini">
206   - <el-tag type="success" size="mini">{{ refundDetail.reqNo }}</el-tag>
207   - </el-descriptions-item>
208 202 <el-descriptions-item label="商户订单号">{{ refundDetail.merchantOrderId }}</el-descriptions-item>
209 203 <el-descriptions-item label="交易订单号">{{ refundDetail.tradeNo }}</el-descriptions-item>
210 204 </el-descriptions>
... ... @@ -299,7 +293,6 @@ const defaultRefundDetail = {
299 293 payAmount: null,
300 294 reason: '',
301 295 refundAmount: null,
302   - reqNo: '',
303 296 status: null,
304 297 subject: '',
305 298 successTime: null,
... ... @@ -333,7 +326,6 @@ export default {
333 326 queryParams: {
334 327 pageNo: 1,
335 328 pageSize: 10,
336   - reqNo: null,
337 329 merchantId: null,
338 330 appId: null,
339 331 channelId: null,
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java
... ... @@ -14,6 +14,7 @@ public interface PayErrorCodeCoreConstants {
14 14 */
15 15 ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
16 16 ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
  17 + ErrorCode PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在交易中的订单,无法删除");
17 18  
18 19 /**
19 20 * ========== CHANNEL 模块 1-007-001-000 ==========
... ... @@ -54,6 +55,7 @@ public interface PayErrorCodeCoreConstants {
54 55 * ========== 支付商户信息 1-007-004-000 ==========
55 56 */
56 57 ErrorCode PAY_MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
  58 + ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除");
57 59  
58 60  
59 61  
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java
1 1 package cn.iocoder.yudao.framework.pay.core.client;
2 2  
3   -import cn.hutool.json.JSONUtil;
4   -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
5 3 import com.fasterxml.jackson.annotation.JsonTypeInfo;
6 4  
  5 +import javax.validation.ConstraintViolation;
  6 +import javax.validation.ConstraintViolationException;
7 7 import javax.validation.Validator;
  8 +import java.util.Set;
8 9  
9 10 /**
10 11 * 支付客户端的配置,本质是支付渠道的配置
... ... @@ -19,8 +20,22 @@ import javax.validation.Validator;
19 20 public interface PayClientConfig {
20 21  
21 22 /**
22   - * 验证配置参数是否正确
  23 + * 配置验证参数是
  24 + *
23 25 * @param validator 校验对象
  26 + * @return 配置好的验证参数
24 27 */
25   - void verifyParam(Validator validator);
  28 + Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator);
  29 +
  30 + /**
  31 + * 参数校验
  32 + *
  33 + * @param validator 校验对象
  34 + */
  35 + default void validate(Validator validator) {
  36 + Set<ConstraintViolation<PayClientConfig>> violations = verifyParam(validator);
  37 + if (!violations.isEmpty()) {
  38 + throw new ConstraintViolationException(violations);
  39 + }
  40 + }
26 41 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java
... ... @@ -2,17 +2,12 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2  
3 3 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
4 4 import lombok.Data;
5   -import org.springframework.beans.factory.annotation.Autowired;
6   -import org.springframework.util.Assert;
7 5  
8   -import javax.annotation.Resource;
9 6 import javax.validation.ConstraintViolation;
10 7 import javax.validation.Validator;
11   -import javax.validation.constraints.AssertTrue;
12 8 import javax.validation.constraints.NotBlank;
13 9 import javax.validation.constraints.NotNull;
14 10 import java.util.Set;
15   -import java.util.stream.Collectors;
16 11  
17 12 // TODO 芋艿:参数校验
18 13  
... ... @@ -114,18 +109,9 @@ public class AlipayPayClientConfig implements PayClientConfig {
114 109 public interface ModeCertificate {
115 110 }
116 111  
117   - /**
118   - * 验证配置参数是否正确
119   - * @param validator 校验对象
120   - */
121 112 @Override
122   - public void verifyParam(Validator validator) {
123   - // 手动调用validate进行验证
124   - Set<ConstraintViolation<AlipayPayClientConfig>> validate = validator.validate(this,
  113 + public Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator) {
  114 + return validator.validate(this,
125 115 MODE_PUBLIC_KEY.equals(this.getMode()) ? ModePublicKey.class : ModeCertificate.class);
126   -
127   - // 断言没有异常
128   - Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage)
129   - .collect(Collectors.joining(",")));
130 116 }
131 117 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPayClientConfig.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
3 3 import cn.hutool.core.io.IoUtil;
4 4 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
5 5 import lombok.Data;
6   -import org.springframework.util.Assert;
7 6  
8 7 import javax.validation.ConstraintViolation;
9 8 import javax.validation.Validator;
... ... @@ -11,7 +10,6 @@ import javax.validation.constraints.NotBlank;
11 10 import java.io.FileInputStream;
12 11 import java.io.FileNotFoundException;
13 12 import java.util.Set;
14   -import java.util.stream.Collectors;
15 13  
16 14 // TODO 芋艿:参数校验
17 15  
... ... @@ -101,19 +99,9 @@ public class WXPayClientConfig implements PayClientConfig {
101 99 public interface V3 {
102 100 }
103 101  
104   - // TODO @aquan:1)已经有注释,不用重复注释;2)方法名改成 validate,比较适合 validator;3)断言是否有异常,可以封一个 ConstraintViolationException 异常
105   - /**
106   - * 验证配置参数是否正确
107   - * @param validator 校验对象
108   - */
109 102 @Override
110   - public void verifyParam(Validator validator) {
111   - // 手动调用validate进行验证
112   - Set<ConstraintViolation<PayClientConfig>> validate = validator.validate(this,
113   - this.getApiVersion().equals(API_VERSION_V2) ? V2.class : V3.class);
114   - // 断言没有异常
115   - Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage)
116   - .collect(Collectors.joining(",")));
  103 + public Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator) {
  104 + return validator.validate(this, this.getApiVersion().equals(API_VERSION_V2) ? V2.class : V3.class);
117 105 }
118 106  
119 107 public static void main(String[] args) throws FileNotFoundException {
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelEnum.java
... ... @@ -17,18 +17,21 @@ import lombok.Getter;
17 17 @AllArgsConstructor
18 18 public enum PayChannelEnum {
19 19  
20   - WX_PUB("wx_pub", "微信 JSAPI 支付"), // 公众号的网页
21   - WX_LITE("wx_lite","微信小程序支付"),
22   - WX_APP("wx_app", "微信 App 支付"),
  20 + /**
  21 + * 公众号网页
  22 + */
  23 + WX_PUB("wx_pub", "微信 JSAPI 支付", WXPayClientConfig.class),
  24 + WX_LITE("wx_lite", "微信小程序支付", WXPayClientConfig.class),
  25 + WX_APP("wx_app", "微信 App 支付", WXPayClientConfig.class),
23 26  
24   - ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付"),
25   - ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付"),
26   - ALIPAY_APP("alipay_app", "支付宝App 支付"),
27   - ALIPAY_QR("alipay_qr", "支付宝扫码支付");
  27 + ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付", AlipayPayClientConfig.class),
  28 + ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付", AlipayPayClientConfig.class),
  29 + ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class),
  30 + ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class);
28 31  
29 32 /**
30 33 * 编码
31   - *
  34 + * <p>
32 35 * 参考 https://www.pingxx.com/api/支付渠道属性值.html
33 36 */
34 37 private String code;
... ... @@ -38,6 +41,11 @@ public enum PayChannelEnum {
38 41 private String name;
39 42  
40 43 /**
  44 + * 配置类
  45 + */
  46 + private Class<? extends PayClientConfig> configClass;
  47 +
  48 + /**
41 49 * 微信支付
42 50 */
43 51 public static final String WECHAT = "WECHAT";
... ... @@ -50,27 +58,6 @@ public enum PayChannelEnum {
50 58 public static PayChannelEnum getByCode(String code) {
51 59 return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
52 60 }
53   -
54   - // TODO @aquan:加一个 configClass 字段,不用 switch 的方式哈。不然新增一个支付方式,需要改的方法有点多
55   - /**
56   - * 根据编码得到支付类
57   - *
58   - * @param code 编码
59   - * @return 支付配置类
60   - */
61   - public static Class<? extends PayClientConfig> findByCodeGetClass(String code) {
62   - switch (PayChannelEnum.getByCode(code)){
63   - case WX_PUB:
64   - case WX_LITE:
65   - case WX_APP:
66   - return WXPayClientConfig.class;
67   - case ALIPAY_PC:
68   - case ALIPAY_WAP:
69   - case ALIPAY_APP:
70   - case ALIPAY_QR:
71   - return AlipayPayClientConfig.class;
72   - }
73   - return null;
74   - }
  61 +
75 62  
76 63 }
... ...