mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 23:31:52 +08:00
优化 支付配置校验方式,优化业务层异常抛出类型,优化支付应用渲染逻辑,添加删除支付商户 支付应用的校验,退款订单去除reqNo字段,支付订单去除 channelExtras 参数展示
This commit is contained in:
parent
08103685f1
commit
d556eae556
@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.yudao.adminserver.modules.pay.controller.app;
|
package cn.iocoder.yudao.adminserver.modules.pay.controller.app;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
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.controller.app.vo.*;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert;
|
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.app.PayAppService;
|
||||||
@ -10,12 +9,12 @@ import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantServ
|
|||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
|
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.PayChannelDO;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
|
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.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
@ -28,20 +27,11 @@ import javax.annotation.Resource;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.util.*;
|
||||||
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.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付应用信息 controller 组件
|
|
||||||
*
|
|
||||||
* @author aquan
|
|
||||||
*/ // TODO @aquan:一般 controller 上就不写注释了,因为有 swagger 注解,不然就重复啦
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Api(tags = "支付应用信息")
|
@Api(tags = "支付应用信息")
|
||||||
@RestController
|
@RestController
|
||||||
@ -119,6 +109,7 @@ public class PayAppController {
|
|||||||
// 得到所有的应用编号,查出所有的通道
|
// 得到所有的应用编号,查出所有的通道
|
||||||
Collection<Long> payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId);
|
Collection<Long> payAppIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getId);
|
||||||
List<PayChannelDO> channels = channelService.getChannelListByAppIds(payAppIds);
|
List<PayChannelDO> channels = channelService.getChannelListByAppIds(payAppIds);
|
||||||
|
Iterator<PayChannelDO> iterator = channels.iterator();
|
||||||
|
|
||||||
// 得到所有的商户信息
|
// 得到所有的商户信息
|
||||||
Collection<Long> merchantIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getMerchantId);
|
Collection<Long> merchantIds = CollectionUtils.convertList(pageResult.getList(), PayAppDO::getMerchantId);
|
||||||
@ -132,22 +123,15 @@ public class PayAppController {
|
|||||||
// 写入商户的数据
|
// 写入商户的数据
|
||||||
respVO.setPayMerchant(PayAppConvert.INSTANCE.convert(deptMap.get(app.getMerchantId())));
|
respVO.setPayMerchant(PayAppConvert.INSTANCE.convert(deptMap.get(app.getMerchantId())));
|
||||||
// 写入支付渠道信息的数据
|
// 写入支付渠道信息的数据
|
||||||
// TODO @aquan:VO 里返回的 payChannel,是不是用一个 Set 集合就好了,里面是渠道的枚举值
|
Set<String> channelCodes = new HashSet<>(PayChannelEnum.values().length);
|
||||||
PayAppPageItemRespVO.PayChannel payChannel = new PayAppPageItemRespVO.PayChannel();
|
while (iterator.hasNext()) {
|
||||||
channels.forEach(c -> {
|
PayChannelDO channelDO = iterator.next();
|
||||||
if (c.getAppId().equals(app.getId())) {
|
if (channelDO.getAppId().equals(app.getId())) {
|
||||||
// 获取 set 方法
|
channelCodes.add(channelDO.getCode());
|
||||||
String methodName = StrUtil.toCamelCase("set_" + c.getCode());
|
iterator.remove();
|
||||||
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);
|
respVO.setChannelCodes(channelCodes);
|
||||||
appList.add(respVO);
|
appList.add(respVO);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo;
|
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.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -8,7 +7,13 @@ import lombok.EqualsAndHashCode;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付应用信息分页查询 Response VO
|
||||||
|
*
|
||||||
|
* @author aquan
|
||||||
|
*/
|
||||||
@ApiModel(value = "支付应用信息分页查询 Response VO", description = "相比于支付信息,还会多出应用渠道的开关信息")
|
@ApiModel(value = "支付应用信息分页查询 Response VO", description = "相比于支付信息,还会多出应用渠道的开关信息")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ -38,39 +43,8 @@ public class PayAppPageItemRespVO extends PayAppBaseVO {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@ApiModelProperty(value = "渠道编码集合", required = true, example = "alipay_pc,alipay_wap...")
|
||||||
* 支付渠道
|
private Set<String> channelCodes;
|
||||||
*/
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ public class PayMerchantController {
|
|||||||
return success(PayMerchantConvert.INSTANCE.convert(merchant));
|
return success(PayMerchantConvert.INSTANCE.convert(merchant));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/list-name") // TODO @aquan:/list-name =》/list-by-name
|
@GetMapping("/list-by-name")
|
||||||
@ApiOperation("根据商户名称获得支付商户信息列表")
|
@ApiOperation("根据商户名称获得支付商户信息列表")
|
||||||
@ApiImplicitParam(name = "name", value = "商户名称", example = "芋道", dataTypeClass = Long.class)
|
@ApiImplicitParam(name = "name", value = "商户名称", example = "芋道", dataTypeClass = Long.class)
|
||||||
@PreAuthorize("@ss.hasPermission('pay:merchant:query')")
|
@PreAuthorize("@ss.hasPermission('pay:merchant:query')")
|
||||||
|
@ -2,11 +2,10 @@ package cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||||
import lombok.*;
|
|
||||||
import java.util.*;
|
|
||||||
import io.swagger.annotations.*;
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付商户信息 Excel VO
|
* 支付商户信息 Excel VO
|
||||||
@ -29,7 +28,7 @@ public class PayMerchantExcelVO {
|
|||||||
private String shortName;
|
private String shortName;
|
||||||
|
|
||||||
@ExcelProperty(value = "开启状态",converter = DictConvert.class)
|
@ExcelProperty(value = "开启状态",converter = DictConvert.class)
|
||||||
@DictFormat("pay_merchant_status")
|
@DictFormat("sys_common_status")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
|
@ -46,9 +46,6 @@ public class PayOrderDetailsRespVO extends PayOrderBaseVO {
|
|||||||
@ApiModelProperty(value = "支付订单号")
|
@ApiModelProperty(value = "支付订单号")
|
||||||
private String no;
|
private String no;
|
||||||
|
|
||||||
@ApiModelProperty(value = "支付渠道的额外参数")
|
|
||||||
private String channelExtras;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "支付异步通知的内容")
|
@ApiModelProperty(value = "支付异步通知的内容")
|
||||||
private String channelNotifyData;
|
private String channelNotifyData;
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@Data
|
@Data
|
||||||
public class PayRefundBaseVO {
|
public class PayRefundBaseVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "退款单请求号", required = true)
|
|
||||||
@NotNull(message = "退款单请求号不能为空")
|
|
||||||
private String reqNo;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "商户编号", required = true)
|
@ApiModelProperty(value = "商户编号", required = true)
|
||||||
@NotNull(message = "商户编号不能为空")
|
@NotNull(message = "商户编号不能为空")
|
||||||
private Long merchantId;
|
private Long merchantId;
|
||||||
|
@ -22,9 +22,6 @@ public class PayRefundExcelVO {
|
|||||||
@ExcelProperty("商品名称")
|
@ExcelProperty("商品名称")
|
||||||
private String subject;
|
private String subject;
|
||||||
|
|
||||||
@ExcelProperty("退款单请求号")
|
|
||||||
private String reqNo;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "商户名称")
|
@ExcelProperty(value = "商户名称")
|
||||||
private String merchantName;
|
private String merchantName;
|
||||||
|
|
||||||
|
@ -13,9 +13,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@Data
|
@Data
|
||||||
public class PayRefundExportReqVO {
|
public class PayRefundExportReqVO {
|
||||||
|
|
||||||
@ApiModelProperty(value = "退款单请求号")
|
|
||||||
private String reqNo;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "商户编号")
|
@ApiModelProperty(value = "商户编号")
|
||||||
private Long merchantId;
|
private Long merchantId;
|
||||||
|
|
||||||
|
@ -18,9 +18,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class PayRefundPageReqVO extends PageParam {
|
public class PayRefundPageReqVO extends PageParam {
|
||||||
|
|
||||||
@ApiModelProperty(value = "退款单请求号")
|
|
||||||
private String reqNo;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "商户编号")
|
@ApiModelProperty(value = "商户编号")
|
||||||
private Long merchantId;
|
private Long merchantId;
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO;
|
|||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
|
||||||
import org.mapstruct.Mappings;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -44,10 +42,6 @@ public interface PayOrderConvert {
|
|||||||
* @param bean 订单扩展DO
|
* @param bean 订单扩展DO
|
||||||
* @return 详细订单扩展 RespVO
|
* @return 详细订单扩展 RespVO
|
||||||
*/
|
*/
|
||||||
@Mappings({
|
|
||||||
@Mapping(target = "channelExtras"
|
|
||||||
, expression = "java(bean.getChannelExtras() != null ? bean.getChannelExtras().toString():null)")
|
|
||||||
})
|
|
||||||
PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
|
PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
|
||||||
|
|
||||||
List<PayOrderRespVO> convertList(List<PayOrderDO> list);
|
List<PayOrderRespVO> convertList(List<PayOrderDO> list);
|
||||||
|
@ -62,7 +62,6 @@ public interface PayRefundConvert {
|
|||||||
PayRefundExcelVO payRefundExcelVO = new PayRefundExcelVO();
|
PayRefundExcelVO payRefundExcelVO = new PayRefundExcelVO();
|
||||||
|
|
||||||
payRefundExcelVO.setId(bean.getId());
|
payRefundExcelVO.setId(bean.getId());
|
||||||
payRefundExcelVO.setReqNo(bean.getReqNo());
|
|
||||||
payRefundExcelVO.setTradeNo(bean.getTradeNo());
|
payRefundExcelVO.setTradeNo(bean.getTradeNo());
|
||||||
payRefundExcelVO.setMerchantOrderId(bean.getMerchantOrderId());
|
payRefundExcelVO.setMerchantOrderId(bean.getMerchantOrderId());
|
||||||
payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo());
|
payRefundExcelVO.setMerchantRefundNo(bean.getMerchantRefundNo());
|
||||||
|
@ -60,12 +60,24 @@ public interface PayAppMapper extends BaseMapperX<PayAppDO> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 商户 ID 查询支付应用信息
|
* 根据 商户 ID 查询支付应用信息
|
||||||
|
*
|
||||||
* @param merchantId 商户 ID
|
* @param merchantId 商户 ID
|
||||||
* @return 支付应用信息列表
|
* @return 支付应用信息列表
|
||||||
*/
|
*/
|
||||||
default List<PayAppDO> getListByMerchantId(String merchantId){
|
default List<PayAppDO> getListByMerchantId(String merchantId) {
|
||||||
return selectList(new LambdaQueryWrapper<PayAppDO>()
|
return selectList(new LambdaQueryWrapper<PayAppDO>()
|
||||||
.select(PayAppDO::getId, PayAppDO::getName)
|
.select(PayAppDO::getId, PayAppDO::getName)
|
||||||
.eq(PayAppDO::getMerchantId, merchantId));
|
.eq(PayAppDO::getMerchantId, merchantId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据商户号统计存在的支付应用数量
|
||||||
|
*
|
||||||
|
* @param merchantId 商户 ID
|
||||||
|
* @return 支付应用数量
|
||||||
|
*/
|
||||||
|
default Long selectCount(Long merchantId) {
|
||||||
|
return selectCount(new LambdaQueryWrapper<PayAppDO>().eq(PayAppDO::getMerchantId, merchantId));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,7 @@ public interface PayChannelMapper extends BaseMapperX<PayChannelDO> {
|
|||||||
* @param code 通道编码
|
* @param code 通道编码
|
||||||
* @return 数量
|
* @return 数量
|
||||||
*/
|
*/
|
||||||
// TODO @aquan:Mapper 的操作,和 db 保持一致
|
default Integer selectCount(Long merchantId, Long appid, String code) {
|
||||||
default Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
|
|
||||||
return this.selectCount(new QueryWrapper<PayChannelDO>().lambda()
|
return this.selectCount(new QueryWrapper<PayChannelDO>().lambda()
|
||||||
.eq(PayChannelDO::getMerchantId, merchantId)
|
.eq(PayChannelDO::getMerchantId, merchantId)
|
||||||
.eq(PayChannelDO::getAppId, appid)
|
.eq(PayChannelDO::getAppId, appid)
|
||||||
@ -71,7 +70,7 @@ public interface PayChannelMapper extends BaseMapperX<PayChannelDO> {
|
|||||||
* @param code 通道编码
|
* @param code 通道编码
|
||||||
* @return 数量
|
* @return 数量
|
||||||
*/
|
*/
|
||||||
default PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
|
default PayChannelDO selectOne(Long merchantId, Long appid, String code) {
|
||||||
return this.selectOne((new QueryWrapper<PayChannelDO>().lambda()
|
return this.selectOne((new QueryWrapper<PayChannelDO>().lambda()
|
||||||
.eq(PayChannelDO::getMerchantId, merchantId)
|
.eq(PayChannelDO::getMerchantId, merchantId)
|
||||||
.eq(PayChannelDO::getAppId, appid)
|
.eq(PayChannelDO::getAppId, appid)
|
||||||
|
@ -62,4 +62,18 @@ public interface PayOrderMapper extends BaseMapperX<PayOrderDO> {
|
|||||||
.in(PayOrderDO::getId, idList));
|
.in(PayOrderDO::getId, idList));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询符合的订单数量
|
||||||
|
*
|
||||||
|
* @param appId 应用编号
|
||||||
|
* @param status 订单状态
|
||||||
|
* @return 条数
|
||||||
|
*/
|
||||||
|
default Long selectCount(Long appId, Integer status) {
|
||||||
|
|
||||||
|
return selectCount(new LambdaQueryWrapper<PayOrderDO>()
|
||||||
|
.eq(PayOrderDO::getAppId, appId)
|
||||||
|
.in(PayOrderDO::getStatus, status));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO
|
|||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -20,7 +21,6 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
|
|||||||
|
|
||||||
default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
|
default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new QueryWrapperX<PayRefundDO>()
|
return selectPage(reqVO, new QueryWrapperX<PayRefundDO>()
|
||||||
.likeIfPresent("req_no", reqVO.getReqNo())
|
|
||||||
.eqIfPresent("merchant_id", reqVO.getMerchantId())
|
.eqIfPresent("merchant_id", reqVO.getMerchantId())
|
||||||
.eqIfPresent("app_id", reqVO.getAppId())
|
.eqIfPresent("app_id", reqVO.getAppId())
|
||||||
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
||||||
@ -37,7 +37,6 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
|
|||||||
.eqIfPresent("merchant_id", reqVO.getMerchantId())
|
.eqIfPresent("merchant_id", reqVO.getMerchantId())
|
||||||
.eqIfPresent("app_id", reqVO.getAppId())
|
.eqIfPresent("app_id", reqVO.getAppId())
|
||||||
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
.eqIfPresent("channel_code", reqVO.getChannelCode())
|
||||||
.likeIfPresent("req_no", reqVO.getReqNo())
|
|
||||||
.likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())
|
.likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())
|
||||||
.eqIfPresent("type", reqVO.getType())
|
.eqIfPresent("type", reqVO.getType())
|
||||||
.eqIfPresent("status", reqVO.getStatus())
|
.eqIfPresent("status", reqVO.getStatus())
|
||||||
@ -46,4 +45,17 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
|
|||||||
.orderByDesc("id"));
|
.orderByDesc("id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询符合的订单数量
|
||||||
|
*
|
||||||
|
* @param appId 应用编号
|
||||||
|
* @param status 订单状态
|
||||||
|
* @return 条数
|
||||||
|
*/
|
||||||
|
default Long selectCount(Long appId, Integer status) {
|
||||||
|
|
||||||
|
return selectCount(new LambdaQueryWrapper<PayRefundDO>()
|
||||||
|
.eq(PayRefundDO::getAppId, appId)
|
||||||
|
.eq(PayRefundDO::getStatus, status));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,13 @@ import cn.iocoder.yudao.adminserver.modules.pay.controller.app.vo.PayAppUpdateRe
|
|||||||
import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert;
|
import cn.iocoder.yudao.adminserver.modules.pay.convert.app.PayAppConvert;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper;
|
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
|
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
|
||||||
|
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.order.PayOrderMapper;
|
||||||
|
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.order.PayRefundMapper;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService;
|
import cn.iocoder.yudao.adminserver.modules.pay.service.app.PayAppService;
|
||||||
import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
|
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.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
|
||||||
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
@ -21,7 +25,7 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_APP_NOT_FOUND;
|
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
|
|
||||||
@ -36,9 +40,17 @@ public class PayAppServiceImpl implements PayAppService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayAppMapper appMapper;
|
private PayAppMapper appMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayMerchantMapper merchantMapper;
|
private PayMerchantMapper merchantMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayOrderMapper orderMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayRefundMapper refundMapper;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createApp(PayAppCreateReqVO createReqVO) {
|
public Long createApp(PayAppCreateReqVO createReqVO) {
|
||||||
// 插入
|
// 插入
|
||||||
@ -61,7 +73,8 @@ public class PayAppServiceImpl implements PayAppService {
|
|||||||
public void deleteApp(Long id) {
|
public void deleteApp(Long id) {
|
||||||
// 校验存在
|
// 校验存在
|
||||||
this.validateAppExists(id);
|
this.validateAppExists(id);
|
||||||
// TODO aquan:校验是否存在进行中的支付单、退款单,如果是,则不允许删除。
|
this.validateOrderTransactionExist(id);
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
appMapper.deleteById(id);
|
appMapper.deleteById(id);
|
||||||
}
|
}
|
||||||
@ -157,4 +170,21 @@ public class PayAppServiceImpl implements PayAppService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证是否存在交易中或者退款中等处理中状态的订单
|
||||||
|
*
|
||||||
|
* @param appId 应用 ID
|
||||||
|
*/
|
||||||
|
private void validateOrderTransactionExist(Long appId) {
|
||||||
|
// 查看交易订单
|
||||||
|
if (orderMapper.selectCount(appId, PayOrderStatusEnum.WAITING.getStatus()) > 0) {
|
||||||
|
throw exception(PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE);
|
||||||
|
}
|
||||||
|
// 查看退款订单
|
||||||
|
if (refundMapper.selectCount(appId, PayRefundStatusEnum.CREATE.getStatus()) > 0) {
|
||||||
|
throw exception(PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl;
|
package cn.iocoder.yudao.adminserver.modules.pay.service.channel.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelCreateReqVO;
|
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelCreateReqVO;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelExportReqVO;
|
import cn.iocoder.yudao.adminserver.modules.pay.controller.channel.vo.PayChannelExportReqVO;
|
||||||
@ -14,7 +15,6 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
|||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@ -46,8 +46,9 @@ public class PayChannelServiceImpl implements PayChannelService {
|
|||||||
public Long createChannel(PayChannelCreateReqVO reqVO) {
|
public Long createChannel(PayChannelCreateReqVO reqVO) {
|
||||||
// 断言是否有重复的
|
// 断言是否有重复的
|
||||||
PayChannelDO channelDO = this.getChannelByConditions(reqVO.getMerchantId(), reqVO.getAppId(), reqVO.getCode());
|
PayChannelDO channelDO = this.getChannelByConditions(reqVO.getMerchantId(), reqVO.getAppId(), reqVO.getCode());
|
||||||
// TODO @aquan:这里会抛出系统异常,不会抛出 ServiceException
|
if (ObjectUtil.isNotNull(channelDO)) {
|
||||||
Assert.isNull(channelDO, CHANNEL_EXIST_SAME_CHANNEL_ERROR.getMsg());
|
throw exception(CHANNEL_EXIST_SAME_CHANNEL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
// 新增渠道
|
// 新增渠道
|
||||||
PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO);
|
PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO);
|
||||||
@ -122,7 +123,7 @@ public class PayChannelServiceImpl implements PayChannelService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
|
public Integer getChannelCountByConditions(Long merchantId, Long appid, String code) {
|
||||||
return this.channelMapper.getChannelCountByConditions(merchantId, appid, code);
|
return this.channelMapper.selectCount(merchantId, appid, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,7 +136,7 @@ public class PayChannelServiceImpl implements PayChannelService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
|
public PayChannelDO getChannelByConditions(Long merchantId, Long appid, String code) {
|
||||||
return this.channelMapper.getChannelByConditions(merchantId, appid, code);
|
return this.channelMapper.selectOne(merchantId, appid, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,11 +147,14 @@ public class PayChannelServiceImpl implements PayChannelService {
|
|||||||
*/
|
*/
|
||||||
private void settingConfigAndCheckParam(PayChannelDO channel, String configStr) {
|
private void settingConfigAndCheckParam(PayChannelDO channel, String configStr) {
|
||||||
// 得到这个渠道是微信的还是支付宝的
|
// 得到这个渠道是微信的还是支付宝的
|
||||||
Class<? extends PayClientConfig> payClass = PayChannelEnum.findByCodeGetClass(channel.getCode());
|
Class<? extends PayClientConfig> payClass = PayChannelEnum.getByCode(channel.getCode()).getConfigClass();
|
||||||
Assert.notNull(payClass, CHANNEL_NOT_EXISTS.getMsg());
|
if (ObjectUtil.isNull(payClass)) {
|
||||||
|
throw exception(CHANNEL_NOT_EXISTS);
|
||||||
|
}
|
||||||
PayClientConfig config = JSONUtil.toBean(configStr, payClass);
|
PayClientConfig config = JSONUtil.toBean(configStr, payClass);
|
||||||
|
|
||||||
// 验证参数
|
// 验证参数
|
||||||
config.verifyParam(validator);
|
config.validate(validator);
|
||||||
channel.setConfig(config);
|
channel.setConfig(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* 支付商户信息 Service 接口
|
* 支付商户信息 Service 接口
|
||||||
*
|
*
|
||||||
* @author 芋艿 TODO @aquan:作者是你哈
|
* @author aquan
|
||||||
*/
|
*/
|
||||||
public interface PayMerchantService {
|
public interface PayMerchantService {
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package cn.iocoder.yudao.adminserver.modules.pay.service.merchant.impl;
|
package cn.iocoder.yudao.adminserver.modules.pay.service.merchant.impl;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantCreateReqVO;
|
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantCreateReqVO;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantExportReqVO;
|
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantExportReqVO;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantPageReqVO;
|
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantPageReqVO;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantUpdateReqVO;
|
import cn.iocoder.yudao.adminserver.modules.pay.controller.merchant.vo.PayMerchantUpdateReqVO;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.convert.merchant.PayMerchantConvert;
|
import cn.iocoder.yudao.adminserver.modules.pay.convert.merchant.PayMerchantConvert;
|
||||||
|
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.app.PayAppMapper;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
|
import cn.iocoder.yudao.adminserver.modules.pay.dal.mysql.merchant.PayMerchantMapper;
|
||||||
import cn.iocoder.yudao.adminserver.modules.pay.service.merchant.PayMerchantService;
|
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.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
|
||||||
@ -19,6 +21,7 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_MERCHANT_EXIST_APP_CANT_DELETE;
|
||||||
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_MERCHANT_NOT_EXISTS;
|
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_MERCHANT_NOT_EXISTS;
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
|
||||||
@ -34,6 +37,9 @@ public class PayMerchantServiceImpl implements PayMerchantService {
|
|||||||
@Resource
|
@Resource
|
||||||
private PayMerchantMapper merchantMapper;
|
private PayMerchantMapper merchantMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayAppMapper appMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createMerchant(PayMerchantCreateReqVO createReqVO) {
|
public Long createMerchant(PayMerchantCreateReqVO createReqVO) {
|
||||||
// 插入
|
// 插入
|
||||||
@ -55,19 +61,13 @@ public class PayMerchantServiceImpl implements PayMerchantService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteMerchant(Long id) {
|
public void deleteMerchant(Long id) {
|
||||||
// 校验存在
|
// 校验
|
||||||
this.validateMerchantExists(id);
|
this.validateMerchantExists(id);
|
||||||
// TODO @aquan:需要校验 PayApp 是否都在。如果在的情况下,不允许删除
|
this.validateAppExists(id);
|
||||||
// 删除
|
// 删除
|
||||||
merchantMapper.deleteById(id);
|
merchantMapper.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateMerchantExists(Long id) {
|
|
||||||
if (merchantMapper.selectById(id) == null) {
|
|
||||||
throw exception(PAY_MERCHANT_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PayMerchantDO getMerchant(Long id) {
|
public PayMerchantDO getMerchant(Long id) {
|
||||||
return merchantMapper.selectById(id);
|
return merchantMapper.selectById(id);
|
||||||
@ -88,13 +88,6 @@ public class PayMerchantServiceImpl implements PayMerchantService {
|
|||||||
return merchantMapper.selectList(exportReqVO);
|
return merchantMapper.selectList(exportReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @aquan:接口上已经有注释,这里不用在有啦
|
|
||||||
/**
|
|
||||||
* 修改商户状态
|
|
||||||
*
|
|
||||||
* @param id 商户编号
|
|
||||||
* @param status 状态
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void updateMerchantStatus(Long id, Integer status) {
|
public void updateMerchantStatus(Long id, Integer status) {
|
||||||
// 校验商户存在
|
// 校验商户存在
|
||||||
@ -106,21 +99,11 @@ public class PayMerchantServiceImpl implements PayMerchantService {
|
|||||||
merchantMapper.updateById(merchant);
|
merchantMapper.updateById(merchant);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据商户名称模糊查询商户集合
|
|
||||||
*
|
|
||||||
* @param merchantName 商户名称
|
|
||||||
* @return 商户集合
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<PayMerchantDO> getMerchantListByName(String merchantName) {
|
public List<PayMerchantDO> getMerchantListByName(String merchantName) {
|
||||||
return this.merchantMapper.getMerchantListByName(merchantName);
|
return this.merchantMapper.getMerchantListByName(merchantName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查商户是否存在
|
|
||||||
* @param id 商户编号
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void checkMerchantExists(Long id) {
|
public void checkMerchantExists(Long id) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
@ -132,6 +115,27 @@ public class PayMerchantServiceImpl implements PayMerchantService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验商户是否存在
|
||||||
|
*
|
||||||
|
* @param id 商户 ID
|
||||||
|
*/
|
||||||
|
private void validateMerchantExists(Long id) {
|
||||||
|
if (ObjectUtil.isNull(merchantMapper.selectById(id))) {
|
||||||
|
throw exception(PAY_MERCHANT_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验商户是否还存在支付应用
|
||||||
|
*
|
||||||
|
* @param id 商户ID
|
||||||
|
*/
|
||||||
|
private void validateAppExists(Long id) {
|
||||||
|
if (appMapper.selectCount(id) > 0) {
|
||||||
|
throw exception(PAY_MERCHANT_EXIST_APP_CANT_DELETE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO @芋艿:后续增加下合适的算法
|
// TODO @芋艿:后续增加下合适的算法
|
||||||
/**
|
/**
|
||||||
@ -139,8 +143,8 @@ public class PayMerchantServiceImpl implements PayMerchantService {
|
|||||||
*
|
*
|
||||||
* @return 商户号
|
* @return 商户号
|
||||||
*/
|
*/
|
||||||
private String generateMerchantNo(){
|
private String generateMerchantNo() {
|
||||||
return "M" + DateUtil.format(LocalDateTime.now(),"yyyyMMddHHmmssSSS");
|
return "M" + DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmssSSS");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,4 @@ yudao:
|
|||||||
- cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
|
- cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
|
||||||
tenant: # 多租户相关配置项
|
tenant: # 多租户相关配置项
|
||||||
tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置
|
tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置
|
||||||
pay:
|
|
||||||
payReturnUrl: http://127.0.0.1 # TODO @aquan:这个变量,配置到 dev 或者 local 里,不同环境有差别哈
|
|
||||||
debug: false
|
debug: false
|
||||||
|
@ -72,8 +72,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
o.setUpdateTime(DateUtils.buildTime(2021, 1, 1, 10, 10, 35));
|
o.setUpdateTime(DateUtils.buildTime(2021, 1, 1, 10, 10, 35));
|
||||||
});
|
});
|
||||||
refundMapper.insert(dbRefund);
|
refundMapper.insert(dbRefund);
|
||||||
// 测试 reqNo 不匹配
|
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setReqNo("RF1111112")));
|
|
||||||
// 测试 merchantId 不匹配
|
// 测试 merchantId 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantId(2L)));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantId(2L)));
|
||||||
// 测试 appId 不匹配
|
// 测试 appId 不匹配
|
||||||
@ -94,7 +92,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
o.setCreateTime(DateUtils.buildTime(2022, 1, 1, 10, 10, 10))));
|
o.setCreateTime(DateUtils.buildTime(2022, 1, 1, 10, 10, 10))));
|
||||||
// 准备参数
|
// 准备参数
|
||||||
PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
|
PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
|
||||||
reqVO.setReqNo("RF0000001");
|
|
||||||
reqVO.setMerchantId(1L);
|
reqVO.setMerchantId(1L);
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
@ -147,8 +144,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
o.setUpdateTime(DateUtils.buildTime(2021, 1, 1, 10, 10, 35));
|
o.setUpdateTime(DateUtils.buildTime(2021, 1, 1, 10, 10, 35));
|
||||||
});
|
});
|
||||||
refundMapper.insert(dbRefund);
|
refundMapper.insert(dbRefund);
|
||||||
// 测试 reqNo 不匹配
|
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setReqNo("RF1111112")));
|
|
||||||
// 测试 merchantId 不匹配
|
// 测试 merchantId 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantId(2L)));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantId(2L)));
|
||||||
// 测试 appId 不匹配
|
// 测试 appId 不匹配
|
||||||
@ -170,7 +165,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
|
|||||||
|
|
||||||
// 准备参数
|
// 准备参数
|
||||||
PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
|
PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
|
||||||
reqVO.setReqNo("RF0000001");
|
|
||||||
reqVO.setMerchantId(1L);
|
reqVO.setMerchantId(1L);
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
|
@ -49,7 +49,7 @@ export function getMerchant(id) {
|
|||||||
// 根据商户名称搜索商户列表
|
// 根据商户名称搜索商户列表
|
||||||
export function getMerchantListByName(name) {
|
export function getMerchantListByName(name) {
|
||||||
return request({
|
return request({
|
||||||
url: '/pay/merchant/list-name',
|
url: '/pay/merchant/list-by-name',
|
||||||
params:{
|
params:{
|
||||||
name:name
|
name:name
|
||||||
},
|
},
|
||||||
|
@ -34,12 +34,6 @@ export const DICT_TYPE = {
|
|||||||
OA_LEAVE_STATUS: 'oa_leave_status',
|
OA_LEAVE_STATUS: 'oa_leave_status',
|
||||||
OA_LEAVE_TYPE: 'oa_leave_type',
|
OA_LEAVE_TYPE: 'oa_leave_type',
|
||||||
|
|
||||||
// 商户状态
|
|
||||||
PAY_MERCHANT_STATUS: 'pay_merchant_status', // TODO @aquan:一般使用 COMMON_RESULT 即可。保持数值一致,以后加更多状态的时候,在单独数据字典
|
|
||||||
// 应用状态
|
|
||||||
PAY_APP_STATUS: 'pay_app_status',
|
|
||||||
// 渠道状态
|
|
||||||
PAY_CHANNEL_STATUS: 'pay_channel_status',
|
|
||||||
// 微信渠道版本
|
// 微信渠道版本
|
||||||
PAY_CHANNEL_WECHAT_VERSION:'pay_channel_wechat_version',
|
PAY_CHANNEL_WECHAT_VERSION:'pay_channel_wechat_version',
|
||||||
// 支付渠道支付宝算法类型
|
// 支付渠道支付宝算法类型
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog :visible.sync="transferParam.aliPayOpen" @closed="close" append-to-body width="800px">
|
<el-dialog :visible.sync="transferParam.aliPayOpen" :title="title" @closed="close" append-to-body width="800px">
|
||||||
<el-form ref="aliPayForm" :model="form" :rules="rules" size="medium" label-width="100px"
|
<el-form ref="aliPayForm" :model="form" :rules="rules" size="medium" label-width="100px"
|
||||||
v-loading="transferParam.loading">
|
v-loading="transferParam.loading">
|
||||||
<el-form-item label-width="180px" label="渠道费率" prop="feeRate">
|
<el-form-item label-width="180px" label="渠道费率" prop="feeRate">
|
||||||
@ -172,6 +172,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
title:'',
|
||||||
form: JSON.parse(JSON.stringify(defaultForm)),
|
form: JSON.parse(JSON.stringify(defaultForm)),
|
||||||
rules: {
|
rules: {
|
||||||
feeRate: [{
|
feeRate: [{
|
||||||
@ -232,7 +233,7 @@ export default {
|
|||||||
},
|
},
|
||||||
fileAccept: ".crt",
|
fileAccept: ".crt",
|
||||||
// 渠道状态 数据字典
|
// 渠道状态 数据字典
|
||||||
statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS),
|
statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
|
||||||
// 支付宝加密方式
|
// 支付宝加密方式
|
||||||
aliPaySignTypeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SIGN_TYPE),
|
aliPaySignTypeDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_ALIPAY_SIGN_TYPE),
|
||||||
// 版本状态 数据字典
|
// 版本状态 数据字典
|
||||||
@ -251,7 +252,10 @@ export default {
|
|||||||
this.form.merchantId = newVal.payMerchant.id;
|
this.form.merchantId = newVal.payMerchant.id;
|
||||||
// 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
|
// 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
|
||||||
if (newVal.edit === true && newVal.loading) {
|
if (newVal.edit === true && newVal.loading) {
|
||||||
|
this.title = "编辑支付渠道";
|
||||||
this.init();
|
this.init();
|
||||||
|
} else {
|
||||||
|
this.title = "创建支付渠道";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog :visible.sync="transferParam.wechatOpen" @close="close" append-to-body width="800px">
|
<el-dialog :visible.sync="transferParam.wechatOpen" :title="title" @close="close" append-to-body width="800px">
|
||||||
<el-form ref="wechatJsApiForm" :model="form" :rules="rules" size="medium" label-width="100px"
|
<el-form ref="wechatJsApiForm" :model="form" :rules="rules" size="medium" label-width="100px"
|
||||||
v-loading="transferParam.loading">
|
v-loading="transferParam.loading">
|
||||||
<el-form-item label-width="180px" label="渠道费率" prop="feeRate">
|
<el-form-item label-width="180px" label="渠道费率" prop="feeRate">
|
||||||
@ -134,6 +134,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
title:'',
|
||||||
form: JSON.parse(JSON.stringify(defaultForm)),
|
form: JSON.parse(JSON.stringify(defaultForm)),
|
||||||
rules: {
|
rules: {
|
||||||
feeRate: [{
|
feeRate: [{
|
||||||
@ -188,7 +189,7 @@ export default {
|
|||||||
},
|
},
|
||||||
fileAccept: ".pem",
|
fileAccept: ".pem",
|
||||||
// 渠道状态 数据字典
|
// 渠道状态 数据字典
|
||||||
statusDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_STATUS),
|
statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
|
||||||
versionDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_WECHAT_VERSION),
|
versionDictDatas: getDictDatas(DICT_TYPE.PAY_CHANNEL_WECHAT_VERSION),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -202,7 +203,10 @@ export default {
|
|||||||
this.form.merchantId = newVal.payMerchant.id;
|
this.form.merchantId = newVal.payMerchant.id;
|
||||||
// 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
|
// 只有在初次进来为编辑 并且为加载中的时候才回去请求数据
|
||||||
if (newVal.edit && newVal.loading) {
|
if (newVal.edit && newVal.loading) {
|
||||||
|
this.title = "编辑支付渠道";
|
||||||
this.init();
|
this.init();
|
||||||
|
} else {
|
||||||
|
this.title = "创建支付渠道";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,59 +57,49 @@
|
|||||||
<el-table-column label="支付宝配置" align="center">
|
<el-table-column label="支付宝配置" align="center">
|
||||||
<el-table-column :label="payChannelEnum.ALIPAY_APP.name" align="center">
|
<el-table-column :label="payChannelEnum.ALIPAY_APP.name" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button type="success" icon="el-icon-check" circle
|
||||||
type="success" icon="el-icon-check" circle
|
v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_APP.code)"
|
||||||
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)"
|
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.ENABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else
|
||||||
type="danger" icon="el-icon-close" circle
|
type="danger" icon="el-icon-close" circle
|
||||||
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)"
|
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayApp === sysCommonStatusEnum.DISABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="payChannelEnum.ALIPAY_PC.name" align="center">
|
<el-table-column :label="payChannelEnum.ALIPAY_PC.name" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button type="success" icon="el-icon-check" circle
|
||||||
type="success" icon="el-icon-check" circle
|
v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_PC.code)"
|
||||||
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_PC.code,payType.ALIPAY)"
|
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.ENABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else
|
||||||
type="danger" icon="el-icon-close" circle
|
type="danger" icon="el-icon-close" circle
|
||||||
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_PC.code,payType.ALIPAY)"
|
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_PC.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayPc === sysCommonStatusEnum.DISABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="payChannelEnum.ALIPAY_WAP.name" align="center">
|
<el-table-column :label="payChannelEnum.ALIPAY_WAP.name" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button type="success" icon="el-icon-check" circle
|
||||||
type="success" icon="el-icon-check" circle
|
v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_WAP.code)"
|
||||||
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_WAP.code,payType.ALIPAY)"
|
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.ENABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else
|
||||||
type="danger" icon="el-icon-close" circle
|
type="danger" icon="el-icon-close" circle
|
||||||
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_WAP.code,payType.ALIPAY)"
|
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_WAP.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayWap === sysCommonStatusEnum.DISABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="payChannelEnum.ALIPAY_QR.name" align="center">
|
<el-table-column :label="payChannelEnum.ALIPAY_QR.name" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button type="success" icon="el-icon-check" circle
|
||||||
type="success" icon="el-icon-check" circle
|
v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.ALIPAY_QR.code)"
|
||||||
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_QR.code,payType.ALIPAY)"
|
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.ENABLE">
|
|
||||||
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else
|
||||||
type="danger" icon="el-icon-close" circle
|
type="danger" icon="el-icon-close" circle
|
||||||
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_QR.code,payType.ALIPAY)"
|
@click="handleCreateChannel(scope.row,payChannelEnum.ALIPAY_QR.code,payType.ALIPAY)">
|
||||||
v-if="scope.row.payChannel.alipayQr === sysCommonStatusEnum.DISABLE">
|
|
||||||
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -117,43 +107,37 @@
|
|||||||
<el-table-column label="微信配置" align="center">
|
<el-table-column label="微信配置" align="center">
|
||||||
<el-table-column :label="payChannelEnum.WX_LITE.name" align="center">
|
<el-table-column :label="payChannelEnum.WX_LITE.name" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button type="success" icon="el-icon-check" circle
|
||||||
type="success" icon="el-icon-check" circle
|
v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_LITE.code)"
|
||||||
@click="handleUpdateChannel(scope.row,payChannelEnum.WX_LITE.code,payType.WECHAT)"
|
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.WECHAT)">
|
||||||
v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.ENABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else
|
||||||
type="danger" icon="el-icon-close" circle
|
type="danger" icon="el-icon-close" circle
|
||||||
@click="handleCreateChannel(scope.row,payChannelEnum.WX_LITE.code,payType.WECHAT)"
|
@click="handleCreateChannel(scope.row,payChannelEnum.WX_LITE.code,payType.WECHAT)">
|
||||||
v-if="scope.row.payChannel.wxLite === sysCommonStatusEnum.DISABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="payChannelEnum.WX_PUB.name" align="center">
|
<el-table-column :label="payChannelEnum.WX_PUB.name" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button type="success" icon="el-icon-check" circle
|
||||||
type="success" icon="el-icon-check" circle
|
v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_PUB.code)"
|
||||||
@click="handleUpdateChannel(scope.row,payChannelEnum.WX_PUB.code,payType.WECHAT)"
|
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.WECHAT)">
|
||||||
v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.ENABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else
|
||||||
type="danger" icon="el-icon-close" circle
|
type="danger" icon="el-icon-close" circle
|
||||||
@click="handleCreateChannel(scope.row,payChannelEnum.WX_PUB.code,payType.WECHAT)"
|
@click="handleCreateChannel(scope.row,payChannelEnum.WX_PUB.code,payType.WECHAT)">
|
||||||
v-if="scope.row.payChannel.wxPub === sysCommonStatusEnum.DISABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="payChannelEnum.WX_APP.name" align="center">
|
<el-table-column :label="payChannelEnum.WX_APP.name" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button type="success" icon="el-icon-check" circle
|
||||||
type="success" icon="el-icon-check" circle
|
v-if="judgeChannelExist(scope.row.channelCodes,payChannelEnum.WX_APP.code)"
|
||||||
@click="handleUpdateChannel(scope.row,payChannelEnum.WX_APP.code,payType.WECHAT)"
|
@click="handleUpdateChannel(scope.row,payChannelEnum.ALIPAY_APP.code,payType.WECHAT)">
|
||||||
v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.ENABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else
|
||||||
type="danger" icon="el-icon-close" circle
|
type="danger" icon="el-icon-close" circle
|
||||||
@click="handleCreateChannel(scope.row,payChannelEnum.WX_APP.code,payType.WECHAT)"
|
@click="handleCreateChannel(scope.row,payChannelEnum.WX_APP.code,payType.WECHAT)">
|
||||||
v-if="scope.row.payChannel.wxApp === sysCommonStatusEnum.DISABLE">
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -276,7 +260,7 @@ export default {
|
|||||||
merchantId: [{required: true, message: "商户编号不能为空", trigger: "blur"}],
|
merchantId: [{required: true, message: "商户编号不能为空", trigger: "blur"}],
|
||||||
},
|
},
|
||||||
// 数据字典
|
// 数据字典
|
||||||
statusDictDatas: getDictDatas(DICT_TYPE.PAY_APP_STATUS),
|
statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
|
||||||
sysCommonStatusEnum: SysCommonStatusEnum,
|
sysCommonStatusEnum: SysCommonStatusEnum,
|
||||||
// 支付渠道枚举
|
// 支付渠道枚举
|
||||||
payChannelEnum: PayChannelEnum,
|
payChannelEnum: PayChannelEnum,
|
||||||
@ -322,6 +306,7 @@ export default {
|
|||||||
// 执行查询
|
// 执行查询
|
||||||
getAppPage(params).then(response => {
|
getAppPage(params).then(response => {
|
||||||
this.list = response.data.list;
|
this.list = response.data.list;
|
||||||
|
console.log(this.list);
|
||||||
this.total = response.data.total;
|
this.total = response.data.total;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
@ -422,7 +407,12 @@ export default {
|
|||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.getList();
|
this.getList();
|
||||||
this.msgSuccess("删除成功");
|
this.msgSuccess("删除成功");
|
||||||
})
|
}).catch(() => {
|
||||||
|
this.$message({
|
||||||
|
type: 'info',
|
||||||
|
message: '已取消删除'
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
handleExport() {
|
handleExport() {
|
||||||
@ -486,6 +476,14 @@ export default {
|
|||||||
this.channelParam.payCode = payCode;
|
this.channelParam.payCode = payCode;
|
||||||
this.channelParam.payMerchant = row.payMerchant;
|
this.channelParam.payMerchant = row.payMerchant;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 根据渠道编码判断渠道列表中是否存在
|
||||||
|
* @param channels 渠道列表
|
||||||
|
* @param channelCode 渠道编码
|
||||||
|
*/
|
||||||
|
judgeChannelExist(channels, channelCode) {
|
||||||
|
return channels.indexOf(channelCode) !== -1;
|
||||||
|
},
|
||||||
refreshTable() {
|
refreshTable() {
|
||||||
this.getList();
|
this.getList();
|
||||||
}
|
}
|
||||||
|
@ -154,8 +154,8 @@ export default {
|
|||||||
shortName: [{ required: true, message: "商户简称不能为空", trigger: "blur" }],
|
shortName: [{ required: true, message: "商户简称不能为空", trigger: "blur" }],
|
||||||
status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }],
|
status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }],
|
||||||
},
|
},
|
||||||
// 数据字典
|
// 商户状态数据字典
|
||||||
statusDictDatas: getDictDatas(DICT_TYPE.PAY_MERCHANT_STATUS)
|
statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -236,9 +236,6 @@
|
|||||||
<el-descriptions-item label="商品描述">
|
<el-descriptions-item label="商品描述">
|
||||||
{{ orderDetail.body }}
|
{{ orderDetail.body }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="支付通道额外扩展参数">
|
|
||||||
{{ orderDetail.payOrderExtension.channelExtras }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="支付通道异步回调内容">
|
<el-descriptions-item label="支付通道异步回调内容">
|
||||||
{{ orderDetail.payOrderExtension.channelNotifyData }}
|
{{ orderDetail.payOrderExtension.channelNotifyData }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@ -278,7 +275,6 @@ const defaultOrderDetail = {
|
|||||||
notifyTime: '',
|
notifyTime: '',
|
||||||
expireTime: '',
|
expireTime: '',
|
||||||
payOrderExtension: {
|
payOrderExtension: {
|
||||||
channelExtras: '',
|
|
||||||
channelNotifyData: '',
|
channelNotifyData: '',
|
||||||
no: ''
|
no: ''
|
||||||
}
|
}
|
||||||
|
@ -43,20 +43,17 @@
|
|||||||
<el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
<el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="退款单号" prop="reqNo">
|
|
||||||
<el-input v-model="queryParams.reqNo" placeholder="请输入退款单请求号" clearable size="small"
|
|
||||||
@keyup.enter.native="handleQuery"/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="商户退款订单号" prop="merchantRefundNo">
|
|
||||||
<el-input v-model="queryParams.merchantRefundNo" placeholder="请输入商户退款订单号" clearable size="small"
|
|
||||||
@keyup.enter.native="handleQuery"/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="退款类型" prop="type">
|
<el-form-item label="退款类型" prop="type">
|
||||||
<el-select v-model="queryParams.type" placeholder="请选择退款类型" clearable size="small">
|
<el-select v-model="queryParams.type" placeholder="请选择退款类型" clearable size="small">
|
||||||
<el-option v-for="dict in payRefundOrderTypeDictDatum" :key="parseInt(dict.value)"
|
<el-option v-for="dict in payRefundOrderTypeDictDatum" :key="parseInt(dict.value)"
|
||||||
:label="dict.label" :value="parseInt(dict.value)"/>
|
:label="dict.label" :value="parseInt(dict.value)"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="商户退款订单号" prop="merchantRefundNo">
|
||||||
|
<el-input v-model="queryParams.merchantRefundNo" placeholder="请输入商户退款订单号" clearable size="small"
|
||||||
|
@keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="退款状态" prop="status">
|
<el-form-item label="退款状态" prop="status">
|
||||||
<el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable size="small">
|
<el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable size="small">
|
||||||
<el-option v-for="dict in payRefundOrderDictDatum" :key="parseInt(dict.value)"
|
<el-option v-for="dict in payRefundOrderDictDatum" :key="parseInt(dict.value)"
|
||||||
@ -112,15 +109,15 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- <el-table-column label="交易订单号" align="center" prop="tradeNo" width="140"/>-->
|
<!-- <el-table-column label="交易订单号" align="center" prop="tradeNo" width="140"/>-->
|
||||||
<!-- <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" width="140"/>-->
|
<!-- <el-table-column label="商户订单编号" align="center" prop="merchantOrderId" width="140"/>-->
|
||||||
<el-table-column label="退款订单号" align="left" width="230">
|
<el-table-column label="商户订单号" align="left" width="230">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<p class="order-font">
|
<p class="order-font">
|
||||||
<el-tag size="mini">退款</el-tag>
|
<el-tag size="mini">退款</el-tag>
|
||||||
{{ scope.row.reqNo }}
|
{{ scope.row.merchantRefundNo }}
|
||||||
</p>
|
</p>
|
||||||
<p class="order-font">
|
<p class="order-font">
|
||||||
<el-tag size="mini" type="success">商户</el-tag>
|
<el-tag type="success">交易</el-tag>
|
||||||
{{ scope.row.merchantRefundNo }}
|
{{ scope.row.merchantOrderId }}
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -202,9 +199,6 @@
|
|||||||
<el-descriptions-item label="商户退款单号">
|
<el-descriptions-item label="商户退款单号">
|
||||||
<el-tag size="mini">{{ refundDetail.merchantRefundNo }}</el-tag>
|
<el-tag size="mini">{{ refundDetail.merchantRefundNo }}</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="商户退款请求单号" size="mini">
|
|
||||||
<el-tag type="success" size="mini">{{ refundDetail.reqNo }}</el-tag>
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="商户订单号">{{ refundDetail.merchantOrderId }}</el-descriptions-item>
|
<el-descriptions-item label="商户订单号">{{ refundDetail.merchantOrderId }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="交易订单号">{{ refundDetail.tradeNo }}</el-descriptions-item>
|
<el-descriptions-item label="交易订单号">{{ refundDetail.tradeNo }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
@ -299,7 +293,6 @@ const defaultRefundDetail = {
|
|||||||
payAmount: null,
|
payAmount: null,
|
||||||
reason: '',
|
reason: '',
|
||||||
refundAmount: null,
|
refundAmount: null,
|
||||||
reqNo: '',
|
|
||||||
status: null,
|
status: null,
|
||||||
subject: '',
|
subject: '',
|
||||||
successTime: null,
|
successTime: null,
|
||||||
@ -333,7 +326,6 @@ export default {
|
|||||||
queryParams: {
|
queryParams: {
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
reqNo: null,
|
|
||||||
merchantId: null,
|
merchantId: null,
|
||||||
appId: null,
|
appId: null,
|
||||||
channelId: null,
|
channelId: null,
|
||||||
|
@ -14,6 +14,7 @@ public interface PayErrorCodeCoreConstants {
|
|||||||
*/
|
*/
|
||||||
ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
|
ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在");
|
||||||
ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
|
ErrorCode PAY_APP_IS_DISABLE = new ErrorCode(1007000002, "App 已经被禁用");
|
||||||
|
ErrorCode PAY_APP_EXIST_TRANSACTION_ORDER_CANT_DELETE = new ErrorCode(1007000003, "支付应用存在交易中的订单,无法删除");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ========== CHANNEL 模块 1-007-001-000 ==========
|
* ========== CHANNEL 模块 1-007-001-000 ==========
|
||||||
@ -54,6 +55,7 @@ public interface PayErrorCodeCoreConstants {
|
|||||||
* ========== 支付商户信息 1-007-004-000 ==========
|
* ========== 支付商户信息 1-007-004-000 ==========
|
||||||
*/
|
*/
|
||||||
ErrorCode PAY_MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
|
ErrorCode PAY_MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
|
||||||
|
ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package cn.iocoder.yudao.framework.pay.core.client;
|
package cn.iocoder.yudao.framework.pay.core.client;
|
||||||
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
|
||||||
|
import javax.validation.ConstraintViolation;
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付客户端的配置,本质是支付渠道的配置
|
* 支付客户端的配置,本质是支付渠道的配置
|
||||||
@ -19,8 +20,22 @@ import javax.validation.Validator;
|
|||||||
public interface PayClientConfig {
|
public interface PayClientConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证配置参数是否正确
|
* 配置验证参数是
|
||||||
|
*
|
||||||
|
* @param validator 校验对象
|
||||||
|
* @return 配置好的验证参数
|
||||||
|
*/
|
||||||
|
Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数校验
|
||||||
|
*
|
||||||
* @param validator 校验对象
|
* @param validator 校验对象
|
||||||
*/
|
*/
|
||||||
void verifyParam(Validator validator);
|
default void validate(Validator validator) {
|
||||||
|
Set<ConstraintViolation<PayClientConfig>> violations = verifyParam(validator);
|
||||||
|
if (!violations.isEmpty()) {
|
||||||
|
throw new ConstraintViolationException(violations);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,12 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
import javax.validation.constraints.AssertTrue;
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
// TODO 芋艿:参数校验
|
// TODO 芋艿:参数校验
|
||||||
|
|
||||||
@ -114,18 +109,9 @@ public class AlipayPayClientConfig implements PayClientConfig {
|
|||||||
public interface ModeCertificate {
|
public interface ModeCertificate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证配置参数是否正确
|
|
||||||
* @param validator 校验对象
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void verifyParam(Validator validator) {
|
public Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator) {
|
||||||
// 手动调用validate进行验证
|
return validator.validate(this,
|
||||||
Set<ConstraintViolation<AlipayPayClientConfig>> validate = validator.validate(this,
|
|
||||||
MODE_PUBLIC_KEY.equals(this.getMode()) ? ModePublicKey.class : ModeCertificate.class);
|
MODE_PUBLIC_KEY.equals(this.getMode()) ? ModePublicKey.class : ModeCertificate.class);
|
||||||
|
|
||||||
// 断言没有异常
|
|
||||||
Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage)
|
|
||||||
.collect(Collectors.joining(",")));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
|
|||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
@ -11,7 +10,6 @@ import javax.validation.constraints.NotBlank;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
// TODO 芋艿:参数校验
|
// TODO 芋艿:参数校验
|
||||||
|
|
||||||
@ -101,19 +99,9 @@ public class WXPayClientConfig implements PayClientConfig {
|
|||||||
public interface V3 {
|
public interface V3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @aquan:1)已经有注释,不用重复注释;2)方法名改成 validate,比较适合 validator;3)断言是否有异常,可以封一个 ConstraintViolationException 异常
|
|
||||||
/**
|
|
||||||
* 验证配置参数是否正确
|
|
||||||
* @param validator 校验对象
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void verifyParam(Validator validator) {
|
public Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator) {
|
||||||
// 手动调用validate进行验证
|
return validator.validate(this, this.getApiVersion().equals(API_VERSION_V2) ? V2.class : V3.class);
|
||||||
Set<ConstraintViolation<PayClientConfig>> validate = validator.validate(this,
|
|
||||||
this.getApiVersion().equals(API_VERSION_V2) ? V2.class : V3.class);
|
|
||||||
// 断言没有异常
|
|
||||||
Assert.isTrue(validate.isEmpty(), validate.stream().map(ConstraintViolation::getMessage)
|
|
||||||
.collect(Collectors.joining(",")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws FileNotFoundException {
|
public static void main(String[] args) throws FileNotFoundException {
|
||||||
|
@ -17,18 +17,21 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum PayChannelEnum {
|
public enum PayChannelEnum {
|
||||||
|
|
||||||
WX_PUB("wx_pub", "微信 JSAPI 支付"), // 公众号的网页
|
/**
|
||||||
WX_LITE("wx_lite","微信小程序支付"),
|
* 公众号网页
|
||||||
WX_APP("wx_app", "微信 App 支付"),
|
*/
|
||||||
|
WX_PUB("wx_pub", "微信 JSAPI 支付", WXPayClientConfig.class),
|
||||||
|
WX_LITE("wx_lite", "微信小程序支付", WXPayClientConfig.class),
|
||||||
|
WX_APP("wx_app", "微信 App 支付", WXPayClientConfig.class),
|
||||||
|
|
||||||
ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付"),
|
ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付", AlipayPayClientConfig.class),
|
||||||
ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付"),
|
ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付", AlipayPayClientConfig.class),
|
||||||
ALIPAY_APP("alipay_app", "支付宝App 支付"),
|
ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class),
|
||||||
ALIPAY_QR("alipay_qr", "支付宝扫码支付");
|
ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编码
|
* 编码
|
||||||
*
|
* <p>
|
||||||
* 参考 https://www.pingxx.com/api/支付渠道属性值.html
|
* 参考 https://www.pingxx.com/api/支付渠道属性值.html
|
||||||
*/
|
*/
|
||||||
private String code;
|
private String code;
|
||||||
@ -37,6 +40,11 @@ public enum PayChannelEnum {
|
|||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置类
|
||||||
|
*/
|
||||||
|
private Class<? extends PayClientConfig> configClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付
|
* 微信支付
|
||||||
*/
|
*/
|
||||||
@ -50,27 +58,6 @@ public enum PayChannelEnum {
|
|||||||
public static PayChannelEnum getByCode(String code) {
|
public static PayChannelEnum getByCode(String code) {
|
||||||
return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
|
return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @aquan:加一个 configClass 字段,不用 switch 的方式哈。不然新增一个支付方式,需要改的方法有点多
|
|
||||||
/**
|
|
||||||
* 根据编码得到支付类
|
|
||||||
*
|
|
||||||
* @param code 编码
|
|
||||||
* @return 支付配置类
|
|
||||||
*/
|
|
||||||
public static Class<? extends PayClientConfig> findByCodeGetClass(String code) {
|
|
||||||
switch (PayChannelEnum.getByCode(code)){
|
|
||||||
case WX_PUB:
|
|
||||||
case WX_LITE:
|
|
||||||
case WX_APP:
|
|
||||||
return WXPayClientConfig.class;
|
|
||||||
case ALIPAY_PC:
|
|
||||||
case ALIPAY_WAP:
|
|
||||||
case ALIPAY_APP:
|
|
||||||
case ALIPAY_QR:
|
|
||||||
return AlipayPayClientConfig.class;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user