From 6069a387ea17434ec9bd246ae070bae5529311cc Mon Sep 17 00:00:00 2001 From: aquan Date: Sun, 21 Nov 2021 19:31:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=8C=E5=96=84=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=BA=94=E7=94=A8=E5=92=8C=E6=94=AF=E4=BB=98=E6=B8=A0?= =?UTF-8?q?=E9=81=93=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91=EF=BC=8C=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=EF=BC=8C=E5=9F=BA?= =?UTF-8?q?=E4=BA=8Evalidator=E5=AE=8C=E6=88=90=E6=89=8B=E5=8A=A8=E6=A0=A1?= =?UTF-8?q?=E9=AA=8Cconfig?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/pay-dict.sql | 16 + .../pay/controller/app/PayAppController.java | 2 +- .../controller/app/vo/PayAppExportReqVO.java | 4 +- .../channel/PayChannelController.java | 123 ++---- .../channel/vo/PayChannelCreateReqVO.java | 11 +- .../channel/vo/PayChannelRespVO.java | 2 + .../channel/vo/PayChannelUpdateReqVO.java | 3 + .../channel/vo/PayWeChatChannelRespVO.java | 65 --- .../vo/PayWechatChannelCreateReqVO.java | 68 --- .../vo/PayWechatChannelUpdateReqVO.java | 68 --- .../convert/channel/PayChannelConvert.java | 13 +- .../pay/dal/mysql/app/PayAppMapper.java | 4 +- .../dal/mysql/channel/PayChannelMapper.java | 48 ++- .../dal/mysql/merchant/PayMerchantMapper.java | 11 + .../service/app/impl/PayAppServiceImpl.java | 25 +- .../service/channel/PayChannelService.java | 36 +- .../channel/impl/PayChannelServiceImpl.java | 171 +++++--- .../service/merchant/PayMerchantService.java | 15 +- .../merchant/impl/PayMerchantServiceImpl.java | 14 +- .../pay/app/service/PayAppServiceTest.java | 193 --------- .../pay/channel/PayChannelServiceTest.java | 202 --------- .../pay/service/app/PayAppServiceTest.java | 249 +++++++++++ .../channel/PayChannelServiceTest.java | 404 ++++++++++++++++++ .../merchant}/PayMerchantServiceTest.java | 8 +- .../src/test/resources/sql/clean.sql | 2 + .../src/test/resources/sql/create_tables.sql | 34 ++ yudao-admin-ui/src/api/pay/channel.js | 33 +- yudao-admin-ui/src/utils/constants.js | 5 + yudao-admin-ui/src/utils/dict.js | 7 +- .../pay/app/components/aliPayChannelForm.vue | 354 +++++++++++++++ ...hatJsApiForm.vue => wechatChannelForm.vue} | 142 +++--- yudao-admin-ui/src/views/pay/app/index.vue | 176 +++++--- .../pay/enums/PayErrorCodeCoreConstants.java | 32 +- .../client/impl/PayClientFactoryImpl.java | 2 + .../impl/alipay/AlipayPayClientConfig.java | 26 +- .../client/impl/wx/WXPayClientConfig.java | 44 +- .../pay/core/enums/PayChannelEnum.java | 32 +- 37 files changed, 1623 insertions(+), 1021 deletions(-) delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWeChatChannelRespVO.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelCreateReqVO.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelUpdateReqVO.java delete mode 100644 yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/app/service/PayAppServiceTest.java delete mode 100644 yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/channel/PayChannelServiceTest.java create mode 100644 yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/PayAppServiceTest.java create mode 100644 yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelServiceTest.java rename yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/{merchant/service => service/merchant}/PayMerchantServiceTest.java (96%) create mode 100644 yudao-admin-ui/src/views/pay/app/components/aliPayChannelForm.vue rename yudao-admin-ui/src/views/pay/app/components/{wechatJsApiForm.vue => wechatChannelForm.vue} (66%) diff --git a/sql/pay-dict.sql b/sql/pay-dict.sql index 3b769568cf..9aa504d198 100644 --- a/sql/pay-dict.sql +++ b/sql/pay-dict.sql @@ -22,3 +22,19 @@ INSERT INTO `sys_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `cre 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'); 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'); + +-- 支付渠道支付宝算法类型 +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'); +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'); + + +-- 支付渠道支付宝公钥类型 +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'); +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'); +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'); + + +-- 支付宝网关地址 +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'); +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'); +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'); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/PayAppController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/PayAppController.java index cf3df2aa49..196666430f 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/PayAppController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/PayAppController.java @@ -123,7 +123,7 @@ public class PayAppController { // 得到所有的应用编号,查出所有的通道 Collection payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId); - List channels = channelService.getSimpleChannels(payAppIds); + List channels = channelService.getChannelListByAppIds(payAppIds); // 得到所有的商户信息 Collection merchantIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getMerchantId); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/vo/PayAppExportReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/vo/PayAppExportReqVO.java index e2c68480de..b5d284447f 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/vo/PayAppExportReqVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/app/vo/PayAppExportReqVO.java @@ -27,8 +27,8 @@ public class PayAppExportReqVO { @ApiModelProperty(value = "退款结果的回调地址") private String refundNotifyUrl; - @ApiModelProperty(value = "商户编号") - private Long merchantId; + @ApiModelProperty(value = "商户名称") + private String merchantName; @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @ApiModelProperty(value = "开始创建时间") diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/PayChannelController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/PayChannelController.java index b44dfa9a9f..2b1d468f8f 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/PayChannelController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/PayChannelController.java @@ -1,40 +1,35 @@ package cn.iocoder.yudao.adminserver.modules.pay.controller.channel; -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient; -import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; - -import org.springframework.validation.annotation.Validated; -import org.springframework.security.access.prepost.PreAuthorize; - -import io.swagger.annotations.*; - -import javax.validation.*; -import javax.servlet.http.*; -import java.util.*; -import java.io.IOException; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; - -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; - -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; - import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*; import cn.iocoder.yudao.adminserver.modules.pay.convert.channel.PayChannelConvert; import cn.iocoder.yudao.adminserver.modules.pay.service.channel.PayChannelService; -import org.springframework.web.multipart.MultipartFile; +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +/** + * 支付渠道 controller 组件 + * @author aquan + */ @Api(tags = "支付渠道") @RestController @RequestMapping("/pay/channel") @@ -44,7 +39,7 @@ public class PayChannelController { @Resource private PayChannelService channelService; - // todo 芋艿 这几个生成的方法是没用到的 您看要不删除了把? -----start + @PostMapping("/create") @ApiOperation("创建支付渠道 ") @PreAuthorize("@ss.hasPermission('pay:channel:create')") @@ -108,28 +103,7 @@ public class PayChannelController { ExcelUtils.write(response, "支付渠道.xls", "数据", PayChannelExcelVO.class, datas); } - // todo 芋艿 这几个生成的方法是没用到的 您看要不删除了把? -----end - - @PostMapping("/parsing-pem") - @ApiOperation("解析pem证书转换为字符串") - @PreAuthorize("@ss.hasPermission('pay:channel:parsing')") - @ApiImplicitParam(name = "file", value = "pem文件", required = true, dataTypeClass = MultipartFile.class) - public CommonResult parsingPemFile(@RequestParam("file") MultipartFile file) { - return success(channelService.parsingPemFile(file)); - } - - @PostMapping("/create-wechat") - @ApiOperation("创建支付渠道 ") - @PreAuthorize("@ss.hasPermission('pay:channel:create')") - public CommonResult createWechatChannel(@Valid @RequestBody PayWechatChannelCreateReqVO reqVO) { - // 针对于 V2 或者 V3 版本的参数校验 - this.paramAdvanceCheck(reqVO.getWeChatConfig().getApiVersion(),reqVO.getWeChatConfig().getMchKey(), - reqVO.getWeChatConfig().getPrivateKeyContent(),reqVO.getWeChatConfig().getPrivateCertContent()); - - return success(channelService.createWechatChannel(reqVO)); - } - - @GetMapping("/get-wechat") + @GetMapping("/get-channel") @ApiOperation("根据条件查询微信支付渠道") @ApiImplicitParams({ @ApiImplicitParam(name = "merchantId", value = "商户编号", @@ -140,51 +114,16 @@ public class PayChannelController { required = true, example = "wx_pub", dataTypeClass = String.class) }) @PreAuthorize("@ss.hasPermission('pay:channel:query')") - public CommonResult getWeChatChannel( + public CommonResult getChannel( @RequestParam Long merchantId, @RequestParam Long appId, @RequestParam String code) { // 獲取渠道 PayChannelDO channel = channelService.getChannelByConditions(merchantId, appId, code); if (channel == null) { - return success(new PayWeChatChannelRespVO()); + return success(new PayChannelRespVO()); } - // 拼凑数据 - PayWeChatChannelRespVO respVo = PayChannelConvert.INSTANCE.convert2(channel); - WXPayClientConfig config = (WXPayClientConfig) channel.getConfig(); - respVo.setWeChatConfig(PayChannelConvert.INSTANCE.configConvert(config)); + PayChannelRespVO respVo = PayChannelConvert.INSTANCE.convert(channel); return success(respVo); } - - @PutMapping("/update-wechat") - @ApiOperation("更新微信支付渠道 ") - @PreAuthorize("@ss.hasPermission('pay:channel:update')") - public CommonResult updateWechatChannel(@Valid @RequestBody PayWechatChannelUpdateReqVO updateReqVO) { - - // 针对于 V2 或者 V3 版本的参数校验 - this.paramAdvanceCheck(updateReqVO.getWeChatConfig().getApiVersion(),updateReqVO.getWeChatConfig().getMchKey(), - updateReqVO.getWeChatConfig().getPrivateKeyContent(),updateReqVO.getWeChatConfig().getPrivateCertContent()); - - channelService.updateWechatChannel(updateReqVO); - return success(true); - } - - /** - * 预检测微信秘钥参数 - * @param version 版本 - * @param mchKey v2版本秘钥 - * @param privateKeyContent v3版本apiclient_key - * @param privateCertContent v3版本中apiclient_cert - */ - private void paramAdvanceCheck(String version, String mchKey, String privateKeyContent, String privateCertContent) { - // 针对于 V2 或者 V3 版本的参数校验 - if (version.equals(WXPayClientConfig.API_VERSION_V2)) { - Assert.notNull(mchKey, "v2版本中商户密钥不可为空"); - } - if (version.equals(WXPayClientConfig.API_VERSION_V3)) { - Assert.notNull(privateKeyContent, "v3版本apiclient_key.pem不可为空"); - Assert.notNull(privateCertContent, "v3版本中apiclient_cert.pem不可为空"); - } - } - } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelCreateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelCreateReqVO.java index 4ff0d75125..e0fac83821 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelCreateReqVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelCreateReqVO.java @@ -1,18 +1,23 @@ package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import javax.validation.constraints.NotBlank; + @ApiModel("支付渠道 创建 Request VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) public class PayChannelCreateReqVO extends PayChannelBaseVO { - // TODO @aquan:我在想,要不这个创建和修改特殊一点。前端传递 string 过来,后端解析成对应的。因为有 code,所以我们都知道是哪个配置类。 - // 然后,在 PayChannelEnum 里,枚举每个渠道对应的配置类。另外,我们就不单独给配置类搞 vo 了。参数校验,通过手动调用 Validator 去校验。 - // 通过这样的方式,VO 和 api 都收成,一个 update,一个 create + + @ApiModelProperty(value = "通道配置的json字符串") + @NotBlank(message = "通道配置不能为空") + private String config; + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelRespVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelRespVO.java index b44625b240..02873b9f52 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelRespVO.java +++ b/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 { @ApiModelProperty(value = "创建时间", required = true) private Date createTime; + @ApiModelProperty(value = "配置", required = true) + private String config; } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelUpdateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelUpdateReqVO.java index 658ed8ba35..fdefc7badc 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayChannelUpdateReqVO.java +++ b/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 { @NotNull(message = "商户编号不能为空") private Long id; + @ApiModelProperty(value = "通道配置的json字符串") + @NotBlank(message = "通道配置不能为空") + private String config; } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWeChatChannelRespVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWeChatChannelRespVO.java deleted file mode 100644 index eafa044fdd..0000000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWeChatChannelRespVO.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import javax.validation.Valid; -import java.util.Date; - -@ApiModel("支付微信渠道 Response VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class PayWeChatChannelRespVO extends PayChannelBaseVO { - - @ApiModelProperty(value = "商户编号", required = true) - private Long id; - - @ApiModelProperty(value = "创建时间", required = true) - private Date createTime; - - /** - * 微信配置类 - */ - @Valid - private WeChatConfig weChatConfig; - - /** - * 微信配置类 - */ - @Data - @ApiModel("微信配置类") - public static class WeChatConfig { - - @ApiModelProperty(value = "公众号或者小程序的 appid", required = true, example = "wx041349c6f39b261b") - private String appId; - - - @ApiModelProperty(value = "商户号", required = true, example = "1545083881") - private String mchId; - - @ApiModelProperty(value = "API 版本", required = true, example = "v2") - private String apiVersion; - - // ========== V2 版本的参数 ========== - - @ApiModelProperty(value = "商户密钥", required = true, example = "0alL64UDQdaCwiKZ73ib7ypaIjMns06p") - private String mchKey; - - /// todo @aquan 暂不支持 .p12上传 后期优化 - /// apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. 对应的字符串 - /// private String keyContent; - - // ========== V3 版本的参数 ========== - - @ApiModelProperty(value = "apiclient_key.pem 证书对应的字符串", required = true, example = "-----BEGIN PRIVATE KEY-----") - private String privateKeyContent; - - @ApiModelProperty(value = "apiclient_cert.pem 证书对应的字符串", required = true, example = "-----BEGIN CERTIFICATE-----") - private String privateCertContent; - } - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelCreateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelCreateReqVO.java deleted file mode 100644 index 36bfd579d3..0000000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelCreateReqVO.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo; - -import com.fasterxml.jackson.annotation.JsonClassDescription; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * 支付渠道微信创建Request VO - * @author aquan - */ -@ApiModel("支付渠道微信创建Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class PayWechatChannelCreateReqVO extends PayChannelBaseVO { - - /** - * 微信配置类 - */ - @Valid - private WeChatConfig weChatConfig; - - /** - * 微信配置类 - */ - @Data - @ApiModel("微信配置类") - public static class WeChatConfig { - - @NotBlank(message = "公众号或者小程序的 appid不能为空") - @ApiModelProperty(value = "公众号或者小程序的 appid", required = true, example = "wx041349c6f39b261b") - private String appId; - - - @NotBlank(message = "商户号不能为空") - @ApiModelProperty(value = "商户号", required = true, example = "1545083881") - private String mchId; - - @NotNull(message = "API 版本不能为空") - @ApiModelProperty(value = "API 版本", required = true, example = "v2") - private String apiVersion; - - // ========== V2 版本的参数 ========== - - @ApiModelProperty(value = "商户密钥", required = true, example = "0alL64UDQdaCwiKZ73ib7ypaIjMns06p") - private String mchKey; - - /// todo @aquan 暂不支持 .p12上传 后期优化 - /// apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. 对应的字符串 - /// private String keyContent; - - // ========== V3 版本的参数 ========== - - @ApiModelProperty(value = "apiclient_key.pem 证书对应的字符串", required = true, example = "-----BEGIN PRIVATE KEY-----") - private String privateKeyContent; - - @ApiModelProperty(value = "apiclient_cert.pem 证书对应的字符串", required = true, example = "-----BEGIN CERTIFICATE-----") - private String privateCertContent; - } - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelUpdateReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelUpdateReqVO.java deleted file mode 100644 index 1685420927..0000000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/controller/channel/vo/PayWechatChannelUpdateReqVO.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -@ApiModel("支付渠道 更新 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class PayWechatChannelUpdateReqVO extends PayChannelBaseVO { - - @ApiModelProperty(value = "商户编号", required = true) - @NotNull(message = "商户编号不能为空") - private Long id; - - /** - * 微信配置类 - */ - @Valid - private PayWechatChannelCreateReqVO.WeChatConfig weChatConfig; - - /** - * 微信配置类 - */ - @Data - @ApiModel("微信配置类") - public static class WeChatConfig { - - @NotBlank(message = "公众号或者小程序的 appid不能为空") - @ApiModelProperty(value = "公众号或者小程序的 appid", required = true, example = "wx041349c6f39b261b") - private String appId; - - - @NotBlank(message = "商户号不能为空") - @ApiModelProperty(value = "商户号", required = true, example = "1545083881") - private String mchId; - - @NotNull(message = "API 版本不能为空") - @ApiModelProperty(value = "API 版本", required = true, example = "v2") - private String apiVersion; - - // ========== V2 版本的参数 ========== - - @ApiModelProperty(value = "商户密钥", required = true, example = "0alL64UDQdaCwiKZ73ib7ypaIjMns06p") - private String mchKey; - - /// todo @aquan 暂不支持 .p12上传 后期优化 - /// apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. 对应的字符串 - /// private String keyContent; - - // ========== V3 版本的参数 ========== - - @ApiModelProperty(value = "apiclient_key.pem 证书对应的字符串", required = true, example = "-----BEGIN PRIVATE KEY-----") - private String privateKeyContent; - - @ApiModelProperty(value = "apiclient_cert.pem 证书对应的字符串", required = true, example = "-----BEGIN CERTIFICATE-----") - private String privateCertContent; - - // TODO @aquan:参数校验。可以使用 @AssertTrue,v2 和 v3 的 - } -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/convert/channel/PayChannelConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/convert/channel/PayChannelConvert.java index 05cb4d5e4d..ee0473c237 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/convert/channel/PayChannelConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/convert/channel/PayChannelConvert.java @@ -23,15 +23,12 @@ public interface PayChannelConvert { PayChannelConvert INSTANCE = Mappers.getMapper(PayChannelConvert.class); @Mapping(target = "config",ignore = true) - PayChannelDO convert(PayWechatChannelCreateReqVO bean); - - @Mapping(target = "config",ignore = true) - PayChannelDO convert(PayWechatChannelUpdateReqVO bean); - PayChannelDO convert(PayChannelCreateReqVO bean); + @Mapping(target = "config",ignore = true) PayChannelDO convert(PayChannelUpdateReqVO bean); + @Mapping(target = "config",expression = "java(cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString(bean.getConfig()))") PayChannelRespVO convert(PayChannelDO bean); List convertList(List list); @@ -39,13 +36,7 @@ public interface PayChannelConvert { PageResult convertPage(PageResult page); List convertList02(List list); - - WXPayClientConfig configConvert(PayWechatChannelCreateReqVO.WeChatConfig bean); - WXPayClientConfig configConvert(PayWechatChannelUpdateReqVO.WeChatConfig bean); - @Mapping(target = "weChatConfig",ignore = true) - PayWeChatChannelRespVO convert2(PayChannelDO bean); - PayWeChatChannelRespVO.WeChatConfig configConvert(WXPayClientConfig bean); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/app/PayAppMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/app/PayAppMapper.java index e6089d6172..4335b46493 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/app/PayAppMapper.java +++ b/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 { .orderByDesc("id")); } - default List selectList(PayAppExportReqVO reqVO) { + default List selectList(PayAppExportReqVO reqVO, Collection merchantIds) { return selectList(new QueryWrapperX() .likeIfPresent("name", reqVO.getName()) .eqIfPresent("status", reqVO.getStatus()) .eqIfPresent("remark", reqVO.getRemark()) .eqIfPresent("pay_notify_url", reqVO.getPayNotifyUrl()) .eqIfPresent("refund_notify_url", reqVO.getRefundNotifyUrl()) - .eqIfPresent("merchant_id", reqVO.getMerchantId()) + .inIfPresent("merchant_id", merchantIds) .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) .orderByDesc("id")); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/channel/PayChannelMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/channel/PayChannelMapper.java index 2134f08d3b..5be2de26ee 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/channel/PayChannelMapper.java +++ b/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 import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*; @@ -26,7 +27,7 @@ public interface PayChannelMapper extends BaseMapperX { .eqIfPresent("fee_rate", reqVO.getFeeRate()) .eqIfPresent("merchant_id", reqVO.getMerchantId()) .eqIfPresent("app_id", reqVO.getAppId()) - .eqIfPresent("config", reqVO.getConfig()) + // .eqIfPresent("config", reqVO.getConfig()) .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) .orderByDesc("id") ); } @@ -39,9 +40,52 @@ public interface PayChannelMapper extends BaseMapperX { .eqIfPresent("fee_rate", reqVO.getFeeRate()) .eqIfPresent("merchant_id", reqVO.getMerchantId()) .eqIfPresent("app_id", reqVO.getAppId()) - .eqIfPresent("config", reqVO.getConfig()) + // .eqIfPresent("config", reqVO.getConfig()) .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) .orderByDesc("id") ); } + /** + * 根据条件获取通道数量 + * + * @param merchantId 商户编号 + * @param appid 应用编号 + * @param code 通道编码 + * @return 数量 + */ + default Integer getChannelCountByConditions(Long merchantId, Long appid, String code) { + + return this.selectCount(new QueryWrapper().lambda() + .eq(PayChannelDO::getMerchantId, merchantId) + .eq(PayChannelDO::getAppId, appid) + .eq(PayChannelDO::getCode, code) + ); + } + + /** + * 根据条件获取通道 + * + * @param merchantId 商户编号 + * @param appid 应用编号 + * @param code 通道编码 + * @return 数量 + */ + default PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) { + return this.selectOne((new QueryWrapper().lambda() + .eq(PayChannelDO::getMerchantId, merchantId) + .eq(PayChannelDO::getAppId, appid) + .eq(PayChannelDO::getCode, code) + )); + } + + /** + * 根据支付应用ID集合获得支付渠道列表 + * + * @param appIds 应用编号集合 + * @return 支付渠道列表 + */ + default List getChannelListByAppIds(Collection appIds){ + return this.selectList(new QueryWrapper().lambda() + .in(PayChannelDO::getAppId, appIds)); + } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/merchant/PayMerchantMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/merchant/PayMerchantMapper.java index 5abc3a2310..f20572509b 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/dal/mysql/merchant/PayMerchantMapper.java +++ b/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 import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.*; @@ -39,4 +40,14 @@ public interface PayMerchantMapper extends BaseMapperX { .orderByDesc("id")); } + /** + * 根据商户名称模糊查询商户集合 + * + * @param merchantName 商户名称 + * @return 商户集合 + */ + default List getMerchantListByName(String merchantName) { + return this.selectList(new QueryWrapper() + .lambda().likeRight(PayMerchantDO::getName, merchantName)); + } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/impl/PayAppServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/impl/PayAppServiceImpl.java index 327c57b421..cfb6fa44bb 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/impl/PayAppServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/impl/PayAppServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.adminserver.modules.pay.service.app.impl; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppCreateReqVO; 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 import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateReqVO; import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert; import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper; +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper; import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService; import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; @@ -18,10 +20,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.APP_NOT_EXISTS; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -43,7 +42,7 @@ public class PayAppServiceImpl implements PayAppService { * 商户 service 组件 */ @Resource - private PayMerchantService merchantService; + private PayMerchantMapper merchantMapper; @Override public Long createApp(PayAppCreateReqVO createReqVO) { @@ -89,13 +88,20 @@ public class PayAppServiceImpl implements PayAppService { @Override public PageResult getAppPage(PayAppPageReqVO pageReqVO) { - // TODO @aquan:会有一个场景,merchantName 匹配不到商户编号的时候,应该返回没数据的 - return appMapper.selectPage(pageReqVO, this.getMerchantCondition(pageReqVO.getMerchantName())); + Set merchantIdList = this.getMerchantCondition(pageReqVO.getMerchantName()); + if (StrUtil.isNotBlank(pageReqVO.getMerchantName()) && CollectionUtil.isEmpty(merchantIdList)) { + return new PageResult<>(); + } + return appMapper.selectPage(pageReqVO, merchantIdList); } @Override public List getAppList(PayAppExportReqVO exportReqVO) { - return appMapper.selectList(exportReqVO); + Set merchantIdList = this.getMerchantCondition(exportReqVO.getMerchantName()); + if (StrUtil.isNotBlank(exportReqVO.getMerchantName()) && CollectionUtil.isEmpty(merchantIdList)) { + return new ArrayList<>(); + } + return appMapper.selectList(exportReqVO, merchantIdList); } /** @@ -108,7 +114,7 @@ public class PayAppServiceImpl implements PayAppService { if (StrUtil.isBlank(merchantName)) { return Collections.emptySet(); } - return convertSet(merchantService.getMerchantListByName(merchantName), PayMerchantDO::getId); + return convertSet(merchantMapper.getMerchantListByName(merchantName), PayMerchantDO::getId); } /** @@ -131,6 +137,7 @@ public class PayAppServiceImpl implements PayAppService { /** * 检查商户是否存在 + * * @param id 商户编号 */ @VisibleForTesting diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelService.java index 49b5384bb0..1eeb567dd4 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelService.java @@ -12,7 +12,7 @@ import java.util.List; /** * 支付渠道 Service 接口 * - * @author 芋艿 // TODO @aquan:作者不要我 + * @author aquan */ public interface PayChannelService { @@ -76,31 +76,12 @@ public interface PayChannelService { List getChannelList(PayChannelExportReqVO exportReqVO); /** - * 根据支付应用ID集合获取所有的支付渠道 + * 根据支付应用ID集合获得支付渠道列表 * - * @param payIds 支付应用编号集合 - * @return 支付渠道 + * @param appIds 应用编号集合 + * @return 支付渠道列表 */ - // TODO @aquan:暂时不用提供这种哈。之前提供的原因,是数据字典比较特殊。 - List getSimpleChannels(Collection payIds); - - /** - * 解析pem文件获取公钥私钥字符串 - * - * @param file pem公私钥文件 - * @return 解析后的字符串 - */ - // TODO @aquan:可以前端读取么? - String parsingPemFile(MultipartFile file); - - /** - * 创建微信的渠道配置 - * - * @param reqVO 创建信息 - * @return 创建结果 - */ - // TODO @aquan:pojo 如果要做参数校验,需要添加 @Valid - Long createWechatChannel(PayWechatChannelCreateReqVO reqVO); + List getChannelListByAppIds(Collection appIds); /** * 根据条件获取通道数量 @@ -122,10 +103,5 @@ public interface PayChannelService { */ PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code); - /** - * 更新微信支付渠道 - * - * @param updateReqVO 更新信息 - */ - void updateWechatChannel(PayWechatChannelUpdateReqVO updateReqVO); + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/impl/PayChannelServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/impl/PayChannelServiceImpl.java index 5e3d1b514d..2272924934 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/impl/PayChannelServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/impl/PayChannelServiceImpl.java @@ -1,23 +1,35 @@ package cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl; import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*; import cn.iocoder.yudao.adminserver.modules.pay.convert.channel.PayChannelConvert; import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper; import cn.iocoder.yudao.adminserver.modules.pay.service.channel.PayChannelService; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; import java.io.IOException; import java.util.Collection; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; 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 /** * 支付渠道 Service 实现类 * - * @author 芋艿 // TODO aquan:作者写自己哈 + * @author aquan */ @Service @Slf4j @@ -36,11 +48,18 @@ public class PayChannelServiceImpl implements PayChannelService { private PayChannelMapper channelMapper; @Override - public Long createChannel(PayChannelCreateReqVO createReqVO) { - // 插入 - PayChannelDO channel = PayChannelConvert.INSTANCE.convert(createReqVO); + public Long createChannel(PayChannelCreateReqVO reqVO) { + + // 判断是否有重复的有责无法新增 + Integer channelCount = this.getChannelCountByConditions(reqVO.getMerchantId(), reqVO.getAppId(), reqVO.getCode()); + if (channelCount > 0) { + throw exception(CHANNEL_EXIST_SAME_CHANNEL_ERROR); + } + + PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO); + settingConfigAndCheckParam(channel, reqVO.getConfig()); + channelMapper.insert(channel); - // 返回 return channel.getId(); } @@ -49,8 +68,9 @@ public class PayChannelServiceImpl implements PayChannelService { // 校验存在 this.validateChannelExists(updateReqVO.getId()); // 更新 - PayChannelDO updateObj = PayChannelConvert.INSTANCE.convert(updateReqVO); - channelMapper.updateById(updateObj); + PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO); + settingConfigAndCheckParam(channel, updateReqVO.getConfig()); + channelMapper.updateById(channel); } @Override @@ -88,53 +108,16 @@ public class PayChannelServiceImpl implements PayChannelService { } /** - * 根据支付应用ID集合获取所有的支付渠道 + * 根据支付应用ID集合获得支付渠道列表 * - * @param payIds 支付应用编号集合 - * @return 支付渠道 + * @param appIds 应用编号集合 + * @return 支付渠道列表 */ @Override - public List getSimpleChannels(Collection payIds) { - return channelMapper.selectList(new QueryWrapper().lambda().in(PayChannelDO::getAppId, payIds)); + public List getChannelListByAppIds(Collection appIds) { + return channelMapper.getChannelListByAppIds(appIds); } - /** - * 解析pem文件获取公钥私钥字符串 - * - * @param file pem公私钥文件 - * @return 解析后的字符串 - */ - @Override - public String parsingPemFile(MultipartFile file) { - try { - return IoUtil.readUtf8(file.getInputStream()); - } catch (IOException e) { - log.error("[parsingPemToString]读取pem[{}]文件错误", file.getOriginalFilename()); - throw exception(CHANNEL_KEY_READ_ERROR); - } - } - - /** - * 创建微信的渠道配置 - * - * @param reqVO 创建信息 - * @return 创建结果 - */ - @Override - public Long createWechatChannel(PayWechatChannelCreateReqVO reqVO) { - - // 判断是否有重复的有责无法新增 - Integer channelCount = this.getChannelCountByConditions(reqVO.getMerchantId(), reqVO.getAppId(), reqVO.getCode()); - if (channelCount > 0) { - throw exception(EXIST_SAME_CHANNEL_ERROR); - } - - PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO); - WXPayClientConfig config = PayChannelConvert.INSTANCE.configConvert(reqVO.getWeChatConfig()); - channel.setConfig(config); - channelMapper.insert(channel); - return channel.getId(); - } /** * 根据条件获取通道数量 @@ -146,14 +129,9 @@ public class PayChannelServiceImpl implements PayChannelService { */ @Override public Integer getChannelCountByConditions(Long merchantId, Long appid, String code) { - return this.channelMapper.selectCount(new QueryWrapper().lambda() - .eq(PayChannelDO::getMerchantId, merchantId) - .eq(PayChannelDO::getAppId, appid) - .eq(PayChannelDO::getCode, code) - ); + return this.channelMapper.getChannelCountByConditions(merchantId, appid, code); } - // TODO @aquan:service 不出现 mybatis plus 哈 /** * 根据条件获取通道 * @@ -164,25 +142,76 @@ public class PayChannelServiceImpl implements PayChannelService { */ @Override public PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) { - return this.channelMapper.selectOne((new QueryWrapper().lambda() - .eq(PayChannelDO::getMerchantId, merchantId) - .eq(PayChannelDO::getAppId, appid) - .eq(PayChannelDO::getCode, code) - )); + return this.channelMapper.getChannelByConditions(merchantId, appid, code); } /** - * 更新微信支付渠道 + * 检测微信秘钥参数 * - * @param updateReqVO 更新信息 + * @param config 信秘钥参数 */ - @Override - public void updateWechatChannel(PayWechatChannelUpdateReqVO updateReqVO) { - // 校验存在 - this.validateChannelExists(updateReqVO.getId()); - PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO); - WXPayClientConfig config = PayChannelConvert.INSTANCE.configConvert(updateReqVO.getWeChatConfig()); - channel.setConfig(config); - this.channelMapper.updateById(channel); + private void wechatParamCheck(WXPayClientConfig config) { + // 针对于 V2 或者 V3 版本的参数校验 + if (WXPayClientConfig.API_VERSION_V2.equals(config.getApiVersion())) { + Assert.notNull(config.getMchKey(), CHANNEL_WECHAT_VERSION_2_MCH_KEY_IS_NULL.getMsg()); + } + if (WXPayClientConfig.API_VERSION_V3.equals(config.getApiVersion())) { + Assert.notNull(config.getPrivateKeyContent(), CHANNEL_WECHAT_VERSION_3_PRIVATE_KEY_IS_NULL.getMsg()); + Assert.notNull(config.getPrivateCertContent(), CHANNEL_WECHAT_VERSION_3_CERT_KEY_IS_NULL.getMsg()); + } + } + + + + /** + * 设置渠道配置以及参数校验 + * + * @param channel 渠道 + * @param configStr 配置 + */ + private void settingConfigAndCheckParam(PayChannelDO channel, String configStr) { + + // 得到这个渠道是微信的还是支付宝的 + String channelType = PayChannelEnum.verifyWechatOrAliPay(channel.getCode()); + Assert.notNull(channelType, CHANNEL_NOT_EXISTS.getMsg()); + + // 进行验证 + ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); + Validator validator = validatorFactory.getValidator(); + + // 微信的验证 + if (PayChannelEnum.WECHAT.equals(channelType)) { + + WXPayClientConfig config = JSON.parseObject(configStr, WXPayClientConfig.class); + // 判断是V2 版本还是 V3 版本 + Class clazz = config.getApiVersion().equals(WXPayClientConfig.API_VERSION_V2) + ? WXPayClientConfig.V2.class : WXPayClientConfig.V3.class; + // 手动调用validate进行验证 + Set> validate = validator.validate(config,clazz); + + // 断言没有异常 + Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage) + .collect(Collectors.joining(","))); + + channel.setConfig(config); + } + + // 支付宝验证 + if (PayChannelEnum.ALIPAY.equals(channelType)) { + + AlipayPayClientConfig config = JSON.parseObject(configStr, AlipayPayClientConfig.class); + + // 判断是V2 版本还是 V3 版本 + Class clazz = config.getMode().equals(AlipayPayClientConfig.MODE_PUBLIC_KEY) + ? AlipayPayClientConfig.ModePublicKey.class : AlipayPayClientConfig.ModeCertificate.class; + // 手动调用validate进行验证 + Set> validate = validator.validate(config,clazz); + + // 断言没有异常 + Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage) + .collect(Collectors.joining(","))); + channel.setConfig(config); + } + } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantService.java index ae13a01eff..9b3876b230 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantService.java @@ -100,15 +100,6 @@ public interface PayMerchantService { */ List getMerchantListByNameLimit(String merchantName); - /** - * 获得指定编号的商户列表 - * - * @param merchantIds 商户编号数组 - * @return 商户列表 - */ - // TODO @aquan:和 getMerchantList 重复了 - List getSimpleMerchants(Collection merchantIds); - /** * 获得指定编号的商户 Map * @@ -116,11 +107,7 @@ public interface PayMerchantService { * @return 商户 Map */ default Map getMerchantMap(Collection merchantIds) { - // TODO @aquan:可以不用判空,交给 getMerchantList 解决 - if (CollUtil.isEmpty(merchantIds)) { - return Collections.emptyMap(); - } - List list = getSimpleMerchants(merchantIds); + List list = this.getMerchantList(merchantIds); return CollectionUtils.convertMap(list, PayMerchantDO::getId); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/impl/PayMerchantServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/impl/PayMerchantServiceImpl.java index 3d749181a2..e37f6f9d3b 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/impl/PayMerchantServiceImpl.java +++ b/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 { */ @Override public List getMerchantListByName(String merchantName) { - // TODO @aquan:Service 层,不要出现 mybatis plus 的代码,要放到 mapper 里提供。技术与业务分离,原则上 - return this.merchantMapper.selectList(new QueryWrapper() - .lambda().likeRight(PayMerchantDO::getName, merchantName)); + return this.merchantMapper.getMerchantListByName(merchantName); } /** @@ -150,16 +148,6 @@ public class PayMerchantServiceImpl implements PayMerchantService { } } - /** - * 获得指定编号的商户列表 - * - * @param merchantIds 商户编号数组 - * @return 商户列表 - */ - @Override - public List getSimpleMerchants(Collection merchantIds) { - return merchantMapper.selectBatchIds(merchantIds); - } // TODO @芋艿:后续增加下合适的算法 /** diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/app/service/PayAppServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/app/service/PayAppServiceTest.java deleted file mode 100644 index 64448dc569..0000000000 --- a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/app/service/PayAppServiceTest.java +++ /dev/null @@ -1,193 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.pay.app.service; - -import cn.iocoder.yudao.adminserver.BaseDbUnitTest; -import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppCreateReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppExportReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppPageReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper; -import cn.iocoder.yudao.adminserver.modules.pay.service.app.impl.PayAppServiceImpl; -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Import; - -import javax.annotation.Resource; -import java.util.List; - -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.APP_NOT_EXISTS; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static org.junit.jupiter.api.Assertions.*; - -/** -* {@link PayAppServiceImpl} 的单元测试类 -* -* @author 芋艿 -*/ -@Import(PayAppServiceImpl.class) -public class PayAppServiceTest extends BaseDbUnitTest { - - @Resource - private PayAppServiceImpl appService; - - @Resource - private PayAppMapper appMapper; - - @Test - public void testCreateApp_success() { - // 准备参数 - PayAppCreateReqVO reqVO = randomPojo(PayAppCreateReqVO.class); - - // 调用 - Long appId = appService.createApp(reqVO); - // 断言 - assertNotNull(appId); - // 校验记录的属性是否正确 - PayAppDO app = appMapper.selectById(appId); - assertPojoEquals(reqVO, app); - } - - @Test - public void testUpdateApp_success() { - // mock 数据 - PayAppDO dbApp = randomPojo(PayAppDO.class); - appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 - // 准备参数 - PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> { - o.setId(dbApp.getId()); // 设置更新的 ID - }); - - // 调用 - appService.updateApp(reqVO); - // 校验是否更新正确 - PayAppDO app = appMapper.selectById(reqVO.getId()); // 获取最新的 - assertPojoEquals(reqVO, app); - } - - @Test - public void testUpdateApp_notExists() { - // 准备参数 - PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_EXISTS); - } - - @Test - public void testDeleteApp_success() { - // mock 数据 - PayAppDO dbApp = randomPojo(PayAppDO.class); - appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbApp.getId(); - - // 调用 - appService.deleteApp(id); - // 校验数据不存在了 - assertNull(appMapper.selectById(id)); - } - - @Test - public void testDeleteApp_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> appService.deleteApp(id), APP_NOT_EXISTS); - } - - @Test // TODO 请修改 null 为需要的值 - public void testGetAppPage() { - // mock 数据 - PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到 - o.setName(null); - o.setStatus(null); - o.setRemark(null); - o.setPayNotifyUrl(null); - o.setRefundNotifyUrl(null); - o.setMerchantId(null); - o.setCreateTime(null); - }); - appMapper.insert(dbApp); - // 测试 name 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName(null))); - // 测试 status 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(null))); - // 测试 remark 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark(null))); - // 测试 payNotifyUrl 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl(null))); - // 测试 refundNotifyUrl 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl(null))); - // 测试 merchantId 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(null))); - // 测试 createTime 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(null))); - // 准备参数 - PayAppPageReqVO reqVO = new PayAppPageReqVO(); - reqVO.setName(null); - reqVO.setStatus(null); - reqVO.setRemark(null); - reqVO.setPayNotifyUrl(null); - reqVO.setRefundNotifyUrl(null); - reqVO.setBeginCreateTime(null); - reqVO.setEndCreateTime(null); - - // 调用 - PageResult pageResult = appService.getAppPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbApp, pageResult.getList().get(0)); - } - - @Test // TODO aquan:请修改 null 为需要的值 - public void testGetAppList() { - // mock 数据 - PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到 - o.setName(null); - o.setStatus(null); - o.setRemark(null); - o.setPayNotifyUrl(null); - o.setRefundNotifyUrl(null); - o.setMerchantId(null); - o.setCreateTime(null); - }); - appMapper.insert(dbApp); - // 测试 name 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName(null))); - // 测试 status 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(null))); - // 测试 remark 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark(null))); - // 测试 payNotifyUrl 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl(null))); - // 测试 refundNotifyUrl 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl(null))); - // 测试 merchantId 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(null))); - // 测试 createTime 不匹配 - appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(null))); - // 准备参数 - PayAppExportReqVO reqVO = new PayAppExportReqVO(); - reqVO.setName(null); - reqVO.setStatus(null); - reqVO.setRemark(null); - reqVO.setPayNotifyUrl(null); - reqVO.setRefundNotifyUrl(null); - reqVO.setMerchantId(null); - reqVO.setBeginCreateTime(null); - reqVO.setEndCreateTime(null); - - // 调用 - List list = appService.getAppList(reqVO); - // 断言 - assertEquals(1, list.size()); - assertPojoEquals(dbApp, list.get(0)); - } - -} diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/channel/PayChannelServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/channel/PayChannelServiceTest.java deleted file mode 100644 index 824cb087bf..0000000000 --- a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/channel/PayChannelServiceTest.java +++ /dev/null @@ -1,202 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.pay.channel; - -import cn.iocoder.yudao.adminserver.BaseDbUnitTest; -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelCreateReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelExportReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelPageReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelUpdateReqVO; -import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper; -import cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl.PayChannelServiceImpl; -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Import; - -import javax.annotation.Resource; -import java.util.List; - -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.CHANNEL_NOT_EXISTS; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static org.junit.jupiter.api.Assertions.*; - -/** -* {@link PayChannelServiceImpl} 的单元测试类 -* -* @author 芋艿 -*/ -@Import(PayChannelServiceImpl.class) -public class PayChannelServiceTest extends BaseDbUnitTest { - - @Resource - private PayChannelServiceImpl channelService; - - @Resource - private PayChannelMapper channelMapper; - - @Test - public void testCreateChannel_success() { - // 准备参数 - PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class); - - // 调用 - Long channelId = channelService.createChannel(reqVO); - // 断言 - assertNotNull(channelId); - // 校验记录的属性是否正确 - PayChannelDO channel = channelMapper.selectById(channelId); - assertPojoEquals(reqVO, channel); - } - - @Test - public void testUpdateChannel_success() { - // mock 数据 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class); - channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 - // 准备参数 - PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> { - o.setId(dbChannel.getId()); // 设置更新的 ID - }); - - // 调用 - channelService.updateChannel(reqVO); - // 校验是否更新正确 - PayChannelDO channel = channelMapper.selectById(reqVO.getId()); // 获取最新的 - assertPojoEquals(reqVO, channel); - } - - @Test - public void testUpdateChannel_notExists() { - // 准备参数 - PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS); - } - - @Test - public void testDeleteChannel_success() { - // mock 数据 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class); - channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbChannel.getId(); - - // 调用 - channelService.deleteChannel(id); - // 校验数据不存在了 - assertNull(channelMapper.selectById(id)); - } - - @Test - public void testDeleteChannel_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS); - } - - @Test // TODO 请修改 null 为需要的值 - public void testGetChannelPage() { - // mock 数据 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到 - o.setCode(null); - o.setStatus(null); - o.setRemark(null); - o.setFeeRate(null); - o.setMerchantId(null); - o.setAppId(null); - o.setConfig(null); - o.setCreateTime(null); - }); - channelMapper.insert(dbChannel); - // 测试 code 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCode(null))); - // 测试 status 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setStatus(null))); - // 测试 remark 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setRemark(null))); - // 测试 feeRate 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setFeeRate(null))); - // 测试 merchantId 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setMerchantId(null))); - // 测试 appId 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setAppId(null))); - // 测试 config 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setConfig(null))); - // 测试 createTime 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCreateTime(null))); - // 准备参数 - PayChannelPageReqVO reqVO = new PayChannelPageReqVO(); - reqVO.setCode(null); - reqVO.setStatus(null); - reqVO.setRemark(null); - reqVO.setFeeRate(null); - reqVO.setMerchantId(null); - reqVO.setAppId(null); - reqVO.setConfig(null); - reqVO.setBeginCreateTime(null); - reqVO.setEndCreateTime(null); - - // 调用 - PageResult pageResult = channelService.getChannelPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbChannel, pageResult.getList().get(0)); - } - - @Test // TODO aquan:请修改 null 为需要的值 - public void testGetChannelList() { - // mock 数据 - PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到 - o.setCode(null); - o.setStatus(null); - o.setRemark(null); - o.setFeeRate(null); - o.setMerchantId(null); - o.setAppId(null); - o.setConfig(null); - o.setCreateTime(null); - }); - channelMapper.insert(dbChannel); - // 测试 code 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCode(null))); - // 测试 status 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setStatus(null))); - // 测试 remark 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setRemark(null))); - // 测试 feeRate 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setFeeRate(null))); - // 测试 merchantId 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setMerchantId(null))); - // 测试 appId 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setAppId(null))); - // 测试 config 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setConfig(null))); - // 测试 createTime 不匹配 - channelMapper.insert(ObjectUtils.clone(dbChannel, o -> o.setCreateTime(null))); - // 准备参数 - PayChannelExportReqVO reqVO = new PayChannelExportReqVO(); - reqVO.setCode(null); - reqVO.setStatus(null); - reqVO.setRemark(null); - reqVO.setFeeRate(null); - reqVO.setMerchantId(null); - reqVO.setAppId(null); - reqVO.setConfig(null); - reqVO.setBeginCreateTime(null); - reqVO.setEndCreateTime(null); - - // 调用 - List list = channelService.getChannelList(reqVO); - // 断言 - assertEquals(1, list.size()); - assertPojoEquals(dbChannel, list.get(0)); - } - -} diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/PayAppServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/PayAppServiceTest.java new file mode 100644 index 0000000000..4e0e19f2d1 --- /dev/null +++ b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/app/PayAppServiceTest.java @@ -0,0 +1,249 @@ +package cn.iocoder.yudao.adminserver.modules.pay.service.app; + +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.adminserver.BaseDbUnitTest; +import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppCreateReqVO; +import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppExportReqVO; +import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppPageReqVO; +import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateReqVO; + + +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper; +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper; +import cn.iocoder.yudao.adminserver.modules.pay.service.app.impl.PayAppServiceImpl; +import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService; +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link PayAppServiceImpl} 的单元测试类 + * + * @author 芋艿 + */ +@Import(PayAppServiceImpl.class) +public class PayAppServiceTest extends BaseDbUnitTest { + + @Resource + private PayAppServiceImpl appService; + + @Resource + private PayAppMapper appMapper; + + @MockBean(name = "payMerchantMapper") + private PayMerchantMapper payMerchantMapper; + + @Test + public void testCreateApp_success() { + // 准备参数 + PayAppCreateReqVO reqVO = randomPojo(PayAppCreateReqVO.class, o -> + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))); + + // 调用 + Long appId = appService.createApp(reqVO); + // 断言 + assertNotNull(appId); + // 校验记录的属性是否正确 + PayAppDO app = appMapper.selectById(appId); + assertPojoEquals(reqVO, app); + } + + @Test + public void testUpdateApp_success() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> + o.setStatus(CommonStatusEnum.DISABLE.getStatus())); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> { + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setId(dbApp.getId()); // 设置更新的 ID + }); + + // 调用 + appService.updateApp(reqVO); + // 校验是否更新正确 + PayAppDO app = appMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, app); + } + + @Test + public void testUpdateApp_notExists() { + // 准备参数 + PayAppUpdateReqVO reqVO = randomPojo(PayAppUpdateReqVO.class, o -> + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))); + // 调用, 并断言异常 + assertServiceException(() -> appService.updateApp(reqVO), APP_NOT_EXISTS); + } + + @Test + public void testDeleteApp_success() { + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> + o.setStatus((RandomUtil.randomEle(CommonStatusEnum.values()).getStatus()))); + appMapper.insert(dbApp);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbApp.getId(); + + // 调用 + appService.deleteApp(id); + // 校验数据不存在了 + assertNull(appMapper.selectById(id)); + } + + @Test + public void testDeleteApp_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> appService.deleteApp(id), APP_NOT_EXISTS); + } + + @Test + public void testGetAppPage() { + Long merchantId = 1L; + Long mismatchMerchantId = 2L; + + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到 + o.setName("灿灿姐的杂货铺"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("敏敏姐的小卖铺"); + o.setPayNotifyUrl("https://www.hc.com"); + o.setRefundNotifyUrl("https://www.xm.com"); + o.setMerchantId(merchantId); + o.setCreateTime(buildTime(2021,11,20)); + }); + + // mock 数据 + PayMerchantDO dbMerchant = randomPojo(PayMerchantDO.class, o -> { // 等会查询到 + o.setId(merchantId); + o.setNo("M1008611"); + o.setName("灿哥的杂货铺"); + o.setShortName("灿灿子"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("灿哥的杂货铺"); + o.setCreateTime(buildTime(2021,11,3)); + }); + + Mockito.when(payMerchantMapper.getMerchantListByName(dbMerchant.getName())) + .thenReturn(Collections.singletonList(dbMerchant)); + + appMapper.insert(dbApp); + // 测试 name 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName("敏敏姐的杂货铺"))); + // 测试 status 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 remark 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark("灿灿姐的小卖部"))); + // 测试 payNotifyUrl 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl("xm.com"))); + // 测试 refundNotifyUrl 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl("hc.com"))); + // 测试 merchantId 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(mismatchMerchantId))); + // 测试 createTime 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(buildTime(2021,12,21)))); + // 准备参数 + PayAppPageReqVO reqVO = new PayAppPageReqVO(); + reqVO.setName("灿灿姐的杂货铺"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setRemark("敏敏姐的小卖铺"); + reqVO.setPayNotifyUrl("https://www.hc.com"); + reqVO.setRefundNotifyUrl("https://www.xm.com"); + reqVO.setMerchantName(dbMerchant.getName()); + reqVO.setBeginCreateTime(buildTime(2021,11,19)); + reqVO.setEndCreateTime(buildTime(2021,11,21)); + + // 调用 + PageResult pageResult = appService.getAppPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbApp, pageResult.getList().get(0)); + } + + @Test // TODO 请修改 null 为需要的值 + public void testGetAppList() { + Long merchantId = 1L; + Long mismatchMerchantId = 2L; + + // mock 数据 + PayAppDO dbApp = randomPojo(PayAppDO.class, o -> { // 等会查询到 + o.setName("灿灿姐的杂货铺"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("敏敏姐的小卖铺"); + o.setPayNotifyUrl("https://www.hc.com"); + o.setRefundNotifyUrl("https://www.xm.com"); + o.setMerchantId(merchantId); + o.setCreateTime(buildTime(2021,11,20)); + }); + + // mock 数据 + PayMerchantDO dbMerchant = randomPojo(PayMerchantDO.class, o -> { // 等会查询到 + o.setId(merchantId); + o.setNo("M1008611"); + o.setName("灿哥的杂货铺"); + o.setShortName("灿灿子"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("灿哥的杂货铺"); + o.setCreateTime(buildTime(2021,11,3)); + }); + + Mockito.when(payMerchantMapper.getMerchantListByName(dbMerchant.getName())) + .thenReturn(Collections.singletonList(dbMerchant)); + + appMapper.insert(dbApp); + // 测试 name 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setName("敏敏姐的杂货铺"))); + // 测试 status 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 remark 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRemark("灿灿姐的小卖部"))); + // 测试 payNotifyUrl 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setPayNotifyUrl("xm.com"))); + // 测试 refundNotifyUrl 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setRefundNotifyUrl("hc.com"))); + // 测试 merchantId 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setMerchantId(mismatchMerchantId))); + // 测试 createTime 不匹配 + appMapper.insert(ObjectUtils.clone(dbApp, o -> o.setCreateTime(buildTime(2021,12,21)))); + // 准备参数 + PayAppExportReqVO reqVO = new PayAppExportReqVO(); + reqVO.setName("灿灿姐的杂货铺"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setRemark("敏敏姐的小卖铺"); + reqVO.setPayNotifyUrl("https://www.hc.com"); + reqVO.setRefundNotifyUrl("https://www.xm.com"); + reqVO.setMerchantName(dbMerchant.getName()); + reqVO.setBeginCreateTime(buildTime(2021,11,19)); + reqVO.setEndCreateTime(buildTime(2021,11,21)); + + // 调用 + List list = appService.getAppList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbApp, list.get(0)); + } + +} \ No newline at end of file diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelServiceTest.java new file mode 100644 index 0000000000..a92860d7c9 --- /dev/null +++ b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/channel/PayChannelServiceTest.java @@ -0,0 +1,404 @@ +package cn.iocoder.yudao.adminserver.modules.pay.service.channel; + +import cn.iocoder.yudao.adminserver.BaseDbUnitTest; +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelCreateReqVO; +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelExportReqVO; +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelPageReqVO; +import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelUpdateReqVO; +import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper; +import cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl.PayChannelServiceImpl; +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import com.alibaba.fastjson.JSON; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import javax.validation.Validator; +import java.util.List; + +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.CHANNEL_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link PayChannelServiceImpl} 的单元测试类 + * + * @author 芋艿 + */ +@Import(PayChannelServiceImpl.class) +public class PayChannelServiceTest extends BaseDbUnitTest { + + @Resource + private PayChannelServiceImpl channelService; + + @Resource + private PayChannelMapper channelMapper; + + + @Test + public void testCreateWechatVersion2Channel_success() { + // 准备参数 + + WXPayClientConfig v2Config = getV2Config(); + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { + o.setCode(PayChannelEnum.WX_PUB.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(JSON.toJSONString(v2Config)); + }); + + // 调用 + Long channelId = channelService.createChannel(reqVO); + // 断言 + assertNotNull(channelId); + // 校验记录的属性是否正确 + PayChannelDO channel = channelMapper.selectById(channelId); + assertPojoEquals(reqVO, channel, "config"); + // 关于config 对象应该拿出来重新对比 + assertPojoEquals(v2Config, channel.getConfig()); + + } + + @Test + public void testCreateWechatVersion3Channel_success() { + // 准备参数 + + WXPayClientConfig v3Config = getV3Config(); + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { + o.setCode(PayChannelEnum.WX_PUB.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(JSON.toJSONString(v3Config)); + }); + + // 调用 + Long channelId = channelService.createChannel(reqVO); + // 断言 + assertNotNull(channelId); + // 校验记录的属性是否正确 + PayChannelDO channel = channelMapper.selectById(channelId); + assertPojoEquals(reqVO, channel, "config"); + // 关于config 对象应该拿出来重新对比 + assertPojoEquals(v3Config, channel.getConfig()); + } + + @Test + public void testCreateAliPayPublicKeyChannel_success() { + // 准备参数 + + AlipayPayClientConfig payClientConfig = getPublicKeyConfig(); + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(JSON.toJSONString(payClientConfig)); + }); + + // 调用 + Long channelId = channelService.createChannel(reqVO); + // 断言 + assertNotNull(channelId); + // 校验记录的属性是否正确 + PayChannelDO channel = channelMapper.selectById(channelId); + assertPojoEquals(reqVO, channel, "config"); + // 关于config 对象应该拿出来重新对比 + assertPojoEquals(payClientConfig, channel.getConfig()); + + } + + @Test + public void testCreateAliPayCertificateChannel_success() { + // 准备参数 + + AlipayPayClientConfig payClientConfig = getCertificateConfig(); + PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(JSON.toJSONString(payClientConfig)); + }); + + // 调用 + Long channelId = channelService.createChannel(reqVO); + // 断言 + assertNotNull(channelId); + // 校验记录的属性是否正确 + PayChannelDO channel = channelMapper.selectById(channelId); + assertPojoEquals(reqVO, channel, "config"); + // 关于config 对象应该拿出来重新对比 + assertPojoEquals(payClientConfig, channel.getConfig()); + } + + @Test + public void testUpdateChannel_success() { + // mock 数据 + AlipayPayClientConfig payClientConfig = getCertificateConfig(); + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(payClientConfig); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + AlipayPayClientConfig payClientPublicKeyConfig = getPublicKeyConfig(); + PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> { + o.setCode(dbChannel.getCode()); + o.setStatus(dbChannel.getStatus()); + o.setConfig(JSON.toJSONString(payClientPublicKeyConfig)); + o.setId(dbChannel.getId()); // 设置更新的 ID + }); + + // 调用 + channelService.updateChannel(reqVO); + // 校验是否更新正确 + PayChannelDO channel = channelMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, channel, "config"); + assertPojoEquals(payClientPublicKeyConfig, channel.getConfig()); + } + + @Test + public void testUpdateChannel_notExists() { + // 准备参数 + AlipayPayClientConfig payClientPublicKeyConfig = getPublicKeyConfig(); + PayChannelUpdateReqVO reqVO = randomPojo(PayChannelUpdateReqVO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(JSON.toJSONString(payClientPublicKeyConfig)); + }); + + // 调用, 并断言异常 + assertServiceException(() -> channelService.updateChannel(reqVO), CHANNEL_NOT_EXISTS); + } + + @Test + public void testDeleteChannel_success() { + // mock 数据 + AlipayPayClientConfig payClientConfig = getCertificateConfig(); + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setConfig(payClientConfig); + }); + channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbChannel.getId(); + + // 调用 + channelService.deleteChannel(id); + // 校验数据不存在了 + assertNull(channelMapper.selectById(id)); + } + + @Test + public void testDeleteChannel_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> channelService.deleteChannel(id), CHANNEL_NOT_EXISTS); + } + + @Test // TODO 请修改 null 为需要的值 + public void testGetChannelPage() { + // mock 数据 + AlipayPayClientConfig payClientConfig = getCertificateConfig(); + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("灿灿子的支付渠道"); + o.setFeeRate(0.03); + o.setMerchantId(1L); + o.setAppId(1L); + o.setConfig(payClientConfig); + o.setCreateTime(buildTime(2021,11,20)); + }); + channelMapper.insert(dbChannel); + // 执行拷贝的时候会出现异常,所以在插入后要重置为null 后续在写入新的 + dbChannel.setConfig(null); + // 测试 code 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setCode(PayChannelEnum.WX_PUB.getCode()); + })); + // 测试 status 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + })); + // 测试 remark 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o ->{ + o.setConfig(payClientConfig); + o.setRemark("敏敏子的渠道"); + })); + // 测试 feeRate 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setFeeRate(1.23); + })); + // 测试 merchantId 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setMerchantId(2L); + })); + // 测试 appId 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setAppId(2L); + })); + // 测试 createTime 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setCreateTime(buildTime(2021, 10, 20)); + })); + // 准备参数 + PayChannelPageReqVO reqVO = new PayChannelPageReqVO(); + reqVO.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setRemark("灿灿子的支付渠道"); + reqVO.setFeeRate(0.03); + reqVO.setMerchantId(1L); + reqVO.setAppId(1L); + reqVO.setConfig(JSON.toJSONString(payClientConfig)); + reqVO.setBeginCreateTime(buildTime(2021,11,19)); + reqVO.setEndCreateTime(buildTime(2021,11,21)); + + // 调用 + PageResult pageResult = channelService.getChannelPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbChannel, pageResult.getList().get(0), "config"); + assertPojoEquals(payClientConfig, pageResult.getList().get(0).getConfig()); + + } + + @Test + public void testGetChannelList() { + // mock 数据 + AlipayPayClientConfig payClientConfig = getCertificateConfig(); + PayChannelDO dbChannel = randomPojo(PayChannelDO.class, o -> { // 等会查询到 + o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setRemark("灿灿子的支付渠道"); + o.setFeeRate(0.03); + o.setMerchantId(1L); + o.setAppId(1L); + o.setConfig(payClientConfig); + o.setCreateTime(buildTime(2021,11,20)); + }); + channelMapper.insert(dbChannel); + // 执行拷贝的时候会出现异常,所以在插入后要重置为null 后续在写入新的 + dbChannel.setConfig(null); + // 测试 code 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setCode(PayChannelEnum.WX_PUB.getCode()); + })); + // 测试 status 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + })); + // 测试 remark 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o ->{ + o.setConfig(payClientConfig); + o.setRemark("敏敏子的渠道"); + })); + // 测试 feeRate 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setFeeRate(1.23); + })); + // 测试 merchantId 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setMerchantId(2L); + })); + // 测试 appId 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setAppId(2L); + })); + // 测试 createTime 不匹配 + channelMapper.insert(ObjectUtils.clone(dbChannel, o -> { + o.setConfig(payClientConfig); + o.setCreateTime(buildTime(2021, 10, 20)); + })); + // 准备参数 + PayChannelExportReqVO reqVO = new PayChannelExportReqVO(); + reqVO.setCode(PayChannelEnum.ALIPAY_APP.getCode()); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setRemark("灿灿子的支付渠道"); + reqVO.setFeeRate(0.03); + reqVO.setMerchantId(1L); + reqVO.setAppId(1L); + reqVO.setConfig(JSON.toJSONString(payClientConfig)); + reqVO.setBeginCreateTime(buildTime(2021,11,19)); + reqVO.setEndCreateTime(buildTime(2021,11,21)); + + // 调用 + List list = channelService.getChannelList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbChannel, list.get(0), "config"); + assertPojoEquals(payClientConfig, list.get(0).getConfig()); + } + + + public WXPayClientConfig getV2Config() { + return new WXPayClientConfig() + .setAppId("APP00001") + .setMchId("MCH00001") + .setApiVersion(WXPayClientConfig.API_VERSION_V2) + .setMchKey("dsa1d5s6a1d6sa16d1sa56d15a61das6") + .setApiV3Key("") + .setPrivateCertContent("") + .setPrivateKeyContent(""); + } + + public WXPayClientConfig getV3Config() { + return new WXPayClientConfig() + .setAppId("APP00001") + .setMchId("MCH00001") + .setApiVersion(WXPayClientConfig.API_VERSION_V3) + .setMchKey("") + .setApiV3Key("sdadasdsadadsa") + .setPrivateKeyContent("dsa445das415d15asd16ad156as") + .setPrivateCertContent("dsadasd45asd4s5a"); + + } + + public AlipayPayClientConfig getPublicKeyConfig() { + return new AlipayPayClientConfig() + .setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD) + .setAppId("APP00001") + .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT) + .setMode(AlipayPayClientConfig.MODE_PUBLIC_KEY) + .setPrivateKey("13131321312") + .setAlipayPublicKey("13321321321") + .setAppCertContent("") + .setAlipayPublicCertContent("") + .setRootCertContent(""); + } + + public AlipayPayClientConfig getCertificateConfig() { + return new AlipayPayClientConfig() + .setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD) + .setAppId("APP00001") + .setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT) + .setMode(AlipayPayClientConfig.MODE_CERTIFICATE) + .setPrivateKey("") + .setAlipayPublicKey("") + .setAppCertContent("13321321321sda") + .setAlipayPublicCertContent("13321321321aqeqw") + .setRootCertContent("13321321321dsad"); + } + + +} diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/merchant/service/PayMerchantServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantServiceTest.java similarity index 96% rename from yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/merchant/service/PayMerchantServiceTest.java rename to yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantServiceTest.java index f09f570d69..abec7e58de 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/merchant/service/PayMerchantServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/pay/service/merchant/PayMerchantServiceTest.java @@ -1,9 +1,6 @@ -package cn.iocoder.yudao.adminserver.modules.pay.merchant.service; +package cn.iocoder.yudao.adminserver.modules.pay.service.merchant; import cn.hutool.core.util.RandomUtil; -import cn.hutool.http.HttpUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.adminserver.BaseDbUnitTest; import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantCreateReqVO; import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantExportReqVO; @@ -54,8 +51,7 @@ public class PayMerchantServiceTest extends BaseDbUnitTest { assertNotNull(merchantId); // 校验记录的属性是否正确 PayMerchantDO merchant = merchantMapper.selectById(merchantId); - // TODO @aquan:需要判断 no 非空 - assertPojoEquals(reqVO, merchant,"no"); + assertPojoEquals(reqVO, merchant); } @Test diff --git a/yudao-admin-server/src/test/resources/sql/clean.sql b/yudao-admin-server/src/test/resources/sql/clean.sql index e4edd4deb6..130a9904a5 100644 --- a/yudao-admin-server/src/test/resources/sql/clean.sql +++ b/yudao-admin-server/src/test/resources/sql/clean.sql @@ -27,3 +27,5 @@ DELETE FROM "sys_social_user"; -- pay 开头的 DB DELETE FROM pay_merchant; +DELETE FROM pay_app; +DELETE FROM pay_channel diff --git a/yudao-admin-server/src/test/resources/sql/create_tables.sql b/yudao-admin-server/src/test/resources/sql/create_tables.sql index 6c6500386f..60b6fa47a8 100644 --- a/yudao-admin-server/src/test/resources/sql/create_tables.sql +++ b/yudao-admin-server/src/test/resources/sql/create_tables.sql @@ -464,3 +464,37 @@ CREATE TABLE IF NOT EXISTS "pay_merchant" ( "deleted" bit(1) NOT NULL DEFAULT FALSE, PRIMARY KEY ("id") ) COMMENT '支付商户信息'; + +CREATE TABLE IF NOT EXISTS "pay_app" ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar(64) NOT NULL, + "status" tinyint NOT NULL, + "remark" varchar(255) DEFAULT NULL, + `pay_notify_url` varchar(1024) NOT NULL, + `refund_notify_url`varchar(1024) NOT NULL, + `merchant_id`bigint(20) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , + "updater" varchar(64) DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit(1) NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT = '支付应用信息'; + +CREATE TABLE "pay_channel" ( + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "code" varchar(32) NOT NULL , + "status" tinyint(4) NOT NULL , + "remark" varchar(255) DEFAULT NULL , + "fee_rate" double NOT NULL DEFAULT 0 , + "merchant_id" bigint(20) NOT NULL , + "app_id" bigint(20) NOT NULL , + "config" varchar(10240) NOT NULL , + "creator" varchar(64) NULL DEFAULT '' , + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , + "updater" varchar(64) NULL DEFAULT '' , + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit(1) NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +)COMMENT = '支付渠道'; + diff --git a/yudao-admin-ui/src/api/pay/channel.js b/yudao-admin-ui/src/api/pay/channel.js index 2a2accbd42..de66770bdb 100644 --- a/yudao-admin-ui/src/api/pay/channel.js +++ b/yudao-admin-ui/src/api/pay/channel.js @@ -28,12 +28,12 @@ export function deleteChannel(id) { } // 获得支付渠道 -export function getChannel(id) { - return request({ - url: '/pay/channel/get?id=' + id, - method: 'get' - }) -} +// export function getChannel(id) { +// return request({ +// url: '/pay/channel/get?id=' + id, +// method: 'get' +// }) +// } @@ -56,19 +56,10 @@ export function exportChannelExcel(query) { }) } -// 创建微信支付渠道 -export function createWechatChannel(data) { - return request({ - url: '/pay/channel/create-wechat', - method: 'post', - data: data - }) -} - // 获得支付渠道 -export function getWechatChannel(merchantId,appId,code) { +export function getChannel(merchantId,appId,code) { return request({ - url: '/pay/channel/get-wechat', + url: '/pay/channel/get-channel', params:{ merchantId:merchantId, appId:appId, @@ -78,11 +69,3 @@ export function getWechatChannel(merchantId,appId,code) { }) } -// 更新支付渠道 -export function updateWechatChannel(data) { - return request({ - url: '/pay/channel/update-wechat', - method: 'put', - data: data - }) -} diff --git a/yudao-admin-ui/src/utils/constants.js b/yudao-admin-ui/src/utils/constants.js index f4cd50a2c8..a22f9e0637 100644 --- a/yudao-admin-ui/src/utils/constants.js +++ b/yudao-admin-ui/src/utils/constants.js @@ -121,3 +121,8 @@ export const PayChannelEnum = { "name": "支付宝扫码支付" }, } + +export const PayType = { + WECHAT: "WECHAT", + ALIPAY: "ALIPAY" +} diff --git a/yudao-admin-ui/src/utils/dict.js b/yudao-admin-ui/src/utils/dict.js index f084b2e624..112fae6699 100644 --- a/yudao-admin-ui/src/utils/dict.js +++ b/yudao-admin-ui/src/utils/dict.js @@ -39,7 +39,12 @@ export const DICT_TYPE = { PAY_CHANNEL_STATUS: 'pay_channel_status', // 微信渠道版本 PAY_CHANNEL_WECHAT_VERSION:'pay_channel_wechat_version', - + // 支付渠道支付宝算法类型 + PAY_CHANNEL_ALIPAY_SIGN_TYPE:'pay_channel_alipay_sign_type', + // 支付宝公钥类型 + PAY_CHANNEL_ALIPAY_MODE:'pay_channel_alipay_mode', + // 支付宝网关地址 + PAY_CHANNEL_ALIPAY_SERVER_TYPE:'pay_channel_alipay_server_type', } /** diff --git a/yudao-admin-ui/src/views/pay/app/components/aliPayChannelForm.vue b/yudao-admin-ui/src/views/pay/app/components/aliPayChannelForm.vue new file mode 100644 index 0000000000..29587aba3a --- /dev/null +++ b/yudao-admin-ui/src/views/pay/app/components/aliPayChannelForm.vue @@ -0,0 +1,354 @@ + + + diff --git a/yudao-admin-ui/src/views/pay/app/components/wechatJsApiForm.vue b/yudao-admin-ui/src/views/pay/app/components/wechatChannelForm.vue similarity index 66% rename from yudao-admin-ui/src/views/pay/app/components/wechatJsApiForm.vue rename to yudao-admin-ui/src/views/pay/app/components/wechatChannelForm.vue index 01a984c2e2..5edd58d3cf 100644 --- a/yudao-admin-ui/src/views/pay/app/components/wechatJsApiForm.vue +++ b/yudao-admin-ui/src/views/pay/app/components/wechatChannelForm.vue @@ -1,6 +1,6 @@