package cn.iocoder.yudao.module.trade.service.aftersale;
|
|
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
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;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleDisagreeReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSalePageReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.AfterSaleRefuseReqVO;
|
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO;
|
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleDeliveryReqVO;
|
import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSalePageReqVO;
|
import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.AfterSaleMapper;
|
import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
|
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum;
|
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
|
import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
import cn.iocoder.yudao.module.trade.framework.aftersale.core.annotations.AfterSaleLog;
|
import cn.iocoder.yudao.module.trade.framework.aftersale.core.utils.AfterSaleLogUtils;
|
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
|
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
import jakarta.annotation.Resource;
|
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.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.*;
|
|
/**
|
* 售后订单 Service 实现类
|
*
|
* @author 芋道源码
|
*/
|
@Slf4j
|
@Service
|
@Validated
|
public class AfterSaleServiceImpl implements AfterSaleService {
|
|
@Resource
|
@Lazy // 延迟加载,避免循环依赖
|
private TradeOrderUpdateService tradeOrderUpdateService;
|
@Resource
|
private TradeOrderQueryService tradeOrderQueryService;
|
@Resource
|
private DeliveryExpressService deliveryExpressService;
|
|
@Resource
|
private AfterSaleMapper tradeAfterSaleMapper;
|
@Resource
|
private TradeNoRedisDAO tradeNoRedisDAO;
|
|
@Resource
|
private PayRefundApi payRefundApi;
|
@Resource
|
private CombinationRecordApi combinationRecordApi;
|
|
@Resource
|
private TradeOrderProperties tradeOrderProperties;
|
|
@Override
|
public PageResult<AfterSaleDO> getAfterSalePage(AfterSalePageReqVO pageReqVO) {
|
return tradeAfterSaleMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public PageResult<AfterSaleDO> getAfterSalePage(Long userId, AppAfterSalePageReqVO pageReqVO) {
|
return tradeAfterSaleMapper.selectPage(userId, pageReqVO);
|
}
|
|
@Override
|
public AfterSaleDO getAfterSale(Long userId, Long id) {
|
return tradeAfterSaleMapper.selectByIdAndUserId(id, userId);
|
}
|
|
@Override
|
public AfterSaleDO getAfterSale(Long id) {
|
return tradeAfterSaleMapper.selectById(id);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CREATE)
|
public Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO) {
|
// 第一步,前置校验
|
TradeOrderItemDO tradeOrderItem = validateOrderItemApplicable(userId, createReqVO);
|
|
// 第二步,存储售后订单
|
AfterSaleDO afterSale = createAfterSale(createReqVO, tradeOrderItem);
|
return afterSale.getId();
|
}
|
|
/**
|
* 校验交易订单项是否可以申请售后
|
*
|
* @param userId 用户编号
|
* @param createReqVO 售后创建信息
|
* @return 交易订单项
|
*/
|
private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppAfterSaleCreateReqVO createReqVO) {
|
// 校验订单项存在
|
TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(userId, createReqVO.getOrderItemId());
|
if (orderItem == null) {
|
throw exception(ORDER_ITEM_NOT_FOUND);
|
}
|
// 已申请售后,不允许再发起售后申请
|
if (!TradeOrderItemAfterSaleStatusEnum.isNone(orderItem.getAfterSaleStatus())) {
|
throw exception(AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED);
|
}
|
// 申请的退款金额,不能超过商品的价格
|
if (createReqVO.getRefundPrice() > orderItem.getPayPrice()) {
|
throw exception(AFTER_SALE_CREATE_FAIL_REFUND_PRICE_ERROR);
|
}
|
|
// 校验订单存在
|
TradeOrderDO order = tradeOrderQueryService.getOrder(userId, orderItem.getOrderId());
|
if (order == null) {
|
throw exception(ORDER_NOT_FOUND);
|
}
|
// TODO 芋艿:超过一定时间,不允许售后
|
// 已取消,无法发起售后
|
if (TradeOrderStatusEnum.isCanceled(order.getStatus())) {
|
throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED);
|
}
|
// 未支付,无法发起售后
|
if (!TradeOrderStatusEnum.havePaid(order.getStatus())) {
|
throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID);
|
}
|
// 如果是【退货退款】的情况,需要额外校验是否发货
|
if (createReqVO.getWay().equals(AfterSaleWayEnum.RETURN_AND_REFUND.getWay())
|
&& !TradeOrderStatusEnum.haveDelivered(order.getStatus())) {
|
throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED);
|
}
|
// 如果是拼团订单,则进行中不允许售后
|
if (TradeOrderTypeEnum.isCombination(order.getType())) {
|
CombinationRecordRespDTO combinationRecord = combinationRecordApi.getCombinationRecordByOrderId(
|
order.getUserId(), order.getId());
|
if (combinationRecord != null && CombinationRecordStatusEnum.isInProgress(combinationRecord.getStatus())) {
|
throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_COMBINATION_IN_PROGRESS);
|
}
|
}
|
return orderItem;
|
}
|
|
private AfterSaleDO createAfterSale(AppAfterSaleCreateReqVO createReqVO,
|
TradeOrderItemDO orderItem) {
|
// 创建售后单
|
AfterSaleDO afterSale = AfterSaleConvert.INSTANCE.convert(createReqVO, orderItem);
|
afterSale.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.AFTER_SALE_NO_PREFIX));
|
afterSale.setStatus(AfterSaleStatusEnum.APPLY.getStatus());
|
// 标记是售中还是售后
|
TradeOrderDO order = tradeOrderQueryService.getOrder(orderItem.getUserId(), orderItem.getOrderId());
|
afterSale.setOrderNo(order.getNo()); // 记录 orderNo 订单流水,方便后续检索
|
afterSale.setType(TradeOrderStatusEnum.isCompleted(order.getStatus())
|
? AfterSaleTypeEnum.AFTER_SALE.getType() : AfterSaleTypeEnum.IN_SALE.getType());
|
tradeAfterSaleMapper.insert(afterSale);
|
|
// 更新交易订单项的售后状态
|
tradeOrderUpdateService.updateOrderItemWhenAfterSaleCreate(orderItem.getId(), afterSale.getId());
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), null,
|
AfterSaleStatusEnum.APPLY.getStatus());
|
return afterSale;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_APPLY)
|
public void agreeAfterSale(Long userId, Long id) {
|
// 校验售后单存在,并状态未审批
|
AfterSaleDO afterSale = validateAfterSaleAuditable(id);
|
|
// 更新售后单的状态
|
// 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态
|
// 情况二:退货退款:需要等用户退货后,才能发起退款
|
Integer newStatus = afterSale.getWay().equals(AfterSaleWayEnum.REFUND.getWay()) ?
|
AfterSaleStatusEnum.WAIT_REFUND.getStatus() : AfterSaleStatusEnum.SELLER_AGREE.getStatus();
|
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.APPLY.getStatus(), new AfterSaleDO()
|
.setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()));
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_APPLY)
|
public void disagreeAfterSale(Long userId, AfterSaleDisagreeReqVO auditReqVO) {
|
// 校验售后单存在,并状态未审批
|
AfterSaleDO afterSale = validateAfterSaleAuditable(auditReqVO.getId());
|
|
// 更新售后单的状态
|
Integer newStatus = AfterSaleStatusEnum.SELLER_DISAGREE.getStatus();
|
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.APPLY.getStatus(), new AfterSaleDO()
|
.setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())
|
.setAuditReason(auditReqVO.getAuditReason()));
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus);
|
|
// 更新交易订单项的售后状态为【未申请】
|
tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId());
|
}
|
|
/**
|
* 校验售后单是否可审批(同意售后、拒绝售后)
|
*
|
* @param id 售后编号
|
* @return 售后单
|
*/
|
private AfterSaleDO validateAfterSaleAuditable(Long id) {
|
AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
|
if (afterSale == null) {
|
throw exception(AFTER_SALE_NOT_FOUND);
|
}
|
if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus())) {
|
throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY);
|
}
|
return afterSale;
|
}
|
|
private void updateAfterSaleStatus(Long id, Integer status, AfterSaleDO updateObj) {
|
int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj);
|
if (updateCount == 0) {
|
throw exception(AFTER_SALE_UPDATE_STATUS_FAIL);
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_DELIVERY)
|
public void deliveryAfterSale(Long userId, AppAfterSaleDeliveryReqVO deliveryReqVO) {
|
// 校验售后单存在,并状态未退货
|
AfterSaleDO afterSale = tradeAfterSaleMapper.selectByIdAndUserId(deliveryReqVO.getId(), userId);
|
if (afterSale == null) {
|
throw exception(AFTER_SALE_NOT_FOUND);
|
}
|
if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.SELLER_AGREE.getStatus())) {
|
throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE);
|
}
|
DeliveryExpressDO express = deliveryExpressService.validateDeliveryExpress(deliveryReqVO.getLogisticsId());
|
|
// 更新售后单的物流信息
|
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.SELLER_AGREE.getStatus(), new AfterSaleDO()
|
.setStatus(AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())
|
.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo())
|
.setDeliveryTime(LocalDateTime.now()));
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
|
AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(),
|
MapUtil.<String, Object>builder().put("deliveryName", express.getName())
|
.put("logisticsNo", deliveryReqVO.getLogisticsNo()).build());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_AGREE_RECEIVE)
|
public void receiveAfterSale(Long userId, Long id) {
|
// 校验售后单存在,并状态为已退货
|
AfterSaleDO afterSale = validateAfterSaleReceivable(id);
|
|
// 更新售后单的状态
|
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO()
|
.setStatus(AfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now()));
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
|
AfterSaleStatusEnum.WAIT_REFUND.getStatus());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_DISAGREE_RECEIVE)
|
public void refuseAfterSale(Long userId, AfterSaleRefuseReqVO refuseReqVO) {
|
// 校验售后单存在,并状态为已退货
|
AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(refuseReqVO.getId());
|
if (afterSale == null) {
|
throw exception(AFTER_SALE_NOT_FOUND);
|
}
|
if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
|
throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
|
}
|
|
// 更新售后单的状态
|
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new AfterSaleDO()
|
.setStatus(AfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now())
|
.setReceiveReason(refuseReqVO.getRefuseMemo()));
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
|
AfterSaleStatusEnum.SELLER_REFUSE.getStatus(),
|
MapUtil.of("reason", refuseReqVO.getRefuseMemo()));
|
|
// 更新交易订单项的售后状态为【未申请】
|
tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId());
|
}
|
|
/**
|
* 校验售后单是否可收货,即处于买家已发货
|
*
|
* @param id 售后编号
|
* @return 售后单
|
*/
|
private AfterSaleDO validateAfterSaleReceivable(Long id) {
|
AfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
|
if (afterSale == null) {
|
throw exception(AFTER_SALE_NOT_FOUND);
|
}
|
if (ObjectUtil.notEqual(afterSale.getStatus(), AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
|
throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
|
}
|
return afterSale;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.ADMIN_REFUND)
|
public void refundAfterSale(Long userId, String userIp, Long id) {
|
// 校验售后单的状态,并状态待退款
|
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);
|
}
|
|
Integer newStatus;
|
if (ObjUtil.equals(afterSale.getRefundPrice(), 0)) {
|
// 特殊:退款为 0 的订单,直接标记为完成(积分商城)。关联案例:https://t.zsxq.com/AQEvL
|
updateAfterSaleStatus(afterSale.getId(), AfterSaleStatusEnum.WAIT_REFUND.getStatus(), new AfterSaleDO()
|
.setStatus(AfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now()));
|
newStatus = AfterSaleStatusEnum.COMPLETE.getStatus();
|
} else {
|
// 发起退款单。注意,需要在事务提交后,再进行发起,避免重复发起
|
createPayRefund(userIp, afterSale);
|
newStatus = afterSale.getStatus(); // 特殊:这里状态不变,而是最终 updateAfterSaleRefunded 处理!!!
|
}
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus);
|
}
|
|
private void createPayRefund(String userIp, AfterSaleDO afterSale) {
|
// 创建退款单
|
PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties)
|
.setUserId(afterSale.getUserId()).setUserType(UserTypeEnum.MEMBER.getValue())
|
.setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));
|
Long payRefundId = payRefundApi.createRefund(createReqDTO);
|
|
// 更新售后单的退款单号
|
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
|
@Transactional(rollbackFor = Exception.class)
|
@AfterSaleLog(operateType = AfterSaleOperateTypeEnum.MEMBER_CANCEL)
|
public void cancelAfterSale(Long userId, Long id) {
|
// 校验售后单的状态,并状态待退款
|
AfterSaleDO afterSale = tradeAfterSaleMapper.selectByIdAndUserId(id, userId);
|
if (afterSale == null) {
|
throw exception(AFTER_SALE_NOT_FOUND);
|
}
|
if (!ObjectUtils.equalsAny(afterSale.getStatus(), AfterSaleStatusEnum.APPLY.getStatus(),
|
AfterSaleStatusEnum.SELLER_AGREE.getStatus(),
|
AfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
|
throw exception(AFTER_SALE_CANCEL_FAIL_STATUS_NOT_APPLY_OR_AGREE_OR_BUYER_DELIVERY);
|
}
|
|
// 更新售后单的状态为【已取消】
|
updateAfterSaleStatus(afterSale.getId(), afterSale.getStatus(), new AfterSaleDO()
|
.setStatus(AfterSaleStatusEnum.BUYER_CANCEL.getStatus()));
|
|
// 记录售后日志
|
AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
|
AfterSaleStatusEnum.BUYER_CANCEL.getStatus());
|
|
// 更新交易订单项的售后状态为【未申请】
|
tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId());
|
}
|
|
@Override
|
public Long getApplyingAfterSaleCount(Long userId) {
|
return tradeAfterSaleMapper.selectCountByUserIdAndStatus(userId, AfterSaleStatusEnum.APPLYING_STATUSES);
|
}
|
|
}
|