AfterSaleOrderServiceImpl.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. package com.ylx.massage.service.impl;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.util.ObjectUtil;
  4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  5. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  6. import com.ylx.common.core.domain.model.WxLoginUser;
  7. import com.ylx.common.exception.ServiceException;
  8. import com.ylx.common.utils.SecurityUtils;
  9. import com.ylx.massage.domain.AfterSaleOrder;
  10. import com.ylx.massage.domain.ProductOrderInfo;
  11. import com.ylx.massage.domain.dto.AfterSaleOrderDTO;
  12. import com.ylx.massage.domain.dto.AfterSaleOrderUpdateDTO;
  13. import com.ylx.massage.domain.vo.OrderAfterSaleVo;
  14. import com.ylx.massage.enums.AfterSaleStatusEnum;
  15. import com.ylx.massage.enums.AfterSaleTypeEnum;
  16. import com.ylx.massage.enums.ProductOrderStatusEnum;
  17. import com.ylx.massage.mapper.AfterSaleOrderMapper;
  18. import com.ylx.massage.service.IAfterSaleOrderService;
  19. import com.ylx.massage.service.IProductOrderInfoService;
  20. import lombok.extern.slf4j.Slf4j;
  21. import org.springframework.stereotype.Service;
  22. import org.springframework.transaction.annotation.Transactional;
  23. import javax.annotation.Resource;
  24. import java.time.LocalDateTime;
  25. @Service
  26. @Slf4j
  27. public class AfterSaleOrderServiceImpl extends ServiceImpl<AfterSaleOrderMapper, AfterSaleOrder> implements IAfterSaleOrderService {
  28. @Resource
  29. private AfterSaleOrderMapper afterSaleOrderMapper;
  30. @Resource
  31. private IProductOrderInfoService productOrderInfoService;
  32. @Override
  33. @Transactional(rollbackFor = Exception.class)
  34. public void add(AfterSaleOrderDTO dto) {
  35. // 1. 获取当前登录用户(公共方法提取)
  36. WxLoginUser loginUser = getCurrentWxLoginUser();
  37. // 2. 查询并校验订单(公共方法提取)
  38. ProductOrderInfo productOrderInfo = this.productOrderInfoService.getAndCheckOrder(dto.getOrderId(), loginUser.getCOpenid());
  39. // 3. 校验订单状态是否允许售后
  40. Integer orderStatus = productOrderInfo.getOrderStatus();
  41. log.info("订单状态:{}", orderStatus);
  42. // 明确不允许的状态
  43. if (orderStatus == 0) {
  44. throw new ServiceException("待付款订单请直接取消");
  45. }
  46. if (orderStatus == 1) {
  47. throw new ServiceException("待发货订单请申请取消");
  48. }
  49. if (orderStatus == 4) {
  50. throw new ServiceException("售后申请已在处理中");
  51. }
  52. if (orderStatus == 11) {
  53. throw new ServiceException("已取消订单不支持售后");
  54. }
  55. // 只允许 2(待发货)或者3(已收货)发起售后
  56. if (orderStatus != 2 && orderStatus != 3) {
  57. throw new ServiceException("当前订单状态不支持发起售后");
  58. }
  59. // 4. 添加售后订单
  60. AfterSaleOrder entity = new AfterSaleOrder();
  61. BeanUtil.copyProperties(dto, entity);
  62. entity.setOpenId(loginUser.getCOpenid());
  63. entity.setCreateTime(LocalDateTime.now());
  64. entity.setAfterSaleStatus(AfterSaleStatusEnum.WAIT_AUDIT.getCode());
  65. entity.setAfterSaleNo(generateAfterSaleNo(dto.getOrderId()));
  66. boolean insertResult = super.save(entity);
  67. if (!insertResult) {
  68. throw new ServiceException("创建售后订单失败");
  69. }
  70. // 5. 更新订单状态
  71. ProductOrderInfo updateInfo = new ProductOrderInfo();
  72. updateInfo.setId(productOrderInfo.getId());
  73. updateInfo.setOrderStatus(ProductOrderStatusEnum.AFTER_SALES.getCode());
  74. updateInfo.setUpdateTime(LocalDateTime.now());
  75. boolean updateResult = this.productOrderInfoService.updateById(updateInfo);
  76. if (!updateResult) {
  77. throw new ServiceException("订单状态变更失败");
  78. }
  79. }
  80. @Override
  81. public OrderAfterSaleVo getOrderAfterSaleVo(Long orderId) {
  82. return this.afterSaleOrderMapper.selectAfterSaleVoByOrderId(orderId);
  83. }
  84. @Override
  85. @Transactional(rollbackFor = Exception.class)
  86. public void edit(AfterSaleOrderUpdateDTO dto) {
  87. // 1. 校验参数
  88. Long id = dto.getAfterSaleOrderId();
  89. if (ObjectUtil.isNull(id)) {
  90. throw new IllegalArgumentException("售后单ID不能为空");
  91. }
  92. // 2. 获取“等待用户寄回”的售后单
  93. LambdaQueryWrapper<AfterSaleOrder> queryWrapper = new LambdaQueryWrapper<>();
  94. queryWrapper.eq(AfterSaleOrder::getId, id)
  95. .eq(AfterSaleOrder::getAfterSaleStatus, AfterSaleStatusEnum.WAITING_USER_RETURN.getCode());
  96. AfterSaleOrder afterSaleOrder = this.afterSaleOrderMapper.selectOne(queryWrapper);
  97. if (ObjectUtil.isNull(afterSaleOrder)) {
  98. throw new ServiceException("等待用户寄回售后单不存在");
  99. }
  100. AfterSaleOrder updateInfo = new AfterSaleOrder();
  101. updateInfo.setId(id);
  102. updateInfo.setLogisticsNo(dto.getLogisticsNo());
  103. updateInfo.setUpdateTime(LocalDateTime.now());
  104. updateInfo.setAfterSaleStatus(AfterSaleStatusEnum.WAITING_MERCHANT_RECEIVE.getCode());
  105. boolean updateResult = this.updateById(updateInfo);
  106. if (!updateResult) {
  107. throw new ServiceException("取消售后单填写物流单号失败");
  108. }
  109. }
  110. @Override
  111. @Transactional(rollbackFor = Exception.class)
  112. public void cancel(Long orderId) {
  113. // 1. 获取当前登录用户(公共方法提取)
  114. WxLoginUser loginUser = getCurrentWxLoginUser();
  115. // 2. 查询并校验订单(公共方法提取)
  116. ProductOrderInfo productOrderInfo = this.productOrderInfoService.getAndCheckOrder(orderId, loginUser.getCOpenid());
  117. // 3. 状态校验:必须是 退货中/退款中 才能取消退货
  118. if (!ProductOrderStatusEnum.AFTER_SALES.getCode().equals(productOrderInfo.getOrderStatus())) {
  119. throw new ServiceException("订单状态异常,仅售后中状态可取消售后");
  120. }
  121. // 4. 取消售后订单(待审核 或 等待用户寄回)
  122. LambdaQueryWrapper<AfterSaleOrder> queryWrapper = new LambdaQueryWrapper<>();
  123. queryWrapper.eq(AfterSaleOrder::getOrderId, orderId)
  124. .eq(AfterSaleOrder::getOpenId, loginUser.getCOpenid())
  125. .in(AfterSaleOrder::getAfterSaleStatus,
  126. AfterSaleStatusEnum.WAIT_AUDIT.getCode(),
  127. AfterSaleStatusEnum.WAITING_USER_RETURN.getCode());
  128. AfterSaleOrder afterSaleOrder = this.afterSaleOrderMapper.selectOne(queryWrapper);
  129. if (ObjectUtil.isNull(afterSaleOrder)) {
  130. throw new ServiceException("未找到可取消的售后订单");
  131. }
  132. // 更新售后订单状态为已取消
  133. afterSaleOrder.setAfterSaleStatus(AfterSaleStatusEnum.CANCELLED.getCode());
  134. afterSaleOrder.setUpdateTime(LocalDateTime.now());
  135. boolean afterSaleUpdateResult = this.updateById(afterSaleOrder);
  136. if (!afterSaleUpdateResult) {
  137. throw new ServiceException("取消售后订单失败");
  138. }
  139. // 5. 更新订单状态
  140. ProductOrderInfo updateInfo = new ProductOrderInfo();
  141. updateInfo.setId(productOrderInfo.getId());
  142. updateInfo.setOrderStatus(ProductOrderStatusEnum.WAIT_RECEIVE.getCode());
  143. updateInfo.setUpdateTime(LocalDateTime.now());
  144. boolean orderUpdateResult = this.productOrderInfoService.updateById(updateInfo);
  145. if (!orderUpdateResult) {
  146. throw new ServiceException("订单状态变更失败");
  147. }
  148. }
  149. @Override
  150. @Transactional(rollbackFor = Exception.class)
  151. public void editByWechat(AfterSaleOrderUpdateDTO dto) {
  152. Long orderId = dto.getOrderId();
  153. if (ObjectUtil.isNull(orderId)) {
  154. throw new IllegalArgumentException("订单ID不能为空");
  155. }
  156. // 1. 获取当前登录用户(公共方法提取)
  157. WxLoginUser loginUser = getCurrentWxLoginUser();
  158. // 2. 查询并校验订单(公共方法提取)
  159. this.productOrderInfoService.getAndCheckOrder(orderId, loginUser.getCOpenid());
  160. // 3. 获取“同意退货/换货”的售后单
  161. LambdaQueryWrapper<AfterSaleOrder> queryWrapper = new LambdaQueryWrapper<>();
  162. queryWrapper.eq(AfterSaleOrder::getOrderId, orderId)
  163. .eq(AfterSaleOrder::getOpenId, loginUser.getCOpenid())
  164. .eq(AfterSaleOrder::getAfterSaleStatus, AfterSaleStatusEnum.WAITING_USER_RETURN.getCode());
  165. AfterSaleOrder afterSaleOrder = this.afterSaleOrderMapper.selectOne(queryWrapper);
  166. if (ObjectUtil.isNull(afterSaleOrder)) {
  167. throw new ServiceException("等待用户寄回售后单不存在");
  168. }
  169. // 4. 更新售后单信息
  170. AfterSaleOrder updateInfo = new AfterSaleOrder();
  171. updateInfo.setId(afterSaleOrder.getId());
  172. updateInfo.setLogisticsNo(dto.getLogisticsNo());
  173. updateInfo.setUpdateTime(LocalDateTime.now());
  174. updateInfo.setAfterSaleStatus(AfterSaleStatusEnum.WAITING_MERCHANT_RECEIVE.getCode());
  175. boolean updateResult = this.updateById(updateInfo);
  176. if (!updateResult) {
  177. throw new ServiceException("取消售后单填写物流单号失败");
  178. }
  179. }
  180. @Override
  181. @Transactional(rollbackFor = Exception.class)
  182. public void agreeReturn(Long orderId) {
  183. // 1. 查询并校验订单(公共方法提取)
  184. ProductOrderInfo productOrderInfo = this.productOrderInfoService.getAndCheckOrder(orderId, null);
  185. // 2. 状态校验:必须是 售后中 才能同意退货
  186. if (!ProductOrderStatusEnum.AFTER_SALES.getCode().equals(productOrderInfo.getOrderStatus())) {
  187. throw new ServiceException("订单状态异常,仅售后中状态可同意退货");
  188. }
  189. // 3. 判断售后单的状态为退货
  190. LambdaQueryWrapper<AfterSaleOrder> queryWrapper = new LambdaQueryWrapper<>();
  191. queryWrapper.eq(AfterSaleOrder::getOrderId, orderId)
  192. .eq(AfterSaleOrder::getAfterSaleType, AfterSaleTypeEnum.RETURN_GOODS.getCode())
  193. .eq(AfterSaleOrder::getAfterSaleStatus, AfterSaleStatusEnum.WAIT_AUDIT.getCode());
  194. AfterSaleOrder afterSaleOrder = this.afterSaleOrderMapper.selectOne(queryWrapper);
  195. if (ObjectUtil.isNull(afterSaleOrder)) {
  196. throw new ServiceException("未找到待审核的退货的售后单");
  197. }
  198. // 4. 更新售后订单状态为等待用户寄回
  199. afterSaleOrder.setAfterSaleStatus(AfterSaleStatusEnum.WAITING_USER_RETURN.getCode());
  200. afterSaleOrder.setUpdateTime(LocalDateTime.now());
  201. boolean afterSaleUpdateResult = this.updateById(afterSaleOrder);
  202. if (!afterSaleUpdateResult) {
  203. throw new ServiceException("更新售后单失败");
  204. }
  205. }
  206. @Override
  207. @Transactional(rollbackFor = Exception.class)
  208. public void agreeExchange(Long orderId) {
  209. // 1. 查询并校验订单(公共方法提取)
  210. ProductOrderInfo productOrderInfo = this.productOrderInfoService.getAndCheckOrder(orderId, null);
  211. // 2. 状态校验:必须是 售后中 才能同意退货
  212. if (!ProductOrderStatusEnum.AFTER_SALES.getCode().equals(productOrderInfo.getOrderStatus())) {
  213. throw new ServiceException("订单状态异常,仅售后中状态可同意换货");
  214. }
  215. // 3. 判断售后单的状态为换货
  216. LambdaQueryWrapper<AfterSaleOrder> queryWrapper = new LambdaQueryWrapper<>();
  217. queryWrapper.eq(AfterSaleOrder::getOrderId, orderId)
  218. .eq(AfterSaleOrder::getAfterSaleType, AfterSaleTypeEnum.EXCHANGE_GOODS.getCode())
  219. .eq(AfterSaleOrder::getAfterSaleStatus, AfterSaleStatusEnum.WAIT_AUDIT.getCode());
  220. AfterSaleOrder afterSaleOrder = this.afterSaleOrderMapper.selectOne(queryWrapper);
  221. if (ObjectUtil.isNull(afterSaleOrder)) {
  222. throw new ServiceException("未找到待审核的换货的售后单");
  223. }
  224. // 4. 更新售后订单状态为等待用户寄回
  225. afterSaleOrder.setAfterSaleStatus(AfterSaleStatusEnum.WAITING_USER_RETURN.getCode());
  226. afterSaleOrder.setUpdateTime(LocalDateTime.now());
  227. boolean afterSaleUpdateResult = this.updateById(afterSaleOrder);
  228. if (!afterSaleUpdateResult) {
  229. throw new ServiceException("更新售后单失败");
  230. }
  231. }
  232. @Override
  233. @Transactional(rollbackFor = Exception.class)
  234. public void agreeRefund(Long orderId) {
  235. // 1. 查询并校验订单(公共方法提取)
  236. ProductOrderInfo productOrderInfo = this.productOrderInfoService.getAndCheckOrder(orderId, null);
  237. // 2. 状态校验:必须是 售后中 才能确认收货
  238. if (!ProductOrderStatusEnum.AFTER_SALES.getCode().equals(productOrderInfo.getOrderStatus())) {
  239. throw new ServiceException("订单状态异常,仅售后中状态可确认收货");
  240. }
  241. // 3. 获取等待商家收货的售后单
  242. LambdaQueryWrapper<AfterSaleOrder> queryWrapper = new LambdaQueryWrapper<>();
  243. queryWrapper.eq(AfterSaleOrder::getOrderId, orderId)
  244. .in(AfterSaleOrder::getAfterSaleStatus,
  245. AfterSaleStatusEnum.WAIT_AUDIT.getCode(),
  246. AfterSaleStatusEnum.WAITING_MERCHANT_RECEIVE.getCode());
  247. AfterSaleOrder afterSaleOrder = this.afterSaleOrderMapper.selectOne(queryWrapper);
  248. if (ObjectUtil.isNull(afterSaleOrder)) {
  249. throw new ServiceException("未找到可审核的售后单");
  250. }
  251. AfterSaleTypeEnum typeEnum = AfterSaleTypeEnum.valueOf(afterSaleOrder.getAfterSaleType());
  252. AfterSaleStatusEnum statusEnum = AfterSaleStatusEnum.valueOf(afterSaleOrder.getAfterSaleStatus());
  253. switch (typeEnum) {
  254. case NOT_RECEIVED:
  255. // ====================== 未收到货 → 仅退款 ======================
  256. if (statusEnum != AfterSaleStatusEnum.WAIT_AUDIT) {
  257. throw new ServiceException("仅退款单状态异常,无法审核");
  258. }
  259. break;
  260. case RETURN_GOODS:
  261. // ====================== 已收到货 → 退货退款 ======================
  262. if (statusEnum != AfterSaleStatusEnum.WAITING_MERCHANT_RECEIVE) {
  263. throw new ServiceException("退货单需用户寄回、商家收货后才能审核退款");
  264. }
  265. break;
  266. default:
  267. throw new ServiceException("不支持的售后类型");
  268. }
  269. // 4. 判断售后单的售后类型
  270. if (ObjectUtil.notEqual(AfterSaleTypeEnum.RETURN_GOODS.getCode(), afterSaleOrder.getAfterSaleType())) {
  271. throw new ServiceException("售后单类型异常,仅退货的售后单可退货");
  272. }
  273. // TODO 5.退款
  274. // 6. 更新售后单数据
  275. afterSaleOrder.setAfterSaleStatus(AfterSaleStatusEnum.REFUND_COMPLETED.getCode());
  276. afterSaleOrder.setUpdateTime(LocalDateTime.now());
  277. boolean afterSaleUpdateResult = this.updateById(afterSaleOrder);
  278. if (!afterSaleUpdateResult) {
  279. throw new ServiceException("更新售后单失败");
  280. }
  281. // TODO 7.更新库存信息
  282. }
  283. @Override
  284. @Transactional(rollbackFor = Exception.class)
  285. public void confirmReceive(Long orderId) {
  286. // 1. 查询并校验订单(公共方法提取)
  287. ProductOrderInfo productOrderInfo = this.productOrderInfoService.getAndCheckOrder(orderId, null);
  288. // 2. 状态校验:必须是 售后中 才能确认收货
  289. if (!ProductOrderStatusEnum.AFTER_SALES.getCode().equals(productOrderInfo.getOrderStatus())) {
  290. throw new ServiceException("订单状态异常,仅售后中状态可确认收货");
  291. }
  292. // 3. 获取等待商家收货的售后单
  293. LambdaQueryWrapper<AfterSaleOrder> queryWrapper = new LambdaQueryWrapper<>();
  294. queryWrapper.eq(AfterSaleOrder::getOrderId, orderId)
  295. .eq(AfterSaleOrder::getAfterSaleStatus, AfterSaleStatusEnum.WAITING_MERCHANT_RECEIVE.getCode());
  296. AfterSaleOrder afterSaleOrder = this.afterSaleOrderMapper.selectOne(queryWrapper);
  297. if (ObjectUtil.isNull(afterSaleOrder)) {
  298. throw new ServiceException("未找到等待商家收货的售后单");
  299. }
  300. // 4. 判断售后单的售后类型
  301. if (ObjectUtil.notEqual(AfterSaleTypeEnum.EXCHANGE_GOODS.getCode(), afterSaleOrder.getAfterSaleType())) {
  302. throw new ServiceException("售后单类型异常,仅换货的售后单可换货");
  303. }
  304. // 5. 更新售后单数据
  305. afterSaleOrder.setAfterSaleStatus(AfterSaleStatusEnum.WAITING_MERCHANT_SHIP.getCode());
  306. afterSaleOrder.setUpdateTime(LocalDateTime.now());
  307. boolean afterSaleUpdateResult = this.updateById(afterSaleOrder);
  308. if (!afterSaleUpdateResult) {
  309. throw new ServiceException("更新售后单失败");
  310. }
  311. }
  312. private WxLoginUser getCurrentWxLoginUser() {
  313. WxLoginUser loginUser = SecurityUtils.getWxLoginUser();
  314. if (ObjectUtil.isNull(loginUser)) {
  315. throw new ServiceException("用户未登录或登录已过期");
  316. }
  317. return loginUser;
  318. }
  319. /**
  320. * 生成售后单号
  321. * @param orderId 订单ID
  322. * @return String 售后单号
  323. */
  324. private String generateAfterSaleNo(Long orderId) {
  325. return "AFTERSALE" + orderId + System.currentTimeMillis();
  326. }
  327. }