增加退款接口
This commit is contained in:
parent
649b7f9bcb
commit
2cb2bd3cb1
|
|
@ -1,18 +1,18 @@
|
|||
package com.mdd.admin.controller.finance;
|
||||
|
||||
import com.mdd.admin.LikeAdminThreadLocal;
|
||||
import com.mdd.admin.service.IFinanceRechargerService;
|
||||
import com.mdd.admin.validate.commons.IdValidate;
|
||||
import com.mdd.admin.validate.commons.PageValidate;
|
||||
import com.mdd.admin.validate.finance.FinanceRechargeSearchValidate;
|
||||
import com.mdd.admin.vo.finance.FinanceRechargeListVo;
|
||||
import com.mdd.common.core.AjaxResult;
|
||||
import com.mdd.common.core.PageResult;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
|
@ -34,8 +34,19 @@ public class FinanceRechargerController {
|
|||
|
||||
@PostMapping("/refund")
|
||||
@ApiOperation("发起退款")
|
||||
public AjaxResult<Object> refund() {
|
||||
iFinanceRechargerService.refund();
|
||||
public AjaxResult<Object> refund(@Validated @RequestBody IdValidate idValidate) {
|
||||
Integer adminId = LikeAdminThreadLocal.getAdminId();
|
||||
|
||||
iFinanceRechargerService.refund(idValidate.getId(), adminId);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@PostMapping("/refundAgain")
|
||||
@ApiModelProperty("重新退款")
|
||||
public AjaxResult<Object> refundAgain(@Validated @RequestBody IdValidate idValidate) {
|
||||
Integer adminId = LikeAdminThreadLocal.getAdminId();
|
||||
|
||||
iFinanceRechargerService.refundAgain(idValidate.getId(), adminId);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,22 @@ public interface IFinanceRechargerService {
|
|||
*/
|
||||
PageResult<FinanceRechargeListVo> list(PageValidate pageValidate, FinanceRechargeSearchValidate searchValidate);
|
||||
|
||||
void refund();
|
||||
/**
|
||||
* 发起退款
|
||||
*
|
||||
* @author fzr
|
||||
* @param orderId 订单ID
|
||||
* @param adminId 管理员ID
|
||||
*/
|
||||
void refund(Integer orderId, Integer adminId);
|
||||
|
||||
/**
|
||||
* 重新退款
|
||||
*
|
||||
* @author fzr
|
||||
* @param recordId 记录ID
|
||||
* @param adminId 管理员ID
|
||||
*/
|
||||
void refundAgain(Integer recordId, Integer adminId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.mdd.admin.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.yulichang.query.MPJQueryWrapper;
|
||||
|
|
@ -10,12 +11,30 @@ import com.mdd.admin.vo.finance.FinanceRechargeListVo;
|
|||
import com.mdd.common.config.GlobalConfig;
|
||||
import com.mdd.common.core.PageResult;
|
||||
import com.mdd.common.entity.RechargeOrder;
|
||||
import com.mdd.common.entity.RefundLog;
|
||||
import com.mdd.common.entity.RefundRecord;
|
||||
import com.mdd.common.entity.user.User;
|
||||
import com.mdd.common.enums.LogMoneyEnum;
|
||||
import com.mdd.common.enums.PaymentEnum;
|
||||
import com.mdd.common.enums.RefundEnum;
|
||||
import com.mdd.common.exception.OperateException;
|
||||
import com.mdd.common.mapper.RechargeOrderMapper;
|
||||
import com.mdd.common.mapper.RefundLogMapper;
|
||||
import com.mdd.common.mapper.RefundRecordMapper;
|
||||
import com.mdd.common.mapper.log.LogMoneyMapper;
|
||||
import com.mdd.common.mapper.user.UserMapper;
|
||||
import com.mdd.common.plugin.wechat.WxPayDriver;
|
||||
import com.mdd.common.plugin.wechat.request.RefundRequestV3;
|
||||
import com.mdd.common.util.AmountUtil;
|
||||
import com.mdd.common.util.StringUtils;
|
||||
import com.mdd.common.util.TimeUtils;
|
||||
import com.mdd.common.util.UrlUtils;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
|
@ -28,6 +47,24 @@ public class FinanceRechargerServiceImpl implements IFinanceRechargerService {
|
|||
@Resource
|
||||
RechargeOrderMapper rechargeOrderMapper;
|
||||
|
||||
@Resource
|
||||
UserMapper userMapper;
|
||||
|
||||
@Resource
|
||||
LogMoneyMapper logMoneyMapper;
|
||||
|
||||
@Resource
|
||||
RefundRecordMapper refundRecordMapper;
|
||||
|
||||
@Resource
|
||||
RefundLogMapper refundLogMapper;
|
||||
|
||||
@Resource
|
||||
DataSourceTransactionManager transactionManager ;
|
||||
|
||||
@Resource
|
||||
TransactionDefinition transactionDefinition;
|
||||
|
||||
/**
|
||||
* 充值记录
|
||||
*
|
||||
|
|
@ -79,10 +116,147 @@ public class FinanceRechargerServiceImpl implements IFinanceRechargerService {
|
|||
|
||||
/**
|
||||
* 发起退款
|
||||
*
|
||||
* @author fzr
|
||||
* @param orderId 订单ID
|
||||
* @param adminId 管理员ID
|
||||
*/
|
||||
@Override
|
||||
public void refund() {
|
||||
public void refund(Integer orderId, Integer adminId) {
|
||||
RechargeOrder rechargeOrder = rechargeOrderMapper.selectById(orderId);
|
||||
|
||||
Assert.notNull(rechargeOrder, "充值订单不存在!");
|
||||
if (!rechargeOrder.getPayStatus().equals(PaymentEnum.OK_PAID.getCode())) {
|
||||
throw new OperateException("当前订单不可退款!");
|
||||
}
|
||||
|
||||
if (rechargeOrder.getRefundStatus().equals(1)) {
|
||||
throw new OperateException("订单已发起退款,退款失败请到退款记录重新退款!");
|
||||
}
|
||||
|
||||
User user = userMapper.selectById(rechargeOrder.getUserId());
|
||||
if (user.getMoney().compareTo(rechargeOrder.getOrderAmount()) < 0) {
|
||||
throw new OperateException("退款失败:用户余额已不足退款金额!");
|
||||
}
|
||||
|
||||
// 开启事务
|
||||
TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
|
||||
|
||||
RefundLog log = null;
|
||||
try {
|
||||
// 标记退款状态
|
||||
rechargeOrder.setRefundStatus(1);
|
||||
rechargeOrderMapper.updateById(rechargeOrder);
|
||||
|
||||
// 更新用户余额
|
||||
user.setMoney(user.getMoney().subtract(rechargeOrder.getOrderAmount()));
|
||||
userMapper.updateById(user);
|
||||
|
||||
// 记录余额日志
|
||||
logMoneyMapper.dec(
|
||||
user.getId(),
|
||||
LogMoneyEnum.UM_DEC_RECHARGE.getCode(),
|
||||
rechargeOrder.getOrderAmount(),
|
||||
rechargeOrder.getId(),
|
||||
rechargeOrder.getOrderSn(),
|
||||
"充值订单退款",
|
||||
null
|
||||
);
|
||||
|
||||
// 生成退款记录
|
||||
String refundSn = refundRecordMapper.randMakeOrderSn("sn");
|
||||
RefundRecord refundRecord = new RefundRecord();
|
||||
refundRecord.setSn(refundSn);
|
||||
refundRecord.setUserId(rechargeOrder.getUserId());
|
||||
refundRecord.setOrderId(rechargeOrder.getId());
|
||||
refundRecord.setOrderSn(rechargeOrder.getOrderSn());
|
||||
refundRecord.setOrderType(RefundEnum.getOrderType(RefundEnum.ORDER_TYPE_RECHARGE.getCode()));
|
||||
refundRecord.setOrderAmount(rechargeOrder.getOrderAmount());
|
||||
refundRecord.setRefundAmount(rechargeOrder.getOrderAmount());
|
||||
refundRecord.setRefundType(RefundEnum.TYPE_ADMIN.getCode());
|
||||
refundRecord.setTransactionId(refundRecord.getTransactionId());
|
||||
refundRecord.setRefundWay(rechargeOrder.getPayWay());
|
||||
refundRecordMapper.insert(refundRecord);
|
||||
|
||||
// 生成退款日志
|
||||
log = new RefundLog();
|
||||
log.setSn(refundLogMapper.randMakeOrderSn("sn"));
|
||||
log.setRecordId(refundRecord.getId());
|
||||
log.setUserId(rechargeOrder.getUserId());
|
||||
log.setHandleId(adminId);
|
||||
log.setOrderAmount(rechargeOrder.getOrderAmount());
|
||||
log.setRefundAmount(refundRecord.getRefundAmount());
|
||||
log.setRefundStatus(RefundEnum.REFUND_ING.getCode());
|
||||
refundLogMapper.insert(log);
|
||||
|
||||
// 发起退款请求
|
||||
RefundRequestV3 requestV3 = new RefundRequestV3();
|
||||
requestV3.setTransactionId(rechargeOrder.getTransactionId());
|
||||
requestV3.setOutTradeNo(rechargeOrder.getOrderSn());
|
||||
requestV3.setOutRefundNo(refundSn);
|
||||
requestV3.setTotalAmount(AmountUtil.yuan2Fen(rechargeOrder.getOrderAmount().toString()));
|
||||
requestV3.setRefundAmount(AmountUtil.yuan2Fen(rechargeOrder.getOrderAmount().toString()));
|
||||
WxPayDriver.refund(requestV3);
|
||||
|
||||
|
||||
log.setRefundStatus(RefundEnum.REFUND_SUCCESS.getCode());
|
||||
refundLogMapper.updateById(log);
|
||||
transactionManager.commit(transactionStatus);
|
||||
} catch (Exception e) {
|
||||
// 事务回滚
|
||||
transactionManager.rollback(transactionStatus);
|
||||
|
||||
if (StringUtils.isNotNull(log)) {
|
||||
log.setRefundStatus(RefundEnum.REFUND_ERROR.getCode());
|
||||
refundLogMapper.updateById(log);
|
||||
}
|
||||
throw new OperateException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新退款
|
||||
*
|
||||
* @author fzr
|
||||
* @param recordId 记录ID
|
||||
* @param adminId 管理员ID
|
||||
*/
|
||||
@Override
|
||||
public void refundAgain(Integer recordId, Integer adminId) {
|
||||
// 开启事务
|
||||
TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
|
||||
|
||||
RefundLog log = null;
|
||||
try {
|
||||
RefundRecord refundRecord = refundRecordMapper.selectById(recordId);
|
||||
RechargeOrder rechargeOrder = rechargeOrderMapper.selectById(refundRecord.getOrderId());
|
||||
|
||||
log = refundLogMapper.selectOne(new QueryWrapper<RefundLog>()
|
||||
.eq("record_id", recordId)
|
||||
.last("limit 1"));
|
||||
|
||||
log.setRefundStatus(RefundEnum.REFUND_ING.getCode());
|
||||
refundLogMapper.updateById(log);
|
||||
|
||||
// 发起退款请求
|
||||
RefundRequestV3 requestV3 = new RefundRequestV3();
|
||||
requestV3.setTransactionId(refundRecord.getTransactionId());
|
||||
requestV3.setOutTradeNo(refundRecord.getOrderSn());
|
||||
requestV3.setOutRefundNo(refundRecord.getSn());
|
||||
requestV3.setTotalAmount(AmountUtil.yuan2Fen(rechargeOrder.getOrderAmount().toString()));
|
||||
requestV3.setRefundAmount(AmountUtil.yuan2Fen(refundRecord.getOrderAmount().toString()));
|
||||
WxPayDriver.refund(requestV3);
|
||||
|
||||
log.setRefundStatus(RefundEnum.REFUND_SUCCESS.getCode());
|
||||
refundLogMapper.updateById(log);
|
||||
transactionManager.commit(transactionStatus);
|
||||
} catch (Exception e) {
|
||||
transactionManager.rollback(transactionStatus);
|
||||
if (StringUtils.isNotNull(log)) {
|
||||
log.setRefundStatus(RefundEnum.REFUND_ERROR.getCode());
|
||||
refundLogMapper.updateById(log);
|
||||
}
|
||||
throw new OperateException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package com.mdd.common.enums;
|
||||
|
||||
public enum RefundEnum {
|
||||
|
||||
// 退款类型
|
||||
TYPE_ADMIN(1, "后台退款"),
|
||||
|
||||
// 退款状态
|
||||
REFUND_ING(0, "退款中"),
|
||||
REFUND_SUCCESS(1, "退款成功"),
|
||||
REFUND_ERROR(2, "退款失败"),
|
||||
|
||||
// 退款订单类型
|
||||
ORDER_TYPE_ORDER(1, "普通订单"),
|
||||
ORDER_TYPE_RECHARGE(2, "充值订单");
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
*/
|
||||
private final int code;
|
||||
private final String msg;
|
||||
RefundEnum(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态码
|
||||
*
|
||||
* @author fzr
|
||||
* @return Long
|
||||
*/
|
||||
public int getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提示
|
||||
*
|
||||
* @author fzr
|
||||
* @return String
|
||||
*/
|
||||
public String getMsg() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码获取Msg
|
||||
*
|
||||
* @author fzr
|
||||
* @param code 类型
|
||||
* @return String
|
||||
*/
|
||||
public static String getOrderType(Integer code){
|
||||
switch (code) {
|
||||
case 1:
|
||||
return "order";
|
||||
case 2:
|
||||
return "recharge";
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
package com.mdd.common.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mdd.common.core.basics.IBaseMapper;
|
||||
import com.mdd.common.entity.RefundLog;
|
||||
import com.mdd.common.entity.RefundRecord;
|
||||
import com.mdd.common.util.TimeUtils;
|
||||
import com.mdd.common.util.ToolUtils;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
|
|
@ -9,4 +13,29 @@ import org.apache.ibatis.annotations.Mapper;
|
|||
*/
|
||||
@Mapper
|
||||
public interface RefundLogMapper extends IBaseMapper<RefundLog> {
|
||||
|
||||
/**
|
||||
* 生成唯一单号
|
||||
*
|
||||
* @author fzr
|
||||
* @param field 字段名
|
||||
* @return String
|
||||
*/
|
||||
default String randMakeOrderSn(String field) {
|
||||
String date = TimeUtils.timestampToDate(System.currentTimeMillis()/1000, "yyyyMMddHHmmss");
|
||||
String sn;
|
||||
while (true) {
|
||||
sn = date + ToolUtils.randomInt(12);
|
||||
RefundLog snModel = this.selectOne(
|
||||
new QueryWrapper<RefundLog>()
|
||||
.select("id")
|
||||
.eq(field, sn)
|
||||
.last("limit 1"));
|
||||
if (snModel == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sn;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package com.mdd.common.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mdd.common.core.basics.IBaseMapper;
|
||||
import com.mdd.common.entity.RechargeOrder;
|
||||
import com.mdd.common.entity.RefundRecord;
|
||||
import com.mdd.common.util.TimeUtils;
|
||||
import com.mdd.common.util.ToolUtils;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
|
|
@ -9,4 +13,29 @@ import org.apache.ibatis.annotations.Mapper;
|
|||
*/
|
||||
@Mapper
|
||||
public interface RefundRecordMapper extends IBaseMapper<RefundRecord> {
|
||||
|
||||
/**
|
||||
* 生成唯一单号
|
||||
*
|
||||
* @author fzr
|
||||
* @param field 字段名
|
||||
* @return String
|
||||
*/
|
||||
default String randMakeOrderSn(String field) {
|
||||
String date = TimeUtils.timestampToDate(System.currentTimeMillis()/1000, "yyyyMMddHHmmss");
|
||||
String sn;
|
||||
while (true) {
|
||||
sn = date + ToolUtils.randomInt(12);
|
||||
RefundRecord snModel = this.selectOne(
|
||||
new QueryWrapper<RefundRecord>()
|
||||
.select("id")
|
||||
.eq(field, sn)
|
||||
.last("limit 1"));
|
||||
if (snModel == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sn;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,18 +115,19 @@ public class WxPayDriver {
|
|||
*/
|
||||
public static WxPayRefundV3Result refund(RefundRequestV3 request) throws WxPayException {
|
||||
WxPayRefundV3Request requestObj = new WxPayRefundV3Request();
|
||||
request.setTransactionId(request.getTransactionId());
|
||||
request.setOutTradeNo(request.getOutRefundNo());
|
||||
request.setOutRefundNo(request.getOutRefundNo());
|
||||
request.setReason(request.getReason());
|
||||
request.setNotifyUrl(request.getNotifyUrl());
|
||||
request.setSubMchid(request.getSubMchid());
|
||||
request.setGoodsDetails(request.getGoodsDetails());
|
||||
requestObj.setTransactionId(request.getTransactionId());
|
||||
requestObj.setOutTradeNo(request.getOutTradeNo());
|
||||
requestObj.setOutRefundNo(request.getOutRefundNo());
|
||||
requestObj.setReason(request.getReason());
|
||||
requestObj.setNotifyUrl(request.getNotifyUrl());
|
||||
requestObj.setSubMchid(request.getSubMchid());
|
||||
requestObj.setGoodsDetails(request.getGoodsDetails());
|
||||
|
||||
WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
|
||||
amount.setRefund(request.getRefundAmount());
|
||||
amount.setTotal(request.getTotalAmount());
|
||||
amount.setCurrency(StringUtils.isEmpty(request.getCurrency()) ? "CNY" : request.getCurrency());
|
||||
requestObj.setAmount(amount);
|
||||
|
||||
return wxPayService.refundV3(requestObj);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,35 +12,35 @@ public class RefundRequestV3 implements Serializable {
|
|||
|
||||
private static final long serialVersionUID = -1L;
|
||||
|
||||
/** 订单流水号 */
|
||||
/** 订单流水号: (必须) */
|
||||
private String transactionId;
|
||||
|
||||
/** 订单单号 */
|
||||
/** 订单单号: (必须) */
|
||||
private String outTradeNo;
|
||||
|
||||
/** 退款单号 */
|
||||
/** 退款单号: (必须) */
|
||||
@SerializedName("out_refund_no")
|
||||
private String outRefundNo;
|
||||
|
||||
/** 退款原因 */
|
||||
private String reason;
|
||||
|
||||
/** 通知接口 */
|
||||
private String notifyUrl;
|
||||
|
||||
/** 退款金额 */
|
||||
/** 退款金额 : (必须)*/
|
||||
private Integer refundAmount;
|
||||
|
||||
/** 订单总额 */
|
||||
/** 订单总额: (必须) */
|
||||
private Integer totalAmount;
|
||||
|
||||
/** 退款币种 */
|
||||
/** 退款原因: 非必须 */
|
||||
private String reason;
|
||||
|
||||
/** 通知接口: 非必须 */
|
||||
private String notifyUrl;
|
||||
|
||||
/** 退款币种: 非必须 */
|
||||
private String currency;
|
||||
|
||||
/** 商品信息 */
|
||||
/** 商品信息: 非必须 */
|
||||
private List<WxPayRefundV3Request.GoodsDetail> goodsDetails;
|
||||
|
||||
/** 子商户号 */
|
||||
/** 子商户号: 非必须 */
|
||||
private String subMchid;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public class PayServiceImpl implements IPayService {
|
|||
if (StringUtils.isNotNull(rechargeOrder)) {
|
||||
orderExist = true;
|
||||
vo.setPayStatus(rechargeOrder.getPayStatus());
|
||||
vo.setPayWay(PaymentEnum.getMsgByCode(rechargeOrder.getPayWay()));
|
||||
vo.setPayWay(PaymentEnum.getPayWayMsg(rechargeOrder.getPayWay()));
|
||||
vo.setOrderId(rechargeOrder.getId());
|
||||
vo.setOrderSn(rechargeOrder.getOrderSn());
|
||||
vo.setOrderAmount(rechargeOrder.getOrderAmount());
|
||||
|
|
|
|||
Loading…
Reference in New Issue