|
@@ -1,20 +1,29 @@
|
|
|
package com.ylx.order.service.impl;
|
|
package com.ylx.order.service.impl;
|
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
+import com.ylx.common.core.domain.model.LoginUser;
|
|
|
import com.ylx.common.exception.ServiceException;
|
|
import com.ylx.common.exception.ServiceException;
|
|
|
import com.ylx.massage.domain.CancelOrderApplication;
|
|
import com.ylx.massage.domain.CancelOrderApplication;
|
|
|
|
|
+import com.ylx.order.domain.OrderDispatch;
|
|
|
|
|
+import com.ylx.order.domain.dto.AdminOrderDispatchDTO;
|
|
|
|
|
+import com.ylx.order.domain.dto.AdminOrderDispatchMerchantQueryDTO;
|
|
|
import com.ylx.order.domain.dto.AdminOrderQueryDTO;
|
|
import com.ylx.order.domain.dto.AdminOrderQueryDTO;
|
|
|
import com.ylx.order.domain.vo.AdminOrderDetailVO;
|
|
import com.ylx.order.domain.vo.AdminOrderDetailVO;
|
|
|
|
|
+import com.ylx.order.domain.vo.AdminOrderDispatchMerchantVO;
|
|
|
|
|
+import com.ylx.order.domain.vo.AdminOrderDispatchOrderVO;
|
|
|
import com.ylx.order.domain.vo.AdminOrderPageVO;
|
|
import com.ylx.order.domain.vo.AdminOrderPageVO;
|
|
|
import com.ylx.order.domain.vo.AdminOrderServiceCategoryVO;
|
|
import com.ylx.order.domain.vo.AdminOrderServiceCategoryVO;
|
|
|
import com.ylx.order.enums.AfterSaleServiceStatusEnum;
|
|
import com.ylx.order.enums.AfterSaleServiceStatusEnum;
|
|
|
import com.ylx.order.mapper.AdminOrderMapper;
|
|
import com.ylx.order.mapper.AdminOrderMapper;
|
|
|
import com.ylx.order.service.AdminOrderService;
|
|
import com.ylx.order.service.AdminOrderService;
|
|
|
|
|
+import org.springframework.security.core.Authentication;
|
|
|
|
|
+import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.util.StringUtils;
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.time.LocalDate;
|
|
import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.LocalTime;
|
|
import java.time.LocalTime;
|
|
@@ -38,6 +47,13 @@ public class AdminOrderServiceImpl implements AdminOrderService {
|
|
|
private static final String USER_SEARCH_NAME = "name";
|
|
private static final String USER_SEARCH_NAME = "name";
|
|
|
private static final String MERCHANT_SEARCH_NICK_NAME = "nickName";
|
|
private static final String MERCHANT_SEARCH_NICK_NAME = "nickName";
|
|
|
private static final String MERCHANT_SEARCH_PHONE = "phone";
|
|
private static final String MERCHANT_SEARCH_PHONE = "phone";
|
|
|
|
|
+ private static final BigDecimal DEFAULT_DISPATCH_RADIUS_METERS = new BigDecimal("10000");
|
|
|
|
|
+ private static final Integer ORDER_STATUS_PENDING_DISPATCH = 1;
|
|
|
|
|
+ private static final Integer ORDER_STATUS_PENDING_ACCEPT = 2;
|
|
|
|
|
+ private static final Integer DISPATCH_STATUS_PENDING_ACCEPT = 1;
|
|
|
|
|
+ private static final Integer DISPATCH_SOURCE_ADMIN = 1;
|
|
|
|
|
+ private static final Integer CURRENT_DISPATCH = 1;
|
|
|
|
|
+ private static final Integer NOT_DELETED = 0;
|
|
|
|
|
|
|
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
@@ -157,6 +173,176 @@ public class AdminOrderServiceImpl implements AdminOrderService {
|
|
|
return detail;
|
|
return detail;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<AdminOrderDispatchMerchantVO> listDispatchMerchants(Long id, AdminOrderDispatchMerchantQueryDTO dto) {
|
|
|
|
|
+ AdminOrderDispatchOrderVO order = getDispatchOrder(id);
|
|
|
|
|
+ validatePendingDispatchOrder(order);
|
|
|
|
|
+ validateDispatchOrderLocation(order);
|
|
|
|
|
+
|
|
|
|
|
+ AdminOrderDispatchMerchantQueryDTO query = normalizeDispatchMerchantQuery(dto);
|
|
|
|
|
+ return adminOrderMapper.selectDispatchMerchantCandidates(order, query);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public void dispatch(Long id, AdminOrderDispatchDTO dto) {
|
|
|
|
|
+ if (dto == null || dto.getMerchantId() == null) {
|
|
|
|
|
+ throw new ServiceException("请选择商户");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (dto.getMerchantId() <= 0) {
|
|
|
|
|
+ throw new ServiceException("商户ID不正确");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ AdminOrderDispatchOrderVO order = getDispatchOrder(id);
|
|
|
|
|
+ validatePendingDispatchOrder(order);
|
|
|
|
|
+ validateDispatchOrderLocation(order);
|
|
|
|
|
+
|
|
|
|
|
+ BigDecimal radiusMeters = normalizeDispatchRadius(dto.getRadiusMeters());
|
|
|
|
|
+ AdminOrderDispatchMerchantVO merchant = adminOrderMapper.selectDispatchMerchantById(order, dto.getMerchantId(), radiusMeters);
|
|
|
|
|
+ if (merchant == null) {
|
|
|
|
|
+ throw new ServiceException("请选择可派单商户");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (adminOrderMapper.countCurrentDispatchByOrderId(id) > 0) {
|
|
|
|
|
+ throw new ServiceException("该订单已存在有效派单记录,请刷新重试");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int orderRows = adminOrderMapper.updateOrderDispatch(id, merchant, ORDER_STATUS_PENDING_DISPATCH, ORDER_STATUS_PENDING_ACCEPT);
|
|
|
|
|
+ if (orderRows <= 0) {
|
|
|
|
|
+ throw new ServiceException("操作失败,请刷新重试");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ OrderDispatch dispatch = buildOrderDispatch(order, merchant, dto);
|
|
|
|
|
+ int dispatchRows = adminOrderMapper.insertOrderDispatch(dispatch);
|
|
|
|
|
+ if (dispatchRows <= 0) {
|
|
|
|
|
+ throw new ServiceException("保存派单记录失败");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int flowRows = adminOrderMapper.insertOrderStatusFlow(id, ORDER_STATUS_PENDING_ACCEPT, getCurrentOperator());
|
|
|
|
|
+ if (flowRows <= 0) {
|
|
|
|
|
+ throw new ServiceException("保存订单状态流转失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取待派单订单详情
|
|
|
|
|
+ * @param id
|
|
|
|
|
+ * @return AdminOrderDispatchOrderVO
|
|
|
|
|
+ */
|
|
|
|
|
+ private AdminOrderDispatchOrderVO getDispatchOrder(Long id) {
|
|
|
|
|
+ validateOrderId(id);
|
|
|
|
|
+ AdminOrderDispatchOrderVO order = adminOrderMapper.selectDispatchOrderById(id);
|
|
|
|
|
+ if (order == null) {
|
|
|
|
|
+ throw new ServiceException("订单不存在或已删除");
|
|
|
|
|
+ }
|
|
|
|
|
+ return order;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验证待派单订单的状态
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param order
|
|
|
|
|
+ */
|
|
|
|
|
+ private void validatePendingDispatchOrder(AdminOrderDispatchOrderVO order) {
|
|
|
|
|
+ if (!ORDER_STATUS_PENDING_DISPATCH.equals(order.getStatus())) {
|
|
|
|
|
+ throw new ServiceException("当前订单状态不是待派单状态,请刷新重试");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void validateDispatchOrderLocation(AdminOrderDispatchOrderVO order) {
|
|
|
|
|
+ if (order.getUserLatitude() == null || order.getUserLongitude() == null) {
|
|
|
|
|
+ throw new ServiceException("订单下单坐标不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建派单商户查询参数,处理默认值和空值
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param dto
|
|
|
|
|
+ * @return AdminOrderDispatchMerchantQueryDTO
|
|
|
|
|
+ */
|
|
|
|
|
+ private AdminOrderDispatchMerchantQueryDTO normalizeDispatchMerchantQuery(AdminOrderDispatchMerchantQueryDTO dto) {
|
|
|
|
|
+ AdminOrderDispatchMerchantQueryDTO query = dto == null ? new AdminOrderDispatchMerchantQueryDTO() : dto;
|
|
|
|
|
+ query.setRadiusMeters(normalizeDispatchRadius(query.getRadiusMeters()));
|
|
|
|
|
+ if (StringUtils.hasText(query.getKeyword())) {
|
|
|
|
|
+ query.setKeyword(query.getKeyword().trim());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ query.setKeyword(null);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StringUtils.hasText(query.getCityCode())) {
|
|
|
|
|
+ query.setCityCode(query.getCityCode().trim());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ query.setCityCode(null);
|
|
|
|
|
+ }
|
|
|
|
|
+ return query;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理派单半径,默认值为1000米
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param radiusMeters
|
|
|
|
|
+ * @return BigDecimal
|
|
|
|
|
+ */
|
|
|
|
|
+ private BigDecimal normalizeDispatchRadius(BigDecimal radiusMeters) {
|
|
|
|
|
+ if (radiusMeters == null || radiusMeters.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
|
|
+ return DEFAULT_DISPATCH_RADIUS_METERS;
|
|
|
|
|
+ }
|
|
|
|
|
+ return radiusMeters;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private OrderDispatch buildOrderDispatch(AdminOrderDispatchOrderVO order, AdminOrderDispatchMerchantVO merchant, AdminOrderDispatchDTO dto) {
|
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
+ String operator = getCurrentOperator();
|
|
|
|
|
+ OrderDispatch dispatch = new OrderDispatch();
|
|
|
|
|
+ dispatch.setOrderId(order.getOrderId());
|
|
|
|
|
+ dispatch.setOrderNo(order.getOrderNo());
|
|
|
|
|
+ dispatch.setMerchantId(merchant.getMerchantId());
|
|
|
|
|
+ dispatch.setMerchantName(merchant.getMerchantName());
|
|
|
|
|
+ dispatch.setMerchantNickName(merchant.getMerchantNickName());
|
|
|
|
|
+ dispatch.setMerchantPhone(merchant.getMerchantPhone());
|
|
|
|
|
+ dispatch.setMerchantAvatar(merchant.getMerchantAvatar());
|
|
|
|
|
+ dispatch.setMerchantType(merchant.getMerchantType());
|
|
|
|
|
+ dispatch.setProjectId(order.getProjectId());
|
|
|
|
|
+ dispatch.setProjectName(order.getProjectName());
|
|
|
|
|
+ dispatch.setCategoryId(order.getCategoryId());
|
|
|
|
|
+ dispatch.setCityCode(StringUtils.hasText(dto.getCityCode()) ? dto.getCityCode().trim() : null);
|
|
|
|
|
+ dispatch.setUserLatitude(order.getUserLatitude());
|
|
|
|
|
+ dispatch.setUserLongitude(order.getUserLongitude());
|
|
|
|
|
+ dispatch.setMerchantLatitude(merchant.getMerchantLatitude());
|
|
|
|
|
+ dispatch.setMerchantLongitude(merchant.getMerchantLongitude());
|
|
|
|
|
+ dispatch.setDistanceMeters(merchant.getDistanceMeters());
|
|
|
|
|
+ dispatch.setDispatchStatus(DISPATCH_STATUS_PENDING_ACCEPT);
|
|
|
|
|
+ dispatch.setDispatchSource(DISPATCH_SOURCE_ADMIN);
|
|
|
|
|
+ dispatch.setCurrentFlag(CURRENT_DISPATCH);
|
|
|
|
|
+ dispatch.setOrderStatusBefore(ORDER_STATUS_PENDING_DISPATCH);
|
|
|
|
|
+ dispatch.setOrderStatusAfter(ORDER_STATUS_PENDING_ACCEPT);
|
|
|
|
|
+ dispatch.setDispatchTime(now);
|
|
|
|
|
+ dispatch.setRemark(StringUtils.hasText(dto.getRemark()) ? dto.getRemark().trim() : null);
|
|
|
|
|
+ dispatch.setOperatorName(operator);
|
|
|
|
|
+ dispatch.setCreateBy(operator);
|
|
|
|
|
+ dispatch.setCreateTime(now);
|
|
|
|
|
+ dispatch.setUpdateBy(operator);
|
|
|
|
|
+ dispatch.setUpdateTime(now);
|
|
|
|
|
+ dispatch.setIsDelete(NOT_DELETED);
|
|
|
|
|
+ return dispatch;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String getCurrentOperator() {
|
|
|
|
|
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
|
|
|
|
+ if (authentication == null || authentication.getPrincipal() == null) {
|
|
|
|
|
+ return "系统";
|
|
|
|
|
+ }
|
|
|
|
|
+ Object principal = authentication.getPrincipal();
|
|
|
|
|
+ if (principal instanceof LoginUser) {
|
|
|
|
|
+ String username = ((LoginUser) principal).getUsername();
|
|
|
|
|
+ return StringUtils.hasText(username) ? username : "系统";
|
|
|
|
|
+ }
|
|
|
|
|
+ if (principal instanceof String && StringUtils.hasText((String) principal)) {
|
|
|
|
|
+ return (String) principal;
|
|
|
|
|
+ }
|
|
|
|
|
+ return "系统";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 填充订单详情显示字段
|
|
* 填充订单详情显示字段
|
|
|
* @param orderInfo
|
|
* @param orderInfo
|
|
@@ -195,6 +381,11 @@ public class AdminOrderServiceImpl implements AdminOrderService {
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验证订单ID
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param id
|
|
|
|
|
+ */
|
|
|
private void validateOrderId(Long id) {
|
|
private void validateOrderId(Long id) {
|
|
|
if (id == null) {
|
|
if (id == null) {
|
|
|
throw new ServiceException("订单ID不能为空");
|
|
throw new ServiceException("订单ID不能为空");
|