| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.doumee.config.wx.WxPayProperties; |
| | | import com.doumee.config.wx.WxPayV3Service; |
| | | import com.doumee.core.constants.Constants; |
| | | import com.doumee.core.constants.ResponseStatus; |
| | | import com.doumee.core.exception.BusinessException; |
| | | import com.doumee.core.model.PageData; |
| | | import com.doumee.core.model.PageWrap; |
| | | import com.doumee.core.utils.Utils; |
| | | import com.doumee.dao.business.OrdersMapper; |
| | | import com.doumee.dao.business.OrdersRefundMapper; |
| | | import com.doumee.dao.business.model.Orders; |
| | | import com.doumee.dao.business.model.OrdersRefund; |
| | | import com.doumee.dao.dto.OrdersRefundPageDTO; |
| | | import com.doumee.dao.vo.OrdersRefundPageVO; |
| | | import com.doumee.service.business.OrdersRefundService; |
| | | import com.github.yulichang.wrapper.MPJLambdaWrapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | * @author rk |
| | | * @date 2026/04/13 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class OrdersRefundServiceImpl implements OrdersRefundService { |
| | | |
| | | @Autowired |
| | | private OrdersRefundMapper ordersRefundMapper; |
| | | |
| | | @Autowired |
| | | private OrdersMapper ordersMapper; |
| | | |
| | | @Autowired |
| | | private WxPayV3Service wxPayV3Service; |
| | | |
| | | @Autowired |
| | | private WxPayProperties wxPayProperties; |
| | | |
| | | @Override |
| | | public Integer create(OrdersRefund ordersRefund) { |
| | |
| | | QueryWrapper<OrdersRefund> wrapper = new QueryWrapper<>(ordersRefund); |
| | | return ordersRefundMapper.selectCount(wrapper); |
| | | } |
| | | |
| | | @Override |
| | | public PageData<OrdersRefundPageVO> refundPage(PageWrap<OrdersRefundPageDTO> pageWrap) { |
| | | OrdersRefundPageDTO model = pageWrap.getModel(); |
| | | IPage<OrdersRefund> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity()); |
| | | |
| | | MPJLambdaWrapper<OrdersRefund> wrapper = new MPJLambdaWrapper<>(); |
| | | wrapper.selectAll(OrdersRefund.class) |
| | | .select("o.code as orderCode") |
| | | .select("o.goods_info as goodsInfo") |
| | | .select("o.type as orderType") |
| | | .select("o.good_level as goodLevel") |
| | | .select("o.total_amount as totalAmount") |
| | | .select("o.pay_amount as payAmount") |
| | | .select("c2.name as goodLevelName") |
| | | .leftJoin("orders o on o.id = t.ORDER_ID and o.DELETED = 0") |
| | | .leftJoin("category c1 on c1.id = o.GOOD_TYPE and c1.DELETED = 0") |
| | | .leftJoin("category c2 on c2.id = c1.RELATION_ID and c2.DELETED = 0 and c2.TYPE = 3") |
| | | .eq(OrdersRefund::getDeleted, 0); |
| | | |
| | | if (model != null) { |
| | | if (StringUtils.isNotBlank(model.getOrderCode())) { |
| | | wrapper.like("o.code", model.getOrderCode()); |
| | | } |
| | | if (StringUtils.isNotBlank(model.getGoodsInfo())) { |
| | | wrapper.like("o.goods_info", model.getGoodsInfo()); |
| | | } |
| | | if (model.getOrderType() != null) { |
| | | wrapper.eq("o.type", model.getOrderType()); |
| | | } |
| | | if (model.getRefundStatus() != null) { |
| | | wrapper.eq(OrdersRefund::getStatus, model.getRefundStatus()); |
| | | } |
| | | if (model.getCreateStartTime() != null) { |
| | | wrapper.ge(OrdersRefund::getCreateTime, model.getCreateStartTime()); |
| | | } |
| | | if (model.getCreateEndTime() != null) { |
| | | wrapper.le(OrdersRefund::getCreateTime, model.getCreateEndTime()); |
| | | } |
| | | } |
| | | |
| | | wrapper.orderByDesc(OrdersRefund::getCreateTime); |
| | | |
| | | IPage<OrdersRefund> refundPage = ordersRefundMapper.selectJoinPage(page, OrdersRefund.class, wrapper); |
| | | |
| | | // 转换为 VO |
| | | List<OrdersRefundPageVO> voList = new ArrayList<>(); |
| | | if (refundPage != null && refundPage.getRecords() != null) { |
| | | for (OrdersRefund r : refundPage.getRecords()) { |
| | | OrdersRefundPageVO vo = new OrdersRefundPageVO(); |
| | | vo.setId(r.getId()); |
| | | vo.setOrderId(r.getOrderId()); |
| | | vo.setOrderCode(r.getOrderCode()); |
| | | vo.setGoodsInfo(r.getGoodsInfo()); |
| | | vo.setOrderType(r.getOrderType()); |
| | | vo.setGoodLevelName(r.getGoodLevelName()); |
| | | vo.setTotalAmount(r.getTotalAmount()); |
| | | vo.setPayAmount(r.getPayAmount()); |
| | | vo.setRefundAmount(r.getRefundAmount()); |
| | | vo.setCreateTime(r.getCreateTime()); |
| | | vo.setRefundStatus(r.getStatus()); |
| | | voList.add(vo); |
| | | } |
| | | } |
| | | |
| | | PageData<OrdersRefundPageVO> result = new PageData<>( |
| | | refundPage != null ? refundPage.getCurrent() : pageWrap.getPage(), |
| | | refundPage != null ? refundPage.getSize() : pageWrap.getCapacity()); |
| | | result.setRecords(voList); |
| | | if (refundPage != null) { |
| | | result.setTotal(refundPage.getTotal()); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void retryRefund(Integer id) { |
| | | // 1. 查询退款记录 |
| | | OrdersRefund refundRecord = ordersRefundMapper.selectById(id); |
| | | if (refundRecord == null || Constants.ONE.equals(refundRecord.getDeleted())) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "退款记录不存在"); |
| | | } |
| | | if (!Constants.TWO.equals(refundRecord.getStatus())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "仅退款失败的记录可重新退款"); |
| | | } |
| | | |
| | | // 2. 查询关联订单 |
| | | Orders order = ordersMapper.selectById(refundRecord.getOrderId()); |
| | | if (order == null || Constants.ONE.equals(order.getDeleted())) { |
| | | throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(), "关联订单不存在"); |
| | | } |
| | | if (StringUtils.isBlank(order.getOutTradeNo())) { |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "订单缺少微信支付单号"); |
| | | } |
| | | |
| | | // 3. 发起微信退款 |
| | | String outRefundNo = com.doumee.core.utils.ID.nextGUID(); |
| | | com.wechat.pay.java.service.refund.model.Refund refundResult; |
| | | try { |
| | | refundResult = wxPayV3Service.refund( |
| | | outRefundNo, |
| | | order.getOutTradeNo(), |
| | | order.getPayAmount(), |
| | | refundRecord.getRefundAmount(), |
| | | "重新退款", |
| | | wxPayProperties.getV3RefundNotifyUrl()); |
| | | } catch (Exception e) { |
| | | log.error("重新退款调用异常, refundRecordId={}", id, e); |
| | | throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "退款失败,请稍后重试"); |
| | | } |
| | | |
| | | // 4. 更新退款记录 |
| | | Date now = new Date(); |
| | | com.wechat.pay.java.service.refund.model.Status wxStatus = refundResult.getStatus(); |
| | | OrdersRefund update = new OrdersRefund(); |
| | | update.setId(id); |
| | | update.setRefundCode(outRefundNo); |
| | | update.setUpdateTime(now); |
| | | |
| | | if (com.wechat.pay.java.service.refund.model.Status.SUCCESS.equals(wxStatus)) { |
| | | update.setStatus(Constants.ONE); |
| | | update.setRefundTime(now); |
| | | } else if (com.wechat.pay.java.service.refund.model.Status.PROCESSING.equals(wxStatus)) { |
| | | update.setStatus(Constants.ZERO); |
| | | } else { |
| | | update.setStatus(Constants.TWO); |
| | | update.setRefundRemark("重新退款仍然失败"); |
| | | } |
| | | ordersRefundMapper.updateById(update); |
| | | } |
| | | } |