mall + pay:

1. 优化退款管理的接口实现
This commit is contained in:
YunaiV 2023-07-19 22:33:19 +08:00
parent b84da30234
commit 3caa5f14bd
17 changed files with 210 additions and 465 deletions

View File

@ -2,6 +2,11 @@ package cn.iocoder.yudao.module.pay.controller.admin.refund;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
@ -10,15 +15,9 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
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 cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
@ -35,6 +34,7 @@ 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.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 退款订单")
@ -56,20 +56,14 @@ public class PayRefundController {
@PreAuthorize("@ss.hasPermission('pay:refund:query')")
public CommonResult<PayRefundDetailsRespVO> getRefund(@RequestParam("id") Long id) {
PayRefundDO refund = refundService.getRefund(id);
if (ObjectUtil.isNull(refund)) {
if (refund == null) {
return success(new PayRefundDetailsRespVO());
}
PayAppDO appDO = appService.getApp(refund.getAppId());
PayChannelEnum channelEnum = PayChannelEnum.getByCode(refund.getChannelCode());
PayOrderDO orderDO = orderService.getOrder(refund.getOrderId());
PayRefundDetailsRespVO refundDetail = PayRefundConvert.INSTANCE.refundDetailConvert(refund);
refundDetail.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
refundDetail.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
refundDetail.setSubject(orderDO.getSubject());
return success(refundDetail);
// 拼接数据
PayAppDO app = appService.getApp(refund.getAppId());
PayOrderDO order = orderService.getOrder(refund.getOrderId());
return success(PayRefundConvert.INSTANCE.convert(refund, order, app));
}
@GetMapping("/page")
@ -82,21 +76,8 @@ public class PayRefundController {
}
// 处理应用ID数据
Map<Long, PayAppDO> appMap = appService.getAppMap(
CollectionUtils.convertList(pageResult.getList(), PayRefundDO::getAppId));
List<PayRefundPageItemRespVO> list = new ArrayList<>(pageResult.getList().size());
pageResult.getList().forEach(c -> {
PayAppDO appDO = appMap.get(c.getAppId());
PayChannelEnum channelEnum = PayChannelEnum.getByCode(c.getChannelCode());
PayRefundPageItemRespVO item = PayRefundConvert.INSTANCE.pageItemConvert(c);
item.setAppName(ObjectUtil.isNotNull(appDO) ? appDO.getName() : "未知应用");
item.setChannelCodeName(ObjectUtil.isNotNull(channelEnum) ? channelEnum.getName() : "未知渠道");
list.add(item);
});
return success(new PageResult<>(list, pageResult.getTotal()));
Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayRefundDO::getAppId));
return success(PayRefundConvert.INSTANCE.convertPage(pageResult, appMap));
}
@GetMapping("/export-excel")
@ -105,21 +86,21 @@ public class PayRefundController {
@OperateLog(type = EXPORT)
public void exportRefundExcel(@Valid PayRefundExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<PayRefundDO> list = refundService.getRefundList(exportReqVO);
if (CollectionUtil.isEmpty(list)) {
ExcelUtils.write(response, "退款订单.xls", "数据",
PayRefundExcelVO.class, new ArrayList<>());
return;
}
// 处理应用ID数据
Map<Long, PayAppDO> appMap = appService.getAppMap(
CollectionUtils.convertList(list, PayRefundDO::getAppId));
convertList(list, PayRefundDO::getAppId));
List<PayRefundExcelVO> excelDatum = new ArrayList<>(list.size());
// 处理商品名称数据
Map<Long, PayOrderDO> orderMap = orderService.getOrderSubjectMap(
CollectionUtils.convertList(list, PayRefundDO::getOrderId));
convertList(list, PayRefundDO::getOrderId));
list.forEach(c -> {
PayAppDO appDO = appMap.get(c.getAppId());

View File

@ -1,13 +1,10 @@
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 退款订单 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
@ -15,83 +12,67 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@Data
public class PayRefundBaseVO {
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "应用编号不能为空")
@Schema(description = "外部退款号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110")
private String no;
@Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long appId;
@Schema(description = "渠道编号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "渠道编号不能为空")
@Schema(description = "渠道编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
private Long channelId;
@Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "渠道编码不能为空")
@Schema(description = "渠道编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_app")
private String channelCode;
@Schema(description = "支付订单编号 pay_order 表id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "支付订单编号 pay_order 表id不能为空")
@Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long orderId;
@Schema(description = "交易订单号 pay_extension 表no 字段", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "交易订单号 pay_extension 表no 字段不能为空")
private String tradeNo;
// ========== 商户相关字段 ==========
@Schema(description = "商户订单编号(商户系统生成)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "商户订单编号(商户系统生成)不能为空")
@Schema(description = "商户订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "225")
private String merchantOrderId;
@Schema(description = "商户退款订单号(商户系统生成)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "商户退款订单号(商户系统生成)不能为空")
private String merchantRefundNo;
@Schema(description = "商户退款订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "512")
private String merchantRefundId;
@Schema(description = "异步通知商户地址", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "异步通知商户地址不能为空")
@Schema(description = "异步通知地址", requiredMode = Schema.RequiredMode.REQUIRED)
private String notifyUrl;
@Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "退款状态不能为空")
// ========== 退款相关字段 ==========
@Schema(description = "退款状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Integer status;
@Schema(description = "退款类型(部分退款,全部退款)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "退款类型(部分退款,全部退款)不能为空")
private Integer type;
@Schema(description = "支付金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private Long payPrice;
@Schema(description = "支付金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "支付金额,单位分不能为空")
private Long payAmount;
@Schema(description = "退款金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
private Long refundPrice;
@Schema(description = "退款金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "退款金额,单位分不能为空")
private Long refundAmount;
@Schema(description = "退款原因", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "退款原因不能为空")
@Schema(description = "退款原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "我要退了")
private String reason;
@Schema(description = "用户 IP")
@Schema(description = "用户 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
private String userIp;
@Schema(description = "渠道订单号pay_order 中的channel_order_no 对应", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "渠道订单号pay_order 中的channel_order_no 对应不能为空")
// ========== 渠道相关字段 ==========
@Schema(description = "渠道订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "233")
private String channelOrderNo;
@Schema(description = "渠道退款单号,渠道返回")
@Schema(description = "渠道退款单号", example = "2022")
private String channelRefundNo;
@Schema(description = "渠道调用报错时,错误码")
@Schema(description = "退款成功时间")
private LocalDateTime successTime;
@Schema(description = "调用渠道的错误码")
private String channelErrorCode;
@Schema(description = "渠道调用报错时,错误信息")
@Schema(description = "调用渠道的错误提示")
private String channelErrorMsg;
@Schema(description = "支付渠道的额外参数")
private String channelExtras;
@Schema(description = "退款失效时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expireTime;
@Schema(description = "退款成功时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime successTime;
private String channelNotifyData;
}

View File

@ -1,11 +0,0 @@
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
@Schema(description = "管理后台 - 退款订单创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayRefundCreateReqVO extends PayRefundBaseVO {
}

View File

@ -5,7 +5,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 退款订单详情 Response VO")
@ -17,14 +16,11 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO {
@Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
private Long id;
@Schema(description = "应用名称")
@Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿")
private String appName;
@Schema(description = "渠道编号名称")
private String channelCodeName;
@NotNull(message = "商品标题不能为空")
private String subject;
@Schema(description = "支付订单", requiredMode = Schema.RequiredMode.REQUIRED)
private Order order;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@ -32,4 +28,13 @@ public class PayRefundDetailsRespVO extends PayRefundBaseVO {
@Schema(description = "更新时间")
private LocalDateTime updateTime;
@Schema(description = "管理后台 - 支付订单")
@Data
public static class Order {
@Schema(description = "商品标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "土豆")
private String subject;
}
}

View File

@ -12,74 +12,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@Data
public class PayRefundExportReqVO {
@Schema(description = "应用编号")
@Schema(description = "应用编号", example = "1024")
private Long appId;
@Schema(description = "渠道编号")
private Long channelId;
@Schema(description = "渠道编码")
@Schema(description = "渠道编码", example = "wx_app")
private String channelCode;
@Schema(description = "支付订单编号 pay_order 表id")
private Long orderId;
@Schema(description = "交易订单号 pay_extension 表no 字段")
private String tradeNo;
@Schema(description = "商户订单编号(商户系统生成)")
@Schema(description = "商户支付单号", example = "10")
private String merchantOrderId;
@Schema(description = "商户退款订单号(商户系统生成)")
private String merchantRefundNo;
@Schema(description = "商户退款单号", example = "20")
private String merchantRefundId;
@Schema(description = "异步通知商户地址")
private String notifyUrl;
@Schema(description = "退款状态")
private Integer status;
@Schema(description = "退款类型(部分退款,全部退款)")
private Integer type;
@Schema(description = "支付金额,单位分")
private Long payPrice;
@Schema(description = "退款金额,单位分")
private Long refundPrice;
@Schema(description = "退款原因")
private String reason;
@Schema(description = "用户 IP")
private String userIp;
@Schema(description = "渠道订单号pay_order 中的channel_order_no 对应")
@Schema(description = "渠道支付单号", example = "30")
private String channelOrderNo;
@Schema(description = "渠道退款单号,渠道返回")
@Schema(description = "渠道退款单号", example = "40")
private String channelRefundNo;
@Schema(description = "渠道调用报错时,错误码")
private String channelErrorCode;
@Schema(description = "渠道调用报错时,错误信息")
private String channelErrorMsg;
@Schema(description = "支付渠道的额外参数")
private String channelExtras;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "退款失效时间")
private LocalDateTime[] expireTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "退款成功时间")
private LocalDateTime[] successTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "退款通知时间")
private LocalDateTime[] notifyTime;
@Schema(description = "退款状态", example = "0")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "创建时间")

View File

@ -13,15 +13,12 @@ import java.time.LocalDateTime;
@ToString(callSuper = true)
public class PayRefundPageItemRespVO extends PayRefundBaseVO {
@Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "支付订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "应用名称")
@Schema(description = "应用名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是芋艿")
private String appName;
@Schema(description = "渠道名称")
private String channelCodeName;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;

View File

@ -17,70 +17,26 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@ToString(callSuper = true)
public class PayRefundPageReqVO extends PageParam {
@Schema(description = "应用编号")
@Schema(description = "应用编号", example = "1024")
private Long appId;
@Schema(description = "渠道编号")
private Long channelId;
@Schema(description = "渠道编码")
@Schema(description = "渠道编码", example = "wx_app")
private String channelCode;
@Schema(description = "支付订单编号 pay_order 表id")
private Long orderId;
@Schema(description = "交易订单号 pay_extension 表no 字段")
private String tradeNo;
@Schema(description = "商户订单编号(商户系统生成)")
@Schema(description = "商户支付单号", example = "10")
private String merchantOrderId;
@Schema(description = "商户退款订单号(商户系统生成)")
private String merchantRefundNo;
@Schema(description = "商户退款单号", example = "20")
private String merchantRefundId;
@Schema(description = "异步通知商户地址")
private String notifyUrl;
@Schema(description = "退款状态")
private Integer status;
@Schema(description = "退款类型(部分退款,全部退款)")
private Integer type;
@Schema(description = "支付金额,单位分")
private Long payPrice;
@Schema(description = "退款金额,单位分")
private Long refundPrice;
@Schema(description = "退款原因")
private String reason;
@Schema(description = "用户 IP")
private String userIp;
@Schema(description = "渠道订单号pay_order 中的channel_order_no 对应")
@Schema(description = "渠道支付单号", example = "30")
private String channelOrderNo;
@Schema(description = "渠道退款单号,渠道返回")
@Schema(description = "渠道退款单号", example = "40")
private String channelRefundNo;
@Schema(description = "渠道调用报错时,错误码")
private String channelErrorCode;
@Schema(description = "渠道调用报错时,错误信息")
private String channelErrorMsg;
@Schema(description = "支付渠道的额外参数")
private String channelExtras;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "退款失效时间")
private LocalDateTime[] expireTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "退款成功时间")
private LocalDateTime[] successTime;
@Schema(description = "退款状态", example = "0")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "创建时间")

View File

@ -1,22 +0,0 @@
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 退款订单 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayRefundRespVO extends PayRefundBaseVO {
@Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -1,16 +0,0 @@
package cn.iocoder.yudao.module.pay.controller.admin.refund.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 退款订单更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PayRefundUpdateReqVO extends PayRefundBaseVO {
@Schema(description = "支付退款编号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "支付退款编号不能为空")
private Long id;
}

View File

@ -1,47 +1,45 @@
package cn.iocoder.yudao.module.pay.convert.refund;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundDetailsRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExcelVO;
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageItemRespVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
@Mapper
public interface PayRefundConvert {
PayRefundConvert INSTANCE = Mappers.getMapper(PayRefundConvert.class);
PayRefundDO convert(PayRefundCreateReqVO bean);
PayRefundDO convert(PayRefundUpdateReqVO bean);
default PayRefundDetailsRespVO convert(PayRefundDO refund, PayOrderDO order, PayAppDO app) {
PayRefundDetailsRespVO respVO = convert(refund)
.setOrder(convert(order));
if (app != null) {
respVO.setAppName(app.getName());
}
return respVO;
}
PayRefundDetailsRespVO convert(PayRefundDO bean);
PayRefundDetailsRespVO.Order convert(PayOrderDO bean);
PayRefundRespVO convert(PayRefundDO bean);
/**
* 退款订单 DO 退款详情订单 VO
*
* @param bean 退款订单 DO
* @return 退款详情订单 VO
*/
PayRefundDetailsRespVO refundDetailConvert(PayRefundDO bean);
/**
* 退款订单DO 分页退款条目VO
*
* @param bean 退款订单DO
* @return 分页退款条目VO
*/
PayRefundPageItemRespVO pageItemConvert(PayRefundDO bean);
List<PayRefundRespVO> convertList(List<PayRefundDO> list);
PageResult<PayRefundRespVO> convertPage(PageResult<PayRefundDO> page);
default PageResult<PayRefundPageItemRespVO> convertPage(PageResult<PayRefundDO> page, Map<Long, PayAppDO> appMap) {
PageResult<PayRefundPageItemRespVO> result = convertPage(page);
result.getList().forEach(order -> MapUtils.findAndThen(appMap, order.getAppId(), app -> order.setAppName(app.getName())));
return result;
}
PageResult<PayRefundPageItemRespVO> convertPage(PageResult<PayRefundDO> page);
/**
* 退款订单DO 导出excel VO

View File

@ -140,7 +140,7 @@ public class PayRefundDO extends BaseDO {
*/
private String channelErrorCode;
/**
* 调用渠道报错时错误信息
* 调用渠道的错误提示
*/
private String channelErrorMsg;

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.dal.mysql.refund;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
@ -44,25 +43,29 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
}
default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<PayRefundDO>()
.eqIfPresent("app_id", reqVO.getAppId())
.eqIfPresent("channel_code", reqVO.getChannelCode())
.likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())
.eqIfPresent("type", reqVO.getType())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getCreateTime())
.orderByDesc("id"));
return selectPage(reqVO, new LambdaQueryWrapperX<PayRefundDO>()
.eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId())
.eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode())
.likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId())
.likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId())
.likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo())
.likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo())
.eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus())
.betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(PayRefundDO::getId));
}
default List<PayRefundDO> selectList(PayRefundExportReqVO reqVO) {
return selectList(new QueryWrapperX<PayRefundDO>()
.eqIfPresent("app_id", reqVO.getAppId())
.eqIfPresent("channel_code", reqVO.getChannelCode())
.likeIfPresent("merchant_refund_no", reqVO.getMerchantRefundNo())
.eqIfPresent("type", reqVO.getType())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getCreateTime())
.orderByDesc("id"));
return selectList(new LambdaQueryWrapperX<PayRefundDO>()
.eqIfPresent(PayRefundDO::getAppId, reqVO.getAppId())
.eqIfPresent(PayRefundDO::getChannelCode, reqVO.getChannelCode())
.likeIfPresent(PayRefundDO::getMerchantOrderId, reqVO.getMerchantOrderId())
.likeIfPresent(PayRefundDO::getMerchantRefundId, reqVO.getMerchantRefundId())
.likeIfPresent(PayRefundDO::getChannelOrderNo, reqVO.getChannelOrderNo())
.likeIfPresent(PayRefundDO::getChannelRefundNo, reqVO.getChannelRefundNo())
.eqIfPresent(PayRefundDO::getStatus, reqVO.getStatus())
.betweenIfPresent(PayRefundDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(PayRefundDO::getId));
}
}

View File

@ -91,7 +91,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
reqVO.setAppId(1L);
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
reqVO.setMerchantRefundNo("MRF0000001");
reqVO.setMerchantRefundId("MRF0000001");
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
@ -145,7 +145,6 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
reqVO.setAppId(1L);
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
reqVO.setMerchantRefundNo("MRF0000001");
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));

View File

@ -58,7 +58,7 @@ export const DICT_TYPE = {
PAY_CHANNEL_CODE: 'pay_channel_code', // 支付渠道编码类型
PAY_NOTIFY_STATUS: 'pay_notify_status', // 商户支付回调状态
PAY_ORDER_STATUS: 'pay_order_status', // 商户支付订单状态
PAY_REFUND_ORDER_STATUS: 'pay_refund_order_status', // 退款订单状态
PAY_REFUND_STATUS: 'pay_refund_status', // 退款订单状态
// ========== MP 模块 ==========
MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型

View File

@ -9,8 +9,7 @@
</el-select>
</el-form-item>
<el-form-item label="支付渠道" prop="channelCode">
<el-select v-model="queryParams.channelCode" placeholder="请选择支付渠道" clearable
@clear="()=>{queryParams.channelCode = null}">
<el-select v-model="queryParams.channelCode" placeholder="请选择支付渠道" clearable>
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
@ -77,9 +76,15 @@
</el-table-column>
<el-table-column label="订单号" align="left" width="300">
<template v-slot="scope">
<p class="order-font"><el-tag size="mini">商户单号</el-tag> {{scope.row.merchantOrderId}}</p>
<p class="order-font" v-if="scope.row.no"><el-tag size="mini" type="warning">支付单号</el-tag> {{scope.row.no}}</p>
<p class="order-font" v-if="scope.row.channelOrderNo"><el-tag size="mini" type="success">渠道单号</el-tag> {{scope.row.channelOrderNo}}</p>
<p class="order-font"><el-tag size="mini">
商户</el-tag> {{scope.row.merchantOrderId}}
</p>
<p class="order-font" v-if="scope.row.no">
<el-tag size="mini" type="warning">支付</el-tag> {{scope.row.no}}
</p>
<p class="order-font" v-if="scope.row.channelOrderNo">
<el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelOrderNo}}
</p>
</template>
</el-table-column>
<el-table-column label="支付状态" align="center" prop="status">

View File

@ -7,25 +7,30 @@
<el-option v-for="item in appList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="渠道编码" prop="channelCode">
<el-select v-model="queryParams.channelCode" placeholder="请输入渠道编码" clearable
@clear="()=>{queryParams.channelCode = null}">
<el-option v-for="dict in payChannelCodeDictDatum" :key="dict.value" :label="dict.label" :value="dict.value"/>
<el-form-item label="退款渠道" prop="channelCode">
<el-select v-model="queryParams.channelCode" placeholder="请选择退款渠道" clearable>
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE)" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="退款类型" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择退款类型" clearable>
<el-option v-for="dict in payRefundOrderTypeDictDatum" :key="parseInt(dict.value)"
:label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
<el-form-item label="商户支付单号" prop="merchantOrderId">
<el-input v-model="queryParams.merchantOrderId" placeholder="请输入商户支付单号" clearable
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="商户退款订单号" prop="merchantRefundNo">
<el-input v-model="queryParams.merchantRefundNo" placeholder="请输入商户退款订单号" clearable
<el-form-item label="商户退款单号" prop="merchantRefundId">
<el-input v-model="queryParams.merchantRefundId" placeholder="请输入商户退款单号" clearable
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="渠道支付单号" prop="channelOrderNo">
<el-input v-model="queryParams.channelOrderNo" placeholder="请输入渠道支付单号" clearable
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="渠道退款单号" prop="channelRefundNo">
<el-input v-model="queryParams.channelRefundNo" placeholder="请输入渠道退款单号" clearable
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="退款状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择退款状态" clearable>
<el-option v-for="dict in payRefundOrderDictDatum" :key="parseInt(dict.value)"
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PAY_REFUND_STATUS)" :key="parseInt(dict.value)"
:label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
@ -52,65 +57,55 @@
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="编号" align="center" prop="id"/>
<el-table-column label="支付渠道" align="center" width="130">
<template v-slot="scope">
<el-popover trigger="hover" placement="top">
<p>应用名称: {{ scope.row.appName }}</p>
<p>渠道名称: {{ scope.row.channelCodeName }}</p>
<div slot="reference" class="name-wrapper">
{{ scope.row.channelCodeName }}
</div>
</el-popover>
</template>
</el-table-column>
<!-- <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="left" width="230">
<template v-slot="scope">
<p class="order-font">
<el-tag size="mini">退款</el-tag>
{{ scope.row.merchantRefundNo }}
</p>
<p class="order-font">
<el-tag type="success">交易</el-tag>
{{ scope.row.merchantOrderId }}
</p>
</template>
</el-table-column>
<el-table-column label="支付订单号" align="center" prop="merchantRefundNo" width="250">
<template v-slot="scope">
<p class="order-font">
<el-tag size="mini">交易</el-tag>
{{ scope.row.tradeNo }}
</p>
<p class="order-font">
<el-tag size="mini" type="warning">渠道</el-tag>
{{ scope.row.channelOrderNo }}
</p>
</template>
</el-table-column>
<el-table-column label="支付金额(元)" align="center" prop="payPrice" width="100">
<template v-slot="scope" class="">
{{ parseFloat(scope.row.payPrice / 100).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="退款金额(元)" align="center" prop="refundPrice" width="100">
<template v-slot="scope">
{{ parseFloat(scope.row.refundPrice / 100).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="退款状态" align="center" prop="status">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="退款原因" align="center" prop="reason" width="140" :show-overflow-tooltip="true"/>
<el-table-column label="创建时间" align="center" prop="createTime" width="100">
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="退款成功时间" align="center" prop="successTime" width="100">
<el-table-column label="支付金额" align="center" prop="payPrice" width="100">
<template v-slot="scope" class="">
{{ (scope.row.payPrice / 100.0).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="退款金额" align="center" prop="refundPrice" width="100">
<template v-slot="scope">
{{ (scope.row.refundPrice / 100.0).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="退款订单号" align="left" width="300">
<template v-slot="scope">
<p class="order-font">
<el-tag size="mini">商户</el-tag> {{scope.row.merchantRefundId}}
</p>
<p class="order-font">
<el-tag size="mini" type="warning">支付</el-tag> {{scope.row.no}}
</p>
<p class="order-font" v-if="scope.row.channelRefundNo">
<el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelRefundNo}}
</p>
</template>
</el-table-column>
<el-table-column label="支付订单号" align="left" width="300">
<template v-slot="scope">
<p class="order-font">
<el-tag size="mini">商户</el-tag> {{scope.row.merchantOrderId}}
</p>
<p class="order-font">
<el-tag size="mini" type="success">渠道</el-tag> {{scope.row.channelOrderNo}}
</p>
</template>
</el-table-column>
<el-table-column label="退款状态" align="center" prop="status">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="退款渠道" align="center" width="140">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.PAY_CHANNEL_CODE" :value="scope.row.channelCode" />
</template>
</el-table-column>
<el-table-column label="成功时间" align="center" prop="successTime" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.successTime) }}</span>
</template>
@ -150,7 +145,7 @@
<el-tag class="tag-purple" size="mini">{{ parseFloat(refundDetail.refundPrice / 100).toFixed(2) }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="退款状态">
<dict-tag :type="DICT_TYPE.PAY_REFUND_ORDER_STATUS" :value="refundDetail.status" />
<dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="refundDetail.status" />
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ parseTime(refundDetail.createTime) }}</el-descriptions-item>
<el-descriptions-item label="退款成功时间">{{ parseTime(refundDetail.successTime) }}</el-descriptions-item>
@ -185,37 +180,7 @@
<script>
import {getRefundPage, exportRefundExcel, getRefund} from "@/api/pay/refund";
import { DICT_TYPE, getDictDatas } from "@/utils/dict";
import { getNowDateTime } from "@/utils/ruoyi";
const defaultRefundDetail = {
id: null,
appId: null,
appName: '',
channelCode: '',
channelCodeName: '',
channelErrorCode: '',
channelErrorMsg: '',
channelExtras: '',
channelId: null,
channelOrderNo: '',
channelRefundNo: '',
createTime: null,
expireTime: null,
merchantOrderId: '',
merchantRefundNo: '',
notifyUrl: '',
orderId: null,
payPrice: null,
reason: '',
refundPrice: null,
status: null,
subject: '',
successTime: null,
tradeNo: '',
type: null,
userIp: ''
}
import { getAppList } from "@/api/pay/app";
export default {
name: "PayRefund",
@ -239,67 +204,30 @@ export default {
pageNo: 1,
pageSize: 10,
appId: null,
channelId: null,
channelCode: null,
orderId: null,
tradeNo: null,
merchantOrderId: null,
merchantRefundNo: null,
notifyUrl: null,
status: null,
type: null,
payPrice: null,
refundPrice: null,
reason: null,
userIp: null,
merchantRefundId: null,
channelOrderNo: null,
channelRefundNo: null,
channelErrorCode: null,
channelErrorMsg: null,
channelExtras: null,
expireTime: [],
successTime: [],
status: null,
createTime: []
},
//
merchantLoading: false,
//
merchantList: null,
//
appList: null,
//
payChannelCodeDictDatum: getDictDatas(DICT_TYPE.PAY_CHANNEL_CODE),
// 退
payRefundOrderDictDatum: getDictDatas(DICT_TYPE.PAY_REFUND_ORDER_STATUS),
//
payOrderNotifyDictDatum: getDictDatas(DICT_TYPE.PAY_NOTIFY_STATUS),
// 退
refundDetail: JSON.parse(JSON.stringify(defaultRefundDetail)),
refundDetail: {},
};
},
created() {
this.initTime();
this.getList();
this.handleGetMerchantListByName(null);
//
getAppList().then(response => {
this.appList = response.data;
})
},
methods: {
initTime(){
this.queryParams.createTime = [getNowDateTime("00:00:00"), getNowDateTime("23:59:59")];
},
/** 查询列表 */
getList() {
//
let oneMonthTime = 31 * 24 * 3600 * 1000;
if (this.queryParams.createTime == null){
this.initTime();
} else {
let minDateTime = new Date(this.queryParams.createTime[0]).getTime();
let maxDateTime = new Date(this.queryParams.createTime[1]).getTime()
if (maxDateTime - minDateTime > oneMonthTime) {
this.$message.error('时间范围最大为 31 天!');
return false;
}
}
this.loading = true;
//
getRefundPage(this.queryParams).then(response => {
@ -335,26 +263,15 @@ export default {
this.$download.excel(response, '退款订单.xls');
}).catch(() => {});
},
/**
* 根据商户名称模糊匹配商户信息
* @param name 商户名称
*/
handleGetMerchantListByName(name) {
getMerchantListByName(name).then(response => {
this.merchantList = response.data;
this.merchantLoading = false;
});
},
/**
* 查看订单详情
*/
handleQueryDetails(row) {
this.refundDetail = JSON.parse(JSON.stringify(defaultRefundDetail));
this.refundDetail = {};
getRefund(row.id).then(response => {
this.refundDetail = response.data;
this.open = true;
});
},
}
};