This commit is contained in:
zt
2025-06-17 15:49:19 +08:00
parent a9a2460a0e
commit 49e74b91c5
10 changed files with 138 additions and 79 deletions

View File

@ -94,6 +94,7 @@ public interface ErrorCodeConstants {
ErrorCode ORDER_NOT_COMPLETE = new ErrorCode(1_007_902_002, "还有订单尚未结算");
ErrorCode WX_ACCOUNT_NO = new ErrorCode(1_007_902_002, "微信充值金额不足");
ErrorCode REFUND_NOT_COMPLETE = new ErrorCode(1_007_902_002, "还有退款正在进行");
ErrorCode REFUND_MOBILE_ERROR = new ErrorCode(1_007_902_002, "手机号错误");
ErrorCode DIVIDE_COMPANY_NOT_EXISTS = new ErrorCode(1_007_903_001, "分账公司不存在");

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.pay.controller.app.divide;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.DrawMoneyVO;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.RefundMoneyVO;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.ActivityRefundMoney;
import cn.iocoder.yudao.module.pay.service.wxprofitsharing.WxProfitsharingService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -31,10 +31,10 @@ public class AppDivideController {
return success(profitsharingService.drawMoney(drawMoneyVO));
}
@PostMapping("/refundMoney")
@Operation(summary = "退款")
public CommonResult<Boolean> refundMoney(@RequestBody RefundMoneyVO refundMoney) {
return success(profitsharingService.refundMoney(refundMoney));
@PostMapping("/activityRefundMoney")
@Operation(summary = "活动退款")
public CommonResult<Boolean> activityRefundMoney(@RequestBody ActivityRefundMoney refundMoney) {
return success(profitsharingService.activityRefundMoney(refundMoney));
}
}

View File

@ -5,11 +5,14 @@ import lombok.Data;
@Schema(description = "管理后台 - 分账单新增/修改 Request VO")
@Data
public class RefundMoneyVO {
public class ActivityRefundMoney {
@Schema(description = "用户编号")
private Long userId;
@Schema(description = "订单编号")
private Long orderId;
@Schema(description = "总金额,单位:分")
//@NotNull(message = "总金额,单位:分不能为空")
private Integer totalPrice;
@ -18,11 +21,8 @@ public class RefundMoneyVO {
*/
private String channelUserId;
/**
* 1-用户退款 2-商家退款
*/
private String type;
private String transactionId;
@Schema(description = "电话号码")
private String mobile;
}

View File

@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.pay.controller.admin.wxprofitsharing.vo.WxProfitsharingPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.wxprofitsharing.vo.WxProfitsharingSaveReqVO;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.DrawMoneyVO;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.RefundMoneyVO;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.ActivityRefundMoney;
import cn.iocoder.yudao.module.pay.dal.dataobject.wxprofitsharing.WxProfitsharingDO;
import javax.validation.Valid;
@ -77,5 +77,5 @@ public interface WxProfitsharingService {
/**
* 活动退款
*/
Boolean refundMoney(RefundMoneyVO refundMoney);
void activityRefundMoney(ActivityRefundMoney refundMoney);
}

View File

@ -15,10 +15,12 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.divide.PayDivideUnifiedDto
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.divide.PayDivideRefundStatusRespEnum;
import cn.iocoder.yudao.module.member.api.activitypay.ActivityApi;
import cn.iocoder.yudao.module.member.api.activitypay.dto.ActivityPayRespDTO;
import cn.iocoder.yudao.module.pay.controller.admin.wxprofitsharing.vo.WxProfitsharingPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.wxprofitsharing.vo.WxProfitsharingSaveReqVO;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.ActivityRefundMoney;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.DrawMoneyVO;
import cn.iocoder.yudao.module.pay.controller.app.divide.vo.RefundMoneyVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.dividecompany.DivideCompanyDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.refundlog.PayRefundLogDO;
@ -92,6 +94,8 @@ public class WxProfitsharingServiceImpl implements WxProfitsharingService {
private WxRefundMapper wxRefundMapper;
@Resource
private PayRefundLogMapper payRefundLogMapper;
@Resource
private ActivityApi activityApi;
@Override
public Long createWxProfitsharing(WxProfitsharingSaveReqVO createReqVO) {
@ -847,7 +851,7 @@ public class WxProfitsharingServiceImpl implements WxProfitsharingService {
}
@Override
public Boolean refundMoney(RefundMoneyVO refundMoney) {
public void activityRefundMoney(ActivityRefundMoney refundMoney) {
//判断用户是否正在退款
List<WxRefundDO> refundDOList1 = wxRefundMapper.selectList(Wrappers.<WxRefundDO>lambdaQuery()
@ -857,91 +861,80 @@ public class WxProfitsharingServiceImpl implements WxProfitsharingService {
throw new ServiceException(REFUND_NOT_COMPLETE);
}
//判断是否有金额可退款
int money = refundMoney.getTotalPrice();
//判断退款金额是否正确
ActivityPayRespDTO activityPay = activityApi.getActivityPay(refundMoney.getOrderId());
if (activityPay == null) {
throw new ServiceException(new ErrorCode(1_007_902_002, "未查询到付款订单"));
}
if (!activityPay.getMobile().equals(refundMoney.getMobile())) {
throw new ServiceException(REFUND_MOBILE_ERROR);
}
int money = activityPay.getPrice().multiply(new BigDecimal(100)).intValue();
//交易时间超过一年的订单无法提交退款(按支付成功时间+365天计算
LocalDateTime now = LocalDateTime.now(); // 获取当前时间
LocalDateTime threeYearsAgo = now.minusDays(364);
//查询最近的充值订单,时间倒序退款
List<WxOrderDO> wxOrderDOList = wxOrderMapper.selectList(Wrappers.<WxOrderDO>lambdaQuery()
.eq(WxOrderDO::getOpenId, refundMoney.getChannelUserId())
.eq(WxOrderDO::getTransactionId, refundMoney.getTransactionId())
.gt(WxOrderDO::getRefundPrice, 0)
.ge(WxOrderDO::getCreateTime, threeYearsAgo)
.orderByDesc(WxOrderDO::getCreateTime));
if(wxOrderDOList.isEmpty()){
throw new ServiceException(new ErrorCode(1_007_902_002, "未查询到付款订单"));
LocalDateTime oneYearAgo = now.minusDays(364);
if (activityPay.getCreateTime().isBefore(oneYearAgo)) {
throw new ServiceException(new ErrorCode(1_007_902_002, "订单已超退款时限"));
}
Map<Long, WxOrderDO> orderMap = wxOrderDOList.stream().collect(Collectors.toMap(WxOrderDO::getId, vo -> vo));
//筛选出未分账的订单
List<WxOrderDO> unDivideList = wxOrderDOList.stream().filter(vo -> vo.getRefundPrice().equals(vo.getProfitsharingPrice())).collect(Collectors.toList());
//筛选出已分账的订单
List<WxOrderDO> divideList = wxOrderDOList.stream().filter(vo -> !vo.getRefundPrice().equals(vo.getProfitsharingPrice())).collect(Collectors.toList());
//筛选出分账完的订单
List<WxOrderDO> divideCpList = divideList.stream().filter(vo -> vo.getProfitsharingPrice() == 0).collect(Collectors.toList());
//剩下的是未分账完的订单
List<WxOrderDO> divideUnCpList = divideList.stream().filter(vo -> vo.getProfitsharingPrice() != 0).collect(Collectors.toList());
//查询充值订单
WxOrderDO wxOrderDO = wxOrderMapper.selectOne(Wrappers.<WxOrderDO>lambdaQuery()
.eq(WxOrderDO::getOpenId, refundMoney.getChannelUserId())
.eq(WxOrderDO::getTransactionId, activityPay.getTransactionId())
.last("limit 1"));
if (wxOrderDO == null) {
throw new ServiceException(new ErrorCode(1_007_902_002, "充值订单不存在"));
}
//生成退款订单
List<WxRefundDO> refundDOList = createRefund(unDivideList, divideCpList, divideUnCpList, money, refundMoney.getUserId());
WxRefundDO refundDO = createActivityRefund(wxOrderDO, money, refundMoney.getUserId());
int failNum = 0;
//调用微信退款接口
if (CollectionUtil.isNotEmpty(refundDOList)) {
for (WxRefundDO wxRefundDO : refundDOList) {
WxOrderDO wxOrderDO = orderMap.get(wxRefundDO.getPayWxOrderId());
PayChannelDO channel = channelService.validPayChannel(wxOrderDO.getChannelId());
PayChannelDO channel = channelService.validPayChannel(wxOrderDO.getChannelId());
PayClient client = channelService.getPayClient(wxOrderDO.getChannelId());
PayRefundUnifiedReqDTO payRefundUnifiedReqDTO = new PayRefundUnifiedReqDTO();
payRefundUnifiedReqDTO.setTransactionId(activityPay.getTransactionId())
.setReason("预定退款")
.setRefundPrice(refundDO.getTotalPrice())
.setOutRefundNo(refundDO.getOutRefundNo())
.setPayPrice(refundDO.getTotalPrice())
.setNotifyUrl(genChannelRefundNotifyUrlActivity(channel,"1"));
PayRefundRespDTO payRefundRespDTO = client.unifiedRefund(payRefundUnifiedReqDTO);
PayClient client = channelService.getPayClient(wxOrderDO.getChannelId());
PayRefundUnifiedReqDTO payRefundUnifiedReqDTO = new PayRefundUnifiedReqDTO();
payRefundUnifiedReqDTO.setTransactionId(wxOrderDO.getTransactionId())
.setReason("预定退款")
.setRefundPrice(wxRefundDO.getTotalPrice())
.setOutRefundNo(wxRefundDO.getOutRefundNo())
.setPayPrice(wxOrderDO.getTotalPrice())
.setNotifyUrl(genChannelRefundNotifyUrl(channel));
PayRefundRespDTO payRefundRespDTO = client.unifiedRefund(payRefundUnifiedReqDTO);
String channelRefundNo = payRefundRespDTO.getChannelRefundNo();
wxRefundDO.setRefundId(channelRefundNo);
if (cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum.WAITING.getStatus().equals(payRefundRespDTO.getStatus())) {
wxRefundDO.setStatus(PayDivideRefundStatusRespEnum.PROCESSING.getStatus());
} else if (cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum.SUCCESS.getStatus().equals(payRefundRespDTO.getStatus())) {
wxRefundDO.setStatus(PayDivideRefundStatusRespEnum.SUCCESS.getStatus());
} else {
failNum++;
wxRefundDO.setStatus(PayDivideRefundStatusRespEnum.ABNORMAL.getStatus());
}
wxRefundMapper.insert(wxRefundDO);
}
String channelRefundNo = payRefundRespDTO.getChannelRefundNo();
refundDO.setRefundId(channelRefundNo);
if (cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum.WAITING.getStatus().equals(payRefundRespDTO.getStatus())) {
refundDO.setStatus(PayDivideRefundStatusRespEnum.PROCESSING.getStatus());
} else if (cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum.SUCCESS.getStatus().equals(payRefundRespDTO.getStatus())) {
refundDO.setStatus(PayDivideRefundStatusRespEnum.SUCCESS.getStatus());
} else {
refundDO.setStatus(PayDivideRefundStatusRespEnum.ABNORMAL.getStatus());
}
return failNum <= 0;
wxRefundMapper.insert(refundDO);
}
public WxRefundDO createRefundOne(WxOrderDO wxOrderDO, int money, Long userId) {
public WxRefundDO createActivityRefund(WxOrderDO wxOrderDO, int money, Long userId) {
//退款订单
List<WxRefundDO> backList = new ArrayList<>();
WxRefundDO wxRefundDO = new WxRefundDO();
wxRefundDO.setPayWxOrderId(wxOrderDO.getId());
wxRefundDO.setUserId(userId);
wxRefundDO.setOutRefundNo(noRedisDAO.generate(payProperties.getRefundNoPrefix()));
wxRefundDO.setTotalPrice(money);
String jsonString = JsonUtils.toJsonString(wxOrderDO);
divideRedisTemplate.opsForValue().set("RA" + wxOrderDO.getId(), jsonString);
return wxRefundDO;
}
private String genChannelRefundNotifyUrlActivity(PayChannelDO channel,String type) {
if("1".equals(type)){
return payProperties.getRefundNotifyUrl() + "/" + channel.getId();
}
return payProperties.getRefundNotifyUrl() + "/" + channel.getId();
}
}