Commit 6069a387ea17434ec9bd246ae070bae5529311cc

Authored by aquan
1 parent b18cd457

优化完善支付应用和支付渠道代码逻辑,完善单元测试,基于validator完成手动校验config

Showing 36 changed files with 1524 additions and 922 deletions
sql/pay-dict.sql
@@ -22,3 +22,19 @@ INSERT INTO `sys_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `cre @@ -22,3 +22,19 @@ INSERT INTO `sys_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `cre
22 22
23 INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 'v2', 'v2', 'pay_channel_wechat_version', 0, 'v2版本', '1', '2021-11-08 17:00:58', '1', '2021-11-08 17:00:58', b'0'); 23 INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 'v2', 'v2', 'pay_channel_wechat_version', 0, 'v2版本', '1', '2021-11-08 17:00:58', '1', '2021-11-08 17:00:58', b'0');
24 INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'v3', 'v3', 'pay_channel_wechat_version', 0, 'v3版本', '1', '2021-11-08 17:01:07', '1', '2021-11-08 17:01:07', b'0'); 24 INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 'v3', 'v3', 'pay_channel_wechat_version', 0, 'v3版本', '1', '2021-11-08 17:01:07', '1', '2021-11-08 17:01:07', b'0');
  25 +
  26 +-- 支付渠道支付宝算法类型
  27 +INSERT INTO `sys_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('支付渠道支付宝算法类型', 'pay_channel_alipay_sign_type', 0, '支付渠道支付宝算法类型', '1', '2021-11-18 15:39:09', '1', '2021-11-18 15:39:09', b'0');
  28 +INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 'RSA2', 'RSA2', 'pay_channel_alipay_sign_type', 0, 'RSA2', '1', '2021-11-18 15:39:29', '1', '2021-11-18 15:39:29', b'0');
  29 +
  30 +
  31 +-- 支付渠道支付宝公钥类型
  32 +INSERT INTO `sys_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('支付渠道支付宝公钥类型', 'pay_channel_alipay_mode', 0, '支付渠道支付宝公钥类型', '1', '2021-11-18 15:44:28', '1', '2021-11-18 15:44:28', b'0');
  33 +INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '公钥模式', '1', 'pay_channel_alipay_mode', 0, '公钥模式:privateKey + alipayPublicKey', '1', '2021-11-18 15:45:23', '1', '2021-11-18 15:45:23', b'0');
  34 +INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '证书模式', '2', 'pay_channel_alipay_mode', 0, '证书模式:appCertContent + alipayPublicCertContent + rootCertContent', '1', '2021-11-18 15:45:40', '1', '2021-11-18 15:45:40', b'0');
  35 +
  36 +
  37 +-- 支付宝网关地址
  38 +INSERT INTO `sys_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('支付宝网关地址', 'pay_channel_alipay_server_type', 0, '支付宝网关地址', '1', '2021-11-18 16:58:55', '1', '2021-11-18 17:01:34', b'0');
  39 +INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '线上', 'https://openapi.alipay.com/gateway.do', 'pay_channel_alipay_server_type', 0, '网关地址 - 线上', '1', '2021-11-18 16:59:32', '1', '2021-11-21 17:37:29', b'0');
  40 +INSERT INTO `sys_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '沙箱', 'https://openapi.alipaydev.com/gateway.do', 'pay_channel_alipay_server_type', 0, '网关地址 - 沙箱', '1', '2021-11-18 16:59:48', '1', '2021-11-21 17:37:39', b'0');
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/PayAppController.java
@@ -123,7 +123,7 @@ public class PayAppController { @@ -123,7 +123,7 @@ public class PayAppController {
123 123
124 // 得到所有的应用编号,查出所有的通道 124 // 得到所有的应用编号,查出所有的通道
125 Collection<Long> payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId); 125 Collection<Long> payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId);
126 - List<PayChannelDO> channels = channelService.getSimpleChannels(payAppIds); 126 + List<PayChannelDO> channels = channelService.getChannelListByAppIds(payAppIds);
127 127
128 // 得到所有的商户信息 128 // 得到所有的商户信息
129 Collection<Long> merchantIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getMerchantId); 129 Collection<Long> merchantIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getMerchantId);
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/vo/PayAppExportReqVO.java
@@ -27,8 +27,8 @@ public class PayAppExportReqVO { @@ -27,8 +27,8 @@ public class PayAppExportReqVO {
27 @ApiModelProperty(value = "退款结果的回调地址") 27 @ApiModelProperty(value = "退款结果的回调地址")
28 private String refundNotifyUrl; 28 private String refundNotifyUrl;
29 29
30 - @ApiModelProperty(value = "商户编号")  
31 - private Long merchantId; 30 + @ApiModelProperty(value = "商户名称")
  31 + private String merchantName;
32 32
33 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 33 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
34 @ApiModelProperty(value = "开始创建时间") 34 @ApiModelProperty(value = "开始创建时间")
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/PayChannelController.java
1 package cn.iocoder.yudao.adminserver.modules.pay.controller.channel; 1 package cn.iocoder.yudao.adminserver.modules.pay.controller.channel;
2 2
  3 +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
  4 +import cn.iocoder.yudao.adminserver.modules.pay.convert.channel.PayChannelConvert;
  5 +import cn.iocoder.yudao.adminserver.modules.pay.service.channel.PayChannelService;
3 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; 6 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
4 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
5 -import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig;  
6 -import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient;  
7 -import org.springframework.util.Assert; 7 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  10 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  11 +import io.swagger.annotations.Api;
  12 +import io.swagger.annotations.ApiImplicitParam;
  13 +import io.swagger.annotations.ApiImplicitParams;
  14 +import io.swagger.annotations.ApiOperation;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
  16 +import org.springframework.validation.annotation.Validated;
8 import org.springframework.web.bind.annotation.*; 17 import org.springframework.web.bind.annotation.*;
9 18
10 import javax.annotation.Resource; 19 import javax.annotation.Resource;
11 -  
12 -import org.springframework.validation.annotation.Validated;  
13 -import org.springframework.security.access.prepost.PreAuthorize;  
14 -  
15 -import io.swagger.annotations.*;  
16 -  
17 -import javax.validation.*;  
18 -import javax.servlet.http.*;  
19 -import java.util.*; 20 +import javax.servlet.http.HttpServletResponse;
  21 +import javax.validation.Valid;
20 import java.io.IOException; 22 import java.io.IOException;
21 -  
22 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
23 -import cn.iocoder.yudao.framework.common.pojo.CommonResult; 23 +import java.util.Collection;
  24 +import java.util.List;
24 25
25 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  27 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
26 28
27 -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;  
28 -  
29 -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;  
30 -  
31 -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;  
32 -  
33 -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;  
34 -import cn.iocoder.yudao.adminserver.modules.pay.convert.channel.PayChannelConvert;  
35 -import cn.iocoder.yudao.adminserver.modules.pay.service.channel.PayChannelService;  
36 -import org.springframework.web.multipart.MultipartFile;  
37 - 29 +/**
  30 + * 支付渠道 controller 组件
  31 + * @author aquan
  32 + */
38 @Api(tags = "支付渠道") 33 @Api(tags = "支付渠道")
39 @RestController 34 @RestController
40 @RequestMapping("/pay/channel") 35 @RequestMapping("/pay/channel")
@@ -44,7 +39,7 @@ public class PayChannelController { @@ -44,7 +39,7 @@ public class PayChannelController {
44 @Resource 39 @Resource
45 private PayChannelService channelService; 40 private PayChannelService channelService;
46 41
47 - // todo 芋艿 这几个生成的方法是没用到的 您看要不删除了把? -----start 42 +
48 @PostMapping("/create") 43 @PostMapping("/create")
49 @ApiOperation("创建支付渠道 ") 44 @ApiOperation("创建支付渠道 ")
50 @PreAuthorize("@ss.hasPermission('pay:channel:create')") 45 @PreAuthorize("@ss.hasPermission('pay:channel:create')")
@@ -108,28 +103,7 @@ public class PayChannelController { @@ -108,28 +103,7 @@ public class PayChannelController {
108 ExcelUtils.write(response, "支付渠道.xls", "数据", PayChannelExcelVO.class, datas); 103 ExcelUtils.write(response, "支付渠道.xls", "数据", PayChannelExcelVO.class, datas);
109 } 104 }
110 105
111 - // todo 芋艿 这几个生成的方法是没用到的 您看要不删除了把? -----end  
112 -  
113 - @PostMapping("/parsing-pem")  
114 - @ApiOperation("解析pem证书转换为字符串")  
115 - @PreAuthorize("@ss.hasPermission('pay:channel:parsing')")  
116 - @ApiImplicitParam(name = "file", value = "pem文件", required = true, dataTypeClass = MultipartFile.class)  
117 - public CommonResult<String> parsingPemFile(@RequestParam("file") MultipartFile file) {  
118 - return success(channelService.parsingPemFile(file));  
119 - }  
120 -  
121 - @PostMapping("/create-wechat")  
122 - @ApiOperation("创建支付渠道 ")  
123 - @PreAuthorize("@ss.hasPermission('pay:channel:create')")  
124 - public CommonResult<Long> createWechatChannel(@Valid @RequestBody PayWechatChannelCreateReqVO reqVO) {  
125 - // 针对于 V2 或者 V3 版本的参数校验  
126 - this.paramAdvanceCheck(reqVO.getWeChatConfig().getApiVersion(),reqVO.getWeChatConfig().getMchKey(),  
127 - reqVO.getWeChatConfig().getPrivateKeyContent(),reqVO.getWeChatConfig().getPrivateCertContent());  
128 -  
129 - return success(channelService.createWechatChannel(reqVO));  
130 - }  
131 -  
132 - @GetMapping("/get-wechat") 106 + @GetMapping("/get-channel")
133 @ApiOperation("根据条件查询微信支付渠道") 107 @ApiOperation("根据条件查询微信支付渠道")
134 @ApiImplicitParams({ 108 @ApiImplicitParams({
135 @ApiImplicitParam(name = "merchantId", value = "商户编号", 109 @ApiImplicitParam(name = "merchantId", value = "商户编号",
@@ -140,51 +114,16 @@ public class PayChannelController { @@ -140,51 +114,16 @@ public class PayChannelController {
140 required = true, example = "wx_pub", dataTypeClass = String.class) 114 required = true, example = "wx_pub", dataTypeClass = String.class)
141 }) 115 })
142 @PreAuthorize("@ss.hasPermission('pay:channel:query')") 116 @PreAuthorize("@ss.hasPermission('pay:channel:query')")
143 - public CommonResult<PayWeChatChannelRespVO> getWeChatChannel( 117 + public CommonResult<PayChannelRespVO> getChannel(
144 @RequestParam Long merchantId, @RequestParam Long appId, @RequestParam String code) { 118 @RequestParam Long merchantId, @RequestParam Long appId, @RequestParam String code) {
145 119
146 // 獲取渠道 120 // 獲取渠道
147 PayChannelDO channel = channelService.getChannelByConditions(merchantId, appId, code); 121 PayChannelDO channel = channelService.getChannelByConditions(merchantId, appId, code);
148 if (channel == null) { 122 if (channel == null) {
149 - return success(new PayWeChatChannelRespVO()); 123 + return success(new PayChannelRespVO());
150 } 124 }
151 -  
152 // 拼凑数据 125 // 拼凑数据
153 - PayWeChatChannelRespVO respVo = PayChannelConvert.INSTANCE.convert2(channel);  
154 - WXPayClientConfig config = (WXPayClientConfig) channel.getConfig();  
155 - respVo.setWeChatConfig(PayChannelConvert.INSTANCE.configConvert(config)); 126 + PayChannelRespVO respVo = PayChannelConvert.INSTANCE.convert(channel);
156 return success(respVo); 127 return success(respVo);
157 } 128 }
158 -  
159 - @PutMapping("/update-wechat")  
160 - @ApiOperation("更新微信支付渠道 ")  
161 - @PreAuthorize("@ss.hasPermission('pay:channel:update')")  
162 - public CommonResult<Boolean> updateWechatChannel(@Valid @RequestBody PayWechatChannelUpdateReqVO updateReqVO) {  
163 -  
164 - // 针对于 V2 或者 V3 版本的参数校验  
165 - this.paramAdvanceCheck(updateReqVO.getWeChatConfig().getApiVersion(),updateReqVO.getWeChatConfig().getMchKey(),  
166 - updateReqVO.getWeChatConfig().getPrivateKeyContent(),updateReqVO.getWeChatConfig().getPrivateCertContent());  
167 -  
168 - channelService.updateWechatChannel(updateReqVO);  
169 - return success(true);  
170 - }  
171 -  
172 - /**  
173 - * 预检测微信秘钥参数  
174 - * @param version 版本  
175 - * @param mchKey v2版本秘钥  
176 - * @param privateKeyContent v3版本apiclient_key  
177 - * @param privateCertContent v3版本中apiclient_cert  
178 - */  
179 - private void paramAdvanceCheck(String version, String mchKey, String privateKeyContent, String privateCertContent) {  
180 - // 针对于 V2 或者 V3 版本的参数校验  
181 - if (version.equals(WXPayClientConfig.API_VERSION_V2)) {  
182 - Assert.notNull(mchKey, "v2版本中商户密钥不可为空");  
183 - }  
184 - if (version.equals(WXPayClientConfig.API_VERSION_V3)) {  
185 - Assert.notNull(privateKeyContent, "v3版本apiclient_key.pem不可为空");  
186 - Assert.notNull(privateCertContent, "v3版本中apiclient_cert.pem不可为空");  
187 - }  
188 - }  
189 -  
190 } 129 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelCreateReqVO.java
1 package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo; 1 package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
2 2
3 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
6 import lombok.ToString; 7 import lombok.ToString;
7 8
  9 +import javax.validation.constraints.NotBlank;
  10 +
8 @ApiModel("支付渠道 创建 Request VO") 11 @ApiModel("支付渠道 创建 Request VO")
9 @Data 12 @Data
10 @EqualsAndHashCode(callSuper = true) 13 @EqualsAndHashCode(callSuper = true)
11 @ToString(callSuper = true) 14 @ToString(callSuper = true)
12 public class PayChannelCreateReqVO extends PayChannelBaseVO { 15 public class PayChannelCreateReqVO extends PayChannelBaseVO {
13 16
14 - // TODO @aquan:我在想,要不这个创建和修改特殊一点。前端传递 string 过来,后端解析成对应的。因为有 code,所以我们都知道是哪个配置类。  
15 - // 然后,在 PayChannelEnum 里,枚举每个渠道对应的配置类。另外,我们就不单独给配置类搞 vo 了。参数校验,通过手动调用 Validator 去校验。  
16 - // 通过这样的方式,VO 和 api 都收成,一个 update,一个 create 17 +
  18 + @ApiModelProperty(value = "通道配置的json字符串")
  19 + @NotBlank(message = "通道配置不能为空")
  20 + private String config;
  21 +
17 22
18 } 23 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelRespVO.java
@@ -16,4 +16,6 @@ public class PayChannelRespVO extends PayChannelBaseVO { @@ -16,4 +16,6 @@ public class PayChannelRespVO extends PayChannelBaseVO {
16 @ApiModelProperty(value = "创建时间", required = true) 16 @ApiModelProperty(value = "创建时间", required = true)
17 private Date createTime; 17 private Date createTime;
18 18
  19 + @ApiModelProperty(value = "配置", required = true)
  20 + private String config;
19 } 21 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelUpdateReqVO.java
@@ -15,4 +15,7 @@ public class PayChannelUpdateReqVO extends PayChannelBaseVO { @@ -15,4 +15,7 @@ public class PayChannelUpdateReqVO extends PayChannelBaseVO {
15 @NotNull(message = "商户编号不能为空") 15 @NotNull(message = "商户编号不能为空")
16 private Long id; 16 private Long id;
17 17
  18 + @ApiModelProperty(value = "通道配置的json字符串")
  19 + @NotBlank(message = "通道配置不能为空")
  20 + private String config;
18 } 21 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWeChatChannelRespVO.java deleted
1 -package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;  
2 -  
3 -import io.swagger.annotations.ApiModel;  
4 -import io.swagger.annotations.ApiModelProperty;  
5 -import lombok.Data;  
6 -import lombok.EqualsAndHashCode;  
7 -import lombok.ToString;  
8 -  
9 -import javax.validation.Valid;  
10 -import java.util.Date;  
11 -  
12 -@ApiModel("支付微信渠道 Response VO")  
13 -@Data  
14 -@EqualsAndHashCode(callSuper = true)  
15 -@ToString(callSuper = true)  
16 -public class PayWeChatChannelRespVO extends PayChannelBaseVO {  
17 -  
18 - @ApiModelProperty(value = "商户编号", required = true)  
19 - private Long id;  
20 -  
21 - @ApiModelProperty(value = "创建时间", required = true)  
22 - private Date createTime;  
23 -  
24 - /**  
25 - * 微信配置类  
26 - */  
27 - @Valid  
28 - private WeChatConfig weChatConfig;  
29 -  
30 - /**  
31 - * 微信配置类  
32 - */  
33 - @Data  
34 - @ApiModel("微信配置类")  
35 - public static class WeChatConfig {  
36 -  
37 - @ApiModelProperty(value = "公众号或者小程序的 appid", required = true, example = "wx041349c6f39b261b")  
38 - private String appId;  
39 -  
40 -  
41 - @ApiModelProperty(value = "商户号", required = true, example = "1545083881")  
42 - private String mchId;  
43 -  
44 - @ApiModelProperty(value = "API 版本", required = true, example = "v2")  
45 - private String apiVersion;  
46 -  
47 - // ========== V2 版本的参数 ==========  
48 -  
49 - @ApiModelProperty(value = "商户密钥", required = true, example = "0alL64UDQdaCwiKZ73ib7ypaIjMns06p")  
50 - private String mchKey;  
51 -  
52 - /// todo @aquan 暂不支持 .p12上传 后期优化  
53 - /// apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. 对应的字符串  
54 - /// private String keyContent;  
55 -  
56 - // ========== V3 版本的参数 ==========  
57 -  
58 - @ApiModelProperty(value = "apiclient_key.pem 证书对应的字符串", required = true, example = "-----BEGIN PRIVATE KEY-----")  
59 - private String privateKeyContent;  
60 -  
61 - @ApiModelProperty(value = "apiclient_cert.pem 证书对应的字符串", required = true, example = "-----BEGIN CERTIFICATE-----")  
62 - private String privateCertContent;  
63 - }  
64 -  
65 -}  
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelCreateReqVO.java deleted
1 -package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;  
2 -  
3 -import com.fasterxml.jackson.annotation.JsonClassDescription;  
4 -import io.swagger.annotations.ApiModel;  
5 -import io.swagger.annotations.ApiModelProperty;  
6 -import lombok.Data;  
7 -import lombok.EqualsAndHashCode;  
8 -import lombok.ToString;  
9 -  
10 -import javax.validation.Valid;  
11 -import javax.validation.constraints.NotBlank;  
12 -import javax.validation.constraints.NotNull;  
13 -  
14 -/**  
15 - * 支付渠道微信创建Request VO  
16 - * @author aquan  
17 - */  
18 -@ApiModel("支付渠道微信创建Request VO")  
19 -@Data  
20 -@EqualsAndHashCode(callSuper = true)  
21 -@ToString(callSuper = true)  
22 -public class PayWechatChannelCreateReqVO extends PayChannelBaseVO {  
23 -  
24 - /**  
25 - * 微信配置类  
26 - */  
27 - @Valid  
28 - private WeChatConfig weChatConfig;  
29 -  
30 - /**  
31 - * 微信配置类  
32 - */  
33 - @Data  
34 - @ApiModel("微信配置类")  
35 - public static class WeChatConfig {  
36 -  
37 - @NotBlank(message = "公众号或者小程序的 appid不能为空")  
38 - @ApiModelProperty(value = "公众号或者小程序的 appid", required = true, example = "wx041349c6f39b261b")  
39 - private String appId;  
40 -  
41 -  
42 - @NotBlank(message = "商户号不能为空")  
43 - @ApiModelProperty(value = "商户号", required = true, example = "1545083881")  
44 - private String mchId;  
45 -  
46 - @NotNull(message = "API 版本不能为空")  
47 - @ApiModelProperty(value = "API 版本", required = true, example = "v2")  
48 - private String apiVersion;  
49 -  
50 - // ========== V2 版本的参数 ==========  
51 -  
52 - @ApiModelProperty(value = "商户密钥", required = true, example = "0alL64UDQdaCwiKZ73ib7ypaIjMns06p")  
53 - private String mchKey;  
54 -  
55 - /// todo @aquan 暂不支持 .p12上传 后期优化  
56 - /// apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. 对应的字符串  
57 - /// private String keyContent;  
58 -  
59 - // ========== V3 版本的参数 ==========  
60 -  
61 - @ApiModelProperty(value = "apiclient_key.pem 证书对应的字符串", required = true, example = "-----BEGIN PRIVATE KEY-----")  
62 - private String privateKeyContent;  
63 -  
64 - @ApiModelProperty(value = "apiclient_cert.pem 证书对应的字符串", required = true, example = "-----BEGIN CERTIFICATE-----")  
65 - private String privateCertContent;  
66 - }  
67 -  
68 -}  
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelUpdateReqVO.java deleted
1 -package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;  
2 -  
3 -import io.swagger.annotations.ApiModel;  
4 -import io.swagger.annotations.ApiModelProperty;  
5 -import lombok.Data;  
6 -import lombok.EqualsAndHashCode;  
7 -import lombok.ToString;  
8 -  
9 -import javax.validation.Valid;  
10 -import javax.validation.constraints.NotBlank;  
11 -import javax.validation.constraints.NotNull;  
12 -  
13 -@ApiModel("支付渠道 更新 Request VO")  
14 -@Data  
15 -@EqualsAndHashCode(callSuper = true)  
16 -@ToString(callSuper = true)  
17 -public class PayWechatChannelUpdateReqVO extends PayChannelBaseVO {  
18 -  
19 - @ApiModelProperty(value = "商户编号", required = true)  
20 - @NotNull(message = "商户编号不能为空")  
21 - private Long id;  
22 -  
23 - /**  
24 - * 微信配置类  
25 - */  
26 - @Valid  
27 - private PayWechatChannelCreateReqVO.WeChatConfig weChatConfig;  
28 -  
29 - /**  
30 - * 微信配置类  
31 - */  
32 - @Data  
33 - @ApiModel("微信配置类")  
34 - public static class WeChatConfig {  
35 -  
36 - @NotBlank(message = "公众号或者小程序的 appid不能为空")  
37 - @ApiModelProperty(value = "公众号或者小程序的 appid", required = true, example = "wx041349c6f39b261b")  
38 - private String appId;  
39 -  
40 -  
41 - @NotBlank(message = "商户号不能为空")  
42 - @ApiModelProperty(value = "商户号", required = true, example = "1545083881")  
43 - private String mchId;  
44 -  
45 - @NotNull(message = "API 版本不能为空")  
46 - @ApiModelProperty(value = "API 版本", required = true, example = "v2")  
47 - private String apiVersion;  
48 -  
49 - // ========== V2 版本的参数 ==========  
50 -  
51 - @ApiModelProperty(value = "商户密钥", required = true, example = "0alL64UDQdaCwiKZ73ib7ypaIjMns06p")  
52 - private String mchKey;  
53 -  
54 - /// todo @aquan 暂不支持 .p12上传 后期优化  
55 - /// apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. 对应的字符串  
56 - /// private String keyContent;  
57 -  
58 - // ========== V3 版本的参数 ==========  
59 -  
60 - @ApiModelProperty(value = "apiclient_key.pem 证书对应的字符串", required = true, example = "-----BEGIN PRIVATE KEY-----")  
61 - private String privateKeyContent;  
62 -  
63 - @ApiModelProperty(value = "apiclient_cert.pem 证书对应的字符串", required = true, example = "-----BEGIN CERTIFICATE-----")  
64 - private String privateCertContent;  
65 -  
66 - // TODO @aquan:参数校验。可以使用 @AssertTrue,v2 和 v3 的  
67 - }  
68 -}  
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/convert/channel/PayChannelConvert.java
@@ -23,15 +23,12 @@ public interface PayChannelConvert { @@ -23,15 +23,12 @@ public interface PayChannelConvert {
23 PayChannelConvert INSTANCE = Mappers.getMapper(PayChannelConvert.class); 23 PayChannelConvert INSTANCE = Mappers.getMapper(PayChannelConvert.class);
24 24
25 @Mapping(target = "config",ignore = true) 25 @Mapping(target = "config",ignore = true)
26 - PayChannelDO convert(PayWechatChannelCreateReqVO bean);  
27 -  
28 - @Mapping(target = "config",ignore = true)  
29 - PayChannelDO convert(PayWechatChannelUpdateReqVO bean);  
30 -  
31 PayChannelDO convert(PayChannelCreateReqVO bean); 26 PayChannelDO convert(PayChannelCreateReqVO bean);
32 27
  28 + @Mapping(target = "config",ignore = true)
33 PayChannelDO convert(PayChannelUpdateReqVO bean); 29 PayChannelDO convert(PayChannelUpdateReqVO bean);
34 30
  31 + @Mapping(target = "config",expression = "java(cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString(bean.getConfig()))")
35 PayChannelRespVO convert(PayChannelDO bean); 32 PayChannelRespVO convert(PayChannelDO bean);
36 33
37 List<PayChannelRespVO> convertList(List<PayChannelDO> list); 34 List<PayChannelRespVO> convertList(List<PayChannelDO> list);
@@ -39,13 +36,7 @@ public interface PayChannelConvert { @@ -39,13 +36,7 @@ public interface PayChannelConvert {
39 PageResult<PayChannelRespVO> convertPage(PageResult<PayChannelDO> page); 36 PageResult<PayChannelRespVO> convertPage(PageResult<PayChannelDO> page);
40 37
41 List<PayChannelExcelVO> convertList02(List<PayChannelDO> list); 38 List<PayChannelExcelVO> convertList02(List<PayChannelDO> list);
42 -  
43 - WXPayClientConfig configConvert(PayWechatChannelCreateReqVO.WeChatConfig bean);  
44 39
45 - WXPayClientConfig configConvert(PayWechatChannelUpdateReqVO.WeChatConfig bean);  
46 40
47 - @Mapping(target = "weChatConfig",ignore = true)  
48 - PayWeChatChannelRespVO convert2(PayChannelDO bean);  
49 41
50 - PayWeChatChannelRespVO.WeChatConfig configConvert(WXPayClientConfig bean);  
51 } 42 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/app/PayAppMapper.java
@@ -31,14 +31,14 @@ public interface PayAppMapper extends BaseMapperX&lt;PayAppDO&gt; { @@ -31,14 +31,14 @@ public interface PayAppMapper extends BaseMapperX&lt;PayAppDO&gt; {
31 .orderByDesc("id")); 31 .orderByDesc("id"));
32 } 32 }
33 33
34 - default List<PayAppDO> selectList(PayAppExportReqVO reqVO) { 34 + default List<PayAppDO> selectList(PayAppExportReqVO reqVO, Collection<Long> merchantIds) {
35 return selectList(new QueryWrapperX<PayAppDO>() 35 return selectList(new QueryWrapperX<PayAppDO>()
36 .likeIfPresent("name", reqVO.getName()) 36 .likeIfPresent("name", reqVO.getName())
37 .eqIfPresent("status", reqVO.getStatus()) 37 .eqIfPresent("status", reqVO.getStatus())
38 .eqIfPresent("remark", reqVO.getRemark()) 38 .eqIfPresent("remark", reqVO.getRemark())
39 .eqIfPresent("pay_notify_url", reqVO.getPayNotifyUrl()) 39 .eqIfPresent("pay_notify_url", reqVO.getPayNotifyUrl())
40 .eqIfPresent("refund_notify_url", reqVO.getRefundNotifyUrl()) 40 .eqIfPresent("refund_notify_url", reqVO.getRefundNotifyUrl())
41 - .eqIfPresent("merchant_id", reqVO.getMerchantId()) 41 + .inIfPresent("merchant_id", merchantIds)
42 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) 42 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
43 .orderByDesc("id")); 43 .orderByDesc("id"));
44 } 44 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/channel/PayChannelMapper.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChann @@ -6,6 +6,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChann
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; 7 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
8 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 8 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
9 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
10 import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*; 11 import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
11 12
@@ -26,7 +27,7 @@ public interface PayChannelMapper extends BaseMapperX&lt;PayChannelDO&gt; { @@ -26,7 +27,7 @@ public interface PayChannelMapper extends BaseMapperX&lt;PayChannelDO&gt; {
26 .eqIfPresent("fee_rate", reqVO.getFeeRate()) 27 .eqIfPresent("fee_rate", reqVO.getFeeRate())
27 .eqIfPresent("merchant_id", reqVO.getMerchantId()) 28 .eqIfPresent("merchant_id", reqVO.getMerchantId())
28 .eqIfPresent("app_id", reqVO.getAppId()) 29 .eqIfPresent("app_id", reqVO.getAppId())
29 - .eqIfPresent("config", reqVO.getConfig()) 30 + // .eqIfPresent("config", reqVO.getConfig())
30 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) 31 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
31 .orderByDesc("id") ); 32 .orderByDesc("id") );
32 } 33 }
@@ -39,9 +40,52 @@ public interface PayChannelMapper extends BaseMapperX&lt;PayChannelDO&gt; { @@ -39,9 +40,52 @@ public interface PayChannelMapper extends BaseMapperX&lt;PayChannelDO&gt; {
39 .eqIfPresent("fee_rate", reqVO.getFeeRate()) 40 .eqIfPresent("fee_rate", reqVO.getFeeRate())
40 .eqIfPresent("merchant_id", reqVO.getMerchantId()) 41 .eqIfPresent("merchant_id", reqVO.getMerchantId())
41 .eqIfPresent("app_id", reqVO.getAppId()) 42 .eqIfPresent("app_id", reqVO.getAppId())
42 - .eqIfPresent("config", reqVO.getConfig()) 43 + // .eqIfPresent("config", reqVO.getConfig())
43 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) 44 .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
44 .orderByDesc("id") ); 45 .orderByDesc("id") );
45 } 46 }
46 47
  48 + /**
  49 + * 根据条件获取通道数量
  50 + *
  51 + * @param merchantId 商户编号
  52 + * @param appid 应用编号
  53 + * @param code 通道编码
  54 + * @return 数量
  55 + */
  56 + default Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
  57 +
  58 + return this.selectCount(new QueryWrapper<PayChannelDO>().lambda()
  59 + .eq(PayChannelDO::getMerchantId, merchantId)
  60 + .eq(PayChannelDO::getAppId, appid)
  61 + .eq(PayChannelDO::getCode, code)
  62 + );
  63 + }
  64 +
  65 + /**
  66 + * 根据条件获取通道
  67 + *
  68 + * @param merchantId 商户编号
  69 + * @param appid 应用编号
  70 + * @param code 通道编码
  71 + * @return 数量
  72 + */
  73 + default PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
  74 + return this.selectOne((new QueryWrapper<PayChannelDO>().lambda()
  75 + .eq(PayChannelDO::getMerchantId, merchantId)
  76 + .eq(PayChannelDO::getAppId, appid)
  77 + .eq(PayChannelDO::getCode, code)
  78 + ));
  79 + }
  80 +
  81 + /**
  82 + * 根据支付应用ID集合获得支付渠道列表
  83 + *
  84 + * @param appIds 应用编号集合
  85 + * @return 支付渠道列表
  86 + */
  87 + default List<PayChannelDO> getChannelListByAppIds(Collection<Long> appIds){
  88 + return this.selectList(new QueryWrapper<PayChannelDO>().lambda()
  89 + .in(PayChannelDO::getAppId, appIds));
  90 + }
47 } 91 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/merchant/PayMerchantMapper.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerch @@ -6,6 +6,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerch
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; 7 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
8 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 8 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
9 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
10 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.*; 11 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.*;
11 12
@@ -39,4 +40,14 @@ public interface PayMerchantMapper extends BaseMapperX&lt;PayMerchantDO&gt; { @@ -39,4 +40,14 @@ public interface PayMerchantMapper extends BaseMapperX&lt;PayMerchantDO&gt; {
39 .orderByDesc("id")); 40 .orderByDesc("id"));
40 } 41 }
41 42
  43 + /**
  44 + * 根据商户名称模糊查询商户集合
  45 + *
  46 + * @param merchantName 商户名称
  47 + * @return 商户集合
  48 + */
  49 + default List<PayMerchantDO> getMerchantListByName(String merchantName) {
  50 + return this.selectList(new QueryWrapper<PayMerchantDO>()
  51 + .lambda().likeRight(PayMerchantDO::getName, merchantName));
  52 + }
42 } 53 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/impl/PayAppServiceImpl.java
1 package cn.iocoder.yudao.adminserver.modules.pay.service.app.impl; 1 package cn.iocoder.yudao.adminserver.modules.pay.service.app.impl;
2 2
  3 +import cn.hutool.core.collection.CollectionUtil;
3 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppCreateReqVO; 5 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppCreateReqVO;
5 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppExportReqVO; 6 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppExportReqVO;
@@ -7,6 +8,7 @@ import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppPageReqV @@ -7,6 +8,7 @@ import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppPageReqV
7 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateReqVO; 8 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateReqVO;
8 import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert; 9 import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert;
9 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper; 10 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper;
  11 +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
10 import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService; 12 import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService;
11 import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService; 13 import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService;
12 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; 14 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
@@ -18,10 +20,7 @@ import org.springframework.stereotype.Service; @@ -18,10 +20,7 @@ import org.springframework.stereotype.Service;
18 import org.springframework.validation.annotation.Validated; 20 import org.springframework.validation.annotation.Validated;
19 21
20 import javax.annotation.Resource; 22 import javax.annotation.Resource;
21 -import java.util.Collection;  
22 -import java.util.Collections;  
23 -import java.util.List;  
24 -import java.util.Set; 23 +import java.util.*;
25 24
26 import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.APP_NOT_EXISTS; 25 import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.APP_NOT_EXISTS;
27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -43,7 +42,7 @@ public class PayAppServiceImpl implements PayAppService { @@ -43,7 +42,7 @@ public class PayAppServiceImpl implements PayAppService {
43 * 商户 service 组件 42 * 商户 service 组件
44 */ 43 */
45 @Resource 44 @Resource
46 - private PayMerchantService merchantService; 45 + private PayMerchantMapper merchantMapper;
47 46
48 @Override 47 @Override
49 public Long createApp(PayAppCreateReqVO createReqVO) { 48 public Long createApp(PayAppCreateReqVO createReqVO) {
@@ -89,13 +88,20 @@ public class PayAppServiceImpl implements PayAppService { @@ -89,13 +88,20 @@ public class PayAppServiceImpl implements PayAppService {
89 88
90 @Override 89 @Override
91 public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) { 90 public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) {
92 - // TODO @aquan:会有一个场景,merchantName 匹配不到商户编号的时候,应该返回没数据的  
93 - return appMapper.selectPage(pageReqVO, this.getMerchantCondition(pageReqVO.getMerchantName())); 91 + Set<Long> merchantIdList = this.getMerchantCondition(pageReqVO.getMerchantName());
  92 + if (StrUtil.isNotBlank(pageReqVO.getMerchantName()) && CollectionUtil.isEmpty(merchantIdList)) {
  93 + return new PageResult<>();
  94 + }
  95 + return appMapper.selectPage(pageReqVO, merchantIdList);
94 } 96 }
95 97
96 @Override 98 @Override
97 public List<PayAppDO> getAppList(PayAppExportReqVO exportReqVO) { 99 public List<PayAppDO> getAppList(PayAppExportReqVO exportReqVO) {
98 - return appMapper.selectList(exportReqVO); 100 + Set<Long> merchantIdList = this.getMerchantCondition(exportReqVO.getMerchantName());
  101 + if (StrUtil.isNotBlank(exportReqVO.getMerchantName()) && CollectionUtil.isEmpty(merchantIdList)) {
  102 + return new ArrayList<>();
  103 + }
  104 + return appMapper.selectList(exportReqVO, merchantIdList);
99 } 105 }
100 106
101 /** 107 /**
@@ -108,7 +114,7 @@ public class PayAppServiceImpl implements PayAppService { @@ -108,7 +114,7 @@ public class PayAppServiceImpl implements PayAppService {
108 if (StrUtil.isBlank(merchantName)) { 114 if (StrUtil.isBlank(merchantName)) {
109 return Collections.emptySet(); 115 return Collections.emptySet();
110 } 116 }
111 - return convertSet(merchantService.getMerchantListByName(merchantName), PayMerchantDO::getId); 117 + return convertSet(merchantMapper.getMerchantListByName(merchantName), PayMerchantDO::getId);
112 } 118 }
113 119
114 /** 120 /**
@@ -131,6 +137,7 @@ public class PayAppServiceImpl implements PayAppService { @@ -131,6 +137,7 @@ public class PayAppServiceImpl implements PayAppService {
131 137
132 /** 138 /**
133 * 检查商户是否存在 139 * 检查商户是否存在
  140 + *
134 * @param id 商户编号 141 * @param id 商户编号
135 */ 142 */
136 @VisibleForTesting 143 @VisibleForTesting
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelService.java
@@ -12,7 +12,7 @@ import java.util.List; @@ -12,7 +12,7 @@ import java.util.List;
12 /** 12 /**
13 * 支付渠道 Service 接口 13 * 支付渠道 Service 接口
14 * 14 *
15 - * @author 芋艿 // TODO @aquan:作者不要我 15 + * @author aquan
16 */ 16 */
17 public interface PayChannelService { 17 public interface PayChannelService {
18 18
@@ -76,31 +76,12 @@ public interface PayChannelService { @@ -76,31 +76,12 @@ public interface PayChannelService {
76 List<PayChannelDO> getChannelList(PayChannelExportReqVO exportReqVO); 76 List<PayChannelDO> getChannelList(PayChannelExportReqVO exportReqVO);
77 77
78 /** 78 /**
79 - * 根据支付应用ID集合获取所有的支付渠道 79 + * 根据支付应用ID集合获得支付渠道列表
80 * 80 *
81 - * @param payIds 支付应用编号集合  
82 - * @return 支付渠道  
83 - */  
84 - // TODO @aquan:暂时不用提供这种哈。之前提供的原因,是数据字典比较特殊。  
85 - List<PayChannelDO> getSimpleChannels(Collection<Long> payIds);  
86 -  
87 - /**  
88 - * 解析pem文件获取公钥私钥字符串  
89 - *  
90 - * @param file pem公私钥文件  
91 - * @return 解析后的字符串  
92 - */  
93 - // TODO @aquan:可以前端读取么?  
94 - String parsingPemFile(MultipartFile file);  
95 -  
96 - /**  
97 - * 创建微信的渠道配置  
98 - *  
99 - * @param reqVO 创建信息  
100 - * @return 创建结果 81 + * @param appIds 应用编号集合
  82 + * @return 支付渠道列表
101 */ 83 */
102 - // TODO @aquan:pojo 如果要做参数校验,需要添加 @Valid  
103 - Long createWechatChannel(PayWechatChannelCreateReqVO reqVO); 84 + List<PayChannelDO> getChannelListByAppIds(Collection<Long> appIds);
104 85
105 /** 86 /**
106 * 根据条件获取通道数量 87 * 根据条件获取通道数量
@@ -122,10 +103,5 @@ public interface PayChannelService { @@ -122,10 +103,5 @@ public interface PayChannelService {
122 */ 103 */
123 PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code); 104 PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code);
124 105
125 - /**  
126 - * 更新微信支付渠道  
127 - *  
128 - * @param updateReqVO 更新信息  
129 - */  
130 - void updateWechatChannel(PayWechatChannelUpdateReqVO updateReqVO); 106 +
131 } 107 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/impl/PayChannelServiceImpl.java
1 package cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl; 1 package cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl;
2 2
3 import cn.hutool.core.io.IoUtil; 3 import cn.hutool.core.io.IoUtil;
  4 +import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*; 5 import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
5 import cn.iocoder.yudao.adminserver.modules.pay.convert.channel.PayChannelConvert; 6 import cn.iocoder.yudao.adminserver.modules.pay.convert.channel.PayChannelConvert;
6 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper; 7 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper;
7 import cn.iocoder.yudao.adminserver.modules.pay.service.channel.PayChannelService; 8 import cn.iocoder.yudao.adminserver.modules.pay.service.channel.PayChannelService;
8 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; 9 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 10 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  11 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  12 +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
10 import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; 13 import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig;
11 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 14 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
  15 +import com.alibaba.fastjson.JSON;
  16 +import com.alibaba.fastjson.JSONObject;
12 import lombok.extern.slf4j.Slf4j; 17 import lombok.extern.slf4j.Slf4j;
13 import org.springframework.stereotype.Service; 18 import org.springframework.stereotype.Service;
  19 +import org.springframework.util.Assert;
14 import org.springframework.validation.annotation.Validated; 20 import org.springframework.validation.annotation.Validated;
15 import org.springframework.web.multipart.MultipartFile; 21 import org.springframework.web.multipart.MultipartFile;
16 22
17 import javax.annotation.Resource; 23 import javax.annotation.Resource;
  24 +import javax.validation.ConstraintViolation;
  25 +import javax.validation.Validation;
  26 +import javax.validation.Validator;
  27 +import javax.validation.ValidatorFactory;
18 import java.io.IOException; 28 import java.io.IOException;
19 import java.util.Collection; 29 import java.util.Collection;
20 import java.util.List; 30 import java.util.List;
  31 +import java.util.Set;
  32 +import java.util.stream.Collectors;
21 33
22 import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; 34 import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -25,7 +37,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @@ -25,7 +37,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
25 /** 37 /**
26 * 支付渠道 Service 实现类 38 * 支付渠道 Service 实现类
27 * 39 *
28 - * @author 芋艿 // TODO aquan:作者写自己哈 40 + * @author aquan
29 */ 41 */
30 @Service 42 @Service
31 @Slf4j 43 @Slf4j
@@ -36,11 +48,18 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -36,11 +48,18 @@ public class PayChannelServiceImpl implements PayChannelService {
36 private PayChannelMapper channelMapper; 48 private PayChannelMapper channelMapper;
37 49
38 @Override 50 @Override
39 - public Long createChannel(PayChannelCreateReqVO createReqVO) {  
40 - // 插入  
41 - PayChannelDO channel = PayChannelConvert.INSTANCE.convert(createReqVO); 51 + public Long createChannel(PayChannelCreateReqVO reqVO) {
  52 +
  53 + // 判断是否有重复的有责无法新增
  54 + Integer channelCount = this.getChannelCountByConditions(reqVO.getMerchantId(), reqVO.getAppId(), reqVO.getCode());
  55 + if (channelCount > 0) {
  56 + throw exception(CHANNEL_EXIST_SAME_CHANNEL_ERROR);
  57 + }
  58 +
  59 + PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO);
  60 + settingConfigAndCheckParam(channel, reqVO.getConfig());
  61 +
42 channelMapper.insert(channel); 62 channelMapper.insert(channel);
43 - // 返回  
44 return channel.getId(); 63 return channel.getId();
45 } 64 }
46 65
@@ -49,8 +68,9 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -49,8 +68,9 @@ public class PayChannelServiceImpl implements PayChannelService {
49 // 校验存在 68 // 校验存在
50 this.validateChannelExists(updateReqVO.getId()); 69 this.validateChannelExists(updateReqVO.getId());
51 // 更新 70 // 更新
52 - PayChannelDO updateObj = PayChannelConvert.INSTANCE.convert(updateReqVO);  
53 - channelMapper.updateById(updateObj); 71 + PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO);
  72 + settingConfigAndCheckParam(channel, updateReqVO.getConfig());
  73 + channelMapper.updateById(channel);
54 } 74 }
55 75
56 @Override 76 @Override
@@ -88,53 +108,16 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -88,53 +108,16 @@ public class PayChannelServiceImpl implements PayChannelService {
88 } 108 }
89 109
90 /** 110 /**
91 - * 根据支付应用ID集合获取所有的支付渠道  
92 - *  
93 - * @param payIds 支付应用编号集合  
94 - * @return 支付渠道  
95 - */  
96 - @Override  
97 - public List<PayChannelDO> getSimpleChannels(Collection<Long> payIds) {  
98 - return channelMapper.selectList(new QueryWrapper<PayChannelDO>().lambda().in(PayChannelDO::getAppId, payIds));  
99 - }  
100 -  
101 - /**  
102 - * 解析pem文件获取公钥私钥字符串 111 + * 根据支付应用ID集合获得支付渠道列表
103 * 112 *
104 - * @param file pem公私钥文件  
105 - * @return 解析后的字符串 113 + * @param appIds 应用编号集合
  114 + * @return 支付渠道列表
106 */ 115 */
107 @Override 116 @Override
108 - public String parsingPemFile(MultipartFile file) {  
109 - try {  
110 - return IoUtil.readUtf8(file.getInputStream());  
111 - } catch (IOException e) {  
112 - log.error("[parsingPemToString]读取pem[{}]文件错误", file.getOriginalFilename());  
113 - throw exception(CHANNEL_KEY_READ_ERROR);  
114 - } 117 + public List<PayChannelDO> getChannelListByAppIds(Collection<Long> appIds) {
  118 + return channelMapper.getChannelListByAppIds(appIds);
115 } 119 }
116 120
117 - /**  
118 - * 创建微信的渠道配置  
119 - *  
120 - * @param reqVO 创建信息  
121 - * @return 创建结果  
122 - */  
123 - @Override  
124 - public Long createWechatChannel(PayWechatChannelCreateReqVO reqVO) {  
125 -  
126 - // 判断是否有重复的有责无法新增  
127 - Integer channelCount = this.getChannelCountByConditions(reqVO.getMerchantId(), reqVO.getAppId(), reqVO.getCode());  
128 - if (channelCount > 0) {  
129 - throw exception(EXIST_SAME_CHANNEL_ERROR);  
130 - }  
131 -  
132 - PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO);  
133 - WXPayClientConfig config = PayChannelConvert.INSTANCE.configConvert(reqVO.getWeChatConfig());  
134 - channel.setConfig(config);  
135 - channelMapper.insert(channel);  
136 - return channel.getId();  
137 - }  
138 121
139 /** 122 /**
140 * 根据条件获取通道数量 123 * 根据条件获取通道数量
@@ -146,14 +129,9 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -146,14 +129,9 @@ public class PayChannelServiceImpl implements PayChannelService {
146 */ 129 */
147 @Override 130 @Override
148 public Integer getChannelCountByConditions(Long merchantId, Long appid, String code) { 131 public Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
149 - return this.channelMapper.selectCount(new QueryWrapper<PayChannelDO>().lambda()  
150 - .eq(PayChannelDO::getMerchantId, merchantId)  
151 - .eq(PayChannelDO::getAppId, appid)  
152 - .eq(PayChannelDO::getCode, code)  
153 - ); 132 + return this.channelMapper.getChannelCountByConditions(merchantId, appid, code);
154 } 133 }
155 134
156 - // TODO @aquan:service 不出现 mybatis plus 哈  
157 /** 135 /**
158 * 根据条件获取通道 136 * 根据条件获取通道
159 * 137 *
@@ -164,25 +142,76 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -164,25 +142,76 @@ public class PayChannelServiceImpl implements PayChannelService {
164 */ 142 */
165 @Override 143 @Override
166 public PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) { 144 public PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
167 - return this.channelMapper.selectOne((new QueryWrapper<PayChannelDO>().lambda()  
168 - .eq(PayChannelDO::getMerchantId, merchantId)  
169 - .eq(PayChannelDO::getAppId, appid)  
170 - .eq(PayChannelDO::getCode, code)  
171 - )); 145 + return this.channelMapper.getChannelByConditions(merchantId, appid, code);
172 } 146 }
173 147
174 /** 148 /**
175 - * 更新微信支付渠道 149 + * 检测微信秘钥参数
176 * 150 *
177 - * @param updateReqVO 更新信息 151 + * @param config 信秘钥参数
178 */ 152 */
179 - @Override  
180 - public void updateWechatChannel(PayWechatChannelUpdateReqVO updateReqVO) {  
181 - // 校验存在  
182 - this.validateChannelExists(updateReqVO.getId());  
183 - PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO);  
184 - WXPayClientConfig config = PayChannelConvert.INSTANCE.configConvert(updateReqVO.getWeChatConfig());  
185 - channel.setConfig(config);  
186 - this.channelMapper.updateById(channel); 153 + private void wechatParamCheck(WXPayClientConfig config) {
  154 + // 针对于 V2 或者 V3 版本的参数校验
  155 + if (WXPayClientConfig.API_VERSION_V2.equals(config.getApiVersion())) {
  156 + Assert.notNull(config.getMchKey(), CHANNEL_WECHAT_VERSION_2_MCH_KEY_IS_NULL.getMsg());
  157 + }
  158 + if (WXPayClientConfig.API_VERSION_V3.equals(config.getApiVersion())) {
  159 + Assert.notNull(config.getPrivateKeyContent(), CHANNEL_WECHAT_VERSION_3_PRIVATE_KEY_IS_NULL.getMsg());
  160 + Assert.notNull(config.getPrivateCertContent(), CHANNEL_WECHAT_VERSION_3_CERT_KEY_IS_NULL.getMsg());
  161 + }
  162 + }
  163 +
  164 +
  165 +
  166 + /**
  167 + * 设置渠道配置以及参数校验
  168 + *
  169 + * @param channel 渠道
  170 + * @param configStr 配置
  171 + */
  172 + private void settingConfigAndCheckParam(PayChannelDO channel, String configStr) {
  173 +
  174 + // 得到这个渠道是微信的还是支付宝的
  175 + String channelType = PayChannelEnum.verifyWechatOrAliPay(channel.getCode());
  176 + Assert.notNull(channelType, CHANNEL_NOT_EXISTS.getMsg());
  177 +
  178 + // 进行验证
  179 + ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
  180 + Validator validator = validatorFactory.getValidator();
  181 +
  182 + // 微信的验证
  183 + if (PayChannelEnum.WECHAT.equals(channelType)) {
  184 +
  185 + WXPayClientConfig config = JSON.parseObject(configStr, WXPayClientConfig.class);
  186 + // 判断是V2 版本还是 V3 版本
  187 + Class clazz = config.getApiVersion().equals(WXPayClientConfig.API_VERSION_V2)
  188 + ? WXPayClientConfig.V2.class : WXPayClientConfig.V3.class;
  189 + // 手动调用validate进行验证
  190 + Set<ConstraintViolation<WXPayClientConfig>> validate = validator.validate(config,clazz);
  191 +
  192 + // 断言没有异常
  193 + Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage)
  194 + .collect(Collectors.joining(",")));
  195 +
  196 + channel.setConfig(config);
  197 + }
  198 +
  199 + // 支付宝验证
  200 + if (PayChannelEnum.ALIPAY.equals(channelType)) {
  201 +
  202 + AlipayPayClientConfig config = JSON.parseObject(configStr, AlipayPayClientConfig.class);
  203 +
  204 + // 判断是V2 版本还是 V3 版本
  205 + Class clazz = config.getMode().equals(AlipayPayClientConfig.MODE_PUBLIC_KEY)
  206 + ? AlipayPayClientConfig.ModePublicKey.class : AlipayPayClientConfig.ModeCertificate.class;
  207 + // 手动调用validate进行验证
  208 + Set<ConstraintViolation<AlipayPayClientConfig>> validate = validator.validate(config,clazz);
  209 +
  210 + // 断言没有异常
  211 + Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage)
  212 + .collect(Collectors.joining(",")));
  213 + channel.setConfig(config);
  214 + }
  215 +
187 } 216 }
188 } 217 }
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantService.java
@@ -101,26 +101,13 @@ public interface PayMerchantService { @@ -101,26 +101,13 @@ public interface PayMerchantService {
101 List<PayMerchantDO> getMerchantListByNameLimit(String merchantName); 101 List<PayMerchantDO> getMerchantListByNameLimit(String merchantName);
102 102
103 /** 103 /**
104 - * 获得指定编号的商户列表  
105 - *  
106 - * @param merchantIds 商户编号数组  
107 - * @return 商户列表  
108 - */  
109 - // TODO @aquan:和 getMerchantList 重复了  
110 - List<PayMerchantDO> getSimpleMerchants(Collection<Long> merchantIds);  
111 -  
112 - /**  
113 * 获得指定编号的商户 Map 104 * 获得指定编号的商户 Map
114 * 105 *
115 * @param merchantIds 商户编号数组 106 * @param merchantIds 商户编号数组
116 * @return 商户 Map 107 * @return 商户 Map
117 */ 108 */
118 default Map<Long, PayMerchantDO> getMerchantMap(Collection<Long> merchantIds) { 109 default Map<Long, PayMerchantDO> getMerchantMap(Collection<Long> merchantIds) {
119 - // TODO @aquan:可以不用判空,交给 getMerchantList 解决  
120 - if (CollUtil.isEmpty(merchantIds)) {  
121 - return Collections.emptyMap();  
122 - }  
123 - List<PayMerchantDO> list = getSimpleMerchants(merchantIds); 110 + List<PayMerchantDO> list = this.getMerchantList(merchantIds);
124 return CollectionUtils.convertMap(list, PayMerchantDO::getId); 111 return CollectionUtils.convertMap(list, PayMerchantDO::getId);
125 } 112 }
126 113
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/impl/PayMerchantServiceImpl.java
@@ -113,9 +113,7 @@ public class PayMerchantServiceImpl implements PayMerchantService { @@ -113,9 +113,7 @@ public class PayMerchantServiceImpl implements PayMerchantService {
113 */ 113 */
114 @Override 114 @Override
115 public List<PayMerchantDO> getMerchantListByName(String merchantName) { 115 public List<PayMerchantDO> getMerchantListByName(String merchantName) {
116 - // TODO @aquan:Service 层,不要出现 mybatis plus 的代码,要放到 mapper 里提供。技术与业务分离,原则上  
117 - return this.merchantMapper.selectList(new QueryWrapper<PayMerchantDO>()  
118 - .lambda().likeRight(PayMerchantDO::getName, merchantName)); 116 + return this.merchantMapper.getMerchantListByName(merchantName);
119 } 117 }
120 118
121 /** 119 /**
@@ -150,16 +148,6 @@ public class PayMerchantServiceImpl implements PayMerchantService { @@ -150,16 +148,6 @@ public class PayMerchantServiceImpl implements PayMerchantService {
150 } 148 }
151 } 149 }
152 150
153 - /**  
154 - * 获得指定编号的商户列表  
155 - *  
156 - * @param merchantIds 商户编号数组  
157 - * @return 商户列表  
158 - */  
159 - @Override  
160 - public List<PayMerchantDO> getSimpleMerchants(Collection<Long> merchantIds) {  
161 - return merchantMapper.selectBatchIds(merchantIds);  
162 - }  
163 151
164 // TODO @芋艿:后续增加下合适的算法 152 // TODO @芋艿:后续增加下合适的算法
165 /** 153 /**
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/channel/PayChannelServiceTest.java deleted
1 -package cn.iocoder.yudao.adminserver.modules.pay.channel;  
2 -  
3 -import cn.iocoder.yudao.adminserver.BaseDbUnitTest;  
4 -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelCreateReqVO;  
5 -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelExportReqVO;  
6 -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelPageReqVO;  
7 -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelUpdateReqVO;  
8 -import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper;  
9 -import cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl.PayChannelServiceImpl;  
10 -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;  
11 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
12 -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;  
13 -import org.junit.jupiter.api.Test;  
14 -import org.springframework.context.annotation.Import;  
15 -  
16 -import javax.annotation.Resource;  
17 -import java.util.List;  
18 -  
19 -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.CHANNEL_NOT_EXISTS;  
20 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;  
21 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;  
22 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;  
23 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;  
24 -import static org.junit.jupiter.api.Assertions.*;  
25 -  
26 -/**  
27 -* {@link PayChannelServiceImpl} 的单元测试类  
28 -*  
29 -* @author 芋艿  
30 -*/  
31 -@Import(PayChannelServiceImpl.class)  
32 -public class PayChannelServiceTest extends BaseDbUnitTest {  
33 -  
34 - @Resource  
35 - private PayChannelServiceImpl channelService;  
36 -  
37 - @Resource  
38 - private PayChannelMapper channelMapper;  
39 -  
40 - @Test  
41 - public void testCreateChannel_success() {  
42 - // 准备参数  
43 - PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class);  
44 -  
45 - // 调用  
46 - Long channelId = channelService.createChannel(reqVO);  
47 - // 断言  
48 - assertNotNull(channelId);  
49 - // 校验记录的属性是否正确  
50 - PayChannelDO channel = channelMapper.selectById(channelId);  
51 - assertPojoEquals(reqVO, channel);  
52 - }  
53 -  
54 - @Test  
55 - public void testUpdateChannel_success() {  
56 - // mock 数据  
57 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class);  
58 - channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据  
59 - // 准备参数  
60 - PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> {  
61 - o.setId(dbChannel.getId()); // 设置更新的 ID  
62 - });  
63 -  
64 - // 调用  
65 - channelService.updateChannel(reqVO);  
66 - // 校验是否更新正确  
67 - PayChannelDO channel = channelMapper.selectById(reqVO.getId()); // 获取最新的  
68 - assertPojoEquals(reqVO, channel);  
69 - }  
70 -  
71 - @Test  
72 - public void testUpdateChannel_notExists() {  
73 - // 准备参数  
74 - PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class);  
75 -  
76 - // 调用, 并断言异常  
77 - assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS);  
78 - }  
79 -  
80 - @Test  
81 - public void testDeleteChannel_success() {  
82 - // mock 数据  
83 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class);  
84 - channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据  
85 - // 准备参数  
86 - Long id = dbChannel.getId();  
87 -  
88 - // 调用  
89 - channelService.deleteChannel(id);  
90 - // 校验数据不存在了  
91 - assertNull(channelMapper.selectById(id));  
92 - }  
93 -  
94 - @Test  
95 - public void testDeleteChannel_notExists() {  
96 - // 准备参数  
97 - Long id = randomLongId();  
98 -  
99 - // 调用, 并断言异常  
100 - assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS);  
101 - }  
102 -  
103 - @Test // TODO 请修改 null 为需要的值  
104 - public void testGetChannelPage() {  
105 - // mock 数据  
106 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到  
107 - o.setCode(null);  
108 - o.setStatus(null);  
109 - o.setRemark(null);  
110 - o.setFeeRate(null);  
111 - o.setMerchantId(null);  
112 - o.setAppId(null);  
113 - o.setConfig(null);  
114 - o.setCreateTime(null);  
115 - });  
116 - channelMapper.insert(dbChannel);  
117 - // 测试 code 不匹配  
118 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCode(null)));  
119 - // 测试 status 不匹配  
120 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setStatus(null)));  
121 - // 测试 remark 不匹配  
122 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setRemark(null)));  
123 - // 测试 feeRate 不匹配  
124 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setFeeRate(null)));  
125 - // 测试 merchantId 不匹配  
126 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setMerchantId(null)));  
127 - // 测试 appId 不匹配  
128 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setAppId(null)));  
129 - // 测试 config 不匹配  
130 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setConfig(null)));  
131 - // 测试 createTime 不匹配  
132 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCreateTime(null)));  
133 - // 准备参数  
134 - PayChannelPageReqVO reqVO = new PayChannelPageReqVO();  
135 - reqVO.setCode(null);  
136 - reqVO.setStatus(null);  
137 - reqVO.setRemark(null);  
138 - reqVO.setFeeRate(null);  
139 - reqVO.setMerchantId(null);  
140 - reqVO.setAppId(null);  
141 - reqVO.setConfig(null);  
142 - reqVO.setBeginCreateTime(null);  
143 - reqVO.setEndCreateTime(null);  
144 -  
145 - // 调用  
146 - PageResult<PayChannelDO> pageResult = channelService.getChannelPage(reqVO);  
147 - // 断言  
148 - assertEquals(1, pageResult.getTotal());  
149 - assertEquals(1, pageResult.getList().size());  
150 - assertPojoEquals(dbChannel, pageResult.getList().get(0));  
151 - }  
152 -  
153 - @Test // TODO aquan:请修改 null 为需要的值  
154 - public void testGetChannelList() {  
155 - // mock 数据  
156 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到  
157 - o.setCode(null);  
158 - o.setStatus(null);  
159 - o.setRemark(null);  
160 - o.setFeeRate(null);  
161 - o.setMerchantId(null);  
162 - o.setAppId(null);  
163 - o.setConfig(null);  
164 - o.setCreateTime(null);  
165 - });  
166 - channelMapper.insert(dbChannel);  
167 - // 测试 code 不匹配  
168 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCode(null)));  
169 - // 测试 status 不匹配  
170 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setStatus(null)));  
171 - // 测试 remark 不匹配  
172 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setRemark(null)));  
173 - // 测试 feeRate 不匹配  
174 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setFeeRate(null)));  
175 - // 测试 merchantId 不匹配  
176 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setMerchantId(null)));  
177 - // 测试 appId 不匹配  
178 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setAppId(null)));  
179 - // 测试 config 不匹配  
180 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setConfig(null)));  
181 - // 测试 createTime 不匹配  
182 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCreateTime(null)));  
183 - // 准备参数  
184 - PayChannelExportReqVO reqVO = new PayChannelExportReqVO();  
185 - reqVO.setCode(null);  
186 - reqVO.setStatus(null);  
187 - reqVO.setRemark(null);  
188 - reqVO.setFeeRate(null);  
189 - reqVO.setMerchantId(null);  
190 - reqVO.setAppId(null);  
191 - reqVO.setConfig(null);  
192 - reqVO.setBeginCreateTime(null);  
193 - reqVO.setEndCreateTime(null);  
194 -  
195 - // 调用  
196 - List<PayChannelDO> list = channelService.getChannelList(reqVO);  
197 - // 断言  
198 - assertEquals(1, list.size());  
199 - assertPojoEquals(dbChannel, list.get(0));  
200 - }  
201 -  
202 -}  
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/app/service/PayAppServiceTest.java renamed to yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/PayAppServiceTest.java
1 -package cn.iocoder.yudao.adminserver.modules.pay.app.service; 1 +package cn.iocoder.yudao.adminserver.modules.pay.service.app;
2 2
  3 +import cn.hutool.core.util.RandomUtil;
3 import cn.iocoder.yudao.adminserver.BaseDbUnitTest; 4 import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
4 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppCreateReqVO; 5 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppCreateReqVO;
5 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppExportReqVO; 6 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppExportReqVO;
6 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppPageReqVO; 7 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppPageReqVO;
7 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateReqVO; 8 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateReqVO;
  9 +
  10 +
8 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper; 11 import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper;
  12 +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
9 import cn.iocoder.yudao.adminserver.modules.pay.service.app.impl.PayAppServiceImpl; 13 import cn.iocoder.yudao.adminserver.modules.pay.service.app.impl.PayAppServiceImpl;
  14 +import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService;
10 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; 15 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
  16 +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
  17 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
11 import cn.iocoder.yudao.framework.common.pojo.PageResult; 18 import cn.iocoder.yudao.framework.common.pojo.PageResult;
12 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 19 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
13 import org.junit.jupiter.api.Test; 20 import org.junit.jupiter.api.Test;
  21 +import org.mockito.InjectMocks;
  22 +import org.mockito.Mockito;
  23 +import org.springframework.boot.test.mock.mockito.MockBean;
14 import org.springframework.context.annotation.Import; 24 import org.springframework.context.annotation.Import;
15 25
16 import javax.annotation.Resource; 26 import javax.annotation.Resource;
  27 +import java.util.Collections;
17 import java.util.List; 28 import java.util.List;
18 29
19 -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.APP_NOT_EXISTS; 30 +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
  31 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
20 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 32 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
21 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 33 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
22 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; 34 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
@@ -24,10 +36,10 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; @@ -24,10 +36,10 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
24 import static org.junit.jupiter.api.Assertions.*; 36 import static org.junit.jupiter.api.Assertions.*;
25 37
26 /** 38 /**
27 -* {@link PayAppServiceImpl} 的单元测试类  
28 -*  
29 -* @author 芋艿  
30 -*/ 39 + * {@link PayAppServiceImpl} 的单元测试类
  40 + *
  41 + * @author 芋艿
  42 + */
31 @Import(PayAppServiceImpl.class) 43 @Import(PayAppServiceImpl.class)
32 public class PayAppServiceTest extends BaseDbUnitTest { 44 public class PayAppServiceTest extends BaseDbUnitTest {
33 45
@@ -37,10 +49,14 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -37,10 +49,14 @@ public class PayAppServiceTest extends BaseDbUnitTest {
37 @Resource 49 @Resource
38 private PayAppMapper appMapper; 50 private PayAppMapper appMapper;
39 51
  52 + @MockBean(name = "payMerchantMapper")
  53 + private PayMerchantMapper payMerchantMapper;
  54 +
40 @Test 55 @Test
41 public void testCreateApp_success() { 56 public void testCreateApp_success() {
42 // 准备参数 57 // 准备参数
43 - PayAppCreateReqVO reqVO = randomPojo(PayAppCreateReqVO.class); 58 + PayAppCreateReqVO reqVO = randomPojo(PayAppCreateReqVO.class, o ->
  59 + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
44 60
45 // 调用 61 // 调用
46 Long appId = appService.createApp(reqVO); 62 Long appId = appService.createApp(reqVO);
@@ -54,10 +70,12 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -54,10 +70,12 @@ public class PayAppServiceTest extends BaseDbUnitTest {
54 @Test 70 @Test
55 public void testUpdateApp_success() { 71 public void testUpdateApp_success() {
56 // mock 数据 72 // mock 数据
57 - PayAppDO dbApp = randomPojo(PayAppDO.class); 73 + PayAppDO dbApp = randomPojo(PayAppDO.class, o ->
  74 + o.setStatus(CommonStatusEnum.DISABLE.getStatus()));
58 appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 75 appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据
59 // 准备参数 76 // 准备参数
60 PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> { 77 PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> {
  78 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
61 o.setId(dbApp.getId()); // 设置更新的 ID 79 o.setId(dbApp.getId()); // 设置更新的 ID
62 }); 80 });
63 81
@@ -71,8 +89,8 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -71,8 +89,8 @@ public class PayAppServiceTest extends BaseDbUnitTest {
71 @Test 89 @Test
72 public void testUpdateApp_notExists() { 90 public void testUpdateApp_notExists() {
73 // 准备参数 91 // 准备参数
74 - PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class);  
75 - 92 + PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o ->
  93 + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
76 // 调用, 并断言异常 94 // 调用, 并断言异常
77 assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_EXISTS); 95 assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_EXISTS);
78 } 96 }
@@ -80,15 +98,16 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -80,15 +98,16 @@ public class PayAppServiceTest extends BaseDbUnitTest {
80 @Test 98 @Test
81 public void testDeleteApp_success() { 99 public void testDeleteApp_success() {
82 // mock 数据 100 // mock 数据
83 - PayAppDO dbApp = randomPojo(PayAppDO.class); 101 + PayAppDO dbApp = randomPojo(PayAppDO.class, o ->
  102 + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus())));
84 appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 103 appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据
85 // 准备参数 104 // 准备参数
86 Long id = dbApp.getId(); 105 Long id = dbApp.getId();
87 106
88 // 调用 107 // 调用
89 appService.deleteApp(id); 108 appService.deleteApp(id);
90 - // 校验数据不存在了  
91 - assertNull(appMapper.selectById(id)); 109 + // 校验数据不存在了
  110 + assertNull(appMapper.selectById(id));
92 } 111 }
93 112
94 @Test 113 @Test
@@ -100,94 +119,131 @@ public class PayAppServiceTest extends BaseDbUnitTest { @@ -100,94 +119,131 @@ public class PayAppServiceTest extends BaseDbUnitTest {
100 assertServiceException(() -> appService.deleteApp(id), APP_NOT_EXISTS); 119 assertServiceException(() -> appService.deleteApp(id), APP_NOT_EXISTS);
101 } 120 }
102 121
103 - @Test // TODO 请修改 null 为需要的值 122 + @Test
104 public void testGetAppPage() { 123 public void testGetAppPage() {
105 - // mock 数据  
106 - PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到  
107 - o.setName(null);  
108 - o.setStatus(null);  
109 - o.setRemark(null);  
110 - o.setPayNotifyUrl(null);  
111 - o.setRefundNotifyUrl(null);  
112 - o.setMerchantId(null);  
113 - o.setCreateTime(null);  
114 - });  
115 - appMapper.insert(dbApp);  
116 - // 测试 name 不匹配  
117 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName(null)));  
118 - // 测试 status 不匹配  
119 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(null)));  
120 - // 测试 remark 不匹配  
121 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark(null)));  
122 - // 测试 payNotifyUrl 不匹配  
123 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl(null)));  
124 - // 测试 refundNotifyUrl 不匹配  
125 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl(null)));  
126 - // 测试 merchantId 不匹配  
127 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(null)));  
128 - // 测试 createTime 不匹配  
129 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(null)));  
130 - // 准备参数  
131 - PayAppPageReqVO reqVO = new PayAppPageReqVO();  
132 - reqVO.setName(null);  
133 - reqVO.setStatus(null);  
134 - reqVO.setRemark(null);  
135 - reqVO.setPayNotifyUrl(null);  
136 - reqVO.setRefundNotifyUrl(null);  
137 - reqVO.setBeginCreateTime(null);  
138 - reqVO.setEndCreateTime(null);  
139 -  
140 - // 调用  
141 - PageResult<PayAppDO> pageResult = appService.getAppPage(reqVO);  
142 - // 断言  
143 - assertEquals(1, pageResult.getTotal());  
144 - assertEquals(1, pageResult.getList().size());  
145 - assertPojoEquals(dbApp, pageResult.getList().get(0)); 124 + Long merchantId = 1L;
  125 + Long mismatchMerchantId = 2L;
  126 +
  127 + // mock 数据
  128 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到
  129 + o.setName("灿灿姐的杂货铺");
  130 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  131 + o.setRemark("敏敏姐的小卖铺");
  132 + o.setPayNotifyUrl("https://www.hc.com");
  133 + o.setRefundNotifyUrl("https://www.xm.com");
  134 + o.setMerchantId(merchantId);
  135 + o.setCreateTime(buildTime(2021,11,20));
  136 + });
  137 +
  138 + // mock 数据
  139 + PayMerchantDO dbMerchant = randomPojo(PayMerchantDO.class, o -> { // 等会查询到
  140 + o.setId(merchantId);
  141 + o.setNo("M1008611");
  142 + o.setName("灿哥的杂货铺");
  143 + o.setShortName("灿灿子");
  144 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  145 + o.setRemark("灿哥的杂货铺");
  146 + o.setCreateTime(buildTime(2021,11,3));
  147 + });
  148 +
  149 + Mockito.when(payMerchantMapper.getMerchantListByName(dbMerchant.getName()))
  150 + .thenReturn(Collections.singletonList(dbMerchant));
  151 +
  152 + appMapper.insert(dbApp);
  153 + // 测试 name 不匹配
  154 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName("敏敏姐的杂货铺")));
  155 + // 测试 status 不匹配
  156 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
  157 + // 测试 remark 不匹配
  158 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark("灿灿姐的小卖部")));
  159 + // 测试 payNotifyUrl 不匹配
  160 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl("xm.com")));
  161 + // 测试 refundNotifyUrl 不匹配
  162 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl("hc.com")));
  163 + // 测试 merchantId 不匹配
  164 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(mismatchMerchantId)));
  165 + // 测试 createTime 不匹配
  166 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(buildTime(2021,12,21))));
  167 + // 准备参数
  168 + PayAppPageReqVO reqVO = new PayAppPageReqVO();
  169 + reqVO.setName("灿灿姐的杂货铺");
  170 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  171 + reqVO.setRemark("敏敏姐的小卖铺");
  172 + reqVO.setPayNotifyUrl("https://www.hc.com");
  173 + reqVO.setRefundNotifyUrl("https://www.xm.com");
  174 + reqVO.setMerchantName(dbMerchant.getName());
  175 + reqVO.setBeginCreateTime(buildTime(2021,11,19));
  176 + reqVO.setEndCreateTime(buildTime(2021,11,21));
  177 +
  178 + // 调用
  179 + PageResult<PayAppDO> pageResult = appService.getAppPage(reqVO);
  180 + // 断言
  181 + assertEquals(1, pageResult.getTotal());
  182 + assertEquals(1, pageResult.getList().size());
  183 + assertPojoEquals(dbApp, pageResult.getList().get(0));
146 } 184 }
147 185
148 - @Test // TODO aquan:请修改 null 为需要的值 186 + @Test // TODO 请修改 null 为需要的值
149 public void testGetAppList() { 187 public void testGetAppList() {
150 - // mock 数据  
151 - PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到  
152 - o.setName(null);  
153 - o.setStatus(null);  
154 - o.setRemark(null);  
155 - o.setPayNotifyUrl(null);  
156 - o.setRefundNotifyUrl(null);  
157 - o.setMerchantId(null);  
158 - o.setCreateTime(null);  
159 - });  
160 - appMapper.insert(dbApp);  
161 - // 测试 name 不匹配  
162 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName(null)));  
163 - // 测试 status 不匹配  
164 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(null)));  
165 - // 测试 remark 不匹配  
166 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark(null)));  
167 - // 测试 payNotifyUrl 不匹配  
168 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl(null)));  
169 - // 测试 refundNotifyUrl 不匹配  
170 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl(null)));  
171 - // 测试 merchantId 不匹配  
172 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(null)));  
173 - // 测试 createTime 不匹配  
174 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(null)));  
175 - // 准备参数  
176 - PayAppExportReqVO reqVO = new PayAppExportReqVO();  
177 - reqVO.setName(null);  
178 - reqVO.setStatus(null);  
179 - reqVO.setRemark(null);  
180 - reqVO.setPayNotifyUrl(null);  
181 - reqVO.setRefundNotifyUrl(null);  
182 - reqVO.setMerchantId(null);  
183 - reqVO.setBeginCreateTime(null);  
184 - reqVO.setEndCreateTime(null);  
185 -  
186 - // 调用  
187 - List<PayAppDO> list = appService.getAppList(reqVO);  
188 - // 断言  
189 - assertEquals(1, list.size());  
190 - assertPojoEquals(dbApp, list.get(0)); 188 + Long merchantId = 1L;
  189 + Long mismatchMerchantId = 2L;
  190 +
  191 + // mock 数据
  192 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到
  193 + o.setName("灿灿姐的杂货铺");
  194 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  195 + o.setRemark("敏敏姐的小卖铺");
  196 + o.setPayNotifyUrl("https://www.hc.com");
  197 + o.setRefundNotifyUrl("https://www.xm.com");
  198 + o.setMerchantId(merchantId);
  199 + o.setCreateTime(buildTime(2021,11,20));
  200 + });
  201 +
  202 + // mock 数据
  203 + PayMerchantDO dbMerchant = randomPojo(PayMerchantDO.class, o -> { // 等会查询到
  204 + o.setId(merchantId);
  205 + o.setNo("M1008611");
  206 + o.setName("灿哥的杂货铺");
  207 + o.setShortName("灿灿子");
  208 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  209 + o.setRemark("灿哥的杂货铺");
  210 + o.setCreateTime(buildTime(2021,11,3));
  211 + });
  212 +
  213 + Mockito.when(payMerchantMapper.getMerchantListByName(dbMerchant.getName()))
  214 + .thenReturn(Collections.singletonList(dbMerchant));
  215 +
  216 + appMapper.insert(dbApp);
  217 + // 测试 name 不匹配
  218 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName("敏敏姐的杂货铺")));
  219 + // 测试 status 不匹配
  220 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
  221 + // 测试 remark 不匹配
  222 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark("灿灿姐的小卖部")));
  223 + // 测试 payNotifyUrl 不匹配
  224 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl("xm.com")));
  225 + // 测试 refundNotifyUrl 不匹配
  226 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl("hc.com")));
  227 + // 测试 merchantId 不匹配
  228 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(mismatchMerchantId)));
  229 + // 测试 createTime 不匹配
  230 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(buildTime(2021,12,21))));
  231 + // 准备参数
  232 + PayAppExportReqVO reqVO = new PayAppExportReqVO();
  233 + reqVO.setName("灿灿姐的杂货铺");
  234 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  235 + reqVO.setRemark("敏敏姐的小卖铺");
  236 + reqVO.setPayNotifyUrl("https://www.hc.com");
  237 + reqVO.setRefundNotifyUrl("https://www.xm.com");
  238 + reqVO.setMerchantName(dbMerchant.getName());
  239 + reqVO.setBeginCreateTime(buildTime(2021,11,19));
  240 + reqVO.setEndCreateTime(buildTime(2021,11,21));
  241 +
  242 + // 调用
  243 + List<PayAppDO> list = appService.getAppList(reqVO);
  244 + // 断言
  245 + assertEquals(1, list.size());
  246 + assertPojoEquals(dbApp, list.get(0));
191 } 247 }
192 248
193 -} 249 -}
  250 +}
194 \ No newline at end of file 251 \ No newline at end of file
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelServiceTest.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.pay.service.channel;
  2 +
  3 +import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelCreateReqVO;
  5 +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelExportReqVO;
  6 +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelPageReqVO;
  7 +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelUpdateReqVO;
  8 +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper;
  9 +import cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl.PayChannelServiceImpl;
  10 +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
  11 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  12 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  13 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  14 +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
  15 +import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig;
  16 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
  17 +import com.alibaba.fastjson.JSON;
  18 +import org.junit.jupiter.api.Test;
  19 +import org.springframework.context.annotation.Import;
  20 +
  21 +import javax.annotation.Resource;
  22 +import javax.validation.Validator;
  23 +import java.util.List;
  24 +
  25 +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.CHANNEL_NOT_EXISTS;
  26 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
  27 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  28 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  29 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  30 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  31 +import static org.junit.jupiter.api.Assertions.*;
  32 +
  33 +/**
  34 + * {@link PayChannelServiceImpl} 的单元测试类
  35 + *
  36 + * @author 芋艿
  37 + */
  38 +@Import(PayChannelServiceImpl.class)
  39 +public class PayChannelServiceTest extends BaseDbUnitTest {
  40 +
  41 + @Resource
  42 + private PayChannelServiceImpl channelService;
  43 +
  44 + @Resource
  45 + private PayChannelMapper channelMapper;
  46 +
  47 +
  48 + @Test
  49 + public void testCreateWechatVersion2Channel_success() {
  50 + // 准备参数
  51 +
  52 + WXPayClientConfig v2Config = getV2Config();
  53 + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> {
  54 + o.setCode(PayChannelEnum.WX_PUB.getCode());
  55 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  56 + o.setConfig(JSON.toJSONString(v2Config));
  57 + });
  58 +
  59 + // 调用
  60 + Long channelId = channelService.createChannel(reqVO);
  61 + // 断言
  62 + assertNotNull(channelId);
  63 + // 校验记录的属性是否正确
  64 + PayChannelDO channel = channelMapper.selectById(channelId);
  65 + assertPojoEquals(reqVO, channel, "config");
  66 + // 关于config 对象应该拿出来重新对比
  67 + assertPojoEquals(v2Config, channel.getConfig());
  68 +
  69 + }
  70 +
  71 + @Test
  72 + public void testCreateWechatVersion3Channel_success() {
  73 + // 准备参数
  74 +
  75 + WXPayClientConfig v3Config = getV3Config();
  76 + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> {
  77 + o.setCode(PayChannelEnum.WX_PUB.getCode());
  78 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  79 + o.setConfig(JSON.toJSONString(v3Config));
  80 + });
  81 +
  82 + // 调用
  83 + Long channelId = channelService.createChannel(reqVO);
  84 + // 断言
  85 + assertNotNull(channelId);
  86 + // 校验记录的属性是否正确
  87 + PayChannelDO channel = channelMapper.selectById(channelId);
  88 + assertPojoEquals(reqVO, channel, "config");
  89 + // 关于config 对象应该拿出来重新对比
  90 + assertPojoEquals(v3Config, channel.getConfig());
  91 + }
  92 +
  93 + @Test
  94 + public void testCreateAliPayPublicKeyChannel_success() {
  95 + // 准备参数
  96 +
  97 + AlipayPayClientConfig payClientConfig = getPublicKeyConfig();
  98 + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> {
  99 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  100 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  101 + o.setConfig(JSON.toJSONString(payClientConfig));
  102 + });
  103 +
  104 + // 调用
  105 + Long channelId = channelService.createChannel(reqVO);
  106 + // 断言
  107 + assertNotNull(channelId);
  108 + // 校验记录的属性是否正确
  109 + PayChannelDO channel = channelMapper.selectById(channelId);
  110 + assertPojoEquals(reqVO, channel, "config");
  111 + // 关于config 对象应该拿出来重新对比
  112 + assertPojoEquals(payClientConfig, channel.getConfig());
  113 +
  114 + }
  115 +
  116 + @Test
  117 + public void testCreateAliPayCertificateChannel_success() {
  118 + // 准备参数
  119 +
  120 + AlipayPayClientConfig payClientConfig = getCertificateConfig();
  121 + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> {
  122 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  123 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  124 + o.setConfig(JSON.toJSONString(payClientConfig));
  125 + });
  126 +
  127 + // 调用
  128 + Long channelId = channelService.createChannel(reqVO);
  129 + // 断言
  130 + assertNotNull(channelId);
  131 + // 校验记录的属性是否正确
  132 + PayChannelDO channel = channelMapper.selectById(channelId);
  133 + assertPojoEquals(reqVO, channel, "config");
  134 + // 关于config 对象应该拿出来重新对比
  135 + assertPojoEquals(payClientConfig, channel.getConfig());
  136 + }
  137 +
  138 + @Test
  139 + public void testUpdateChannel_success() {
  140 + // mock 数据
  141 + AlipayPayClientConfig payClientConfig = getCertificateConfig();
  142 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
  143 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  144 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  145 + o.setConfig(payClientConfig);
  146 + });
  147 + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
  148 + // 准备参数
  149 + AlipayPayClientConfig payClientPublicKeyConfig = getPublicKeyConfig();
  150 + PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> {
  151 + o.setCode(dbChannel.getCode());
  152 + o.setStatus(dbChannel.getStatus());
  153 + o.setConfig(JSON.toJSONString(payClientPublicKeyConfig));
  154 + o.setId(dbChannel.getId()); // 设置更新的 ID
  155 + });
  156 +
  157 + // 调用
  158 + channelService.updateChannel(reqVO);
  159 + // 校验是否更新正确
  160 + PayChannelDO channel = channelMapper.selectById(reqVO.getId()); // 获取最新的
  161 + assertPojoEquals(reqVO, channel, "config");
  162 + assertPojoEquals(payClientPublicKeyConfig, channel.getConfig());
  163 + }
  164 +
  165 + @Test
  166 + public void testUpdateChannel_notExists() {
  167 + // 准备参数
  168 + AlipayPayClientConfig payClientPublicKeyConfig = getPublicKeyConfig();
  169 + PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> {
  170 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  171 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  172 + o.setConfig(JSON.toJSONString(payClientPublicKeyConfig));
  173 + });
  174 +
  175 + // 调用, 并断言异常
  176 + assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS);
  177 + }
  178 +
  179 + @Test
  180 + public void testDeleteChannel_success() {
  181 + // mock 数据
  182 + AlipayPayClientConfig payClientConfig = getCertificateConfig();
  183 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> {
  184 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  185 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  186 + o.setConfig(payClientConfig);
  187 + });
  188 + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据
  189 + // 准备参数
  190 + Long id = dbChannel.getId();
  191 +
  192 + // 调用
  193 + channelService.deleteChannel(id);
  194 + // 校验数据不存在了
  195 + assertNull(channelMapper.selectById(id));
  196 + }
  197 +
  198 + @Test
  199 + public void testDeleteChannel_notExists() {
  200 + // 准备参数
  201 + Long id = randomLongId();
  202 +
  203 + // 调用, 并断言异常
  204 + assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS);
  205 + }
  206 +
  207 + @Test // TODO 请修改 null 为需要的值
  208 + public void testGetChannelPage() {
  209 + // mock 数据
  210 + AlipayPayClientConfig payClientConfig = getCertificateConfig();
  211 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到
  212 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  213 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  214 + o.setRemark("灿灿子的支付渠道");
  215 + o.setFeeRate(0.03);
  216 + o.setMerchantId(1L);
  217 + o.setAppId(1L);
  218 + o.setConfig(payClientConfig);
  219 + o.setCreateTime(buildTime(2021,11,20));
  220 + });
  221 + channelMapper.insert(dbChannel);
  222 + // 执行拷贝的时候会出现异常,所以在插入后要重置为null 后续在写入新的
  223 + dbChannel.setConfig(null);
  224 + // 测试 code 不匹配
  225 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  226 + o.setConfig(payClientConfig);
  227 + o.setCode(PayChannelEnum.WX_PUB.getCode());
  228 + }));
  229 + // 测试 status 不匹配
  230 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  231 + o.setConfig(payClientConfig);
  232 + o.setStatus(CommonStatusEnum.DISABLE.getStatus());
  233 + }));
  234 + // 测试 remark 不匹配
  235 + channelMapper.insert(ObjectUtils.clone(dbChannel, o ->{
  236 + o.setConfig(payClientConfig);
  237 + o.setRemark("敏敏子的渠道");
  238 + }));
  239 + // 测试 feeRate 不匹配
  240 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  241 + o.setConfig(payClientConfig);
  242 + o.setFeeRate(1.23);
  243 + }));
  244 + // 测试 merchantId 不匹配
  245 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  246 + o.setConfig(payClientConfig);
  247 + o.setMerchantId(2L);
  248 + }));
  249 + // 测试 appId 不匹配
  250 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  251 + o.setConfig(payClientConfig);
  252 + o.setAppId(2L);
  253 + }));
  254 + // 测试 createTime 不匹配
  255 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  256 + o.setConfig(payClientConfig);
  257 + o.setCreateTime(buildTime(2021, 10, 20));
  258 + }));
  259 + // 准备参数
  260 + PayChannelPageReqVO reqVO = new PayChannelPageReqVO();
  261 + reqVO.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  262 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  263 + reqVO.setRemark("灿灿子的支付渠道");
  264 + reqVO.setFeeRate(0.03);
  265 + reqVO.setMerchantId(1L);
  266 + reqVO.setAppId(1L);
  267 + reqVO.setConfig(JSON.toJSONString(payClientConfig));
  268 + reqVO.setBeginCreateTime(buildTime(2021,11,19));
  269 + reqVO.setEndCreateTime(buildTime(2021,11,21));
  270 +
  271 + // 调用
  272 + PageResult<PayChannelDO> pageResult = channelService.getChannelPage(reqVO);
  273 + // 断言
  274 + assertEquals(1, pageResult.getTotal());
  275 + assertEquals(1, pageResult.getList().size());
  276 + assertPojoEquals(dbChannel, pageResult.getList().get(0), "config");
  277 + assertPojoEquals(payClientConfig, pageResult.getList().get(0).getConfig());
  278 +
  279 + }
  280 +
  281 + @Test
  282 + public void testGetChannelList() {
  283 + // mock 数据
  284 + AlipayPayClientConfig payClientConfig = getCertificateConfig();
  285 + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到
  286 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  287 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  288 + o.setRemark("灿灿子的支付渠道");
  289 + o.setFeeRate(0.03);
  290 + o.setMerchantId(1L);
  291 + o.setAppId(1L);
  292 + o.setConfig(payClientConfig);
  293 + o.setCreateTime(buildTime(2021,11,20));
  294 + });
  295 + channelMapper.insert(dbChannel);
  296 + // 执行拷贝的时候会出现异常,所以在插入后要重置为null 后续在写入新的
  297 + dbChannel.setConfig(null);
  298 + // 测试 code 不匹配
  299 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  300 + o.setConfig(payClientConfig);
  301 + o.setCode(PayChannelEnum.WX_PUB.getCode());
  302 + }));
  303 + // 测试 status 不匹配
  304 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  305 + o.setConfig(payClientConfig);
  306 + o.setStatus(CommonStatusEnum.DISABLE.getStatus());
  307 + }));
  308 + // 测试 remark 不匹配
  309 + channelMapper.insert(ObjectUtils.clone(dbChannel, o ->{
  310 + o.setConfig(payClientConfig);
  311 + o.setRemark("敏敏子的渠道");
  312 + }));
  313 + // 测试 feeRate 不匹配
  314 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  315 + o.setConfig(payClientConfig);
  316 + o.setFeeRate(1.23);
  317 + }));
  318 + // 测试 merchantId 不匹配
  319 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  320 + o.setConfig(payClientConfig);
  321 + o.setMerchantId(2L);
  322 + }));
  323 + // 测试 appId 不匹配
  324 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  325 + o.setConfig(payClientConfig);
  326 + o.setAppId(2L);
  327 + }));
  328 + // 测试 createTime 不匹配
  329 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> {
  330 + o.setConfig(payClientConfig);
  331 + o.setCreateTime(buildTime(2021, 10, 20));
  332 + }));
  333 + // 准备参数
  334 + PayChannelExportReqVO reqVO = new PayChannelExportReqVO();
  335 + reqVO.setCode(PayChannelEnum.ALIPAY_APP.getCode());
  336 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  337 + reqVO.setRemark("灿灿子的支付渠道");
  338 + reqVO.setFeeRate(0.03);
  339 + reqVO.setMerchantId(1L);
  340 + reqVO.setAppId(1L);
  341 + reqVO.setConfig(JSON.toJSONString(payClientConfig));
  342 + reqVO.setBeginCreateTime(buildTime(2021,11,19));
  343 + reqVO.setEndCreateTime(buildTime(2021,11,21));
  344 +
  345 + // 调用
  346 + List<PayChannelDO> list = channelService.getChannelList(reqVO);
  347 + // 断言
  348 + assertEquals(1, list.size());
  349 + assertPojoEquals(dbChannel, list.get(0), "config");
  350 + assertPojoEquals(payClientConfig, list.get(0).getConfig());
  351 + }
  352 +
  353 +
  354 + public WXPayClientConfig getV2Config() {
  355 + return new WXPayClientConfig()
  356 + .setAppId("APP00001")
  357 + .setMchId("MCH00001")
  358 + .setApiVersion(WXPayClientConfig.API_VERSION_V2)
  359 + .setMchKey("dsa1d5s6a1d6sa16d1sa56d15a61das6")
  360 + .setApiV3Key("")
  361 + .setPrivateCertContent("")
  362 + .setPrivateKeyContent("");
  363 + }
  364 +
  365 + public WXPayClientConfig getV3Config() {
  366 + return new WXPayClientConfig()
  367 + .setAppId("APP00001")
  368 + .setMchId("MCH00001")
  369 + .setApiVersion(WXPayClientConfig.API_VERSION_V3)
  370 + .setMchKey("")
  371 + .setApiV3Key("sdadasdsadadsa")
  372 + .setPrivateKeyContent("dsa445das415d15asd16ad156as")
  373 + .setPrivateCertContent("dsadasd45asd4s5a");
  374 +
  375 + }
  376 +
  377 + public AlipayPayClientConfig getPublicKeyConfig() {
  378 + return new AlipayPayClientConfig()
  379 + .setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD)
  380 + .setAppId("APP00001")
  381 + .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
  382 + .setMode(AlipayPayClientConfig.MODE_PUBLIC_KEY)
  383 + .setPrivateKey("13131321312")
  384 + .setAlipayPublicKey("13321321321")
  385 + .setAppCertContent("")
  386 + .setAlipayPublicCertContent("")
  387 + .setRootCertContent("");
  388 + }
  389 +
  390 + public AlipayPayClientConfig getCertificateConfig() {
  391 + return new AlipayPayClientConfig()
  392 + .setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD)
  393 + .setAppId("APP00001")
  394 + .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
  395 + .setMode(AlipayPayClientConfig.MODE_CERTIFICATE)
  396 + .setPrivateKey("")
  397 + .setAlipayPublicKey("")
  398 + .setAppCertContent("13321321321sda")
  399 + .setAlipayPublicCertContent("13321321321aqeqw")
  400 + .setRootCertContent("13321321321dsad");
  401 + }
  402 +
  403 +
  404 +}
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/merchant/service/PayMerchantServiceTest.java renamed to yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantServiceTest.java
1 -package cn.iocoder.yudao.adminserver.modules.pay.merchant.service; 1 +package cn.iocoder.yudao.adminserver.modules.pay.service.merchant;
2 2
3 import cn.hutool.core.util.RandomUtil; 3 import cn.hutool.core.util.RandomUtil;
4 -import cn.hutool.http.HttpUtil;  
5 -import cn.hutool.json.JSONObject;  
6 -import cn.hutool.json.JSONUtil;  
7 import cn.iocoder.yudao.adminserver.BaseDbUnitTest; 4 import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
8 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantCreateReqVO; 5 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantCreateReqVO;
9 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantExportReqVO; 6 import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantExportReqVO;
@@ -54,8 +51,7 @@ public class PayMerchantServiceTest extends BaseDbUnitTest { @@ -54,8 +51,7 @@ public class PayMerchantServiceTest extends BaseDbUnitTest {
54 assertNotNull(merchantId); 51 assertNotNull(merchantId);
55 // 校验记录的属性是否正确 52 // 校验记录的属性是否正确
56 PayMerchantDO merchant = merchantMapper.selectById(merchantId); 53 PayMerchantDO merchant = merchantMapper.selectById(merchantId);
57 - // TODO @aquan:需要判断 no 非空  
58 - assertPojoEquals(reqVO, merchant,"no"); 54 + assertPojoEquals(reqVO, merchant);
59 } 55 }
60 56
61 @Test 57 @Test
yudao-admin-server/src/test/resources/sql/clean.sql
@@ -27,3 +27,5 @@ DELETE FROM &quot;sys_social_user&quot;; @@ -27,3 +27,5 @@ DELETE FROM &quot;sys_social_user&quot;;
27 27
28 -- pay 开头的 DB 28 -- pay 开头的 DB
29 DELETE FROM pay_merchant; 29 DELETE FROM pay_merchant;
  30 +DELETE FROM pay_app;
  31 +DELETE FROM pay_channel
yudao-admin-server/src/test/resources/sql/create_tables.sql
@@ -464,3 +464,37 @@ CREATE TABLE IF NOT EXISTS &quot;pay_merchant&quot; ( @@ -464,3 +464,37 @@ CREATE TABLE IF NOT EXISTS &quot;pay_merchant&quot; (
464 "deleted" bit(1) NOT NULL DEFAULT FALSE, 464 "deleted" bit(1) NOT NULL DEFAULT FALSE,
465 PRIMARY KEY ("id") 465 PRIMARY KEY ("id")
466 ) COMMENT '支付商户信息'; 466 ) COMMENT '支付商户信息';
  467 +
  468 +CREATE TABLE IF NOT EXISTS "pay_app" (
  469 + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  470 + "name" varchar(64) NOT NULL,
  471 + "status" tinyint NOT NULL,
  472 + "remark" varchar(255) DEFAULT NULL,
  473 + `pay_notify_url` varchar(1024) NOT NULL,
  474 + `refund_notify_url`varchar(1024) NOT NULL,
  475 + `merchant_id`bigint(20) NOT NULL,
  476 + "creator" varchar(64) DEFAULT '',
  477 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,
  478 + "updater" varchar(64) DEFAULT '',
  479 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  480 + "deleted" bit(1) NOT NULL DEFAULT FALSE,
  481 + PRIMARY KEY ("id")
  482 +) COMMENT = '支付应用信息';
  483 +
  484 +CREATE TABLE "pay_channel" (
  485 + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  486 + "code" varchar(32) NOT NULL ,
  487 + "status" tinyint(4) NOT NULL ,
  488 + "remark" varchar(255) DEFAULT NULL ,
  489 + "fee_rate" double NOT NULL DEFAULT 0 ,
  490 + "merchant_id" bigint(20) NOT NULL ,
  491 + "app_id" bigint(20) NOT NULL ,
  492 + "config" varchar(10240) NOT NULL ,
  493 + "creator" varchar(64) NULL DEFAULT '' ,
  494 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,
  495 + "updater" varchar(64) NULL DEFAULT '' ,
  496 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  497 + "deleted" bit(1) NOT NULL DEFAULT FALSE,
  498 + PRIMARY KEY ("id")
  499 +)COMMENT = '支付渠道';
  500 +
yudao-admin-ui/src/api/pay/channel.js
@@ -28,12 +28,12 @@ export function deleteChannel(id) { @@ -28,12 +28,12 @@ export function deleteChannel(id) {
28 } 28 }
29 29
30 // 获得支付渠道 30 // 获得支付渠道
31 -export function getChannel(id) {  
32 - return request({  
33 - url: '/pay/channel/get?id=' + id,  
34 - method: 'get'  
35 - })  
36 -} 31 +// export function getChannel(id) {
  32 +// return request({
  33 +// url: '/pay/channel/get?id=' + id,
  34 +// method: 'get'
  35 +// })
  36 +// }
37 37
38 38
39 39
@@ -56,19 +56,10 @@ export function exportChannelExcel(query) { @@ -56,19 +56,10 @@ export function exportChannelExcel(query) {
56 }) 56 })
57 } 57 }
58 58
59 -// 创建微信支付渠道  
60 -export function createWechatChannel(data) {  
61 - return request({  
62 - url: '/pay/channel/create-wechat',  
63 - method: 'post',  
64 - data: data  
65 - })  
66 -}  
67 -  
68 // 获得支付渠道 59 // 获得支付渠道
69 -export function getWechatChannel(merchantId,appId,code) { 60 +export function getChannel(merchantId,appId,code) {
70 return request({ 61 return request({
71 - url: '/pay/channel/get-wechat', 62 + url: '/pay/channel/get-channel',
72 params:{ 63 params:{
73 merchantId:merchantId, 64 merchantId:merchantId,
74 appId:appId, 65 appId:appId,
@@ -78,11 +69,3 @@ export function getWechatChannel(merchantId,appId,code) { @@ -78,11 +69,3 @@ export function getWechatChannel(merchantId,appId,code) {
78 }) 69 })
79 } 70 }
80 71
81 -// 更新支付渠道  
82 -export function updateWechatChannel(data) {  
83 - return request({  
84 - url: '/pay/channel/update-wechat',  
85 - method: 'put',  
86 - data: data  
87 - })  
88 -}  
yudao-admin-ui/src/utils/constants.js
@@ -121,3 +121,8 @@ export const PayChannelEnum = { @@ -121,3 +121,8 @@ export const PayChannelEnum = {
121 "name": "支付宝扫码支付" 121 "name": "支付宝扫码支付"
122 }, 122 },
123 } 123 }
  124 +
  125 +export const PayType = {
  126 + WECHAT: "WECHAT",
  127 + ALIPAY: "ALIPAY"
  128 +}
yudao-admin-ui/src/utils/dict.js
@@ -39,7 +39,12 @@ export const DICT_TYPE = { @@ -39,7 +39,12 @@ export const DICT_TYPE = {
39 PAY_CHANNEL_STATUS: 'pay_channel_status', 39 PAY_CHANNEL_STATUS: 'pay_channel_status',
40 // 微信渠道版本 40 // 微信渠道版本
41 PAY_CHANNEL_WECHAT_VERSION:'pay_channel_wechat_version', 41 PAY_CHANNEL_WECHAT_VERSION:'pay_channel_wechat_version',
42 - 42 + // 支付渠道支付宝算法类型
  43 + PAY_CHANNEL_ALIPAY_SIGN_TYPE:'pay_channel_alipay_sign_type',
  44 + // 支付宝公钥类型
  45 + PAY_CHANNEL_ALIPAY_MODE:'pay_channel_alipay_mode',
  46 + // 支付宝网关地址
  47 + PAY_CHANNEL_ALIPAY_SERVER_TYPE:'pay_channel_alipay_server_type',
43 } 48 }
44 49
45 /** 50 /**
yudao-admin-ui/src/views/pay/app/components/aliPayChannelForm.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-dialog :visible.sync="transferParam.aliPayOpen" @closed="close" append-to-body width="800px">
  4 + <el-form ref="aliPayForm" :model="form" :rules="rules" size="medium" label-width="100px"
  5 + v-loading="transferParam.loading">
  6 + <el-form-item label-width="180px" label="渠道费率" prop="feeRate">
  7 + <el-input v-model="form.feeRate" placeholder="请输入渠道费率" clearable :style="{width: '100%'}">
  8 + <template slot="append">%</template>
  9 + </el-input>
  10 + </el-form-item>
  11 + <el-form-item label-width="180px" label="开放平台APPID" prop="aliPayConfig.appId">
  12 + <el-input v-model="form.aliPayConfig.appId" placeholder="请输入开放平台APPID" clearable :style="{width: '100%'}">
  13 + </el-input>
  14 + </el-form-item>
  15 + <el-form-item label-width="180px" label="渠道状态" prop="status">
  16 + <el-radio-group v-model="form.status" size="medium">
  17 + <el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
  18 + {{ dict.label }}
  19 + </el-radio>
  20 + </el-radio-group>
  21 + </el-form-item>
  22 + <el-form-item label-width="180px" label="网关地址" prop="aliPayConfig.serverUrl">
  23 + <el-radio-group v-model="form.aliPayConfig.serverUrl" size="medium">
  24 + <el-radio v-for="dict in aliPayServerDatas" :key="dict.value" :label="dict.value">
  25 + {{ dict.label }}
  26 + </el-radio>
  27 + </el-radio-group>
  28 + </el-form-item>
  29 + <el-form-item label-width="180px" label="算法类型" prop="aliPayConfig.signType">
  30 + <el-radio-group v-model="form.aliPayConfig.signType" size="medium">
  31 + <el-radio v-for="dict in aliPaySignTypeDatas" :key="dict.value" :label="dict.value">
  32 + {{ dict.label }}
  33 + </el-radio>
  34 + </el-radio-group>
  35 + </el-form-item>
  36 + <el-form-item label-width="180px" label="公钥类型" prop="aliPayConfig.mode">
  37 + <el-radio-group v-model="form.aliPayConfig.mode" size="medium">
  38 + <el-radio v-for="dict in aliPayModeDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
  39 + {{ dict.label }}
  40 + </el-radio>
  41 + </el-radio-group>
  42 + </el-form-item>
  43 + <div v-if="form.aliPayConfig.mode === 1">
  44 + <el-form-item label-width="180px" label="商户私钥" prop="aliPayConfig.privateKey">
  45 + <el-input type="textarea" :autosize="{minRows: 8, maxRows: 8}" v-model="form.aliPayConfig.privateKey"
  46 + placeholder="请输入商户私钥" clearable :style="{width: '100%'}">
  47 + </el-input>
  48 + </el-form-item>
  49 + <el-form-item label-width="180px" label="支付宝公钥字符串" prop="aliPayConfig.alipayPublicKey">
  50 + <el-input
  51 + type="textarea"
  52 + :autosize="{minRows: 8, maxRows: 8}"
  53 + v-model="form.aliPayConfig.alipayPublicKey"
  54 + placeholder="请输入支付宝公钥字符串" clearable
  55 + :style="{width: '100%'}">
  56 + </el-input>
  57 + </el-form-item>
  58 + </div>
  59 + <div v-if="form.aliPayConfig.mode === 2">
  60 + <el-form-item label-width="180px" label="商户公钥应用证书" prop="aliPayConfig.appCertContent">
  61 + <el-input v-model="form.aliPayConfig.appCertContent" type="textarea"
  62 + placeholder="请上传商户公钥应用证书"
  63 + readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
  64 + </el-form-item>
  65 + <el-form-item label-width="180px" label="">
  66 + <el-upload
  67 + action=""
  68 + ref="privateKeyContentFile"
  69 + :limit="1"
  70 + :accept="fileAccept"
  71 + :http-request="appCertUpload"
  72 + :before-upload="fileBeforeUpload">
  73 + <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  74 + </el-upload>
  75 + </el-form-item>
  76 + <el-form-item label-width="180px" label="支付宝公钥证书" prop="aliPayConfig.alipayPublicCertContent">
  77 + <el-input v-model="form.aliPayConfig.alipayPublicCertContent" type="textarea"
  78 + placeholder="请上传支付宝公钥证书"
  79 + readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
  80 + </el-form-item>
  81 + <el-form-item label-width="180px" label="">
  82 + <el-upload
  83 + ref="privateCertContentFile"
  84 + action=""
  85 + :limit="1"
  86 + :accept="fileAccept"
  87 + :before-upload="fileBeforeUpload"
  88 + :http-request="alipayPublicCertUpload">
  89 + <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  90 + </el-upload>
  91 + </el-form-item>
  92 + <el-form-item label-width="180px" label="根证书" prop="aliPayConfig.rootCertContent">
  93 + <el-input
  94 + v-model="form.aliPayConfig.rootCertContent"
  95 + type="textarea"
  96 + placeholder="请上传根证书"
  97 + readonly :autosize="{minRows: 8, maxRows: 8}"
  98 + :style="{width: '100%'}">
  99 + </el-input>
  100 + </el-form-item>
  101 + <el-form-item label-width="180px" label="">
  102 + <el-upload
  103 + ref="privateCertContentFile"
  104 + :limit="1"
  105 + :accept="fileAccept"
  106 + action=""
  107 + :before-upload="fileBeforeUpload"
  108 + :http-request="rootCertUpload">
  109 + <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
  110 + </el-upload>
  111 + </el-form-item>
  112 + </div>
  113 + <el-form-item label-width="180px" label="备注" prop="remark">
  114 + <el-input v-model="form.remark" :style="{width: '100%'}"></el-input>
  115 + </el-form-item>
  116 + </el-form>
  117 + <div slot="footer" class="dialog-footer">
  118 + <el-button @click="close">取消</el-button>
  119 + <el-button type="primary" @click="handleConfirm">确定</el-button>
  120 + </div>
  121 + </el-dialog>
  122 + </div>
  123 +</template>
  124 +<script>
  125 +import {DICT_TYPE, getDictDatas} from "@/utils/dict";
  126 +import {createChannel, getChannel, updateChannel} from "@/api/pay/channel";
  127 +
  128 +const defaultForm = {
  129 + code: '',
  130 + status: null,
  131 + remark: '',
  132 + feeRate: null,
  133 + appId: '',
  134 + merchantId: null,
  135 + aliPayConfig: {
  136 + appId: '',
  137 + serverUrl: null,
  138 + signType: '',
  139 + mode: null,
  140 + privateKey: '',
  141 + alipayPublicKey: '',
  142 + appCertContent: '',
  143 + alipayPublicCertContent: '',
  144 + rootCertContent: ''
  145 + }
  146 +};
  147 +
  148 +export default {
  149 + name: "aliPayChannelForm",
  150 + components: {},
  151 + props: {
  152 + // 传输的参数
  153 + transferParam: {
  154 + // 加载动画
  155 + "loading": false,
  156 + // 是否修改
  157 + "edit": false,
  158 + // 是否显示
  159 + "aliPayOpen": false,
  160 + // 应用ID
  161 + "appId": null,
  162 + // 渠道编码
  163 + "payCode": null,
  164 + // 商户对象
  165 + "payMerchant": {
  166 + // 编号
  167 + "id": null,
  168 + // 名称
  169 + "name": null
  170 + },
  171 + }
  172 + },
  173 + data() {
  174 + return {
  175 + form: JSON.parse(JSON.stringify(defaultForm)),
  176 + rules: {
  177 + feeRate: [{
  178 + required: true,
  179 + message: '请输入渠道费率',
  180 + trigger: 'blur'
  181 + }],
  182 + 'aliPayConfig.appId': [{
  183 + required: true,
  184 + message: '请输入开放平台上创建的应用的 ID',
  185 + trigger: 'blur'
  186 + }],
  187 + status: [{
  188 + required: true,
  189 + message: '渠道状态不能为空',
  190 + trigger: 'blur'
  191 + }],
  192 + 'aliPayConfig.serverUrl': [{
  193 + required: true,
  194 + message: '请传入网关地址',
  195 + trigger: 'blur'
  196 + }],
  197 + 'aliPayConfig.signType': [{
  198 + required: true,
  199 + message: '请传入签名算法类型',
  200 + trigger: 'blur'
  201 + }],
  202 + 'aliPayConfig.mode': [{
  203 + required: true,
  204 + message: '公钥类型不能为空',
  205 + trigger: 'blur'
  206 + }],
  207 + 'aliPayConfig.privateKey': [{
  208 + required: true,
  209 + message: '请输入商户私钥',
  210 + trigger: 'blur'
  211 + }],
  212 + 'aliPayConfig.alipayPublicKey': [{
  213 + required: true,
  214 + message: '请输入支付宝公钥字符串',
  215 + trigger: 'blur'
  216 + }],
  217 + 'aliPayConfig.appCertContent': [{
  218 + required: true,
  219 + message: '请上传商户公钥应用证书',
  220 + trigger: 'blur'
  221 + }],
  222 + 'aliPayConfig.alipayPublicCertContent': [{
  223 + required: true,
  224 + message: '请上传支付宝公钥证书',
  225 + trigger: 'blur'
  226 + }],
  227 + 'aliPayConfig.rootCertContent': [{
  228 + required: true,
  229 + message: '请上传指定根证书',
  230 + trigger: 'blur'
  231 + }],
  232 + },
  233 + fileAccept: ".crt",
  234 + // 渠道状态 数据字典
  235 + statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS),
  236 + // 支付宝加密方式
  237 + aliPaySignTypeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SIGN_TYPE),
  238 + // 版本状态 数据字典
  239 + aliPayModeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_MODE),
  240 + // 支付宝网关地址
  241 + aliPayServerDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SERVER_TYPE),
  242 + }
  243 + },
  244 + watch: {
  245 + transferParam: {
  246 + deep: true, // 深度监听
  247 + handler(newVal) {
  248 + if (newVal.aliPayOpen) {
  249 + this.form.code = newVal.payCode;
  250 + this.form.appId = newVal.appId;
  251 + this.form.merchantId = newVal.payMerchant.id;
  252 + // 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
  253 + if (newVal.edit === true && newVal.loading) {
  254 + this.init();
  255 + }
  256 + }
  257 + }
  258 + }
  259 + },
  260 +
  261 + methods: {
  262 + init() {
  263 + getChannel(this.transferParam.payMerchant.id, this.transferParam.appId, this.transferParam.payCode)
  264 + .then(response => {
  265 + this.form.id = response.data.id;
  266 + this.form.feeRate = response.data.feeRate;
  267 + this.form.status = response.data.status;
  268 + this.form.remark = response.data.remark;
  269 +
  270 + let config = JSON.parse(response.data.config);
  271 + this.form.aliPayConfig.appId = config.appId;
  272 + this.form.aliPayConfig.serverUrl = config.serverUrl;
  273 + this.form.aliPayConfig.signType = config.signType;
  274 + this.form.aliPayConfig.mode = config.mode;
  275 + this.form.aliPayConfig.privateKey = config.privateKey;
  276 + this.form.aliPayConfig.alipayPublicKey = config.alipayPublicKey;
  277 + this.form.aliPayConfig.appCertContent = config.appCertContent;
  278 + this.form.aliPayConfig.alipayPublicCertContent = config.alipayPublicCertContent;
  279 + this.form.aliPayConfig.rootCertContent = config.rootCertContent;
  280 + this.transferParam.loading = false;
  281 + })
  282 + },
  283 + close() {
  284 + this.transferParam.aliPayOpen = false;
  285 + this.form = JSON.parse(JSON.stringify(defaultForm));
  286 + },
  287 + handleConfirm() {
  288 + this.$refs['aliPayForm'].validate(valid => {
  289 + if (!valid) {
  290 + return
  291 + }
  292 + let data = this.form;
  293 + data.config = JSON.stringify(this.form.aliPayConfig);
  294 + if (this.transferParam.edit) {
  295 + updateChannel(data).then(response => {
  296 + if (response.code === 0) {
  297 + this.msgSuccess("修改成功");
  298 + this.close();
  299 + }
  300 +
  301 + })
  302 + } else {
  303 +
  304 + createChannel(data).then(response => {
  305 + if (response.code === 0) {
  306 + this.msgSuccess("新增成功");
  307 + this.$parent.refreshTable();
  308 + this.close();
  309 + }
  310 + });
  311 + }
  312 + });
  313 + },
  314 + fileBeforeUpload(file) {
  315 + let format = '.' + file.name.split(".")[1];
  316 + if (format !== this.fileAccept) {
  317 + this.$message.error('请上传指定格式"' + this.fileAccept + '"文件');
  318 + return false;
  319 + }
  320 + let isRightSize = file.size / 1024 / 1024 < 2
  321 + if (!isRightSize) {
  322 + this.$message.error('文件大小超过 2MB')
  323 + }
  324 + return isRightSize
  325 + },
  326 + appCertUpload(event) {
  327 + const readFile = new FileReader()
  328 + readFile.onload = (e) => {
  329 + this.form.aliPayConfig.appCertContent = e.target.result
  330 + }
  331 + readFile.readAsText(event.file);
  332 + },
  333 + alipayPublicCertUpload(event) {
  334 + const readFile = new FileReader()
  335 + readFile.onload = (e) => {
  336 + this.form.aliPayConfig.alipayPublicCertContent = e.target.result
  337 + }
  338 + readFile.readAsText(event.file);
  339 + },
  340 + rootCertUpload(event) {
  341 + const readFile = new FileReader()
  342 + readFile.onload = (e) => {
  343 + this.form.aliPayConfig.rootCertContent = e.target.result
  344 + }
  345 + readFile.readAsText(event.file);
  346 + },
  347 +
  348 + }
  349 +}
  350 +
  351 +</script>
  352 +<style scoped>
  353 +
  354 +</style>
yudao-admin-ui/src/views/pay/app/components/wechatJsApiForm.vue renamed to yudao-admin-ui/src/views/pay/app/components/wechatChannelForm.vue
1 <template> 1 <template>
2 <div> 2 <div>
3 - <el-dialog :visible.sync="transferParam.open" @close="close" append-to-body> 3 + <el-dialog :visible.sync="transferParam.wechatOpen" @close="close" append-to-body width="800px">
4 <el-form ref="wechatJsApiForm" :model="form" :rules="rules" size="medium" label-width="100px" 4 <el-form ref="wechatJsApiForm" :model="form" :rules="rules" size="medium" label-width="100px"
5 v-loading="transferParam.loading"> 5 v-loading="transferParam.loading">
6 <el-form-item label-width="180px" label="渠道费率" prop="feeRate"> 6 <el-form-item label-width="180px" label="渠道费率" prop="feeRate">
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 </el-radio> 22 </el-radio>
23 </el-radio-group> 23 </el-radio-group>
24 </el-form-item> 24 </el-form-item>
25 - <el-form-item label-width="180px" label="API 版本" prop="weChatConfig.apiVersion"> 25 + <el-form-item label-width="180px" label="API 版本" prop="weChatConfig.apiVersion">
26 <el-radio-group v-model="form.weChatConfig.apiVersion" size="medium"> 26 <el-radio-group v-model="form.weChatConfig.apiVersion" size="medium">
27 <el-radio v-for="dict in versionDictDatas" :key="dict.value" :label="dict.value"> 27 <el-radio v-for="dict in versionDictDatas" :key="dict.value" :label="dict.value">
28 {{ dict.label }} 28 {{ dict.label }}
@@ -32,9 +32,13 @@ @@ -32,9 +32,13 @@
32 <el-form-item label-width="180px" label="商户秘钥" prop="weChatConfig.mchKey" 32 <el-form-item label-width="180px" label="商户秘钥" prop="weChatConfig.mchKey"
33 v-if="form.weChatConfig.apiVersion === 'v2'"> 33 v-if="form.weChatConfig.apiVersion === 'v2'">
34 <el-input v-model="form.weChatConfig.mchKey" placeholder="请输入商户秘钥" clearable 34 <el-input v-model="form.weChatConfig.mchKey" placeholder="请输入商户秘钥" clearable
35 - :style="{width: '100%'}"></el-input> 35 + :style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input>
36 </el-form-item> 36 </el-form-item>
37 <div v-if="form.weChatConfig.apiVersion === 'v3'"> 37 <div v-if="form.weChatConfig.apiVersion === 'v3'">
  38 + <el-form-item label-width="180px" label="API V3秘钥" prop="weChatConfig.apiV3Key">
  39 + <el-input v-model="form.weChatConfig.apiV3Key" placeholder="请输入API V3秘钥" clearable
  40 + :style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input>
  41 + </el-form-item>
38 <el-form-item label-width="180px" label="apiclient_key.perm证书" prop="weChatConfig.privateKeyContent"> 42 <el-form-item label-width="180px" label="apiclient_key.perm证书" prop="weChatConfig.privateKeyContent">
39 <el-input v-model="form.weChatConfig.privateKeyContent" type="textarea" 43 <el-input v-model="form.weChatConfig.privateKeyContent" type="textarea"
40 placeholder="请上传apiclient_key.perm证书" 44 placeholder="请上传apiclient_key.perm证书"
@@ -45,9 +49,9 @@ @@ -45,9 +49,9 @@
45 :limit="1" 49 :limit="1"
46 :accept="fileAccept" 50 :accept="fileAccept"
47 :headers="header" 51 :headers="header"
48 - :action="pemUploadAction" 52 + action=""
49 :before-upload="pemFileBeforeUpload" 53 :before-upload="pemFileBeforeUpload"
50 - :on-success="privateKeyUploadSuccess" 54 + :http-request="privateKeyUpload"
51 > 55 >
52 <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button> 56 <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
53 </el-upload> 57 </el-upload>
@@ -62,9 +66,9 @@ @@ -62,9 +66,9 @@
62 :limit="1" 66 :limit="1"
63 :accept="fileAccept" 67 :accept="fileAccept"
64 :headers="header" 68 :headers="header"
65 - :action="pemUploadAction" 69 + action=""
66 :before-upload="pemFileBeforeUpload" 70 :before-upload="pemFileBeforeUpload"
67 - :on-success="privateCertUploadSuccess" 71 + :http-request="privateCertUpload"
68 > 72 >
69 <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button> 73 <el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
70 </el-upload> 74 </el-upload>
@@ -83,10 +87,28 @@ @@ -83,10 +87,28 @@
83 </template> 87 </template>
84 <script> 88 <script>
85 import {DICT_TYPE, getDictDatas} from "@/utils/dict"; 89 import {DICT_TYPE, getDictDatas} from "@/utils/dict";
86 -import {createWechatChannel, getWechatChannel, updateWechatChannel} from "@/api/pay/channel"; 90 +import {createChannel, getChannel, updateChannel} from "@/api/pay/channel";
  91 +
  92 +const defaultForm = {
  93 + code: '',
  94 + status: null,
  95 + remark: '',
  96 + feeRate: null,
  97 + appId: '',
  98 + merchantId: null,
  99 + weChatConfig: {
  100 + appId: '',
  101 + mchId: '',
  102 + apiVersion: '',
  103 + mchKey: '',
  104 + privateKeyContent: '',
  105 + privateCertContent: '',
  106 + apiV3Key:'',
  107 + }
  108 +}
87 109
88 export default { 110 export default {
89 - name: "wechatJsApiForm", 111 + name: "wechatChannelForm",
90 components: {}, 112 components: {},
91 props: { 113 props: {
92 // 传输的参数 114 // 传输的参数
@@ -96,7 +118,7 @@ export default { @@ -96,7 +118,7 @@ export default {
96 // 是否修改 118 // 是否修改
97 "edit": false, 119 "edit": false,
98 // 是否显示 120 // 是否显示
99 - "open": false, 121 + "wechatOpen": false,
100 // 应用ID 122 // 应用ID
101 "appId": null, 123 "appId": null,
102 // 渠道编码 124 // 渠道编码
@@ -112,22 +134,7 @@ export default { @@ -112,22 +134,7 @@ export default {
112 }, 134 },
113 data() { 135 data() {
114 return { 136 return {
115 - form: {  
116 - code: undefined,  
117 - status: undefined,  
118 - remark: undefined,  
119 - feeRate: undefined,  
120 - appId: undefined,  
121 - merchantId: undefined,  
122 - weChatConfig: {  
123 - appId: undefined,  
124 - mchId: undefined,  
125 - apiVersion: undefined,  
126 - mchKey: undefined,  
127 - privateKeyContent: undefined,  
128 - privateCertContent: undefined,  
129 - }  
130 - }, 137 + form: JSON.parse(JSON.stringify(defaultForm)),
131 rules: { 138 rules: {
132 feeRate: [{ 139 feeRate: [{
133 required: true, 140 required: true,
@@ -147,12 +154,12 @@ export default { @@ -147,12 +154,12 @@ export default {
147 status: [{ 154 status: [{
148 required: true, 155 required: true,
149 message: '渠道状态不能为空', 156 message: '渠道状态不能为空',
150 - trigger: 'change' 157 + trigger: 'blur'
151 }], 158 }],
152 'weChatConfig.apiVersion': [{ 159 'weChatConfig.apiVersion': [{
153 required: true, 160 required: true,
154 message: 'API版本不能为空', 161 message: 'API版本不能为空',
155 - trigger: 'change' 162 + trigger: 'blur'
156 }], 163 }],
157 'weChatConfig.mchKey': [{ 164 'weChatConfig.mchKey': [{
158 required: true, 165 required: true,
@@ -169,12 +176,16 @@ export default { @@ -169,12 +176,16 @@ export default {
169 message: '请上传apiclient_cert.perm证书', 176 message: '请上传apiclient_cert.perm证书',
170 trigger: 'blur' 177 trigger: 'blur'
171 }], 178 }],
  179 + 'weChatConfig.apiV3Key': [{
  180 + required: true,
  181 + message: '请上传apiV3秘钥值',
  182 + trigger: 'blur'
  183 + }],
172 }, 184 },
173 // 文件上传的header 185 // 文件上传的header
174 header: { 186 header: {
175 "Authorization": null 187 "Authorization": null
176 }, 188 },
177 - pemUploadAction: 'http://127.0.0.1:48080/api/pay/channel/parsing-pem',  
178 fileAccept: ".pem", 189 fileAccept: ".pem",
179 // 渠道状态 数据字典 190 // 渠道状态 数据字典
180 statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS), 191 statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS),
@@ -185,51 +196,66 @@ export default { @@ -185,51 +196,66 @@ export default {
185 transferParam: { 196 transferParam: {
186 deep: true, // 深度监听 197 deep: true, // 深度监听
187 handler(newVal) { 198 handler(newVal) {
188 - this.form.code = newVal.payCode;  
189 - this.form.appId = newVal.appId;  
190 - this.form.merchantId = newVal.payMerchant.id;  
191 - // 只有在初次进来为编辑 并且为加载中的时候才回去请求数据  
192 - if (newVal.edit === true && newVal.loading) {  
193 - this.init(); 199 + if (newVal.wechatOpen) {
  200 + this.form.code = newVal.payCode;
  201 + this.form.appId = newVal.appId;
  202 + this.form.merchantId = newVal.payMerchant.id;
  203 + // 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
  204 + if (newVal.edit && newVal.loading) {
  205 + this.init();
  206 + }
194 } 207 }
195 } 208 }
196 } 209 }
197 }, 210 },
198 - created() {  
199 - this.header.Authorization = "Bearer " + this.$store.getters.token;  
200 - },  
201 methods: { 211 methods: {
202 init() { 212 init() {
203 - getWechatChannel(this.transferParam.payMerchant.id, this.transferParam.appId, this.transferParam.payCode) 213 + getChannel(this.transferParam.payMerchant.id, this.transferParam.appId, this.transferParam.payCode)
204 .then(response => { 214 .then(response => {
205 - this.form = response.data; 215 + this.form.id = response.data.id;
  216 + this.form.feeRate = response.data.feeRate;
  217 + this.form.appId = response.data.appId;
  218 + this.form.status = response.data.status;
  219 + this.form.remark = response.data.remark;
  220 +
  221 + let config = JSON.parse(response.data.config);
  222 + this.form.weChatConfig.appId = config.appId;
  223 + this.form.weChatConfig.apiVersion = config.apiVersion;
  224 + this.form.weChatConfig.mchId = config.mchId;
  225 + this.form.weChatConfig.mchKey = config.mchKey;
  226 + this.form.weChatConfig.privateKeyContent = config.privateKeyContent;
  227 + this.form.weChatConfig.privateCertContent = config.privateCertContent;
  228 + this.form.weChatConfig.apiV3Key = config.apiV3Key;
206 this.transferParam.loading = false; 229 this.transferParam.loading = false;
207 }) 230 })
208 }, 231 },
209 close() { 232 close() {
210 - this.transferParam.open = false;  
211 - this.$refs['wechatJsApiForm'].resetFields(); 233 + this.transferParam.wechatOpen = false;
  234 + this.form = JSON.parse(JSON.stringify(defaultForm));
212 }, 235 },
213 handleConfirm() { 236 handleConfirm() {
214 this.$refs['wechatJsApiForm'].validate(valid => { 237 this.$refs['wechatJsApiForm'].validate(valid => {
215 if (!valid) { 238 if (!valid) {
216 return 239 return
217 } 240 }
  241 + let data = this.form;
  242 + data.config = JSON.stringify(this.form.weChatConfig);
218 if (this.transferParam.edit) { 243 if (this.transferParam.edit) {
219 - updateWechatChannel(this.form).then(response => {  
220 - if (response.code === 0 ) { 244 + updateChannel(data).then(response => {
  245 + if (response.code === 0) {
221 this.msgSuccess("修改成功"); 246 this.msgSuccess("修改成功");
222 this.close(); 247 this.close();
223 } 248 }
224 249
225 }) 250 })
226 } else { 251 } else {
227 - createWechatChannel(this.form).then(response => {  
228 - if (response.code === 0) {  
229 - this.msgSuccess("新增成功");  
230 - this.$parent.refreshTable();  
231 - this.close();  
232 - } 252 +
  253 + createChannel(data).then(response => {
  254 + if (response.code === 0) {
  255 + this.msgSuccess("新增成功");
  256 + this.$parent.refreshTable();
  257 + this.close();
  258 + }
233 }); 259 });
234 } 260 }
235 }); 261 });
@@ -246,11 +272,19 @@ export default { @@ -246,11 +272,19 @@ export default {
246 } 272 }
247 return isRightSize 273 return isRightSize
248 }, 274 },
249 - privateKeyUploadSuccess(response) {  
250 - this.form.weChatConfig.privateKeyContent = response.data; 275 + privateKeyUpload(event) {
  276 + const readFile = new FileReader()
  277 + readFile.onload = (e) => {
  278 + this.form.weChatConfig.privateKeyContent = e.target.result
  279 + }
  280 + readFile.readAsText(event.file);
251 }, 281 },
252 - privateCertUploadSuccess(response) {  
253 - this.form.weChatConfig.privateCertContent = response.data; 282 + privateCertUpload(event) {
  283 + const readFile = new FileReader()
  284 + readFile.onload = (e) => {
  285 + this.form.weChatConfig.privateCertContent = e.target.result
  286 + }
  287 + readFile.readAsText(event.file);
254 } 288 }
255 } 289 }
256 } 290 }
yudao-admin-ui/src/views/pay/app/index.vue
@@ -57,68 +57,104 @@ @@ -57,68 +57,104 @@
57 <el-table-column label="支付宝配置" align="center"> 57 <el-table-column label="支付宝配置" align="center">
58 <el-table-column :label="payChannelEnum.ALIPAY_APP.name" align="center"> 58 <el-table-column :label="payChannelEnum.ALIPAY_APP.name" align="center">
59 <template slot-scope="scope"> 59 <template slot-scope="scope">
60 - <el-button type="success" icon="el-icon-check" circle  
61 - v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.ENABLE"></el-button>  
62 - <el-button type="danger" icon="el-icon-close" circle  
63 - v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.DISABLE"></el-button> 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">
  64 + </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">
  69 + </el-button>
64 </template> 70 </template>
65 </el-table-column> 71 </el-table-column>
66 <el-table-column :label="payChannelEnum.ALIPAY_PC.name" align="center"> 72 <el-table-column :label="payChannelEnum.ALIPAY_PC.name" align="center">
67 <template slot-scope="scope"> 73 <template slot-scope="scope">
68 - <el-button type="success" icon="el-icon-check" circle  
69 - v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.ENABLE"></el-button>  
70 - <el-button type="danger" icon="el-icon-close" circle  
71 - v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.DISABLE"></el-button> 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">
  78 + </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">
  83 + </el-button>
72 </template> 84 </template>
73 </el-table-column> 85 </el-table-column>
74 <el-table-column :label="payChannelEnum.ALIPAY_WAP.name" align="center"> 86 <el-table-column :label="payChannelEnum.ALIPAY_WAP.name" align="center">
75 <template slot-scope="scope"> 87 <template slot-scope="scope">
76 - <el-button type="success" icon="el-icon-check" circle  
77 - v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.ENABLE"></el-button>  
78 - <el-button type="danger" icon="el-icon-close" circle  
79 - v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.DISABLE"></el-button> 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">
  92 + </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">
  97 + </el-button>
80 </template> 98 </template>
81 </el-table-column> 99 </el-table-column>
82 <el-table-column :label="payChannelEnum.ALIPAY_QR.name" align="center"> 100 <el-table-column :label="payChannelEnum.ALIPAY_QR.name" align="center">
83 <template slot-scope="scope"> 101 <template slot-scope="scope">
84 - <el-button type="success" icon="el-icon-check" circle  
85 - v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.ENABLE"></el-button>  
86 - <el-button type="danger" icon="el-icon-close" circle  
87 - v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.DISABLE"></el-button> 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 +
  107 + </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 +
  113 + </el-button>
88 </template> 114 </template>
89 </el-table-column> 115 </el-table-column>
90 </el-table-column> 116 </el-table-column>
91 <el-table-column label="微信配置" align="center"> 117 <el-table-column label="微信配置" align="center">
92 <el-table-column :label="payChannelEnum.WX_LITE.name" align="center"> 118 <el-table-column :label="payChannelEnum.WX_LITE.name" align="center">
93 <template slot-scope="scope"> 119 <template slot-scope="scope">
94 - <el-button type="success" icon="el-icon-check" circle  
95 - @click="handleUpdateChannel(scope.row,payChannelEnum.WX_LITE.code)"  
96 - v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.ENABLE"></el-button>  
97 - <el-button type="danger" icon="el-icon-close" circle  
98 - @click="handleCreateChannel(scope.row,payChannelEnum.WX_LITE.code)"  
99 - v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.DISABLE"></el-button> 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">
  124 + </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">
  129 + </el-button>
100 </template> 130 </template>
101 </el-table-column> 131 </el-table-column>
102 <el-table-column :label="payChannelEnum.WX_PUB.name" align="center"> 132 <el-table-column :label="payChannelEnum.WX_PUB.name" align="center">
103 <template slot-scope="scope"> 133 <template slot-scope="scope">
104 <el-button 134 <el-button
105 type="success" icon="el-icon-check" circle 135 type="success" icon="el-icon-check" circle
106 - @click="handleUpdateChannel(scope.row,payChannelEnum.WX_PUB.code)" 136 + @click="handleUpdateChannel(scope.row,payChannelEnum.WX_PUB.code,payType.WECHAT)"
107 v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.ENABLE"> 137 v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.ENABLE">
108 </el-button> 138 </el-button>
109 - <el-button type="danger" icon="el-icon-close" circle  
110 - @click="handleCreateChannel(scope.row,payChannelEnum.WX_PUB.code)"  
111 - v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.DISABLE"></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">
  143 + </el-button>
112 </template> 144 </template>
113 </el-table-column> 145 </el-table-column>
114 <el-table-column :label="payChannelEnum.WX_APP.name" align="center"> 146 <el-table-column :label="payChannelEnum.WX_APP.name" align="center">
115 <template slot-scope="scope"> 147 <template slot-scope="scope">
116 - <el-button type="success" icon="el-icon-check" circle  
117 - @click="handleUpdateChannel(scope.row,payChannelEnum.WX_APP.code)"  
118 - v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.ENABLE"></el-button>  
119 - <el-button type="danger" icon="el-icon-close" circle  
120 - @click="handleCreateChannel(scope.row,payChannelEnum.WX_APP.code)"  
121 - v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.DISABLE"></el-button> 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">
  152 + </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">
  157 + </el-button>
122 </template> 158 </template>
123 </el-table-column> 159 </el-table-column>
124 </el-table-column> 160 </el-table-column>
@@ -186,21 +222,24 @@ @@ -186,21 +222,24 @@
186 </div> 222 </div>
187 </el-dialog> 223 </el-dialog>
188 224
189 - <wechat-js-api-form :transferParam="wechatChannelParam"></wechat-js-api-form> 225 + <wechat-channel-form :transferParam="channelParam"></wechat-channel-form>
  226 + <ali-pay-channel-form :transferParam="channelParam"></ali-pay-channel-form>
190 </div> 227 </div>
191 </template> 228 </template>
192 229
193 <script> 230 <script>
194 import {createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage, exportAppExcel} from "@/api/pay/app"; 231 import {createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage, exportAppExcel} from "@/api/pay/app";
195 import {DICT_TYPE, getDictDatas} from "@/utils/dict"; 232 import {DICT_TYPE, getDictDatas} from "@/utils/dict";
196 -import {PayChannelEnum, SysCommonStatusEnum} from "@/utils/constants"; 233 +import {PayType, PayChannelEnum, SysCommonStatusEnum} from "@/utils/constants";
197 import {getMerchantListByName} from "@/api/pay/merchant"; 234 import {getMerchantListByName} from "@/api/pay/merchant";
198 -import wechatJsApiForm from "@/views/pay/app/components/wechatJsApiForm"; 235 +import wechatChannelForm from "@/views/pay/app/components/wechatChannelForm";
  236 +import aliPayChannelForm from "@/views/pay/app/components/aliPayChannelForm";
199 237
200 export default { 238 export default {
201 name: "App", 239 name: "App",
202 components: { 240 components: {
203 - "wechatJsApiForm": wechatJsApiForm 241 + "wechatChannelForm": wechatChannelForm,
  242 + "aliPayChannelForm": aliPayChannelForm
204 }, 243 },
205 data() { 244 data() {
206 return { 245 return {
@@ -243,16 +282,20 @@ export default { @@ -243,16 +282,20 @@ export default {
243 sysCommonStatusEnum: SysCommonStatusEnum, 282 sysCommonStatusEnum: SysCommonStatusEnum,
244 // 支付渠道枚举 283 // 支付渠道枚举
245 payChannelEnum: PayChannelEnum, 284 payChannelEnum: PayChannelEnum,
  285 + // 支付类型
  286 + payType: PayType,
246 // 商户列表 287 // 商户列表
247 merchantList: [], 288 merchantList: [],
248 // 是否显示支付窗口 289 // 是否显示支付窗口
249 payOpen: false, 290 payOpen: false,
250 // 微信组件传参参数 291 // 微信组件传参参数
251 - wechatChannelParam: { 292 + channelParam: {
252 // 是否修改 293 // 是否修改
253 - "edit":false,  
254 - // 是否显示  
255 - "open":false, 294 + "edit": false,
  295 + // 微信是否显示
  296 + "wechatOpen": false,
  297 + // 支付宝是否显示
  298 + "aliPayOpen": false,
256 // 应用ID 299 // 应用ID
257 "appId": null, 300 "appId": null,
258 // 渠道编码 301 // 渠道编码
@@ -279,7 +322,6 @@ export default { @@ -279,7 +322,6 @@ export default {
279 this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime'); 322 this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
280 // 执行查询 323 // 执行查询
281 getAppPage(params).then(response => { 324 getAppPage(params).then(response => {
282 - console.log(response.data);  
283 this.list = response.data.list; 325 this.list = response.data.list;
284 this.total = response.data.total; 326 this.total = response.data.total;
285 this.loading = false; 327 this.loading = false;
@@ -355,9 +397,9 @@ export default { @@ -355,9 +397,9 @@ export default {
355 // 修改的提交 397 // 修改的提交
356 if (this.form.id != null) { 398 if (this.form.id != null) {
357 updateApp(this.form).then(response => { 399 updateApp(this.form).then(response => {
358 - this.msgSuccess("修改成功");  
359 - this.open = false;  
360 - this.getList(); 400 + this.msgSuccess("修改成功");
  401 + this.open = false;
  402 + this.getList();
361 }); 403 });
362 return; 404 return;
363 } 405 }
@@ -407,33 +449,47 @@ export default { @@ -407,33 +449,47 @@ export default {
407 */ 449 */
408 handleGetMerchantListByName(name) { 450 handleGetMerchantListByName(name) {
409 getMerchantListByName(name).then(response => { 451 getMerchantListByName(name).then(response => {
410 - console.log(response)  
411 this.merchantList = response.data; 452 this.merchantList = response.data;
412 }); 453 });
413 }, 454 },
414 /** 455 /**
415 * 修改支付渠道信息 456 * 修改支付渠道信息
416 */ 457 */
417 - handleUpdateChannel(row, payCode) {  
418 - this.wechatChannelParam.edit = true;  
419 - this.wechatChannelParam.loading = true;  
420 - this.wechatChannelParam.appId = row.id;  
421 - this.wechatChannelParam.payCode = payCode;  
422 - this.wechatChannelParam.payMerchant = row.payMerchant;  
423 - this.wechatChannelParam.open = true; 458 + handleUpdateChannel(row, payCode, type) {
  459 + this.settingChannelParam(row, payCode, type)
  460 + this.channelParam.edit = true;
  461 + this.channelParam.loading = true;
  462 +
424 }, 463 },
425 /** 464 /**
426 * 新增支付渠道信息 465 * 新增支付渠道信息
427 */ 466 */
428 - handleCreateChannel(row, payCode) {  
429 - this.wechatChannelParam.edit = false;  
430 - this.wechatChannelParam.loading = false;  
431 - this.wechatChannelParam.appId = row.id;  
432 - this.wechatChannelParam.payCode = payCode;  
433 - this.wechatChannelParam.payMerchant = row.payMerchant;  
434 - this.wechatChannelParam.open = true; 467 + handleCreateChannel(row, payCode, type) {
  468 + this.settingChannelParam(row, payCode, type)
  469 + this.channelParam.edit = false;
  470 + this.channelParam.loading = false;
  471 +
  472 +
  473 + },
  474 + /**
  475 + * 设置支付渠道信息
  476 + */
  477 + settingChannelParam(row, payCode, type) {
  478 + if (type === PayType.WECHAT) {
  479 + this.channelParam.wechatOpen = true;
  480 + this.channelParam.aliPayOpen = false;
  481 + }
  482 + if (type === PayType.ALIPAY) {
  483 + this.channelParam.aliPayOpen = true;
  484 + this.channelParam.wechatOpen = false;
  485 + }
  486 + this.channelParam.edit = false;
  487 + this.channelParam.loading = false;
  488 + this.channelParam.appId = row.id;
  489 + this.channelParam.payCode = payCode;
  490 + this.channelParam.payMerchant = row.payMerchant;
435 }, 491 },
436 - refreshTable(){ 492 + refreshTable() {
437 this.getList(); 493 this.getList();
438 } 494 }
439 } 495 }
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java
@@ -9,21 +9,35 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -9,21 +9,35 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
9 */ 9 */
10 public interface PayErrorCodeCoreConstants { 10 public interface PayErrorCodeCoreConstants {
11 11
12 - // ========== APP 模块 1-007-000-000 ========== 12 + /**
  13 + * ========== APP 模块 1-007-000-000 ==========
  14 + */
13 ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在"); 15 ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
14 ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用"); 16 ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
15 17
16 - // ========== CHANNEL 模块 1-007-001-000 ========== 18 + /**
  19 + * ========== CHANNEL 模块 1-007-001-000 ==========
  20 + */
17 ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在"); 21 ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在");
18 ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用"); 22 ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用");
19 ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在"); 23 ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在");
20 -  
21 - // ========== ORDER 模块 1-007-002-000 ========== 24 + ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在");
  25 + ErrorCode CHANNEL_KEY_READ_ERROR = new ErrorCode(1007001004, "支付渠道秘钥文件读取失败");
  26 + ErrorCode CHANNEL_EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道");
  27 + ErrorCode CHANNEL_WECHAT_VERSION_2_MCH_KEY_IS_NULL = new ErrorCode(1007001006,"微信渠道v2版本中商户密钥不可为空");
  28 + ErrorCode CHANNEL_WECHAT_VERSION_3_PRIVATE_KEY_IS_NULL = new ErrorCode(1007001006,"微信渠道v3版本apiclient_key.pem不可为空");
  29 + ErrorCode CHANNEL_WECHAT_VERSION_3_CERT_KEY_IS_NULL = new ErrorCode(1007001006,"微信渠道v3版本中apiclient_cert.pem不可为空");
  30 + /**
  31 + * ========== ORDER 模块 1-007-002-000 ==========
  32 + */
22 ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在"); 33 ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(1007002000, "支付订单不存在");
23 ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付"); 34 ErrorCode PAY_ORDER_STATUS_IS_NOT_WAITING = new ErrorCode(1007002001, "支付订单不处于待支付");
24 ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付"); 35 ErrorCode PAY_ORDER_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007002002, "支付订单不处于已支付");
25 ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(1007002003, "支付订单用户不正确"); 36 ErrorCode PAY_ORDER_ERROR_USER = new ErrorCode(1007002003, "支付订单用户不正确");
26 - // ========== ORDER 模块(拓展单) 1-007-003-000 ========== 37 +
  38 + /**
  39 + * ========== ORDER 模块(拓展单) 1-007-003-000 ==========
  40 + */
27 ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在"); 41 ErrorCode PAY_ORDER_EXTENSION_NOT_FOUND = new ErrorCode(1007003000, "支付交易拓展单不存在");
28 ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付"); 42 ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
29 ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007003002, "支付订单不处于已支付"); 43 ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_SUCCESS = new ErrorCode(1007003002, "支付订单不处于已支付");
@@ -46,12 +60,4 @@ public interface PayErrorCodeCoreConstants { @@ -46,12 +60,4 @@ public interface PayErrorCodeCoreConstants {
46 ErrorCode APP_NOT_EXISTS = new ErrorCode(1007005000, "支付应用信息不存在"); 60 ErrorCode APP_NOT_EXISTS = new ErrorCode(1007005000, "支付应用信息不存在");
47 61
48 62
49 - /**  
50 - * ========== 支付渠道 1-007-001-000 ==========  
51 - */  
52 - ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007001003, "支付渠道不存在");  
53 - ErrorCode CHANNEL_KEY_READ_ERROR = new ErrorCode(1007001004, "支付渠道秘钥文件读取失败");  
54 - // TODO @aquan:下面这个错误码,缺了 CHANNEL 前缀。另外,错误码的分段,上面有啦,合并下进去哈  
55 - ErrorCode EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007001005, "已存在相同的渠道");  
56 -  
57 } 63 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java
@@ -65,6 +65,8 @@ public class PayClientFactoryImpl implements PayClientFactory { @@ -65,6 +65,8 @@ public class PayClientFactoryImpl implements PayClientFactory {
65 case WX_APP: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config); 65 case WX_APP: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config);
66 case ALIPAY_WAP: return (AbstractPayClient<Config>) new AlipayWapPayClient(channelId, (AlipayPayClientConfig) config); 66 case ALIPAY_WAP: return (AbstractPayClient<Config>) new AlipayWapPayClient(channelId, (AlipayPayClientConfig) config);
67 case ALIPAY_QR: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config); 67 case ALIPAY_QR: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
  68 + case ALIPAY_APP: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
  69 + case ALIPAY_PC: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
68 } 70 }
69 // 创建失败,错误日志 + 抛出异常 71 // 创建失败,错误日志 + 抛出异常
70 log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", config); 72 log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", config);
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java
@@ -3,7 +3,11 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; @@ -3,7 +3,11 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
3 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; 3 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
4 import lombok.Data; 4 import lombok.Data;
5 5
  6 +import javax.validation.constraints.NotBlank;
  7 +import javax.validation.constraints.NotNull;
  8 +
6 // TODO 芋艿:参数校验 9 // TODO 芋艿:参数校验
  10 +
7 /** 11 /**
8 * 支付宝的 PayClientConfig 实现类 12 * 支付宝的 PayClientConfig 实现类
9 * 属性主要来自 {@link com.alipay.api.AlipayConfig} 的必要属性 13 * 属性主要来自 {@link com.alipay.api.AlipayConfig} 的必要属性
@@ -25,11 +29,11 @@ public class AlipayPayClientConfig implements PayClientConfig { @@ -25,11 +29,11 @@ public class AlipayPayClientConfig implements PayClientConfig {
25 /** 29 /**
26 * 公钥类型 - 公钥模式 30 * 公钥类型 - 公钥模式
27 */ 31 */
28 - private static final Integer MODE_PUBLIC_KEY = 1; 32 + public static final Integer MODE_PUBLIC_KEY = 1;
29 /** 33 /**
30 * 公钥类型 - 证书模式 34 * 公钥类型 - 证书模式
31 */ 35 */
32 - private static final Integer MODE_CERTIFICATE = 2; 36 + public static final Integer MODE_CERTIFICATE = 2;
33 37
34 /** 38 /**
35 * 签名算法类型 - RSA 39 * 签名算法类型 - RSA
@@ -41,18 +45,21 @@ public class AlipayPayClientConfig implements PayClientConfig { @@ -41,18 +45,21 @@ public class AlipayPayClientConfig implements PayClientConfig {
41 * 1. {@link #SERVER_URL_PROD} 45 * 1. {@link #SERVER_URL_PROD}
42 * 2. {@link #SERVER_URL_SANDBOX} 46 * 2. {@link #SERVER_URL_SANDBOX}
43 */ 47 */
  48 + @NotBlank(message = "网关地址不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
44 private String serverUrl; 49 private String serverUrl;
45 50
46 /** 51 /**
47 * 开放平台上创建的应用的 ID 52 * 开放平台上创建的应用的 ID
48 */ 53 */
  54 + @NotBlank(message = "开放平台上创建的应用的 ID不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
49 private String appId; 55 private String appId;
50 56
51 /** 57 /**
52 * 签名算法类型,推荐:RSA2 58 * 签名算法类型,推荐:RSA2
53 - * 59 + * <p>
54 * {@link #SIGN_TYPE_DEFAULT} 60 * {@link #SIGN_TYPE_DEFAULT}
55 */ 61 */
  62 + @NotBlank(message = "签名算法类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
56 private String signType; 63 private String signType;
57 64
58 /** 65 /**
@@ -60,30 +67,43 @@ public class AlipayPayClientConfig implements PayClientConfig { @@ -60,30 +67,43 @@ public class AlipayPayClientConfig implements PayClientConfig {
60 * 1. {@link #MODE_PUBLIC_KEY} 情况,privateKey + alipayPublicKey 67 * 1. {@link #MODE_PUBLIC_KEY} 情况,privateKey + alipayPublicKey
61 * 2. {@link #MODE_CERTIFICATE} 情况,appCertContent + alipayPublicCertContent + rootCertContent 68 * 2. {@link #MODE_CERTIFICATE} 情况,appCertContent + alipayPublicCertContent + rootCertContent
62 */ 69 */
  70 + @NotNull(message = "公钥类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
63 private Integer mode; 71 private Integer mode;
64 72
65 // ========== 公钥模式 ========== 73 // ========== 公钥模式 ==========
66 /** 74 /**
67 * 商户私钥 75 * 商户私钥
68 */ 76 */
  77 + @NotBlank(message = "商户私钥不能为空", groups = {ModePublicKey.class})
69 private String privateKey; 78 private String privateKey;
  79 +
70 /** 80 /**
71 * 支付宝公钥字符串 81 * 支付宝公钥字符串
72 */ 82 */
  83 + @NotBlank(message = "支付宝公钥字符串不能为空", groups = {ModePublicKey.class})
73 private String alipayPublicKey; 84 private String alipayPublicKey;
74 85
75 // ========== 证书模式 ========== 86 // ========== 证书模式 ==========
76 /** 87 /**
77 * 指定商户公钥应用证书内容字符串 88 * 指定商户公钥应用证书内容字符串
78 */ 89 */
  90 + @NotBlank(message = "指定商户公钥应用证书内容不能为空", groups = {ModeCertificate.class})
79 private String appCertContent; 91 private String appCertContent;
80 /** 92 /**
81 * 指定支付宝公钥证书内容字符串 93 * 指定支付宝公钥证书内容字符串
82 */ 94 */
  95 + @NotBlank(message = "指定支付宝公钥证书内容不能为空", groups = {ModeCertificate.class})
83 private String alipayPublicCertContent; 96 private String alipayPublicCertContent;
84 /** 97 /**
85 * 指定根证书内容字符串 98 * 指定根证书内容字符串
86 */ 99 */
  100 + @NotBlank(message = "指定根证书内容字符串不能为空", groups = {ModeCertificate.class})
87 private String rootCertContent; 101 private String rootCertContent;
88 102
  103 + public interface ModePublicKey {
  104 + }
  105 +
  106 + public interface ModeCertificate {
  107 + }
  108 +
89 } 109 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPayClientConfig.java
@@ -4,10 +4,12 @@ import cn.hutool.core.io.IoUtil; @@ -4,10 +4,12 @@ import cn.hutool.core.io.IoUtil;
4 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; 4 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
5 import lombok.Data; 5 import lombok.Data;
6 6
  7 +import javax.validation.constraints.NotBlank;
7 import java.io.FileInputStream; 8 import java.io.FileInputStream;
8 import java.io.FileNotFoundException; 9 import java.io.FileNotFoundException;
9 10
10 // TODO 芋艿:参数校验 11 // TODO 芋艿:参数校验
  12 +
11 /** 13 /**
12 * 微信支付的 PayClientConfig 实现类 14 * 微信支付的 PayClientConfig 实现类
13 * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性 15 * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性
@@ -20,13 +22,13 @@ public class WXPayClientConfig implements PayClientConfig { @@ -20,13 +22,13 @@ public class WXPayClientConfig implements PayClientConfig {
20 // TODO 芋艿:V2 or V3 客户端 22 // TODO 芋艿:V2 or V3 客户端
21 /** 23 /**
22 * API 版本 - V2 24 * API 版本 - V2
23 - * 25 + * <p>
24 * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1 26 * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1
25 */ 27 */
26 public static final String API_VERSION_V2 = "v2"; 28 public static final String API_VERSION_V2 = "v2";
27 /** 29 /**
28 * API 版本 - V3 30 * API 版本 - V3
29 - * 31 + * <p>
30 * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml 32 * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml
31 */ 33 */
32 public static final String API_VERSION_V3 = "v3"; 34 public static final String API_VERSION_V3 = "v3";
@@ -34,14 +36,17 @@ public class WXPayClientConfig implements PayClientConfig { @@ -34,14 +36,17 @@ public class WXPayClientConfig implements PayClientConfig {
34 /** 36 /**
35 * 公众号或者小程序的 appid 37 * 公众号或者小程序的 appid
36 */ 38 */
  39 + @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class})
37 private String appId; 40 private String appId;
38 /** 41 /**
39 * 商户号 42 * 商户号
40 */ 43 */
  44 + @NotBlank(message = "商户号 不能为空", groups = {V2.class, V3.class})
41 private String mchId; 45 private String mchId;
42 /** 46 /**
43 * API 版本 47 * API 版本
44 */ 48 */
  49 + @NotBlank(message = "API 版本 不能为空", groups = {V2.class, V3.class})
45 private String apiVersion; 50 private String apiVersion;
46 51
47 // ========== V2 版本的参数 ========== 52 // ========== V2 版本的参数 ==========
@@ -49,33 +54,37 @@ public class WXPayClientConfig implements PayClientConfig { @@ -49,33 +54,37 @@ public class WXPayClientConfig implements PayClientConfig {
49 /** 54 /**
50 * 商户密钥 55 * 商户密钥
51 */ 56 */
  57 + @NotBlank(message = "商户密钥 不能为空", groups = {V2.class})
52 private String mchKey; 58 private String mchKey;
53 -// /**  
54 -// * apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径.  
55 -// * 对应的字符串  
56 -// *  
57 -// * 注意,可通过 {@link #main(String[])} 读取  
58 -// */  
59 -// private String keyContent; 59 + /**
  60 + * apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径.
  61 + * 对应的字符串
  62 + *
  63 + * 注意,可通过 {@link #main(String[])} 读取
  64 + */
  65 + /// private String keyContent;
60 66
61 // ========== V3 版本的参数 ========== 67 // ========== V3 版本的参数 ==========
62 /** 68 /**
63 * apiclient_key.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. 69 * apiclient_key.pem 证书文件的绝对路径或者以 classpath: 开头的类路径.
64 * 对应的字符串 70 * 对应的字符串
65 - * 71 + * <p>
66 * 注意,可通过 {@link #main(String[])} 读取 72 * 注意,可通过 {@link #main(String[])} 读取
67 */ 73 */
  74 + @NotBlank(message = "apiclient_key 不能为空", groups = {V3.class})
68 private String privateKeyContent; 75 private String privateKeyContent;
69 /** 76 /**
70 * apiclient_cert.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. 77 * apiclient_cert.pem 证书文件的绝对路径或者以 classpath: 开头的类路径.
71 * 对应的字符串 78 * 对应的字符串
72 - * 79 + * <p>
73 * 注意,可通过 {@link #main(String[])} 读取 80 * 注意,可通过 {@link #main(String[])} 读取
74 */ 81 */
  82 + @NotBlank(message = "apiclient_cert 不能为空", groups = {V3.class})
75 private String privateCertContent; 83 private String privateCertContent;
76 /** 84 /**
77 * apiV3 秘钥值 85 * apiV3 秘钥值
78 */ 86 */
  87 + @NotBlank(message = "apiV3 秘钥值 不能为空", groups = {V3.class})
79 private String apiV3Key; 88 private String apiV3Key;
80 89
81 public static void main(String[] args) throws FileNotFoundException { 90 public static void main(String[] args) throws FileNotFoundException {
@@ -85,4 +94,17 @@ public class WXPayClientConfig implements PayClientConfig { @@ -85,4 +94,17 @@ public class WXPayClientConfig implements PayClientConfig {
85 System.out.println(IoUtil.readUtf8(new FileInputStream(path))); 94 System.out.println(IoUtil.readUtf8(new FileInputStream(path)));
86 } 95 }
87 96
  97 +
  98 + /**
  99 + * 分组校验 v2版本
  100 + */
  101 + public interface V2 {
  102 + }
  103 +
  104 + /**
  105 + * 分组校验 v3版本
  106 + */
  107 + public interface V3 {
  108 + }
  109 +
88 } 110 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelEnum.java
@@ -15,8 +15,6 @@ import lombok.Getter; @@ -15,8 +15,6 @@ import lombok.Getter;
15 public enum PayChannelEnum { 15 public enum PayChannelEnum {
16 16
17 WX_PUB("wx_pub", "微信 JSAPI 支付"), // 公众号的网页 17 WX_PUB("wx_pub", "微信 JSAPI 支付"), // 公众号的网页
18 - // TODO @芋艿 这个地方你写的是 wx_lit 是不是少写了一个e? 还是我这里多加了一个e  
19 - // TODO @aquan:这里就是 lite 哈,轻量  
20 WX_LITE("wx_lite","微信小程序支付"), 18 WX_LITE("wx_lite","微信小程序支付"),
21 WX_APP("wx_app", "微信 App 支付"), 19 WX_APP("wx_app", "微信 App 支付"),
22 20
@@ -36,8 +34,38 @@ public enum PayChannelEnum { @@ -36,8 +34,38 @@ public enum PayChannelEnum {
36 */ 34 */
37 private String name; 35 private String name;
38 36
  37 + /**
  38 + * 微信支付
  39 + */
  40 + public static final String WECHAT = "WECHAT";
  41 +
  42 + /**
  43 + * 支付宝支付
  44 + */
  45 + public static final String ALIPAY = "ALIPAY";
  46 +
39 public static PayChannelEnum getByCode(String code) { 47 public static PayChannelEnum getByCode(String code) {
40 return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); 48 return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
41 } 49 }
42 50
  51 + /**
  52 + * 判断当前渠道是那种支付方式
  53 + * @param code
  54 + * @return
  55 + */
  56 + public static String verifyWechatOrAliPay(String code){
  57 + switch (PayChannelEnum.getByCode(code)){
  58 + case WX_PUB:
  59 + case WX_LITE:
  60 + case WX_APP:
  61 + return WECHAT;
  62 + case ALIPAY_PC:
  63 + case ALIPAY_WAP:
  64 + case ALIPAY_APP:
  65 + case ALIPAY_QR:
  66 + return ALIPAY;
  67 + }
  68 + return null;
  69 + }
  70 +
43 } 71 }