package com.cyl.manager.oms.service; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.cyl.manager.act.domain.entity.IntegralHistory; import com.cyl.manager.act.mapper.IntegralHistoryMapper; import com.cyl.manager.act.service.MemberCouponService; import com.cyl.manager.oms.convert.OrderOperateHistoryConvert; import com.cyl.manager.oms.domain.entity.*; import com.cyl.manager.oms.mapper.*; import com.cyl.manager.oms.domain.form.DealWithAftersaleForm; import com.cyl.manager.oms.domain.form.ManagerAftersaleOrderForm; import com.cyl.manager.oms.domain.vo.*; import com.cyl.manager.pms.mapper.SkuMapper; import com.cyl.manager.ums.domain.entity.Member; import com.cyl.manager.ums.domain.entity.MemberWechat; import com.cyl.manager.ums.mapper.MemberMapper; import com.cyl.manager.ums.mapper.MemberWechatMapper; import com.cyl.wechat.WechatPayService; import com.github.pagehelper.PageHelper; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.enums.AftersaleStatus; import com.ruoyi.common.enums.OrderRefundStatus; import com.ruoyi.common.enums.OrderStatus; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.framework.config.LocalDataUtil; import com.wechat.pay.java.service.refund.model.Refund; import com.wechat.pay.java.service.refund.model.RefundNotification; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; /** * 订单售后Service业务层处理 * * @author zcc */ @Service @Slf4j public class AftersaleService { @Autowired private AftersaleMapper aftersaleMapper; @Autowired private OrderMapper orderMapper; @Autowired private OrderItemMapper orderItemMapper; @Autowired private OrderOperateHistoryMapper orderOperateHistoryMapper; @Autowired private MemberMapper memberMapper; @Autowired private OrderOperateHistoryConvert historyConvert; @Autowired private SkuMapper skuMapper; @Autowired private MemberCouponService memberCouponService; @Autowired private WechatPaymentHistoryMapper wechatPaymentHistoryMapper; @Autowired private MemberWechatMapper memberWechatMapper; @Autowired(required = false) private WechatPayService wechatPayService; @Autowired private OrderOperateHistoryMapper operateHistoryMapper; @Autowired private IntegralHistoryMapper integralHistoryMapper; /** * 查询订单售后 * * @param id 订单售后主键 * @return 订单售后 */ public ManagerRefundOrderDetailVO selectById(Long id) { Order order = orderMapper.selectById(id); if (order == null) { throw new RuntimeException("无该订单信息"); } ManagerRefundOrderDetailVO result = new ManagerRefundOrderDetailVO(); //订单基本信息 result.setOrderId(order.getId()); result.setOrderSn(order.getOrderSn()); result.setCreateTime(order.getCreateTime()); result.setPayType(order.getPayType()); result.setPayTime(order.getPaymentTime()); result.setStatus(order.getStatus()); result.setExpressName(order.getDeliveryCompany()); result.setDeliveryTime(order.getDeliveryTime()); result.setExpressNo(order.getDeliverySn()); result.setTotalAmount(order.getTotalAmount()); result.setPayAmount(order.getPayAmount()); //用户信息 Member member = memberMapper.selectById(order.getMemberId()); result.setNickName(member.getNickname()); result.setPhone(member.getPhoneHidden()); //收货信息 OrderAddressVO orderAddressVO = new OrderAddressVO(); orderAddressVO.setAddress(order.getReceiverDetailAddress()); orderAddressVO.setName(order.getReceiverName()); orderAddressVO.setUserPhone(order.getReceiverPhone()); orderAddressVO.setArea(order.getReceiverProvince() + order.getReceiverCity() + order.getReceiverDistrict()); result.setAddressInfo(orderAddressVO); //orderItem QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>(); orderItemQw.eq("order_id", id); List<OrderItem> orderItemList = orderItemMapper.selectList(orderItemQw); List<ManagerOrderProductVO> productList = new ArrayList<>(); orderItemList.forEach(orderItem -> { ManagerOrderProductVO productVO = new ManagerOrderProductVO(); productVO.setPic(orderItem.getPic()); productVO.setSpData(orderItem.getSpData()); productVO.setProductName(orderItem.getProductName()); productVO.setSalePrice(orderItem.getSalePrice()); productVO.setBuyNum(orderItem.getQuantity()); productVO.setProductId(orderItem.getProductId()); productList.add(productVO); }); result.setProductList(productList); //售后信息 QueryWrapper<Aftersale> aftersaleQw = new QueryWrapper<>(); aftersaleQw.eq("order_id", order.getId()); aftersaleQw.orderByDesc("create_time"); List<Aftersale> aftersaleList = aftersaleMapper.selectList(aftersaleQw); List<RefundInfoVO> refundInfoList = new ArrayList<>(); aftersaleList.forEach(aftersale -> { RefundInfoVO refundInfo = new RefundInfoVO(); refundInfo.setId(aftersale.getId()); refundInfo.setApplyRefundType(aftersale.getType()); refundInfo.setApplyRefundTime(aftersale.getCreateTime()); refundInfo.setRefundAmount(aftersale.getReturnAmount()); refundInfo.setReason(aftersale.getReason()); refundInfo.setDescription(aftersale.getDescription()); refundInfo.setProofPics(aftersale.getProofPics()); refundInfo.setRefundStatus(aftersale.getStatus()); refundInfo.setRefundWpCode(aftersale.getRefundWpCode()); refundInfo.setRefundWaybillCode(aftersale.getRefundWaybillCode()); refundInfo.setRefundStatus(aftersale.getStatus()); refundInfo.setRemark(aftersale.getHandleNote()); refundInfoList.add(refundInfo); }); result.setRefundInfoList(refundInfoList); return result; } /** * 查询订单售后列表 * * @param query 查询条件 * @param page 分页条件 * @return 订单售后 */ public List<ManagerRefundOrderVO> selectList(ManagerAftersaleOrderForm query, Pageable page) { if (page != null) { PageHelper.startPage(page.getPageNumber() + 1, page.getPageSize()); } if (StrUtil.isNotBlank(query.getOrderSn()) && query.getOrderSn().length() > 7) { query.setOrderSn(query.getOrderSn().substring(7)); } List<ManagerRefundOrderVO> managerRefundOrderVOS = aftersaleMapper.selectManagerRefundOrder(query); if (CollectionUtil.isEmpty(managerRefundOrderVOS)) { return managerRefundOrderVOS; } Set<Long> idSet = managerRefundOrderVOS.stream().map(ManagerRefundOrderVO::getOrderId).collect(Collectors.toSet()); //查一下orderSn集合 QueryWrapper<Order> orderQw = new QueryWrapper<>(); orderQw.in("id", idSet); Map<Long, Order> orderMap = orderMapper.selectList(orderQw).stream().collect(Collectors.toMap(Order::getId, it -> it)); //封装售后单商品数据 QueryWrapper<OrderItem> orderItemQw = new QueryWrapper<>(); orderItemQw.in("order_id", idSet); Map<Long, List<OrderItem>> orderItemMap = orderItemMapper.selectList(orderItemQw).stream().collect(Collectors.groupingBy(OrderItem::getOrderId)); managerRefundOrderVOS.forEach(vo -> { Order order = orderMap.get(vo.getOrderId()); vo.setOrderSn(order.getOrderSn()); List<OrderItem> orderItemList = orderItemMap.get(vo.getOrderId()); List<ManagerOrderProductVO> productList = new ArrayList<>(); orderItemList.forEach(item -> { ManagerOrderProductVO productVO = new ManagerOrderProductVO(); productVO.setProductName(item.getProductName()); productVO.setSalePrice(item.getSalePrice()); productVO.setPic(item.getPic()); productVO.setBuyNum(item.getQuantity()); productVO.setProductId(item.getProductId()); productVO.setSpData(item.getSpData()); productList.add(productVO); }); vo.setProductList(productList); }); return managerRefundOrderVOS; } /** * 新增订单售后 * * @param aftersale 订单售后 * @return 结果 */ public int insert(Aftersale aftersale) { aftersale.setCreateTime(LocalDateTime.now()); return aftersaleMapper.insert(aftersale); } /** * 修改订单售后 * * @param aftersale 订单售后 * @return 结果 */ public int update(Aftersale aftersale) { return aftersaleMapper.updateById(aftersale); } /** * 删除订单售后信息 * * @param id 订单售后主键 * @return 结果 */ public int deleteById(Long id) { return aftersaleMapper.deleteById(id); } /** * 售后处理 * * @param request 请求体 * @return */ @Transactional(rollbackFor = Exception.class) public void dealWith(DealWithAftersaleForm request, Long userId, String optUserName) { Order order = orderMapper.selectById(request.getOrderId()); if (order == null) { throw new RuntimeException("无该订单"); } LocalDateTime optDate = LocalDateTime.now(); //不是0元订单 if (order.getPayAmount().compareTo(BigDecimal.ZERO) > 0) { //只申请一笔售后 if (request.getOrderItemId() != null) { List<OrderItem> orderItem = orderItemMapper.selectList(new QueryWrapper<OrderItem>().eq("id", request.getOrderItemId())); if (CollectionUtil.isNotEmpty(orderItem)) { // 是否需要发起退款 if (request.getOptType() == Constants.OptType.AGREE) { BigDecimal money = new BigDecimal("0.00"); if (orderItem.get(0).getCouponMoney() == null || orderItem.get(0).getCouponMoney().compareTo(BigDecimal.ZERO) <= 0) { money = orderItem.get(0).getSalePrice(); } else { money = orderItem.get(0).getCouponMoney(); } BigDecimal multiply = money.multiply(BigDecimal.valueOf(orderItem.get(0).getQuantity())); //开始退款 Refund wechatResponse = wechatPayService.refundPay(order.getOrderSn() + RandomUtil.randomNumbers(5), order.getPayId() + "", "https://wenchuang.yyinhong.cn/api/no-auth/wechat/weChatRefundNotify", multiply.multiply(new BigDecimal("100")).longValue(), order.getPayAmount().multiply(new BigDecimal("100")).longValue(), request.getReason()); log.info("发起微信退款返回信息,tradeRefund:{}", JSONObject.toJSONString(wechatResponse == null ? "" : wechatResponse)); //库存回滚 orderItem.stream().collect(Collectors.groupingBy(it -> it.getSkuId())).forEach((k, v) -> { AtomicReference<Integer> totalCount = new AtomicReference<>(0); v.forEach(it -> totalCount.updateAndGet(v1 -> v1 + it.getQuantity())); skuMapper.updateStockById(k, optDate, -1 * totalCount.get()); }); //处理积分 sendBack(request.getMemberId(), null, orderItem.get(0).getId()); } } //全部退款 } else { if (request.getOptType() == Constants.OptType.AGREE) { //开始退款 Refund wechatResponse = wechatPayService.refundPay(order.getOrderSn() + RandomUtil.randomNumbers(5), order.getPayId() + "", "https://wenchuang.yyinhong.cn/api/no-auth/wechat/weChatRefundNotify", order.getPayAmount().multiply(new BigDecimal("100")).longValue(), order.getPayAmount().multiply(new BigDecimal("100")).longValue(), request.getReason()); log.info("发起微信退款返回信息,tradeRefund:{}", JSONObject.toJSONString(wechatResponse == null ? "" : wechatResponse)); List<OrderItem> orderItem = orderItemMapper.selectList(new QueryWrapper<OrderItem>().eq("order_id", request.getOrderId())); if (CollectionUtil.isNotEmpty(orderItem)) { //库存回滚 orderItem.stream().collect(Collectors.groupingBy(it -> it.getSkuId())).forEach((k, v) -> { AtomicReference<Integer> totalCount = new AtomicReference<>(0); v.forEach(it -> totalCount.updateAndGet(v1 -> v1 + it.getQuantity())); skuMapper.updateStockById(k, optDate, -1 * totalCount.get()); }); } //处理积分 sendBack(request.getMemberId(), order.getId(), null); //修改子订单状态 List<OrderItem> orderItems = orderItemMapper.selectList(new QueryWrapper<OrderItem>().eq("order_id", request.getOrderId())); if (CollectionUtil.isNotEmpty(orderItems)) { for (OrderItem item : orderItems) { item.setStatus("9"); orderItemMapper.updateById(item); } } } } } else { //处理积分 sendBack(request.getMemberId(), order.getId(),null); } //要创建的订单操作记录,status后续判断再设置 OrderOperateHistory optHistory = new OrderOperateHistory(); optHistory.setOrderId(order.getId()); optHistory.setOrderSn(order.getOrderSn()); optHistory.setOperateMan("后台管理员"); optHistory.setCreateTime(optDate); optHistory.setCreateBy(userId); optHistory.setUpdateBy(userId); optHistory.setUpdateTime(optDate); //封装订单wrapper UpdateWrapper<Order> orderWrapper = new UpdateWrapper<>(); orderWrapper.eq("id", request.getOrderId()); orderWrapper.set("update_time", optDate); orderWrapper.set("update_by", userId); orderWrapper.set("reason", request.getReason()); orderWrapper.set("proof_pics", request.getProofPics()); orderWrapper.set("status", OrderStatus.CLOSED.getType()); int row = orderMapper.update(null, orderWrapper); if (row != 1) { throw new RuntimeException("修改订单状态失败"); } List<OrderItem> orderItem = orderItemMapper.selectList(new QueryWrapper<OrderItem>().eq("order_id", request.getOrderId())); //库存回滚 orderItem.stream().collect(Collectors.groupingBy(it -> it.getSkuId())).forEach((k, v) -> { AtomicReference<Integer> totalCount = new AtomicReference<>(0); v.forEach(it -> totalCount.updateAndGet(v1 -> v1 + it.getQuantity())); skuMapper.updateStockById(k, optDate, -1 * totalCount.get()); }); optHistory.setOrderStatus(OrderStatus.CLOSED.getType()); int his = orderOperateHistoryMapper.insert(optHistory); if (his != 1) { log.info("订单日志记录失败!"); } } /** * 退回积分 */ public void sendBack(Long memberId, Long orderId, Long orderItemId) { BigDecimal integral = new BigDecimal("0.00"); if (orderItemId != null) { //只返回一部分积分 OrderItem orderItem = orderItemMapper.selectById(orderItemId); if (null == orderItem) { throw new ServiceException("退款商品信息有误!"); } else { if (orderItem.getUseIntegral() != null && orderItem.getUseIntegral().compareTo(BigDecimal.ZERO) > 0) { //记录积分流水 IntegralHistory integralHistory = new IntegralHistory(); integralHistory.setMemberId(memberId); integralHistory.setAmount(orderItem.getUseIntegral()); integralHistory.setOpType(Constants.OptType.AGREE); integralHistory.setSubOpType(25); integralHistory.setOrderAmount(orderItem.getCouponMoney()); integralHistory.setOrderId(orderItem.getOrderId()); integralHistoryMapper.insert(integralHistory); //修改用户积分 Member member = memberMapper.selectById(memberId); if (null == member) { throw new ServiceException("会员信息有误!"); } BigDecimal add = member.getIntegral().add(orderItem.getUseIntegral()); UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", memberId); updateWrapper.set("integral", add); memberMapper.update(null, updateWrapper); } } } if (orderId != null) { //全部退款 Order order = orderMapper.selectById(orderId); if (order == null) { throw new ServiceException("订单信息有误!"); } //记录积分流水 if (order.getTotalIntegral() != null && order.getTotalIntegral().compareTo(BigDecimal.ZERO) > 0) { IntegralHistory integralHistory = new IntegralHistory(); integralHistory.setMemberId(memberId); integralHistory.setAmount(order.getTotalIntegral()); integralHistory.setOpType(Constants.OptType.AGREE); integralHistory.setSubOpType(25); integral = order.getTotalIntegral(); integralHistory.setCreateTime(LocalDateTime.now()); integralHistory.setOrderAmount(order.getPayAmount()); integralHistory.setOrderId(order.getId()); integralHistoryMapper.insert(integralHistory); //修改用户积分 Member member = memberMapper.selectById(memberId); if (null == member) { throw new ServiceException("会员信息有误!"); } BigDecimal add = member.getIntegral().add(integral); UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", memberId); updateWrapper.set("integral", add); memberMapper.update(null, updateWrapper); } } } /** * 订单退款回调MQ * * @param weChatRefundNotify */ @Transactional public void refundOrderExc(RefundNotification weChatRefundNotify) { log.info("收到订单回调MQ:" + JSONObject.toJSONString(weChatRefundNotify)); if ("PROCESSING".equals(weChatRefundNotify.getRefundStatus().name())) { return; } } public List<OrderOperateHistoryVO> log(Long orderId) { LambdaQueryWrapper<OrderOperateHistory> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(OrderOperateHistory::getOrderId, orderId); wrapper.in(OrderOperateHistory::getOrderStatus, Arrays.asList(11, 12, 13, 14)); wrapper.orderByDesc(OrderOperateHistory::getCreateTime); List<OrderOperateHistory> historyList = orderOperateHistoryMapper.selectList(wrapper); return historyConvert.dos2vos(historyList); } public Aftersale queryAfterSale(Long orderId) { QueryWrapper<Aftersale> itemQw = new QueryWrapper<>(); itemQw.eq("order_id", orderId); itemQw.in("status", Arrays.asList(AftersaleStatus.APPLY.getType(), AftersaleStatus.WAIT.getType())); return aftersaleMapper.selectOne(itemQw); } }