|
|
@@ -0,0 +1,204 @@
|
|
|
+package org.dromara.main.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import cn.hutool.core.util.RandomUtil;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.dromara.common.core.exception.ServiceException;
|
|
|
+import org.dromara.main.domain.MainBackOrder;
|
|
|
+import org.dromara.main.domain.MainBackRecord;
|
|
|
+import org.dromara.main.domain.MainOrder;
|
|
|
+import org.dromara.main.domain.Payment;
|
|
|
+import org.dromara.main.domain.Refund;
|
|
|
+import org.dromara.main.domain.vo.RefundVo;
|
|
|
+import org.dromara.main.mapper.MainBackOrderMapper;
|
|
|
+import org.dromara.main.mapper.MainBackRecordMapper;
|
|
|
+import org.dromara.main.mapper.MainOrderMapper;
|
|
|
+import org.dromara.main.mapper.PaymentMapper;
|
|
|
+import org.dromara.main.mapper.RefundMapper;
|
|
|
+import org.dromara.main.service.ICompanyAccountService;
|
|
|
+import org.dromara.main.service.IPaymentService;
|
|
|
+import org.dromara.main.service.IRefundService;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 退款服务实现
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RequiredArgsConstructor
|
|
|
+@Service
|
|
|
+public class RefundServiceImpl implements IRefundService {
|
|
|
+
|
|
|
+ private static final int PAYMENT_METHOD_ALIPAY = 2;
|
|
|
+ private static final int PAYMENT_METHOD_BALANCE = 3;
|
|
|
+
|
|
|
+ private final RefundMapper refundMapper;
|
|
|
+ private final MainOrderMapper mainOrderMapper;
|
|
|
+ private final MainBackOrderMapper mainBackOrderMapper;
|
|
|
+ private final MainBackRecordMapper mainBackRecordMapper;
|
|
|
+ private final PaymentMapper paymentMapper;
|
|
|
+ private final ICompanyAccountService companyAccountService;
|
|
|
+ private final IPaymentService paymentService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Long createRefund(Long orderId, BigDecimal refundAmount, String refundReason, Long operatorId, String operatorName) {
|
|
|
+ MainOrder order = mainOrderMapper.selectById(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ throw new ServiceException("订单不存在");
|
|
|
+ }
|
|
|
+ if (order.getOrderType() == null || (order.getOrderType() != 3 && order.getOrderType() != 4)) {
|
|
|
+ throw new ServiceException("仅支持背调订单退款");
|
|
|
+ }
|
|
|
+ if (order.getBusinessId() == null) {
|
|
|
+ throw new ServiceException("背调订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ MainBackOrder backOrder = mainBackOrderMapper.selectById(order.getBusinessId());
|
|
|
+ if (backOrder == null) {
|
|
|
+ throw new ServiceException("背调订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (order.getPayStatus() == null || order.getPayStatus() != 2) {
|
|
|
+ throw new ServiceException("订单未支付,无法退款");
|
|
|
+ }
|
|
|
+ if (order.getOrderStatus() != null && (order.getOrderStatus() == 4 || order.getOrderStatus() == 5)) {
|
|
|
+ throw new ServiceException("订单已在退款流程中,无法重复退款");
|
|
|
+ }
|
|
|
+ if (order.getRefundAmount() != null && order.getRefundAmount().compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ throw new ServiceException("订单已退款,不支持多次退款");
|
|
|
+ }
|
|
|
+ if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ throw new ServiceException("退款金额必须大于0");
|
|
|
+ }
|
|
|
+ if (order.getPaidAmount() == null || refundAmount.compareTo(order.getPaidAmount()) > 0) {
|
|
|
+ throw new ServiceException("退款金额不能大于已支付金额");
|
|
|
+ }
|
|
|
+
|
|
|
+ boolean fullRefund = refundAmount.compareTo(order.getPaidAmount()) == 0;
|
|
|
+ int refundType = fullRefund ? 1 : 2;
|
|
|
+
|
|
|
+ Payment payment = paymentMapper.selectOne(
|
|
|
+ Wrappers.<Payment>lambdaQuery()
|
|
|
+ .eq(Payment::getOrderId, order.getId())
|
|
|
+ .orderByDesc(Payment::getCreateTime)
|
|
|
+ .last("limit 1")
|
|
|
+ );
|
|
|
+
|
|
|
+ Integer paymentMethod = payment == null || payment.getPaymentMethod() == null
|
|
|
+ ? PAYMENT_METHOD_BALANCE
|
|
|
+ : payment.getPaymentMethod();
|
|
|
+
|
|
|
+ Refund refund = new Refund();
|
|
|
+ refund.setTenantId(order.getTenantId());
|
|
|
+ refund.setRefundNo(generateRefundNo());
|
|
|
+ refund.setPaymentId(payment == null ? null : payment.getId());
|
|
|
+ refund.setOrderId(order.getId());
|
|
|
+ refund.setOrderNo(order.getOrderNo());
|
|
|
+ refund.setTradeNo(payment == null ? null : payment.getTradeNo());
|
|
|
+ refund.setRefundAmount(refundAmount);
|
|
|
+ refund.setRefundReason(refundReason);
|
|
|
+ refund.setRefundType(refundType);
|
|
|
+ refund.setPaymentMethod(paymentMethod);
|
|
|
+ refund.setRefundStatus(0);
|
|
|
+ refund.setOperatorId(operatorId);
|
|
|
+ refund.setOperatorName(operatorName);
|
|
|
+ refundMapper.insert(refund);
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (paymentMethod == PAYMENT_METHOD_BALANCE) {
|
|
|
+ companyAccountService.refundToAvailable(
|
|
|
+ order.getBuyerId(),
|
|
|
+ refundAmount,
|
|
|
+ order.getId(),
|
|
|
+ order.getOrderNo(),
|
|
|
+ refundReason
|
|
|
+ );
|
|
|
+ } else if (paymentMethod == PAYMENT_METHOD_ALIPAY) {
|
|
|
+ if (payment == null || payment.getTradeNo() == null || payment.getTradeNo().isBlank()) {
|
|
|
+ throw new ServiceException("支付宝交易号不存在,无法退款");
|
|
|
+ }
|
|
|
+ boolean success = paymentService.alipayRefund(payment.getTradeNo(), refundAmount, refund.getRefundNo(), refundReason);
|
|
|
+ if (!success) {
|
|
|
+ throw new ServiceException("支付宝退款失败");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("不支持的支付方式:" + paymentMethod);
|
|
|
+ }
|
|
|
+
|
|
|
+ refund.setRefundStatus(1);
|
|
|
+ refund.setRefundTime(new Date());
|
|
|
+ refundMapper.updateById(refund);
|
|
|
+ } catch (Exception e) {
|
|
|
+ refund.setRefundStatus(2);
|
|
|
+ refund.setFailReason(e.getMessage());
|
|
|
+ refundMapper.updateById(refund);
|
|
|
+ log.error("退款失败:orderId={}, error={}", order.getId(), e.getMessage(), e);
|
|
|
+ throw new ServiceException("退款失败:{}", e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (paymentMethod == PAYMENT_METHOD_BALANCE && !fullRefund) {
|
|
|
+ BigDecimal remainingAmount = order.getPaidAmount().subtract(refundAmount);
|
|
|
+ if (remainingAmount.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ companyAccountService.deductInUseBalance(
|
|
|
+ order.getBuyerId(),
|
|
|
+ remainingAmount,
|
|
|
+ order.getId(),
|
|
|
+ order.getOrderNo(),
|
|
|
+ "部分退款,扣除剩余金额"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ order.setRefundAmount(refundAmount);
|
|
|
+ order.setOrderStatus(fullRefund ? 4 : 2);
|
|
|
+ if (fullRefund) {
|
|
|
+ order.setCancelTime(new Date());
|
|
|
+ } else {
|
|
|
+ order.setCompleteTime(new Date());
|
|
|
+ }
|
|
|
+ mainOrderMapper.updateById(order);
|
|
|
+
|
|
|
+ backOrder.setStatus(fullRefund ? "3" : "2");
|
|
|
+ mainBackOrderMapper.updateById(backOrder);
|
|
|
+
|
|
|
+ List<MainBackRecord> records = mainBackRecordMapper.selectList(
|
|
|
+ Wrappers.<MainBackRecord>lambdaQuery()
|
|
|
+ .eq(MainBackRecord::getOrderId, backOrder.getId())
|
|
|
+ );
|
|
|
+ for (MainBackRecord record : records) {
|
|
|
+ if (!"已完成".equals(record.getStatus()) && !"完成".equals(record.getStatus())) {
|
|
|
+ record.setStatus("已取消");
|
|
|
+ mainBackRecordMapper.updateById(record);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("退款完成:orderId={}, refundNo={}, refundAmount={}, refundType={}",
|
|
|
+ order.getId(), refund.getRefundNo(), refundAmount, fullRefund ? "全额" : "部分");
|
|
|
+ return refund.getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<RefundVo> queryByOrderId(Long orderId) {
|
|
|
+ return refundMapper.selectVoList(
|
|
|
+ Wrappers.<Refund>lambdaQuery()
|
|
|
+ .eq(Refund::getOrderId, orderId)
|
|
|
+ .orderByDesc(Refund::getCreateTime)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public RefundVo queryById(Long refundId) {
|
|
|
+ return refundMapper.selectVoById(refundId);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String generateRefundNo() {
|
|
|
+ return "RF" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomNumbers(4);
|
|
|
+ }
|
|
|
+}
|