Commit 6069a387ea17434ec9bd246ae070bae5529311cc
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<PayAppDO> { | @@ -31,14 +31,14 @@ public interface PayAppMapper extends BaseMapperX<PayAppDO> { | ||
| 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<PayChannelDO> { | @@ -26,7 +27,7 @@ public interface PayChannelMapper extends BaseMapperX<PayChannelDO> { | ||
| 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<PayChannelDO> { | @@ -39,9 +40,52 @@ public interface PayChannelMapper extends BaseMapperX<PayChannelDO> { | ||
| 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<PayMerchantDO> { | @@ -39,4 +40,14 @@ public interface PayMerchantMapper extends BaseMapperX<PayMerchantDO> { | ||
| 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
yudao-admin-server/src/test/resources/sql/create_tables.sql
| @@ -464,3 +464,37 @@ CREATE TABLE IF NOT EXISTS "pay_merchant" ( | @@ -464,3 +464,37 @@ CREATE TABLE IF NOT EXISTS "pay_merchant" ( | ||
| 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
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 | } |