完成支付模块支付应用信息和微信类型的支付渠道配置。

This commit is contained in:
aquan 2021-11-09 16:36:07 +08:00
parent 6265e4a736
commit e46a27b937
56 changed files with 3373 additions and 28 deletions

64
sql/pay-app-menu.sql Normal file
View File

@ -0,0 +1,64 @@
-- 菜单 SQL
INSERT INTO `sys_menu`(
`name`, `permission`, `menu_type`, `sort`, `parent_id`,
`path`, `icon`, `component`, `status`
)
VALUES (
'支付应用信息管理', '', 2, 0, 1117,
'app', '', 'pay/app/index', 0
);
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
INSERT INTO `sys_menu`(
`name`, `permission`, `menu_type`, `sort`, `parent_id`,
`path`, `icon`, `component`, `status`
)
VALUES (
'支付应用信息查询', 'pay:app:query', 3, 1, @parentId,
'', '', '', 0
);
INSERT INTO `sys_menu`(
`name`, `permission`, `menu_type`, `sort`, `parent_id`,
`path`, `icon`, `component`, `status`
)
VALUES (
'支付应用信息创建', 'pay:app:create', 3, 2, @parentId,
'', '', '', 0
);
INSERT INTO `sys_menu`(
`name`, `permission`, `menu_type`, `sort`, `parent_id`,
`path`, `icon`, `component`, `status`
)
VALUES (
'支付应用信息更新', 'pay:app:update', 3, 3, @parentId,
'', '', '', 0
);
INSERT INTO `sys_menu`(
`name`, `permission`, `menu_type`, `sort`, `parent_id`,
`path`, `icon`, `component`, `status`
)
VALUES (
'支付应用信息删除', 'pay:app:delete', 3, 4, @parentId,
'', '', '', 0
);
INSERT INTO `sys_menu`(
`name`, `permission`, `menu_type`, `sort`, `parent_id`,
`path`, `icon`, `component`, `status`
)
VALUES (
'支付应用信息导出', 'pay:app:export', 3, 5, @parentId,
'', '', '', 0
);
INSERT INTO `sys_menu` (
`name`, `permission`, `menu_type`, `sort`, `parent_id`,
`path`, `icon`, `component`, `status`, `creator`, `create_time`,
`updater`, `update_time`, `deleted`
) VALUES (
'秘钥解析', 'pay:channel:parsing', 3, 6, 1129, '', '', '', 0, '1',
'2021-11-08 15:15:47', '1', '2021-11-08 15:15:47', b'0'
);

24
sql/pay-dict.sql Normal file
View File

@ -0,0 +1,24 @@
-- 商户状态 status
INSERT INTO `sys_dict_type` ( `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( '商户状态', 'pay_merchant_status', 0, '商户的启用于停用状态', '1', '2021-11-03 11:29:04', '1', '2021-11-03 11:29:04', b'0');
INSERT INTO `sys_dict_data` ( `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( 1, '启用', '0', 'pay_merchant_status', 0, '商户启用', '1', '2021-11-03 11:30:52', '1', '2021-11-03 11:31:15', b'0');
INSERT INTO `sys_dict_data` ( `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( 2, '停用', '1', 'pay_merchant_status', 0, '商户停用', '1', '2021-11-03 11:31:05', '1', '2021-11-03 11:31:05', b'0');
-- 支付应用状态 status
INSERT INTO `sys_dict_type` ( `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('支付应用状态', 'pay_app_status', 0, '支付应用的启停状态', '1', '2021-11-06 19:41:50', '1', '2021-11-06 19:41:50', b'0');
INSERT INTO `sys_dict_data` ( `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( 1, '开启', '0', 'pay_app_status', 0, NULL, '1', '2021-11-06 19:42:10', '1', '2021-11-06 19:42:10', b'0');
INSERT INTO `sys_dict_data` ( `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( 2, '关闭', '1', 'pay_app_status', 0, NULL, '1', '2021-11-06 19:42:17', '1', '2021-11-06 19:42:17', b'0');
-- 支付渠道状态 status
INSERT INTO `sys_dict_type` ( `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( '支付渠道状态', 'pay_channel_status', 0, '支付渠道的启停状态', '1', '2021-11-08 16:47:21', '1', '2021-11-08 16:47:21', b'0');
INSERT INTO `sys_dict_data` ( `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( 1, '开启', '0', 'pay_channel_status', 0, '开启', '1', '2021-11-08 16:47:45', '1', '2021-11-08 16:47:45', b'0');
INSERT INTO `sys_dict_data` ( `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ( 2, '关闭', '1', 'pay_channel_status', 0, '关闭', '1', '2021-11-08 16:47:52', '1', '2021-11-08 16:47:52', b'0');
-- 微信渠道版本控制
INSERT INTO `sys_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('支付渠道微信版本', 'pay_channel_wechat_version', 0, '支付渠道微信版本', '1', '2021-11-08 17:00:26', '1', '2021-11-08 17:00:26', b'0');
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');

View File

@ -1,9 +1,4 @@
-- 支付模块-商户中心-菜单SQL
-- 菜单 SQL
INSERT INTO `sys_menu` (
`name`, `permission`,`menu_type`,`sort`, `parent_id`, `path`, `icon`, `component`,
`status`, `creator`,`create_time`, `updater`, `update_time`, `deleted`
) VALUES ('支付管理', '', 1, 4,0, '/pay','pay', NULL, 0, '1', '2021-11-03 10:35:04', '1', '2021-11-03 10:35:04', b'0');
INSERT INTO `sys_menu`(
`name`, `permission`, `menu_type`, `sort`, `parent_id`,

View File

@ -0,0 +1,175 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.*;
import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert;
import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService;
import cn.iocoder.yudao.adminserver.modules.pay.service.channel.PayChannelService;
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.PayChannelDO;
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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
/**
* 支付应用信息 controller 组件
*
* @author aquan
*/
@Slf4j
@Api(tags = "支付应用信息")
@RestController
@RequestMapping("/pay/app")
@Validated
public class PayAppController {
@Resource
private PayAppService appService;
@Resource
private PayChannelService channelService;
@Resource
private PayMerchantService merchantService;
@PostMapping("/create")
@ApiOperation("创建支付应用信息")
@PreAuthorize("@ss.hasPermission('pay:app:create')")
public CommonResult<Long> createApp(@Valid @RequestBody PayAppCreateReqVO createReqVO) {
return success(appService.createApp(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新支付应用信息")
@PreAuthorize("@ss.hasPermission('pay:app:update')")
public CommonResult<Boolean> updateApp(@Valid @RequestBody PayAppUpdateReqVO updateReqVO) {
appService.updateApp(updateReqVO);
return success(true);
}
@PutMapping("/update-status")
@ApiOperation("更新支付应用状态")
@PreAuthorize("@ss.hasPermission('pay:app:update')")
public CommonResult<Boolean> updateAppStatus(@Valid @RequestBody PayAppUpdateStatusReqVO updateReqVO) {
appService.updateAppStatus(updateReqVO.getId(), updateReqVO.getStatus());
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除支付应用信息")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('pay:app:delete')")
public CommonResult<Boolean> deleteApp(@RequestParam("id") Long id) {
appService.deleteApp(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得支付应用信息")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('pay:app:query')")
public CommonResult<PayAppRespVO> getApp(@RequestParam("id") Long id) {
PayAppDO app = appService.getApp(id);
return success(PayAppConvert.INSTANCE.convert(app));
}
@GetMapping("/list")
@ApiOperation("获得支付应用信息列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('pay:app:query')")
public CommonResult<List<PayAppRespVO>> getAppList(@RequestParam("ids") Collection<Long> ids) {
List<PayAppDO> list = appService.getAppList(ids);
return success(PayAppConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得支付应用信息分页")
@PreAuthorize("@ss.hasPermission('pay:app:query')")
public CommonResult<PageResult<PayAppPageItemRespVO>> getAppPage(@Valid PayAppPageReqVO pageVO) {
// 得到应用分页列表
PageResult<PayAppDO> pageResult = appService.getAppPage(pageVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(new PageResult<>(pageResult.getTotal()));
}
// 得到所有的应用编号查出所有的通道
Collection<Long> payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId);
List<PayChannelDO> channels = channelService.getSimpleChannels(payAppIds);
// 得到所有的商户信息
Collection<Long> merchantIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getMerchantId);
Map<Long, PayMerchantDO> deptMap = merchantService.getMerchantMap(merchantIds);
// 利用反射将通道数据复制到返回的数据结构中去
List<PayAppPageItemRespVO> appList = new ArrayList<>(pageResult.getList().size());
pageResult.getList().forEach(app -> {
// 写入应用信息的数据
PayAppPageItemRespVO respVO = PayAppConvert.INSTANCE.pageConvert(app);
// 写入商户的数据
respVO.setPayMerchant(PayAppConvert.INSTANCE.convert(deptMap.get(app.getMerchantId())));
// 写入支付渠道信息的数据
PayAppPageItemRespVO.PayChannel payChannel = new PayAppPageItemRespVO.PayChannel();
channels.forEach(c -> {
if (c.getAppId().equals(app.getId())) {
// 获取 set 方法
String methodName = StrUtil.toCamelCase("set_" + c.getCode());
try {
// 根据 set 方法将值写入
payChannel.getClass().getMethod(methodName, Integer.class)
.invoke(payChannel, CommonStatusEnum.ENABLE.getStatus());
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
log.error("[getAppPage]调用方法[{}]设置参数[{}]异常", c.getCode(), methodName);
}
}
});
respVO.setPayChannel(payChannel);
appList.add(respVO);
});
return success(new PageResult<>(appList, pageResult.getTotal()));
}
@GetMapping("/export-excel")
@ApiOperation("导出支付应用信息 Excel")
@PreAuthorize("@ss.hasPermission('pay:app:export')")
@OperateLog(type = EXPORT)
public void exportAppExcel(@Valid PayAppExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<PayAppDO> list = appService.getAppList(exportReqVO);
// 导出 Excel
List<PayAppExcelVO> datas = PayAppConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "支付应用信息.xls", "数据", PayAppExcelVO.class, datas);
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import lombok.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
/**
* 支付应用信息 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class PayAppBaseVO {
@ApiModelProperty(value = "应用名", required = true)
@NotNull(message = "应用名不能为空")
private String name;
@ApiModelProperty(value = "开启状态", required = true)
@NotNull(message = "开启状态不能为空")
private Integer status;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "支付结果的回调地址", required = true)
@NotNull(message = "支付结果的回调地址不能为空")
private String payNotifyUrl;
@ApiModelProperty(value = "退款结果的回调地址", required = true)
@NotNull(message = "退款结果的回调地址不能为空")
private String refundNotifyUrl;
@ApiModelProperty(value = "商户编号", required = true)
@NotNull(message = "商户编号不能为空")
private Long merchantId;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("支付应用信息创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayAppCreateReqVO extends PayAppBaseVO {
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* 支付应用信息 Excel VO
*
* @author 芋艿
*/
@Data
public class PayAppExcelVO {
@ExcelProperty("应用编号")
private Long id;
@ExcelProperty("应用名")
private String name;
@ExcelProperty("开启状态")
private Integer status;
@ExcelProperty("备注")
private String remark;
@ExcelProperty("支付结果的回调地址")
private String payNotifyUrl;
@ExcelProperty("退款结果的回调地址")
private String refundNotifyUrl;
@ExcelProperty("商户编号")
private Long merchantId;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "支付应用信息 Excel 导出 Request VO", description = "参数和 PayAppPageReqVO 是一致的")
@Data
public class PayAppExportReqVO {
@ApiModelProperty(value = "应用名")
private String name;
@ApiModelProperty(value = "开启状态")
private Integer status;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "支付结果的回调地址")
private String payNotifyUrl;
@ApiModelProperty(value = "退款结果的回调地址")
private String refundNotifyUrl;
@ApiModelProperty(value = "商户编号")
private Long merchantId;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,75 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel(value = "支付应用信息分页查询 Response VO", description = "相比于支付信息,还会多出应用渠道的开关信息")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayAppPageItemRespVO extends PayAppBaseVO {
@ApiModelProperty(value = "应用编号", required = true)
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
/**
* 所属商户
*/
private PayMerchant payMerchant;
@ApiModel("商户")
@Data
public static class PayMerchant {
@ApiModelProperty(value = "商户编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "商户名称", required = true, example = "研发部")
private String name;
}
/**
* 支付渠道
*/
private PayChannel payChannel;
/**
* 支付渠道开通情况
* 1默认为未开通当前支付渠道0为已开通支付渠道
*/
@Data
@ApiModel("支付渠道")
public static class PayChannel {
@ApiModelProperty(value = "微信 JSAPI 支付", required = true, example = "1")
private Integer wxPub = CommonStatusEnum.DISABLE.getStatus();
@ApiModelProperty(value = "微信小程序支付", required = true, example = "1")
private Integer wxLite = CommonStatusEnum.DISABLE.getStatus();
@ApiModelProperty(value = "微信 App 支付", required = true, example = "1")
private Integer wxApp = CommonStatusEnum.DISABLE.getStatus();
@ApiModelProperty(value = "支付宝 PC 网站支付", required = true, example = "1")
private Integer alipayPc = CommonStatusEnum.DISABLE.getStatus();
@ApiModelProperty(value = "支付宝 Wap 网站支付", required = true, example = "1")
private Integer alipayWap = CommonStatusEnum.DISABLE.getStatus();
@ApiModelProperty(value = "支付宝App 支付", required = true, example = "1")
private Integer alipayApp = CommonStatusEnum.DISABLE.getStatus();
@ApiModelProperty(value = "支付宝扫码支付", required = true, example = "1")
private Integer alipayQr = CommonStatusEnum.DISABLE.getStatus();
}
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("支付应用信息分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayAppPageReqVO extends PageParam {
@ApiModelProperty(value = "应用名")
private String name;
@ApiModelProperty(value = "开启状态")
private Integer status;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "支付结果的回调地址")
private String payNotifyUrl;
@ApiModelProperty(value = "退款结果的回调地址")
private String refundNotifyUrl;
@ApiModelProperty(value = "商户名称")
private String merchantName;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("支付应用信息 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayAppRespVO extends PayAppBaseVO {
@ApiModelProperty(value = "应用编号", required = true)
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("支付应用信息更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayAppUpdateReqVO extends PayAppBaseVO {
@ApiModelProperty(value = "应用编号", required = true)
@NotNull(message = "应用编号不能为空")
private Long id;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@ApiModel("应用更新状态 Request VO")
@Data
public class PayAppUpdateStatusReqVO {
@ApiModelProperty(value = "商户编号", required = true, example = "1024")
@NotNull(message = "商户编号不能为空")
private Long id;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 SysCommonStatusEnum 枚举")
@NotNull(message = "状态不能为空")
private Integer status;
}

View File

@ -0,0 +1,190 @@
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;
@Api(tags = "支付渠道")
@RestController
@RequestMapping("/pay/channel")
@Validated
public class PayChannelController {
@Resource
private PayChannelService channelService;
// todo 芋艿 这几个生成的方法是没用到的 您看要不删除了把 -----start
@PostMapping("/create")
@ApiOperation("创建支付渠道 ")
@PreAuthorize("@ss.hasPermission('pay:channel:create')")
public CommonResult<Long> createChannel(@Valid @RequestBody PayChannelCreateReqVO createReqVO) {
return success(channelService.createChannel(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新支付渠道 ")
@PreAuthorize("@ss.hasPermission('pay:channel:update')")
public CommonResult<Boolean> updateChannel(@Valid @RequestBody PayChannelUpdateReqVO updateReqVO) {
channelService.updateChannel(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除支付渠道 ")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('pay:channel:delete')")
public CommonResult<Boolean> deleteChannel(@RequestParam("id") Long id) {
channelService.deleteChannel(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得支付渠道 ")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('pay:channel:query')")
public CommonResult<PayChannelRespVO> getChannel(@RequestParam("id") Long id) {
PayChannelDO channel = channelService.getChannel(id);
return success(PayChannelConvert.INSTANCE.convert(channel));
}
@GetMapping("/list")
@ApiOperation("获得支付渠道列表")
@ApiImplicitParam(name = "ids", value = "编号列表",
required = true, example = "1024,2048", dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('pay:channel:query')")
public CommonResult<List<PayChannelRespVO>> getChannelList(@RequestParam("ids") Collection<Long> ids) {
List<PayChannelDO> list = channelService.getChannelList(ids);
return success(PayChannelConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得支付渠道分页")
@PreAuthorize("@ss.hasPermission('pay:channel:query')")
public CommonResult<PageResult<PayChannelRespVO>> getChannelPage(@Valid PayChannelPageReqVO pageVO) {
PageResult<PayChannelDO> pageResult = channelService.getChannelPage(pageVO);
return success(PayChannelConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出支付渠道Excel")
@PreAuthorize("@ss.hasPermission('pay:channel:export')")
@OperateLog(type = EXPORT)
public void exportChannelExcel(@Valid PayChannelExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<PayChannelDO> list = channelService.getChannelList(exportReqVO);
// 导出 Excel
List<PayChannelExcelVO> datas = PayChannelConvert.INSTANCE.convertList02(list);
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<String> parsingPemFile(@RequestParam("file") MultipartFile file) {
return success(channelService.parsingPemFile(file));
}
@PostMapping("/create-wechat")
@ApiOperation("创建支付渠道 ")
@PreAuthorize("@ss.hasPermission('pay:channel:create')")
public CommonResult<Long> 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")
@ApiOperation("根据条件查询微信支付渠道")
@ApiImplicitParams({
@ApiImplicitParam(name = "merchantId", value = "商户编号",
required = true, example = "1", dataTypeClass = Long.class),
@ApiImplicitParam(name = "appId", value = "应用编号",
required = true, example = "1", dataTypeClass = Long.class),
@ApiImplicitParam(name = "code", value = "支付渠道编码",
required = true, example = "wx_pub", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermission('pay:channel:query')")
public CommonResult<PayWeChatChannelRespVO> getWeChatChannel(
@RequestParam Long merchantId, @RequestParam Long appId, @RequestParam String code) {
// 獲取渠道
PayChannelDO channel = channelService.getChannelByConditions(merchantId, appId, code);
if (channel == null) {
return success(new PayWeChatChannelRespVO());
}
// 拼凑数据
PayWeChatChannelRespVO respVo = PayChannelConvert.INSTANCE.convert2(channel);
WXPayClientConfig config = (WXPayClientConfig) channel.getConfig();
respVo.setWeChatConfig(PayChannelConvert.INSTANCE.configConvert(config));
return success(respVo);
}
@PutMapping("/update-wechat")
@ApiOperation("更新微信支付渠道 ")
@PreAuthorize("@ss.hasPermission('pay:channel:update')")
public CommonResult<Boolean> 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不可为空");
}
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
/**
* 支付渠道
Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class PayChannelBaseVO {
@ApiModelProperty(value = "渠道编码", required = true)
@NotNull(message = "渠道编码不能为空")
private String code;
@ApiModelProperty(value = "开启状态", required = true)
@NotNull(message = "开启状态不能为空")
private Integer status;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "渠道费率,单位:百分比", required = true)
@NotNull(message = "渠道费率,单位:百分比不能为空")
private Double feeRate;
@ApiModelProperty(value = "商户编号", required = true)
@NotNull(message = "商户编号不能为空")
private Long merchantId;
@ApiModelProperty(value = "应用编号", required = true)
@NotNull(message = "应用编号不能为空")
private Long appId;
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("支付渠道 创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayChannelCreateReqVO extends PayChannelBaseVO {
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* 支付渠道
Excel VO
*
* @author 芋艿
*/
@Data
public class PayChannelExcelVO {
@ExcelProperty("商户编号")
private Long id;
@ExcelProperty("渠道编码")
private String code;
@ExcelProperty("开启状态")
private Integer status;
@ExcelProperty("备注")
private String remark;
@ExcelProperty("渠道费率,单位:百分比")
private Double feeRate;
@ExcelProperty("商户编号")
private Long merchantId;
@ExcelProperty("应用编号")
private Long appId;
/**
* todo @芋艿 mapStruct 存在转换问题
* java: Can't map property "PayClientConfig payChannelDO.config" to "String payChannelExcelVO.config".
* Consider to declare/implement a mapping method: "String map(PayClientConfig value)".
*/
/// @ExcelProperty("支付渠道配置")
/// private String config;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "支付渠道 Excel 导出 Request VO", description = "参数和 PayChannelPageReqVO 是一致的")
@Data
public class PayChannelExportReqVO {
@ApiModelProperty(value = "渠道编码")
private String code;
@ApiModelProperty(value = "开启状态")
private Integer status;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "渠道费率,单位:百分比")
private Double feeRate;
@ApiModelProperty(value = "商户编号")
private Long merchantId;
@ApiModelProperty(value = "应用编号")
private Long appId;
@ApiModelProperty(value = "支付渠道配置")
private String config;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("支付渠道 分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayChannelPageReqVO extends PageParam {
@ApiModelProperty(value = "渠道编码")
private String code;
@ApiModelProperty(value = "开启状态")
private Integer status;
@ApiModelProperty(value = "备注")
private String remark;
@ApiModelProperty(value = "渠道费率,单位:百分比")
private Double feeRate;
@ApiModelProperty(value = "商户编号")
private Long merchantId;
@ApiModelProperty(value = "应用编号")
private Long appId;
@ApiModelProperty(value = "支付渠道配置")
private String config;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("支付渠道 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayChannelRespVO extends PayChannelBaseVO {
@ApiModelProperty(value = "商户编号", required = true)
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("支付渠道 更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayChannelUpdateReqVO extends PayChannelBaseVO {
@ApiModelProperty(value = "商户编号", required = true)
@NotNull(message = "商户编号不能为空")
private Long id;
}

View File

@ -0,0 +1,65 @@
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;
}
}

View File

@ -0,0 +1,68 @@
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;
}
}

View File

@ -0,0 +1,66 @@
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;
}
}

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.adminserver.modules.pay.controller.merchant;
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.*;
import cn.iocoder.yudao.adminserver.modules.pay.convert.merchant.PayMerchantConvert;
import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService;
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserUpdateStatusReqVO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -76,6 +75,15 @@ public class PayMerchantController {
return success(PayMerchantConvert.INSTANCE.convert(merchant));
}
@GetMapping("/list-name")
@ApiOperation("根据商户名称获得支付商户信息列表")
@ApiImplicitParam(name = "name", value = "商户名称", required = true, example = "芋道", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('pay:merchant:query')")
public CommonResult<List<PayMerchantRespVO>> getMerchantListByName(@RequestParam("name") String name) {
List<PayMerchantDO> merchantListDO = merchantService.getMerchantListByNameLimit(name);
return success(PayMerchantConvert.INSTANCE.convertList(merchantListDO));
}
@GetMapping("/list")
@ApiOperation("获得支付商户信息列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)

View File

@ -12,10 +12,6 @@ import javax.validation.constraints.NotNull;
@Data
public class PayMerchantBaseVO {
// TODO @aquanno 应该不允许修改啊哈哈我的原型没画对
@ApiModelProperty(value = "商户号")
private String no;
@ApiModelProperty(value = "商户全称", required = true)
@NotNull(message = "商户全称不能为空")
private String name;

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.adminserver.modules.pay.convert.app;
import java.util.*;
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
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.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.*;
/**
* 支付应用信息 Convert
*
* @author 芋艿
*/
@Mapper
public interface PayAppConvert {
PayAppConvert INSTANCE = Mappers.getMapper(PayAppConvert.class);
PayAppPageItemRespVO pageConvert (PayAppDO bean);
PayAppPageItemRespVO.PayMerchant convert(PayMerchantDO bean);
PayAppDO convert(PayAppCreateReqVO bean);
PayAppDO convert(PayAppUpdateReqVO bean);
PayAppRespVO convert(PayAppDO bean);
List<PayAppRespVO> convertList(List<PayAppDO> list);
PageResult<PayAppRespVO> convertPage(PageResult<PayAppDO> page);
List<PayAppExcelVO> convertList02(List<PayAppDO> list);
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.adminserver.modules.pay.convert.channel;
import java.util.*;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
/**
* 支付渠道
Convert
*
* @author 芋艿
*/
@Mapper
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);
PayChannelDO convert(PayChannelUpdateReqVO bean);
PayChannelRespVO convert(PayChannelDO bean);
List<PayChannelRespVO> convertList(List<PayChannelDO> list);
PageResult<PayChannelRespVO> convertPage(PageResult<PayChannelDO> page);
List<PayChannelExcelVO> convertList02(List<PayChannelDO> 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);
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app;
import java.util.*;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
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 org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.*;
/**
* 支付应用信息 Mapper
*
* @author 芋艿
*/
@Mapper
public interface PayAppMapper extends BaseMapperX<PayAppDO> {
default PageResult<PayAppDO> selectPage(PayAppPageReqVO reqVO,Collection<Long> merchantIds) {
return selectPage(reqVO, new QueryWrapperX<PayAppDO>()
.likeIfPresent("name", reqVO.getName())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("remark", reqVO.getRemark())
.eqIfPresent("pay_notify_url", reqVO.getPayNotifyUrl())
.eqIfPresent("refund_notify_url", reqVO.getRefundNotifyUrl())
.inIfPresent("merchant_id", merchantIds)
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
default List<PayAppDO> selectList(PayAppExportReqVO reqVO) {
return selectList(new QueryWrapperX<PayAppDO>()
.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())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id") );
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel;
import java.util.*;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
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 org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
/**
* 支付渠道
Mapper
*
* @author 芋艿
*/
@Mapper
public interface PayChannelMapper extends BaseMapperX<PayChannelDO> {
default PageResult<PayChannelDO> selectPage(PayChannelPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<PayChannelDO>()
.eqIfPresent("code", reqVO.getCode())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("remark", reqVO.getRemark())
.eqIfPresent("fee_rate", reqVO.getFeeRate())
.eqIfPresent("merchant_id", reqVO.getMerchantId())
.eqIfPresent("app_id", reqVO.getAppId())
.eqIfPresent("config", reqVO.getConfig())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id") );
}
default List<PayChannelDO> selectList(PayChannelExportReqVO reqVO) {
return selectList(new QueryWrapperX<PayChannelDO>()
.eqIfPresent("code", reqVO.getCode())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("remark", reqVO.getRemark())
.eqIfPresent("fee_rate", reqVO.getFeeRate())
.eqIfPresent("merchant_id", reqVO.getMerchantId())
.eqIfPresent("app_id", reqVO.getAppId())
.eqIfPresent("config", reqVO.getConfig())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id") );
}
}

View File

@ -0,0 +1,81 @@
package cn.iocoder.yudao.adminserver.modules.pay.service.app;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.*;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.web.multipart.MultipartFile;
/**
* 支付应用信息 Service 接口
*
* @author 芋艿
*/
public interface PayAppService {
/**
* 创建支付应用信息
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createApp(@Valid PayAppCreateReqVO createReqVO);
/**
* 更新支付应用信息
*
* @param updateReqVO 更新信息
*/
void updateApp(@Valid PayAppUpdateReqVO updateReqVO);
/**
* 删除支付应用信息
*
* @param id 编号
*/
void deleteApp(Long id);
/**
* 获得支付应用信息
*
* @param id 编号
* @return 支付应用信息
*/
PayAppDO getApp(Long id);
/**
* 获得支付应用信息列表
*
* @param ids 编号
* @return 支付应用信息列表
*/
List<PayAppDO> getAppList(Collection<Long> ids);
/**
* 获得支付应用信息分页
*
* @param pageReqVO 分页查询
* @return 支付应用信息分页
*/
PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO);
/**
* 获得支付应用信息列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 支付应用信息列表
*/
List<PayAppDO> getAppList(PayAppExportReqVO exportReqVO);
/**
* 修改应用信息状态
*
* @param id 应用编号
* @param status 状态{@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
*/
void updateAppStatus(Long id, Integer status);
}

View File

@ -0,0 +1,140 @@
package cn.iocoder.yudao.adminserver.modules.pay.service.app.impl;
import cn.hutool.core.util.StrUtil;
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.util.collection.CollectionUtils;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.service.app.PayAppService;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
/**
* 支付应用信息 Service 实现类
*
* @author aquan
*/
@Service
@Validated
public class PayAppServiceImpl implements PayAppService {
@Resource
private PayAppMapper appMapper;
/**
* 商户 service 组件
*/
@Resource
private PayMerchantService merchantService;
@Override
public Long createApp(PayAppCreateReqVO createReqVO) {
// 插入
PayAppDO app = PayAppConvert.INSTANCE.convert(createReqVO);
appMapper.insert(app);
// 返回
return app.getId();
}
@Override
public void updateApp(PayAppUpdateReqVO updateReqVO) {
// 校验存在
this.validateAppExists(updateReqVO.getId());
// 更新
PayAppDO updateObj = PayAppConvert.INSTANCE.convert(updateReqVO);
appMapper.updateById(updateObj);
}
@Override
public void deleteApp(Long id) {
// 校验存在
this.validateAppExists(id);
// 删除
appMapper.deleteById(id);
}
private void validateAppExists(Long id) {
if (appMapper.selectById(id) == null) {
throw exception(APP_NOT_EXISTS);
}
}
@Override
public PayAppDO getApp(Long id) {
return appMapper.selectById(id);
}
@Override
public List<PayAppDO> getAppList(Collection<Long> ids) {
return appMapper.selectBatchIds(ids);
}
@Override
public PageResult<PayAppDO> getAppPage(PayAppPageReqVO pageReqVO) {
return appMapper.selectPage(pageReqVO,this.getMerchantCondition(pageReqVO.getMerchantName()));
}
@Override
public List<PayAppDO> getAppList(PayAppExportReqVO exportReqVO) {
return appMapper.selectList(exportReqVO);
}
/**
* 获取商户编号集合根据商户名称模糊查询得到所有的商户编号集合
* @param merchantName 商户名称
* @return 商户编号集合
*/
private Set<Long> getMerchantCondition(String merchantName) {
if (StrUtil.isBlank(merchantName)) {
return Collections.emptySet();
}
return CollectionUtils.convertSet(merchantService.getMerchantListByName(merchantName), PayMerchantDO::getId);
}
/**
* 修改应用信息状态
*
* @param id 应用编号
* @param status 状态{@link CommonStatusEnum}
*/
@Override
public void updateAppStatus(Long id, Integer status) {
// 校验商户存在
this.checkAppExists(id);
// 更新状态
PayAppDO app = new PayAppDO();
app.setId(id);
app.setStatus(status);
appMapper.updateById(app);
}
/**
* 检查商户是否存在
* @param id 商户编号
*/
@VisibleForTesting
public void checkAppExists(Long id) {
if (id == null) {
return;
}
PayAppDO payApp = appMapper.selectById(id);
if (payApp == null) {
throw exception(APP_NOT_EXISTS);
}
}
}

View File

@ -0,0 +1,130 @@
package cn.iocoder.yudao.adminserver.modules.pay.service.channel;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.web.multipart.MultipartFile;
/**
* 支付渠道
* Service 接口
*
* @author 芋艿
*/
public interface PayChannelService {
/**
* 创建支付渠道
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createChannel(@Valid PayChannelCreateReqVO createReqVO);
/**
* 更新支付渠道
*
* @param updateReqVO 更新信息
*/
void updateChannel(@Valid PayChannelUpdateReqVO updateReqVO);
/**
* 删除支付渠道
*
* @param id 编号
*/
void deleteChannel(Long id);
/**
* 获得支付渠道
*
* @param id 编号
* @return 支付渠道
*/
PayChannelDO getChannel(Long id);
/**
* 获得支付渠道
* 列表
*
* @param ids 编号
* @return 支付渠道
* 列表
*/
List<PayChannelDO> getChannelList(Collection<Long> ids);
/**
* 获得支付渠道
* 分页
*
* @param pageReqVO 分页查询
* @return 支付渠道
* 分页
*/
PageResult<PayChannelDO> getChannelPage(PayChannelPageReqVO pageReqVO);
/**
* 获得支付渠道
* 列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 支付渠道
* 列表
*/
List<PayChannelDO> getChannelList(PayChannelExportReqVO exportReqVO);
/**
* 根据支付应用ID集合获取所有的支付渠道
*
* @param payIds 支付应用编号集合
* @return 支付渠道
*/
List<PayChannelDO> getSimpleChannels(Collection<Long> payIds);
/**
* 解析pem文件获取公钥私钥字符串
*
* @param file pem公私钥文件
* @return 解析后的字符串
*/
String parsingPemFile(MultipartFile file);
/**
* 创建微信的渠道配置
*
* @param reqVO 创建信息
* @return 创建结果
*/
Long createWechatChannel(PayWechatChannelCreateReqVO reqVO);
/**
* 根据条件获取通道数量
*
* @param merchantId 商户编号
* @param appid 应用编号
* @param code 通道编码
* @return 数量
*/
Integer getChannelCountByConditions(Long merchantId, Long appid, String code);
/**
* 根据条件获取通道
*
* @param merchantId 商户编号
* @param appid 应用编号
* @param code 通道编码
* @return 数量
*/
PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code);
/**
* 更新微信支付渠道
*
* @param updateReqVO 更新信息
*/
void updateWechatChannel(PayWechatChannelUpdateReqVO updateReqVO);
}

View File

@ -0,0 +1,196 @@
package cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl;
import cn.hutool.core.io.IoUtil;
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 com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import java.io.IOException;
import java.util.*;
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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 org.springframework.web.multipart.MultipartFile;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
/**
* 支付渠道
* Service 实现类
*
* @author 芋艿
*/
@Slf4j
@Service
@Validated
public class PayChannelServiceImpl implements PayChannelService {
@Resource
private PayChannelMapper channelMapper;
@Override
public Long createChannel(PayChannelCreateReqVO createReqVO) {
// 插入
PayChannelDO channel = PayChannelConvert.INSTANCE.convert(createReqVO);
channelMapper.insert(channel);
// 返回
return channel.getId();
}
@Override
public void updateChannel(PayChannelUpdateReqVO updateReqVO) {
// 校验存在
this.validateChannelExists(updateReqVO.getId());
// 更新
PayChannelDO updateObj = PayChannelConvert.INSTANCE.convert(updateReqVO);
channelMapper.updateById(updateObj);
}
@Override
public void deleteChannel(Long id) {
// 校验存在
this.validateChannelExists(id);
// 删除
channelMapper.deleteById(id);
}
private void validateChannelExists(Long id) {
if (channelMapper.selectById(id) == null) {
throw exception(CHANNEL_NOT_EXISTS);
}
}
@Override
public PayChannelDO getChannel(Long id) {
return channelMapper.selectById(id);
}
@Override
public List<PayChannelDO> getChannelList(Collection<Long> ids) {
return channelMapper.selectBatchIds(ids);
}
@Override
public PageResult<PayChannelDO> getChannelPage(PayChannelPageReqVO pageReqVO) {
return channelMapper.selectPage(pageReqVO);
}
@Override
public List<PayChannelDO> getChannelList(PayChannelExportReqVO exportReqVO) {
return channelMapper.selectList(exportReqVO);
}
/**
* 根据支付应用ID集合获取所有的支付渠道
*
* @param payIds 支付应用编号集合
* @return 支付渠道
*/
@Override
public List<PayChannelDO> getSimpleChannels(Collection<Long> payIds) {
return channelMapper.selectList(new QueryWrapper<PayChannelDO>().lambda().in(PayChannelDO::getAppId, payIds));
}
/**
* 解析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();
}
/**
* 根据条件获取通道数量
*
* @param merchantId 商户编号
* @param appid 应用编号
* @param code 通道编码
* @return 数量
*/
@Override
public Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
return this.channelMapper.selectCount(new QueryWrapper<PayChannelDO>().lambda()
.eq(PayChannelDO::getMerchantId, merchantId)
.eq(PayChannelDO::getAppId, appid)
.eq(PayChannelDO::getCode, code)
);
}
/**
* 根据条件获取通道
*
* @param merchantId 商户编号
* @param appid 应用编号
* @param code 通道编码
* @return 数量
*/
@Override
public PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
return this.channelMapper.selectOne((new QueryWrapper<PayChannelDO>().lambda()
.eq(PayChannelDO::getMerchantId, merchantId)
.eq(PayChannelDO::getAppId, appid)
.eq(PayChannelDO::getCode, code)
));
}
/**
* 更新微信支付渠道
*
* @param updateReqVO 更新信息
*/
@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);
}
}

View File

@ -2,9 +2,13 @@ package cn.iocoder.yudao.adminserver.modules.pay.service.merchant;
import java.util.*;
import javax.validation.*;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.*;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
/**
* 支付商户信息 Service 接口
@ -69,9 +73,46 @@ public interface PayMerchantService {
/**
* 修改商户状态
* @param id 商户编号
*
* @param id 商户编号
* @param status 状态
*/
void updateMerchantStatus(Long id, Integer status);
/**
* 根据商户名称模糊查询商户集合
*
* @param merchantName 商户名称
* @return 商户集合
*/
List<PayMerchantDO> getMerchantListByName(String merchantName);
/**
* 根据商户名称模糊查询一定数量的商户集合
* @param merchantName 商户名称
* @return 商户集合
*/
List<PayMerchantDO> getMerchantListByNameLimit(String merchantName);
/**
* 获得指定编号的商户列表
*
* @param merchantIds 商户编号数组
* @return 商户列表
*/
List<PayMerchantDO> getSimpleMerchants(Collection<Long> merchantIds);
/**
* 获得指定编号的商户 Map
*
* @param merchantIds 商户编号数组
* @return 商户 Map
*/
default Map<Long, PayMerchantDO> getMerchantMap(Collection<Long> merchantIds){
if (CollUtil.isEmpty(merchantIds)) {
return Collections.emptyMap();
}
List<PayMerchantDO> list = getSimpleMerchants(merchantIds);
return CollectionUtils.convertMap(list, PayMerchantDO::getId);
}
}

View File

@ -10,6 +10,8 @@ import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMa
import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -24,7 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
/**
* 支付商户信息 Service 实现类
*
* @author 芋艿
* @author aquan
*/
@Service
@Validated
@ -37,10 +39,7 @@ public class PayMerchantServiceImpl implements PayMerchantService {
public Long createMerchant(PayMerchantCreateReqVO createReqVO) {
// 插入
PayMerchantDO merchant = PayMerchantConvert.INSTANCE.convert(createReqVO);
// 根据 年月日时分秒毫秒 生成时间戳
// TODO @aquan生成 no 可以单独一个小方法
String merchantNo = "M" + DateUtil.format(LocalDateTime.now(),"yyyyMMddHHmmssSSS");
merchant.setNo(merchantNo);
merchant.setNo(this.generateMerchantNo());
merchantMapper.insert(merchant);
// 返回
return merchant.getId();
@ -106,6 +105,35 @@ public class PayMerchantServiceImpl implements PayMerchantService {
merchantMapper.updateById(merchant);
}
/**
* 根据商户名称模糊查询商户集合
*
* @param merchantName 商户名称
* @return 商户集合
*/
@Override
public List<PayMerchantDO> getMerchantListByName(String merchantName) {
return this.merchantMapper.selectList(new QueryWrapper<PayMerchantDO>()
.lambda().likeRight(PayMerchantDO::getName, merchantName));
}
/**
* 根据商户名称模糊查询一定数量的商户集合
*
* @param merchantName 商户名称
* @return 商户集合
*/
@Override
public List<PayMerchantDO> getMerchantListByNameLimit(String merchantName) {
LambdaQueryWrapper<PayMerchantDO> queryWrapper = new QueryWrapper<PayMerchantDO>().lambda()
.select(PayMerchantDO::getId, PayMerchantDO::getName)
.likeRight(PayMerchantDO::getName, merchantName)
.last("limit 200");
return this.merchantMapper.selectList(queryWrapper);
}
/**
* 检查商户是否存在
* @param id 商户编号
@ -121,5 +149,24 @@ public class PayMerchantServiceImpl implements PayMerchantService {
}
}
/**
* 获得指定编号的商户列表
*
* @param merchantIds 商户编号数组
* @return 商户列表
*/
@Override
public List<PayMerchantDO> getSimpleMerchants(Collection<Long> merchantIds) {
return merchantMapper.selectBatchIds(merchantIds);
}
/**
* 根据年月日时分秒毫秒生成商户号
* @return 商户号
*/
private String generateMerchantNo(){
return "M" + DateUtil.format(LocalDateTime.now(),"yyyyMMddHHmmssSSS");
}
}

View File

@ -44,16 +44,16 @@ spring:
datasource:
master:
name: ruoyi-vue-pro
url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
url: jdbc:mysql://rm-j6cxl87683w973f78ho.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
username: chenquan
password: Miraclequan@990429
slave: # 模拟从库,可根据自己需要修改
name: ruoyi-vue-pro
url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
url: jdbc:mysql://rm-j6cxl87683w973f78ho.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
username: chenquan
password: Miraclequan@990429
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:

View File

@ -60,5 +60,6 @@ yudao:
constants-class-list:
- cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants
- cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
pay:
payReturnUrl: http://127.0.0.1
debug: false

View File

@ -0,0 +1,196 @@
package cn.iocoder.yudao.adminserver.modules.pay.app.service;
import javax.annotation.Resource;
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.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import java.util.*;
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
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.common.util.date.DateUtils.buildTime;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* {@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<PayAppDO> 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() {
// 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<PayAppDO> list = appService.getAppList(reqVO);
// 断言
assertEquals(1, list.size());
assertPojoEquals(dbApp, list.get(0));
}
}

View File

@ -0,0 +1,204 @@
package cn.iocoder.yudao.adminserver.modules.pay.channel;
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
import org.junit.jupiter.api.Test;
import javax.annotation.Resource;
import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
import cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl.PayChannelServiceImpl;
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.*;
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.channel.PayChannelMapper;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import java.util.*;
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
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.common.util.date.DateUtils.buildTime;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* {@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<PayChannelDO> pageResult = channelService.getChannelPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbChannel, pageResult.getList().get(0));
}
@Test // TODO 请修改 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<PayChannelDO> list = channelService.getChannelList(reqVO);
// 断言
assertEquals(1, list.size());
assertPojoEquals(dbChannel, list.get(0));
}
}

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.adminserver.modules.pay.merchant.service;
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;
@ -28,7 +31,7 @@ import static org.junit.jupiter.api.Assertions.*;
/**
* {@link PayMerchantServiceImpl} 的单元测试类
*
* @author 芋艿 // TODO @aquan修改成自己的
* @author aquan
*/
@Import(PayMerchantServiceImpl.class)
public class PayMerchantServiceTest extends BaseDbUnitTest {

View File

@ -0,0 +1,67 @@
import request from '@/utils/request'
// 创建支付应用信息
export function createApp(data) {
return request({
url: '/pay/app/create',
method: 'post',
data: data
})
}
// 更新支付应用信息
export function updateApp(data) {
return request({
url: '/pay/app/update',
method: 'put',
data: data
})
}
// 支付应用信息状态修改
export function changeAppStatus(id, status) {
const data = {
id,
status
}
return request({
url: '/pay/app/update-status',
method: 'put',
data: data
})
}
// 删除支付应用信息
export function deleteApp(id) {
return request({
url: '/pay/app/delete?id=' + id,
method: 'delete'
})
}
// 获得支付应用信息
export function getApp(id) {
return request({
url: '/pay/app/get?id=' + id,
method: 'get'
})
}
// 获得支付应用信息分页
export function getAppPage(query) {
return request({
url: '/pay/app/page',
method: 'get',
params: query
})
}
// 导出支付应用信息 Excel
export function exportAppExcel(query) {
return request({
url: '/pay/app/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@ -0,0 +1,88 @@
import request from '@/utils/request'
// 创建支付渠道
export function createChannel(data) {
return request({
url: '/pay/channel/create',
method: 'post',
data: data
})
}
// 更新支付渠道
export function updateChannel(data) {
return request({
url: '/pay/channel/update',
method: 'put',
data: data
})
}
// 删除支付渠道
export function deleteChannel(id) {
return request({
url: '/pay/channel/delete?id=' + id,
method: 'delete'
})
}
// 获得支付渠道
export function getChannel(id) {
return request({
url: '/pay/channel/get?id=' + id,
method: 'get'
})
}
// 获得支付渠道分页
export function getChannelPage(query) {
return request({
url: '/pay/channel/page',
method: 'get',
params: query
})
}
// 导出支付渠道Excel
export function exportChannelExcel(query) {
return request({
url: '/pay/channel/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}
// 创建微信支付渠道
export function createWechatChannel(data) {
return request({
url: '/pay/channel/create-wechat',
method: 'post',
data: data
})
}
// 获得支付渠道
export function getWechatChannel(merchantId,appId,code) {
return request({
url: '/pay/channel/get-wechat',
params:{
merchantId:merchantId,
appId:appId,
code:code
},
method: 'get'
})
}
// 更新支付渠道
export function updateWechatChannel(data) {
return request({
url: '/pay/channel/update-wechat',
method: 'put',
data: data
})
}

View File

@ -46,6 +46,16 @@ export function getMerchant(id) {
method: 'get'
})
}
// 根据商户名称搜索商户列表
export function getMerchantListByName(name) {
return request({
url: '/pay/merchant/list-name',
params:{
name:name
},
method: 'get'
})
}
// 获得支付商户信息分页
export function getMerchantPage(query) {

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1636341153732" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2282" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: element-icons; src: url("chrome-extension://moombeodfomdpjnpocobemoiaemednkg/fonts/element-icons.woff") format("woff"), url("chrome-extension://moombeodfomdpjnpocobemoiaemednkg/fonts/element-icons.ttf ") format("truetype"); }
</style></defs><path d="M294.912 874.666667a21.333333 21.333333 0 0 1-17.194667-33.962667l469.333334-640a21.333333 21.333333 0 0 1 34.432 25.258667l-469.333334 640a21.248 21.248 0 0 1-17.237333 8.704zM358.912 533.333333a161.28 161.28 0 0 1-149.333333-170.666666 161.28 161.28 0 0 1 149.333333-170.666667 161.28 161.28 0 0 1 149.333333 170.666667 161.28 161.28 0 0 1-149.333333 170.666666z m0-298.666666a118.912 118.912 0 0 0-106.666667 128 118.912 118.912 0 0 0 106.666667 128 118.912 118.912 0 0 0 106.666667-128 118.912 118.912 0 0 0-106.666667-128zM700.245333 874.666667a161.28 161.28 0 0 1-149.333333-170.666667 161.28 161.28 0 0 1 149.333333-170.666667 161.28 161.28 0 0 1 149.333334 170.666667 161.28 161.28 0 0 1-149.333334 170.666667z m0-298.666667a118.912 118.912 0 0 0-106.666666 128 118.912 118.912 0 0 0 106.666666 128 118.912 118.912 0 0 0 106.666667-128 118.912 118.912 0 0 0-106.666667-128z" fill="#757575" p-id="2283"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -16,7 +16,7 @@ export const SysCommonStatusEnum = {
* 菜单的类型枚举
*/
export const SysMenuTypeEnum = {
DIR : 1, // 目录
DIR: 1, // 目录
MENU: 2, // 菜单
BUTTON: 3 // 按钮
}
@ -90,3 +90,34 @@ export const SysUserSocialTypeEnum = {
img: "https://cdn.jsdelivr.net/gh/justauth/justauth-oauth-logo@1.11/wechat_enterprise.png",
}
}
export const PayChannelEnum = {
WX_PUB: {
"code": "wx_pub",
"name": "微信 JSAPI 支付",
},
WX_LITE: {
"code": "wx_lite",
"name": "微信小程序支付"
},
WX_APP: {
"code": "wx_app",
"name": "微信 APP 支付"
},
ALIPAY_PC: {
"code": "alipay_pc",
"name": "支付宝 PC 网站支付"
},
ALIPAY_WAP: {
"code": "alipay_wap",
"name": "支付宝 WAP 网站支付"
},
ALIPAY_APP: {
"code": "alipay_app",
"name": "支付宝 APP 支付"
},
ALIPAY_QR: {
"code": "alipay_qr",
"name": "支付宝扫码支付"
},
}

View File

@ -32,7 +32,14 @@ export const DICT_TYPE = {
TOOL_CODEGEN_TEMPLATE_TYPE: 'tool_codegen_template_type',
// 商户状态
PAY_MERCHANT_STATUS: 'pay_merchant_status'
PAY_MERCHANT_STATUS: 'pay_merchant_status',
// 应用状态
PAY_APP_STATUS: 'pay_app_status',
// 渠道状态
PAY_CHANNEL_STATUS: 'pay_channel_status',
// 微信渠道版本
PAY_CHANNEL_WECHAT_VERSION:'pay_channel_wechat_version',
}
/**

View File

@ -0,0 +1,261 @@
<template>
<div>
<el-dialog :visible.sync="transferParam.open" @close="close" append-to-body>
<el-form ref="wechatJsApiForm" :model="form" :rules="rules" size="medium" label-width="100px"
v-loading="transferParam.loading">
<el-form-item label-width="180px" label="渠道费率" prop="feeRate">
<el-input v-model="form.feeRate" placeholder="请输入渠道费率" clearable :style="{width: '100%'}">
<template slot="append">%</template>
</el-input>
</el-form-item>
<el-form-item label-width="180px" label="公众号APPID" prop="weChatConfig.appId">
<el-input v-model="form.weChatConfig.appId" placeholder="请输入公众号APPID" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label-width="180px" label="商户号" prop="weChatConfig.mchId">
<el-input v-model="form.weChatConfig.mchId" :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label-width="180px" label="渠道状态" prop="status">
<el-radio-group v-model="form.status" size="medium">
<el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label-width="180px" label="API 版本" prop="weChatConfig.apiVersion">
<el-radio-group v-model="form.weChatConfig.apiVersion" size="medium">
<el-radio v-for="dict in versionDictDatas" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label-width="180px" label="商户秘钥" prop="weChatConfig.mchKey"
v-if="form.weChatConfig.apiVersion === 'v2'">
<el-input v-model="form.weChatConfig.mchKey" placeholder="请输入商户秘钥" clearable
:style="{width: '100%'}"></el-input>
</el-form-item>
<div v-if="form.weChatConfig.apiVersion === 'v3'">
<el-form-item label-width="180px" label="apiclient_key.perm证书" prop="weChatConfig.privateKeyContent">
<el-input v-model="form.weChatConfig.privateKeyContent" type="textarea"
placeholder="请上传apiclient_key.perm证书"
readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label-width="180px" label="" prop="privateKeyContentFile">
<el-upload ref="privateKeyContentFile"
:limit="1"
:accept="fileAccept"
:headers="header"
:action="pemUploadAction"
:before-upload="pemFileBeforeUpload"
:on-success="privateKeyUploadSuccess"
>
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
</el-upload>
</el-form-item>
<el-form-item label-width="180px" label="apiclient_cert.perm证书" prop="weChatConfig.privateCertContent">
<el-input v-model="form.weChatConfig.privateCertContent" type="textarea"
placeholder="请上传apiclient_cert.perm证书"
readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label-width="180px" label="" prop="privateCertContentFile">
<el-upload ref="privateCertContentFile"
:limit="1"
:accept="fileAccept"
:headers="header"
:action="pemUploadAction"
:before-upload="pemFileBeforeUpload"
:on-success="privateCertUploadSuccess"
>
<el-button size="small" type="primary" icon="el-icon-upload">点击上传</el-button>
</el-upload>
</el-form-item>
</div>
<el-form-item label-width="180px" label="备注" prop="remark">
<el-input v-model="form.remark" :style="{width: '100%'}"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
import {createWechatChannel, getWechatChannel, updateWechatChannel} from "@/api/pay/channel";
export default {
name: "wechatJsApiForm",
components: {},
props: {
//
transferParam: {
//
"loading": false,
//
"edit": false,
//
"open": false,
// ID
"appId": null,
//
"payCode": null,
//
"payMerchant": {
//
"id": null,
//
"name": null
},
}
},
data() {
return {
form: {
code: undefined,
status: undefined,
remark: undefined,
feeRate: undefined,
appId: undefined,
merchantId: undefined,
weChatConfig: {
appId: undefined,
mchId: undefined,
apiVersion: undefined,
mchKey: undefined,
privateKeyContent: undefined,
privateCertContent: undefined,
}
},
rules: {
feeRate: [{
required: true,
message: '请输入渠道费率',
trigger: 'blur'
}],
'weChatConfig.mchId': [{
required: true,
message: '请传入商户号',
trigger: 'blur'
}],
'weChatConfig.appId': [{
required: true,
message: '请输入公众号APPID',
trigger: 'blur'
}],
status: [{
required: true,
message: '渠道状态不能为空',
trigger: 'change'
}],
'weChatConfig.apiVersion': [{
required: true,
message: 'API版本不能为空',
trigger: 'change'
}],
'weChatConfig.mchKey': [{
required: true,
message: '请输入商户秘钥',
trigger: 'blur'
}],
'weChatConfig.privateKeyContent': [{
required: true,
message: '请上传apiclient_key.perm证书',
trigger: 'blur'
}],
'weChatConfig.privateCertContent': [{
required: true,
message: '请上传apiclient_cert.perm证书',
trigger: 'blur'
}],
},
// header
header: {
"Authorization": null
},
pemUploadAction: 'http://127.0.0.1:48080/api/pay/channel/parsing-pem',
fileAccept: ".pem",
//
statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS),
versionDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_WECHAT_VERSION),
}
},
watch: {
transferParam: {
deep: true, //
handler(newVal) {
this.form.code = newVal.payCode;
this.form.appId = newVal.appId;
this.form.merchantId = newVal.payMerchant.id;
//
if (newVal.edit === true && newVal.loading) {
this.init();
}
}
}
},
created() {
this.header.Authorization = "Bearer " + this.$store.getters.token;
},
methods: {
init() {
getWechatChannel(this.transferParam.payMerchant.id, this.transferParam.appId, this.transferParam.payCode)
.then(response => {
this.form = response.data;
this.transferParam.loading = false;
})
},
close() {
this.transferParam.open = false;
this.$refs['wechatJsApiForm'].resetFields();
},
handleConfirm() {
this.$refs['wechatJsApiForm'].validate(valid => {
if (!valid) {
return
}
if (this.transferParam.edit) {
updateWechatChannel(this.form).then(response => {
if (response.code === 0 ) {
this.msgSuccess("修改成功");
this.close();
}
})
} else {
createWechatChannel(this.form).then(response => {
if (response.code === 0) {
this.msgSuccess("新增成功");
this.$parent.refreshTable();
this.close();
}
});
}
});
},
pemFileBeforeUpload(file) {
let format = '.' + file.name.split(".")[1];
if (format !== this.fileAccept) {
this.$message.error('请上传指定格式"' + this.fileAccept + '"文件');
return false;
}
let isRightSize = file.size / 1024 / 1024 < 2
if (!isRightSize) {
this.$message.error('文件大小超过 2MB')
}
return isRightSize
},
privateKeyUploadSuccess(response) {
this.form.weChatConfig.privateKeyContent = response.data;
},
privateCertUploadSuccess(response) {
this.form.weChatConfig.privateCertContent = response.data;
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,441 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="应用名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入应用名" clearable size="small"
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="商户名称" prop="merchantName">
<el-input v-model="queryParams.merchantName" placeholder="请输入商户名称" clearable size="small"
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="开启状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable size="small">
<el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label"
:value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['pay:app:create']">新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['pay:app:export']">导出
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="应用编号" align="center" prop="id"/>
<el-table-column label="应用名" align="center" prop="name"/>
<el-table-column label="开启状态" align="center" prop="status">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1"
@change="handleStatusChange(scope.row)"/>
</template>
</el-table-column>
<el-table-column label="商户名称" align="center" prop="payMerchant.name"/>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="支付宝配置" align="center">
<el-table-column :label="payChannelEnum.ALIPAY_APP.name" align="center">
<template slot-scope="scope">
<el-button type="success" icon="el-icon-check" circle
v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.ENABLE"></el-button>
<el-button type="danger" icon="el-icon-close" circle
v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.DISABLE"></el-button>
</template>
</el-table-column>
<el-table-column :label="payChannelEnum.ALIPAY_PC.name" align="center">
<template slot-scope="scope">
<el-button type="success" icon="el-icon-check" circle
v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.ENABLE"></el-button>
<el-button type="danger" icon="el-icon-close" circle
v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.DISABLE"></el-button>
</template>
</el-table-column>
<el-table-column :label="payChannelEnum.ALIPAY_WAP.name" align="center">
<template slot-scope="scope">
<el-button type="success" icon="el-icon-check" circle
v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.ENABLE"></el-button>
<el-button type="danger" icon="el-icon-close" circle
v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.DISABLE"></el-button>
</template>
</el-table-column>
<el-table-column :label="payChannelEnum.ALIPAY_QR.name" align="center">
<template slot-scope="scope">
<el-button type="success" icon="el-icon-check" circle
v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.ENABLE"></el-button>
<el-button type="danger" icon="el-icon-close" circle
v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.DISABLE"></el-button>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="微信配置" align="center">
<el-table-column :label="payChannelEnum.WX_LITE.name" align="center">
<template slot-scope="scope">
<el-button type="success" icon="el-icon-check" circle
@click="handleUpdateChannel(scope.row,payChannelEnum.WX_LITE.code)"
v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.ENABLE"></el-button>
<el-button type="danger" icon="el-icon-close" circle
@click="handleCreateChannel(scope.row,payChannelEnum.WX_LITE.code)"
v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.DISABLE"></el-button>
</template>
</el-table-column>
<el-table-column :label="payChannelEnum.WX_PUB.name" align="center">
<template slot-scope="scope">
<el-button
type="success" icon="el-icon-check" circle
@click="handleUpdateChannel(scope.row,payChannelEnum.WX_PUB.code)"
v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.ENABLE">
</el-button>
<el-button type="danger" icon="el-icon-close" circle
@click="handleCreateChannel(scope.row,payChannelEnum.WX_PUB.code)"
v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.DISABLE"></el-button>
</template>
</el-table-column>
<el-table-column :label="payChannelEnum.WX_APP.name" align="center">
<template slot-scope="scope">
<el-button type="success" icon="el-icon-check" circle
@click="handleUpdateChannel(scope.row,payChannelEnum.WX_APP.code)"
v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.ENABLE"></el-button>
<el-button type="danger" icon="el-icon-close" circle
@click="handleCreateChannel(scope.row,payChannelEnum.WX_APP.code)"
v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.DISABLE"></el-button>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['pay:app:update']">修改
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['pay:app:delete']">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="160px">
<el-form-item label="应用名" prop="name">
<el-input v-model="form.name" placeholder="请输入应用名"/>
</el-form-item>
<el-form-item label="所属商户" prop="merchantId">
<el-select
v-model="form.merchantId"
filterable
remote
reserve-keyword
placeholder="请选择所属商户"
:remote-method="handleGetMerchantListByName"
:loading="loading">
<el-option
v-for="item in merchantList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<!-- <el-input v-model="form.merchantId" placeholder="请输入商户编号"/>-->
</el-form-item>
<el-form-item label="开启状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="支付结果的回调地址" prop="payNotifyUrl">
<el-input v-model="form.payNotifyUrl" placeholder="请输入支付结果的回调地址"/>
</el-form-item>
<el-form-item label="退款结果的回调地址" prop="refundNotifyUrl">
<el-input v-model="form.refundNotifyUrl" placeholder="请输入退款结果的回调地址"/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<wechat-js-api-form :transferParam="wechatChannelParam"></wechat-js-api-form>
</div>
</template>
<script>
import {createApp, updateApp, changeAppStatus, deleteApp, getApp, getAppPage, exportAppExcel} from "@/api/pay/app";
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
import {PayChannelEnum, SysCommonStatusEnum} from "@/utils/constants";
import {getMerchantListByName} from "@/api/pay/merchant";
import wechatJsApiForm from "@/views/pay/app/components/wechatJsApiForm";
export default {
name: "App",
components: {
"wechatJsApiForm": wechatJsApiForm
},
data() {
return {
//
loading: true,
//
showSearch: true,
//
total: 0,
//
list: [],
//
title: "",
//
open: false,
dateRangeCreateTime: [],
//
queryParams: {
pageNo: 1,
pageSize: 10,
name: null,
status: null,
remark: null,
payNotifyUrl: null,
refundNotifyUrl: null,
merchantName: null,
},
//
form: {},
//
rules: {
name: [{required: true, message: "应用名不能为空", trigger: "blur"}],
status: [{required: true, message: "开启状态不能为空", trigger: "blur"}],
payNotifyUrl: [{required: true, message: "支付结果的回调地址不能为空", trigger: "blur"}],
refundNotifyUrl: [{required: true, message: "退款结果的回调地址不能为空", trigger: "blur"}],
merchantId: [{required: true, message: "商户编号不能为空", trigger: "blur"}],
},
//
statusDictDatas: getDictDatas(DICT_TYPE.PAY_APP_STATUS),
sysCommonStatusEnum: SysCommonStatusEnum,
//
payChannelEnum: PayChannelEnum,
//
merchantList: [],
//
payOpen: false,
//
wechatChannelParam: {
//
"edit":false,
//
"open":false,
// ID
"appId": null,
//
"payCode": null,
//
"payMerchant": {
//
"id": null,
//
"name": null
},
}
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
let params = {...this.queryParams};
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
//
getAppPage(params).then(response => {
console.log(response.data);
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
name: undefined,
status: undefined,
remark: undefined,
payNotifyUrl: undefined,
refundNotifyUrl: undefined,
merchantId: undefined,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRangeCreateTime = [];
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加支付应用信息";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getApp(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改支付应用信息";
});
},
//
handleStatusChange(row) {
let text = row.status === SysCommonStatusEnum.ENABLE ? "启用" : "停用";
this.$confirm('确认要"' + text + '""' + row.name + '"应用吗?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function () {
return changeAppStatus(row.id, row.status);
}).then(() => {
this.msgSuccess(text + "成功");
}).catch(function () {
row.status = row.status === SysCommonStatusEnum.ENABLE ? SysCommonStatusEnum.DISABLE
: SysCommonStatusEnum.ENABLE;
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
updateApp(this.form).then(response => {
this.msgSuccess("修改成功");
this.open = false;
this.getList();
});
return;
}
//
createApp(this.form).then(response => {
this.msgSuccess("新增成功");
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$confirm('是否确认删除支付应用信息编号为"' + id + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function () {
return deleteApp(id);
}).then(() => {
this.getList();
this.msgSuccess("删除成功");
})
},
/** 导出按钮操作 */
handleExport() {
//
let params = {...this.queryParams};
params.pageNo = undefined;
params.pageSize = undefined;
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
//
this.$confirm('是否确认导出所有支付应用信息数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function () {
return exportAppExcel(params);
}).then(response => {
this.downloadExcel(response, '支付应用信息.xls');
})
},
/**
* 根据商户名称模糊匹配商户信息
* @param name 商户名称
*/
handleGetMerchantListByName(name) {
getMerchantListByName(name).then(response => {
console.log(response)
this.merchantList = response.data;
});
},
/**
* 修改支付渠道信息
*/
handleUpdateChannel(row, payCode) {
this.wechatChannelParam.edit = true;
this.wechatChannelParam.loading = true;
this.wechatChannelParam.appId = row.id;
this.wechatChannelParam.payCode = payCode;
this.wechatChannelParam.payMerchant = row.payMerchant;
this.wechatChannelParam.open = true;
},
/**
* 新增支付渠道信息
*/
handleCreateChannel(row, payCode) {
this.wechatChannelParam.edit = false;
this.wechatChannelParam.loading = false;
this.wechatChannelParam.appId = row.id;
this.wechatChannelParam.payCode = payCode;
this.wechatChannelParam.payMerchant = row.payMerchant;
this.wechatChannelParam.open = true;
},
refreshTable(){
this.getList();
}
}
};
</script>

View File

@ -47,6 +47,11 @@ public class PayChannelDO extends BaseDO {
*/
private Double feeRate;
/**
* 备注
*/
private String remark;
/**
* 商户编号
*

View File

@ -33,7 +33,6 @@ public class PayMerchantDO extends BaseDO {
* 例如说M233666999
* 只有新增时插入不允许修改
*/
@TableField(fill = FieldFill.INSERT) // TODO @aquanService 逻辑里设置所以不用这个注解哈
private String no;
/**
* 商户全称

View File

@ -32,4 +32,18 @@ public interface PayErrorCodeCoreConstants {
* ========== 支付商户信息 1-007-004-000 ==========
*/
ErrorCode MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
/**
* ========== 支付应用信息 1-007-005-000 ==========
*/
ErrorCode APP_NOT_EXISTS = new ErrorCode(1007005000, "支付应用信息不存在");
/**
* ========== 支付渠道 1-007-006-000 ==========
*/
ErrorCode CHANNEL_NOT_EXISTS = new ErrorCode(1007006000, "支付渠道不存在");
ErrorCode CHANNEL_KEY_READ_ERROR = new ErrorCode(1007006002, "支付渠道秘钥文件读取失败");
ErrorCode EXIST_SAME_CHANNEL_ERROR = new ErrorCode(1007006003, "已存在相同的渠道");
}

View File

@ -58,8 +58,11 @@ public class PayClientFactoryImpl implements PayClientFactory {
PayChannelEnum channelEnum = PayChannelEnum.getByCode(channelCode);
Assert.notNull(channelEnum, String.format("支付渠道(%s) 为空", channelEnum));
// 创建客户端
// TODO @芋艿 WX_LITE WX_APP 如果不添加在 项目启动的时候去初始化会报错无法启动所以我手动加了两个具体需要你来配
switch (channelEnum) {
case WX_PUB: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config);
case WX_LITE: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config);
case WX_APP: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config);
case ALIPAY_WAP: return (AbstractPayClient<Config>) new AlipayWapPayClient(channelId, (AlipayPayClientConfig) config);
case ALIPAY_QR: return (AbstractPayClient<Config>) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config);
}

View File

@ -15,7 +15,8 @@ import lombok.Getter;
public enum PayChannelEnum {
WX_PUB("wx_pub", "微信 JSAPI 支付"), // 公众号的网页
WX_LITE("wx_lit","微信小程序支付"),
// TODO @芋艿 这个地方你写的是 wx_lit 是不是少写了一个e 还是我这里多加了一个e
WX_LITE("wx_lite","微信小程序支付"),
WX_APP("wx_app", "微信 App 支付"),
ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付"),