|
|
@@ -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());
|
|
|
+ afterSale.getStatus()); // 特殊:这里状态不变,而是最终 updateAfterSaleRefunded 处理!!!
|
|
|
+ }
|
|
|
|
|
|
- // TODO 发送售后消息
|
|
|
+ private void createPayRefund(String userIp, AfterSaleDO afterSale) {
|
|
|
+ // 创建退款单
|
|
|
+ PayRefundCreateReqDTO createReqDTO = AfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties)
|
|
|
+ .setReason(StrUtil.format("退款【{}】", afterSale.getSpuName()));
|
|
|
+ Long payRefundId = payRefundApi.createRefund(createReqDTO);
|
|
|
|
|
|
- // 更新交易订单项的售后状态为【已完成】
|
|
|
- tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice());
|
|
|
+ // 更新售后单的退款单号
|
|
|
+ tradeAfterSaleMapper.updateById(new AfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));
|
|
|
}
|
|
|
|
|
|
- private void createPayRefund(String userIp, AfterSaleDO afterSale) {
|
|
|
- TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
|
|
-
|
|
|
- @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));
|
|
|
- }
|
|
|
- });
|
|
|
+ @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());
|
|
|
}
|