|
|
@@ -0,0 +1,215 @@
|
|
|
+package com.ylx.massage.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.ylx.common.exception.ServiceException;
|
|
|
+import com.ylx.common.utils.StringUtils;
|
|
|
+import com.ylx.massage.domain.CancelOrderApplication;
|
|
|
+import com.ylx.massage.domain.TJs;
|
|
|
+import com.ylx.massage.domain.TOrder;
|
|
|
+import com.ylx.massage.domain.TWxUser;
|
|
|
+import com.ylx.massage.enums.OrderStatusEnum;
|
|
|
+import com.ylx.massage.service.CancelOrderApplicationService;
|
|
|
+import com.ylx.massage.service.TJsService;
|
|
|
+import com.ylx.massage.service.TOrderService;
|
|
|
+import com.ylx.massage.service.TWxUserService;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.time.Duration;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 退单申请服务实现类
|
|
|
+ *
|
|
|
+ * @author claude
|
|
|
+ * @date 2025-01-14
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class CancelOrderApplicationServiceImpl extends ServiceImpl<com.ylx.massage.mapper.CancelOrderApplicationMapper, CancelOrderApplication>
|
|
|
+ implements CancelOrderApplicationService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TOrderService orderService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TJsService jsService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TWxUserService wxUserService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建退单申请
|
|
|
+ *
|
|
|
+ * @param orderId 订单ID
|
|
|
+ * @param cancelReason 退单原因
|
|
|
+ * @return String 申请记录ID
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public String createApplication(String orderId, String cancelReason) {
|
|
|
+ log.info("开始创建退单申请,订单ID:{},退单原因:{}", orderId, cancelReason);
|
|
|
+
|
|
|
+ // 1. 参数校验
|
|
|
+ if (StringUtils.isEmpty(orderId)) {
|
|
|
+ throw new ServiceException("订单ID不能为空");
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(cancelReason)) {
|
|
|
+ throw new ServiceException("退单原因不能为空");
|
|
|
+ }
|
|
|
+ if (cancelReason.length() > 50) {
|
|
|
+ throw new ServiceException("退单原因不能超过50个字符");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询订单信息
|
|
|
+ TOrder order = orderService.getById(orderId);
|
|
|
+ if (order == null) {
|
|
|
+ throw new ServiceException("订单不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 校验订单状态 - 只有进行中的订单才能申请退单
|
|
|
+ // 进行中状态包括: 待接单(0)、已接单(1)、已出发(6)、已到达(2)、服务中(3)
|
|
|
+ Integer currentStatus = order.getnStatus();
|
|
|
+ if (!isOrderInProgress(currentStatus)) {
|
|
|
+ throw new ServiceException("当前订单状态不允许申请退单,只有进行中的订单可以申请退单");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 检查是否已有待审核的退单申请
|
|
|
+ CancelOrderApplication existingApplication = getLatestByOrderId(orderId);
|
|
|
+ if (existingApplication != null && existingApplication.getAuditStatus() == 0) {
|
|
|
+ throw new ServiceException("该订单已有待审核的退单申请,请勿重复提交");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 6. 查询技师信息
|
|
|
+ TJs technician = null;
|
|
|
+ if (StringUtils.isNotEmpty(order.getcJsId())) {
|
|
|
+ technician = jsService.getById(order.getcJsId());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 7. 构建退单申请记录
|
|
|
+ CancelOrderApplication application = new CancelOrderApplication();
|
|
|
+ application.setOrderId(order.getcId());
|
|
|
+ application.setOrderNo(order.getOrderNo());
|
|
|
+ application.setOpenId(order.getcOpenId());
|
|
|
+ application.setUserName(order.getcName());
|
|
|
+ application.setUserPhone(order.getcPhone());
|
|
|
+ application.setTechId(order.getcJsId());
|
|
|
+ application.setTechName(technician != null ? technician.getcName() : null);
|
|
|
+ application.setTechNickName(technician != null ? technician.getcNickName() : null);
|
|
|
+
|
|
|
+ // 从订单明细中提取项目名称
|
|
|
+ String projectName = extractProjectName(order);
|
|
|
+ application.setProjectName(projectName);
|
|
|
+
|
|
|
+ // 计算已服务时长
|
|
|
+ String serviceDuration = calculateServiceDuration(order);
|
|
|
+ application.setServiceDuration(serviceDuration);
|
|
|
+
|
|
|
+ // 设置金额
|
|
|
+ application.setOrderAmount(order.getTotalPrice() != null ? order.getTotalPrice() : BigDecimal.ZERO);
|
|
|
+ //application.setRefundAmount(order.getTotalPrice() != null ? order.getTotalPrice() : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 设置申请信息
|
|
|
+ application.setAuditStatus(0); // 0:待审核
|
|
|
+ application.setApplicationTime(LocalDateTime.now());
|
|
|
+ application.setCancelOrderReason(cancelReason);
|
|
|
+
|
|
|
+ // 设置创建时间
|
|
|
+ application.setCreateTime(LocalDateTime.now());
|
|
|
+ application.setUpdateTime(LocalDateTime.now());
|
|
|
+ application.setIsDelete(0);
|
|
|
+
|
|
|
+ // 8. 保存退单申请记录
|
|
|
+ boolean saved = this.save(application);
|
|
|
+ if (!saved) {
|
|
|
+ throw new ServiceException("创建退单申请失败");
|
|
|
+ }
|
|
|
+ log.info("退单申请创建成功,申请ID:{},订单ID:{}", application.getId(), orderId);
|
|
|
+ return application.getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据订单ID查询最新的退单申请
|
|
|
+ *
|
|
|
+ * @param orderId 订单ID
|
|
|
+ * @return CancelOrderApplication 退单申请记录
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public CancelOrderApplication getLatestByOrderId(String orderId) {
|
|
|
+ LambdaQueryWrapper<CancelOrderApplication> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(CancelOrderApplication::getOrderId, orderId)
|
|
|
+ .orderByDesc(CancelOrderApplication::getCreateTime)
|
|
|
+ .last("LIMIT 1");
|
|
|
+ return this.getOne(wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断订单是否为进行中状态
|
|
|
+ * 进行中状态包括: 待接单(0)、已接单(1)、已出发(6)、已到达(2)、服务中(3)
|
|
|
+ *
|
|
|
+ * @param status 订单状态
|
|
|
+ * @return true-进行中,false-非进行中
|
|
|
+ */
|
|
|
+ private boolean isOrderInProgress(Integer status) {
|
|
|
+ return status != null &&
|
|
|
+ (status.equals(OrderStatusEnum.WAIT_JD.getCode()) || // 待接单
|
|
|
+ status.equals(OrderStatusEnum.RECEIVED_ORDER.getCode()) || // 已接单
|
|
|
+ status.equals(OrderStatusEnum.DEPART.getCode()) || // 已出发
|
|
|
+ status.equals(OrderStatusEnum.ARRIVED.getCode()) || // 已到达
|
|
|
+ status.equals(OrderStatusEnum.SERVICE.getCode())); // 服务中
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从订单中提取项目名称
|
|
|
+ *
|
|
|
+ * @param order 订单对象
|
|
|
+ * @return String 项目名称
|
|
|
+ */
|
|
|
+ private String extractProjectName(TOrder order) {
|
|
|
+ try {
|
|
|
+ if (order.getcGoods() != null && !order.getcGoods().isEmpty()) {
|
|
|
+ // cGoods是JSONArray,解析第一个项目的名称
|
|
|
+ return order.getcGoods().getJSONObject(0).getString("cTitle");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("解析订单项目名称失败,订单ID:{}", order.getcId(), e);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算已服务时长(分钟)
|
|
|
+ *
|
|
|
+ * @param order 订单对象
|
|
|
+ * @return String服务时长字符串,如"40分钟"
|
|
|
+ */
|
|
|
+ private String calculateServiceDuration(TOrder order) {
|
|
|
+ try {
|
|
|
+ LocalDateTime startTime = order.getStartTime();
|
|
|
+ LocalDateTime endTime = order.getEndTime();
|
|
|
+
|
|
|
+ if (startTime != null && endTime != null) {
|
|
|
+ long minutes = Duration.between(startTime, endTime).toMinutes();
|
|
|
+ if (minutes > 0) {
|
|
|
+ return minutes + "分钟";
|
|
|
+ }
|
|
|
+ } else if (startTime != null) {
|
|
|
+ // 如果只有开始时间,计算到现在的时长
|
|
|
+ long minutes = Duration.between(startTime, LocalDateTime.now()).toMinutes();
|
|
|
+ if (minutes > 0) {
|
|
|
+ return minutes + "分钟";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("计算服务时长失败,订单ID:{}", order.getcId(), e);
|
|
|
+ }
|
|
|
+ return "0分钟";
|
|
|
+ }
|
|
|
+}
|