reactor:【PAY 支付】优化退款回调接口,增加 merchantRefundId 退款编号参数
reactor:【MALL 商城】售后退款时,基于回调处理
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.trade.controller.admin.aftersale;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
@@ -15,10 +16,12 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||
import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService;
|
||||
import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -46,6 +49,8 @@ public class AfterSaleController {
|
||||
@Resource
|
||||
private TradeOrderQueryService tradeOrderQueryService;
|
||||
@Resource
|
||||
private TradeOrderUpdateService tradeOrderUpdateService;
|
||||
@Resource
|
||||
private AfterSaleLogService afterSaleLogService;
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
@@ -133,11 +138,19 @@ public class AfterSaleController {
|
||||
|
||||
@PostMapping("/update-refunded")
|
||||
@Operation(summary = "更新售后订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
|
||||
@PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现
|
||||
public CommonResult<Boolean> updateAfterRefund(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
|
||||
// 目前业务逻辑,不需要做任何事情
|
||||
// 当然,退款会有小概率会失败的情况,可以监控失败状态,进行告警
|
||||
@PermitAll // 无需登录,安全由 AfterSaleService 内部校验实现
|
||||
public CommonResult<Boolean> updateAfterSaleRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
|
||||
log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO);
|
||||
if (StrUtil.startWithAny(notifyReqDTO.getMerchantRefundId(), "order-")) {
|
||||
tradeOrderUpdateService.updatePaidOrderRefunded(
|
||||
Long.parseLong(notifyReqDTO.getMerchantRefundId()),
|
||||
notifyReqDTO.getPayRefundId());
|
||||
} else {
|
||||
afterSaleService.updateAfterSaleRefunded(
|
||||
Long.parseLong(notifyReqDTO.getMerchantRefundId()),
|
||||
Long.parseLong(notifyReqDTO.getMerchantOrderId()),
|
||||
notifyReqDTO.getPayRefundId());
|
||||
}
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ public class BrokerageWithdrawController {
|
||||
public CommonResult<Boolean> updateBrokerageWithdrawTransferred(@RequestBody PayTransferNotifyReqDTO notifyReqDTO) {
|
||||
log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO);
|
||||
brokerageWithdrawService.updateBrokerageWithdrawTransferred(
|
||||
Long.parseLong(notifyReqDTO.getMerchantOrderId()), notifyReqDTO.getPayTransferId());
|
||||
Long.parseLong(notifyReqDTO.getMerchantTransferId()), notifyReqDTO.getPayTransferId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
package cn.iocoder.yudao.module.trade.framework.aftersale.core.aop;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO;
|
||||
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations.AfterSaleLog;
|
||||
import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService;
|
||||
import cn.iocoder.yudao.module.trade.service.aftersale.bo.AfterSaleLogCreateReqBO;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
@@ -50,6 +52,10 @@ public class AfterSaleLogAspect {
|
||||
* 操作后的状态
|
||||
*/
|
||||
private static final ThreadLocal<Integer> AFTER_STATUS = new ThreadLocal<>();
|
||||
/**
|
||||
* 操作类型(仅“动态场景”需要使用)
|
||||
*/
|
||||
private static final ThreadLocal<AfterSaleOperateTypeEnum> OPERATE_TYPE = new ThreadLocal<>();
|
||||
/**
|
||||
* 拓展参数 Map,用于格式化操作内容
|
||||
*/
|
||||
@@ -69,6 +75,7 @@ public class AfterSaleLogAspect {
|
||||
if (afterSaleId == null) { // 如果未设置,只有注解,说明不需要记录日志
|
||||
return;
|
||||
}
|
||||
AfterSaleOperateTypeEnum operateType = ObjUtil.defaultIfNull(OPERATE_TYPE.get(), afterSaleLog.operateType());
|
||||
Integer beforeStatus = BEFORE_STATUS.get();
|
||||
Integer afterStatus = AFTER_STATUS.get();
|
||||
Map<String, Object> exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap());
|
||||
@@ -78,7 +85,7 @@ public class AfterSaleLogAspect {
|
||||
AfterSaleLogCreateReqBO createBO = new AfterSaleLogCreateReqBO()
|
||||
.setUserId(userId).setUserType(userType)
|
||||
.setAfterSaleId(afterSaleId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus)
|
||||
.setOperateType(afterSaleLog.operateType().getType()).setContent(content);
|
||||
.setOperateType(operateType.getType()).setContent(content);
|
||||
afterSaleLogService.createAfterSaleLog(createBO);
|
||||
} catch (Exception exception) {
|
||||
log.error("[doAfterReturning][afterSaleLog({}) 日志记录错误]", toJsonString(afterSaleLog), exception);
|
||||
@@ -116,6 +123,10 @@ public class AfterSaleLogAspect {
|
||||
EXTS.set(exts);
|
||||
}
|
||||
|
||||
public static void setAfterSaleOperateType(AfterSaleOperateTypeEnum operateType) {
|
||||
OPERATE_TYPE.set(operateType);
|
||||
}
|
||||
|
||||
public static void setUserInfo(Long userId, Integer userType) {
|
||||
USER_ID.set(userId);
|
||||
USER_TYPE.set(userType);
|
||||
@@ -127,6 +138,7 @@ public class AfterSaleLogAspect {
|
||||
AFTER_SALE_ID.remove();
|
||||
BEFORE_STATUS.remove();
|
||||
AFTER_STATUS.remove();
|
||||
OPERATE_TYPE.remove();
|
||||
EXTS.remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.trade.framework.aftersale.core.utils;
|
||||
|
||||
|
||||
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.framework.aftersale.core.aop.AfterSaleLogAspect;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -13,6 +14,10 @@ import java.util.Map;
|
||||
*/
|
||||
public class AfterSaleLogUtils {
|
||||
|
||||
public static void setAfterSaleOperateType(AfterSaleOperateTypeEnum operateType) {
|
||||
AfterSaleLogAspect.setAfterSaleOperateType(operateType);
|
||||
}
|
||||
|
||||
public static void setAfterSaleInfo(Long id, Integer beforeStatus, Integer afterStatus) {
|
||||
setAfterSaleInfo(id, beforeStatus, afterStatus, null);
|
||||
}
|
||||
|
||||
@@ -108,6 +108,15 @@ public interface AfterSaleService {
|
||||
*/
|
||||
void refundAfterSale(Long userId, String userIp, Long id);
|
||||
|
||||
/**
|
||||
* 更新售后订单为已退款
|
||||
*
|
||||
* @param id 售后编号
|
||||
* @param orderId 订单编号
|
||||
* @param payRefundId 支付退款编号
|
||||
*/
|
||||
void updateAfterSaleRefunded(Long id, Long orderId, Long payRefundId);
|
||||
|
||||
/**
|
||||
* 【会员】取消售后
|
||||
*
|
||||
|
||||
@@ -7,6 +7,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
|
||||
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.enums.refund.PayRefundStatusEnum;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
||||
@@ -41,13 +43,12 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
@@ -184,8 +185,6 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
// 记录售后日志
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), null,
|
||||
AfterSaleStatusEnum.APPLY.getStatus());
|
||||
|
||||
// TODO 发送售后消息
|
||||
return afterSale;
|
||||
}
|
||||
|
||||
@@ -206,8 +205,6 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
|
||||
// 记录售后日志
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus);
|
||||
|
||||
// TODO 发送售后消息
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,8 +223,6 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
// 记录售后日志
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus);
|
||||
|
||||
// TODO 发送售后消息
|
||||
|
||||
// 更新交易订单项的售后状态为【未申请】
|
||||
tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId());
|
||||
}
|
||||
@@ -281,8 +276,6 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(),
|
||||
MapUtil.<String, Object>builder().put("deliveryName", express.getName())
|
||||
.put("logisticsNo", deliveryReqVO.getLogisticsNo()).build());
|
||||
|
||||
// TODO 发送售后消息
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -299,8 +292,6 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
// 记录售后日志
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
|
||||
AfterSaleStatusEnum.WAIT_REFUND.getStatus());
|
||||
|
||||
// TODO 发送售后消息
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -326,8 +317,6 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
AfterSaleStatusEnum.SELLER_REFUSE.getStatus(),
|
||||
MapUtil.of("reason", refuseReqVO.getRefuseMemo()));
|
||||
|
||||
// TODO 发送售后消息
|
||||
|
||||
// 更新交易订单项的售后状态为【未申请】
|
||||
tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId());
|
||||
}
|
||||
@@ -365,33 +354,90 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
// 发起退款单。注意,需要在事务提交后,再进行发起,避免重复发起
|
||||
createPayRefund(userIp, afterSale);
|
||||
|
||||
// 更新售后单的状态为【已完成】
|
||||
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), new AfterSaleDO()
|
||||
.setStatus(AfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now()));
|
||||
|
||||
// 记录售后日志
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
|
||||
AfterSaleStatusEnum.COMPLETE.getStatus());
|
||||
|
||||
// TODO 发送售后消息
|
||||
|
||||
// 更新交易订单项的售后状态为【已完成】
|
||||
tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice());
|
||||
afterSale.getStatus()); // 特殊:这里状态不变,而是最终 updateAfterSaleRefunded 处理!!!
|
||||
}
|
||||
|
||||
private void createPayRefund(String userIp, AfterSaleDO afterSale) {
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
// 创建退款单
|
||||
PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties)
|
||||
.setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));
|
||||
Long payRefundId = payRefundApi.createRefund(createReqDTO);
|
||||
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
// 创建退款单
|
||||
PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties)
|
||||
.setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));
|
||||
Long payRefundId = payRefundApi.createRefund(createReqDTO);
|
||||
// 更新售后单的退款单号
|
||||
tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));
|
||||
}
|
||||
});
|
||||
// 更新售后单的退款单号
|
||||
tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.SYSTEM_REFUND_SUCCESS)
|
||||
public void updateAfterSaleRefunded(Long id, Long orderId, Long payRefundId) {
|
||||
// 1. 校验售后单的状态,并状态待退款
|
||||
AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
|
||||
if (afterSale == null) {
|
||||
throw exception(AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.WAIT_REFUND.getStatus())) {
|
||||
throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND);
|
||||
}
|
||||
|
||||
// 2. 校验退款单
|
||||
PayRefundRespDTO payRefund = validatePayRefund(afterSale, payRefundId);
|
||||
|
||||
// 3. 处理退款结果
|
||||
if (PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
|
||||
// 【情况一:退款成功】
|
||||
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), new AfterSaleDO()
|
||||
.setStatus(AfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now()));
|
||||
|
||||
// 记录售后日志
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), AfterSaleStatusEnum.COMPLETE.getStatus());
|
||||
|
||||
// 更新交易订单项的售后状态为【已完成】
|
||||
tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice());
|
||||
// 【情况二:退款失败】
|
||||
} else if (PayRefundStatusEnum.isFailure(payRefund.getStatus())) {
|
||||
// 记录售后日志
|
||||
AfterSaleLogUtils.setAfterSaleOperateType(AfterSaleOperateTypeEnum.SYSTEM_REFUND_FAIL);
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), afterSale.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验退款单的合法性
|
||||
*
|
||||
* @param afterSale 售后单
|
||||
* @param payRefundId 退款单编号
|
||||
* @return 退款单
|
||||
*/
|
||||
private PayRefundRespDTO validatePayRefund(AfterSaleDO afterSale, Long payRefundId) {
|
||||
// 1. 校验退款单是否存在
|
||||
PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
|
||||
if (payRefund == null) {
|
||||
log.error("[validatePayRefund][afterSale({}) payRefund({}) 不存在,请进行处理!]", afterSale.getId(), payRefundId);
|
||||
throw exception(AFTER_SALE_REFUND_FAIL_REFUND_NOT_FOUND);
|
||||
}
|
||||
// 2.1 校验退款单无退款结果(成功、失败)
|
||||
if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())
|
||||
&& !PayRefundStatusEnum.isFailure(payRefund.getStatus())) {
|
||||
log.error("[validatePayRefund][afterSale({}) payRefund({}) 无退款结果,请进行处理!payRefund 数据是:{}]",
|
||||
afterSale.getId(), payRefundId, toJsonString(payRefund));
|
||||
throw exception(AFTER_SALE_REFUND_FAIL_REFUND_NOT_SUCCESS_OR_FAILURE);
|
||||
}
|
||||
// 2.2 校验退款金额一致
|
||||
if (ObjectUtil.notEqual(payRefund.getRefundPrice(), afterSale.getRefundPrice())) {
|
||||
log.error("[validatePayRefund][afterSale({}) payRefund({}) 退款金额不匹配,请进行处理!afterSale 数据是:{},payRefund 数据是:{}]",
|
||||
afterSale.getId(), payRefundId, toJsonString(afterSale), toJsonString(payRefund));
|
||||
throw exception(AFTER_SALE_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
|
||||
}
|
||||
// 2.3 校验退款订单匹配(二次)
|
||||
if (ObjectUtil.notEqual(payRefund.getMerchantRefundId(), afterSale.getId().toString())) {
|
||||
log.error("[validatePayRefund][afterSale({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]",
|
||||
afterSale.getId(), payRefundId, toJsonString(payRefund));
|
||||
throw exception(AFTER_SALE_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
|
||||
}
|
||||
return payRefund;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -417,8 +463,6 @@ public class AfterSaleServiceImpl implements AfterSaleService {
|
||||
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
|
||||
AfterSaleStatusEnum.BUYER_CANCEL.getStatus());
|
||||
|
||||
// TODO 发送售后消息
|
||||
|
||||
// 更新交易订单项的售后状态为【未申请】
|
||||
tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId());
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@ import cn.iocoder.yudao.module.pay.api.wallet.PayWalletApi;
|
||||
import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.enums.PayChannelEnum;
|
||||
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
|
||||
import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
|
||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO;
|
||||
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO;
|
||||
import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert;
|
||||
@@ -71,8 +68,6 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
|
||||
@Resource
|
||||
private PayTransferApi payTransferApi;
|
||||
@Resource
|
||||
private SocialUserApi socialUserApi;
|
||||
@Resource
|
||||
private PayWalletApi payWalletApi;
|
||||
|
||||
@Resource
|
||||
@@ -140,13 +135,8 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
|
||||
if (Objects.equal(withdraw.getType(), BrokerageWithdrawTypeEnum.ALIPAY_API.getType())) {
|
||||
channelCode = PayChannelEnum.ALIPAY_PC.getCode();
|
||||
} else if (Objects.equal(withdraw.getType(), BrokerageWithdrawTypeEnum.WECHAT_API.getType())) {
|
||||
SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(
|
||||
UserTypeEnum.MEMBER.getValue(), withdraw.getUserId(), SocialTypeEnum.WECHAT_MINI_PROGRAM.getType());
|
||||
if (socialUser == null) {
|
||||
throw exception(BROKERAGE_WITHDRAW_TRANSFER_FAIL_WECHAT_NOT_BIND);
|
||||
}
|
||||
channelCode = PayChannelEnum.WX_LITE.getCode();
|
||||
userAccount = socialUser.getOpenid();
|
||||
userAccount = withdraw.getUserAccount();
|
||||
// 特殊:微信需要有报备信息
|
||||
channelExtras = PayTransferCreateReqDTO.buildWeiXinChannelExtra1000("佣金提现", "佣金提现");
|
||||
} else if (Objects.equal(withdraw.getType(), BrokerageWithdrawTypeEnum.WALLET.getType())) {
|
||||
@@ -158,7 +148,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
|
||||
// 1.2 构建请求
|
||||
PayTransferCreateReqDTO transferReqDTO = new PayTransferCreateReqDTO()
|
||||
.setAppKey(tradeOrderProperties.getPayAppKey()).setChannelCode(channelCode)
|
||||
.setMerchantOrderId(withdraw.getId().toString()).setSubject("佣金提现").setPrice(withdraw.getPrice())
|
||||
.setMerchantTransferId(withdraw.getId().toString()).setSubject("佣金提现").setPrice(withdraw.getPrice())
|
||||
.setUserAccount(userAccount).setUserName(userName).setUserIp(getClientIP())
|
||||
.setChannelExtras(channelExtras);
|
||||
// 1.3 发起请求
|
||||
@@ -293,7 +283,7 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
|
||||
throw exception(BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_PRICE_NOT_MATCH);
|
||||
}
|
||||
// 2.3 校验转账订单匹配
|
||||
if (ObjectUtil.notEqual(payTransfer.getMerchantOrderId(), withdraw.getId().toString())) {
|
||||
if (ObjectUtil.notEqual(payTransfer.getMerchantTransferId(), withdraw.getId().toString())) {
|
||||
log.error("[validateBrokerageTransferStatusCanUpdate][withdraw({}) 转账单不匹配({}),请进行处理!payTransfer 数据是:{}]",
|
||||
withdraw.getId(), payTransferId, JsonUtils.toJsonString(payTransfer));
|
||||
throw exception(BROKERAGE_WITHDRAW_UPDATE_STATUS_FAIL_PAY_MERCHANT_EXISTS);
|
||||
|
||||
@@ -209,6 +209,14 @@ public interface TradeOrderUpdateService {
|
||||
*/
|
||||
void cancelPaidOrder(Long userId, Long orderId, Integer cancelType);
|
||||
|
||||
/**
|
||||
* 取消支付订单的退款回调
|
||||
*
|
||||
* @param id 订单编号
|
||||
* @param payRefundId 支付退款编号
|
||||
*/
|
||||
void updatePaidOrderRefunded(Long id, Long payRefundId);
|
||||
|
||||
/**
|
||||
* 更新下单赠送的优惠券编号到订单
|
||||
*
|
||||
|
||||
@@ -20,7 +20,9 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
|
||||
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.enums.order.PayOrderStatusEnum;
|
||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
|
||||
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
|
||||
@@ -938,10 +940,24 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
.setAppKey(tradeOrderProperties.getPayAppKey()) // 支付应用
|
||||
.setUserIp(NetUtil.getLocalhostStr()) // 使用本机 IP,因为是服务器发起退款的
|
||||
.setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
|
||||
.setMerchantRefundId(String.valueOf(order.getId()))
|
||||
// 特殊:因为订单支持 AfterSale 单个售后退款,也支持整单退款,所以需要通过 order- 进行下区分
|
||||
// 具体可见 AfterSaleController 的 updateAfterSaleRefunded 方法
|
||||
.setMerchantRefundId("order-" + order.getId())
|
||||
.setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice())); // 价格信息
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePaidOrderRefunded(Long id, Long payRefundId) {
|
||||
PayRefundRespDTO payRefund = payRefundApi.getRefund(payRefundId);
|
||||
if (payRefund == null) {
|
||||
throw exception(ORDER_UPDATE_PAID_ORDER_REFUNDED_FAIL_REFUND_NOT_FOUND);
|
||||
}
|
||||
// 特殊:因为在 cancelPaidOrder 已经进行订单的取消,所以这里必须退款成功!!!
|
||||
if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
|
||||
throw exception(ORDER_UPDATE_PAID_ORDER_REFUNDED_FAIL_REFUND_STATUS_NOT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOrderGiveCouponIds(Long userId, Long orderId, List<Long> giveCouponIds) {
|
||||
// 1. 检验订单存在
|
||||
|
||||
Reference in New Issue
Block a user