|
|
@@ -0,0 +1,373 @@
|
|
|
+package org.dromara.order.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.dromara.common.core.context.PlatformContext;
|
|
|
+import org.dromara.common.core.enums.OrderAssignStatus;
|
|
|
+import org.dromara.common.core.enums.OrderSplitStatus;
|
|
|
+import org.dromara.common.core.enums.SysPlatformCode;
|
|
|
+import org.dromara.common.core.exception.ServiceException;
|
|
|
+import org.dromara.common.core.utils.MapstructUtils;
|
|
|
+import org.dromara.common.core.utils.PlatformContextUtil;
|
|
|
+import org.dromara.common.core.utils.StringUtils;
|
|
|
+import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
+import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
+import org.dromara.common.redis.utils.SequenceUtils;
|
|
|
+import org.dromara.common.satoken.utils.LoginHelper;
|
|
|
+import org.dromara.order.domain.OrderAssignment;
|
|
|
+import org.dromara.order.domain.OrderMain;
|
|
|
+import org.dromara.order.domain.OrderProduct;
|
|
|
+import org.dromara.order.domain.OrderProductAssignRule;
|
|
|
+import org.dromara.order.domain.bo.OrderAssignmentBo;
|
|
|
+import org.dromara.order.domain.bo.OrderSplitAssignBo;
|
|
|
+import org.dromara.order.domain.vo.OrderAssignmentVo;
|
|
|
+import org.dromara.order.domain.vo.OrderMainVo;
|
|
|
+import org.dromara.order.mapper.OrderAssignmentMapper;
|
|
|
+import org.dromara.order.mapper.OrderMainMapper;
|
|
|
+import org.dromara.order.mapper.OrderProductMapper;
|
|
|
+import org.dromara.order.service.IOrderAssignmentService;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.time.Duration;
|
|
|
+import java.util.*;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 订单分配记录Service业务层处理
|
|
|
+ *
|
|
|
+ * @author LionLi
|
|
|
+ * @date 2026-01-07
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RequiredArgsConstructor
|
|
|
+@Service
|
|
|
+public class OrderAssignmentServiceImpl extends ServiceImpl<OrderAssignmentMapper, OrderAssignment> implements IOrderAssignmentService {
|
|
|
+
|
|
|
+ private static final String CHILD_ORDER_NO_KEY = "order_main:child_order_no";
|
|
|
+
|
|
|
+ private final OrderAssignmentMapper baseMapper;
|
|
|
+
|
|
|
+ private final OrderMainMapper orderMainMapper;
|
|
|
+
|
|
|
+ private final OrderProductMapper orderProductMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询订单分配记录
|
|
|
+ *
|
|
|
+ * @param id 主键
|
|
|
+ * @return 订单分配记录
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public OrderAssignmentVo queryById(Long id) {
|
|
|
+ return baseMapper.selectVoById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页查询订单分配记录列表
|
|
|
+ *
|
|
|
+ * @param bo 查询条件
|
|
|
+ * @param pageQuery 分页参数
|
|
|
+ * @return 订单分配记录分页列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public TableDataInfo<OrderAssignmentVo> queryPageList(OrderAssignmentBo bo, PageQuery pageQuery) {
|
|
|
+ LambdaQueryWrapper<OrderAssignment> lqw = buildQueryWrapper(bo);
|
|
|
+ Page<OrderAssignmentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
|
+ return TableDataInfo.build(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询符合条件的订单分配记录列表
|
|
|
+ *
|
|
|
+ * @param bo 查询条件
|
|
|
+ * @return 订单分配记录列表
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<OrderAssignmentVo> queryList(OrderAssignmentBo bo) {
|
|
|
+ LambdaQueryWrapper<OrderAssignment> lqw = buildQueryWrapper(bo);
|
|
|
+ return baseMapper.selectVoList(lqw);
|
|
|
+ }
|
|
|
+
|
|
|
+ private LambdaQueryWrapper<OrderAssignment> buildQueryWrapper(OrderAssignmentBo bo) {
|
|
|
+ Map<String, Object> params = bo.getParams();
|
|
|
+ LambdaQueryWrapper<OrderAssignment> lqw = Wrappers.lambdaQuery();
|
|
|
+ lqw.orderByAsc(OrderAssignment::getId);
|
|
|
+ lqw.eq(bo.getOrderId() != null, OrderAssignment::getOrderId, bo.getOrderId());
|
|
|
+ lqw.eq(StringUtils.isNotBlank(bo.getPlatformBefore()), OrderAssignment::getPlatformBefore, bo.getPlatformBefore());
|
|
|
+ lqw.eq(StringUtils.isNotBlank(bo.getPlatformAfter()), OrderAssignment::getPlatformAfter, bo.getPlatformAfter());
|
|
|
+ lqw.eq(bo.getAssignedBy() != null, OrderAssignment::getAssignedBy, bo.getAssignedBy());
|
|
|
+ lqw.eq(StringUtils.isNotBlank(bo.getAssignType()), OrderAssignment::getAssignType, bo.getAssignType());
|
|
|
+ if (params != null) {
|
|
|
+ lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
|
|
|
+ OrderAssignment::getAssignTime, params.get("beginTime"), params.get("endTime"));
|
|
|
+ }
|
|
|
+ return lqw;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增订单分配记录
|
|
|
+ *
|
|
|
+ * @param bo 订单分配记录
|
|
|
+ * @return 是否新增成功
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean insertByBo(OrderAssignmentBo bo) {
|
|
|
+ Date now = new Date();
|
|
|
+ Long operatorId = LoginHelper.getUserId();
|
|
|
+
|
|
|
+ // 1. 解析订单ID列表
|
|
|
+ List<Long> orderIdList = parseOrderIds(bo.getOrderIds());
|
|
|
+
|
|
|
+ // 2. 查询原始订单信息
|
|
|
+ List<OrderMainVo> orderVos = orderMainMapper.selectVoByIds(orderIdList);
|
|
|
+ Map<Long, String> orderIdToPlatformBefore = orderVos.stream()
|
|
|
+ .collect(Collectors.toMap(OrderMainVo::getId, OrderMainVo::getPlatformCode));
|
|
|
+ Map<Long, String> orderNoToMap = orderVos.stream()
|
|
|
+ .collect(Collectors.toMap(OrderMainVo::getId, OrderMainVo::getOrderNo));
|
|
|
+
|
|
|
+ // 3. 准备分配记录 & 主订单更新对象
|
|
|
+ List<OrderAssignment> assignmentsToInsert = new ArrayList<>();
|
|
|
+ List<OrderMain> ordersToUpdate = new ArrayList<>();
|
|
|
+
|
|
|
+ for (Long orderId : orderIdList) {
|
|
|
+ OrderAssignment assignment = buildAssignment(bo, orderId, orderNoToMap, orderIdToPlatformBefore, operatorId, now);
|
|
|
+ validEntityBeforeSave(assignment);
|
|
|
+ assignmentsToInsert.add(assignment);
|
|
|
+
|
|
|
+ OrderMain orderMain = new OrderMain();
|
|
|
+ orderMain.setId(orderId);
|
|
|
+ orderMain.setPlatformCode(bo.getPlatformAfter());
|
|
|
+ orderMain.setAssignmentStatus(OrderAssignStatus.ASSIGNED.getCode());
|
|
|
+ ordersToUpdate.add(orderMain);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 批量插入分配记录
|
|
|
+ boolean insertSuccess = !assignmentsToInsert.isEmpty() && baseMapper.insertBatch(assignmentsToInsert);
|
|
|
+ if (!insertSuccess) {
|
|
|
+ log.error("订单分配记录插入失败");
|
|
|
+ throw new ServiceException("订单分配记录插入失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 批量更新订单商品表:设置 platform_code 和 assignment_status
|
|
|
+ if (!orderIdList.isEmpty()) {
|
|
|
+ orderProductMapper.updatePlatformAndStatusByOrderIds(
|
|
|
+ orderIdList,
|
|
|
+ bo.getPlatformAfter(),
|
|
|
+ OrderAssignStatus.ASSIGNED.getCode()
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 批量更新订单主表(在目标平台上下文中执行)
|
|
|
+ String targetPlatform = bo.getPlatformAfter();
|
|
|
+ String currentPlatform = PlatformContext.getPlatform();
|
|
|
+ if (StringUtils.isEmpty(currentPlatform)) {
|
|
|
+ currentPlatform = SysPlatformCode.OMS.getCode();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (SysPlatformCode.OMS.getCode().equals(currentPlatform)) {
|
|
|
+ PlatformContextUtil.executeWithPlatform(targetPlatform, () -> {
|
|
|
+ for (OrderMain order : ordersToUpdate) {
|
|
|
+ orderMainMapper.updateById(order);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 如果已在目标平台上下文,直接更新
|
|
|
+ for (OrderMain order : ordersToUpdate) {
|
|
|
+ orderMainMapper.updateById(order);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Boolean splitAssign(OrderSplitAssignBo bo) {
|
|
|
+ Long parentId = bo.getOrderId();
|
|
|
+ List<OrderProductAssignRule> rules = bo.getItemRules();
|
|
|
+
|
|
|
+ if (CollUtil.isEmpty(rules)) {
|
|
|
+ throw new ServiceException("未选择任何商品进行分配");
|
|
|
+ }
|
|
|
+
|
|
|
+ Date now = new Date();
|
|
|
+ Long operatorId = LoginHelper.getUserId();
|
|
|
+
|
|
|
+ // 1. 查询父订单
|
|
|
+ OrderMain parentOrder = orderMainMapper.selectById(parentId);
|
|
|
+ if (parentOrder == null) {
|
|
|
+ throw new ServiceException("父订单不存在");
|
|
|
+ }
|
|
|
+ if (OrderSplitStatus.SPLITED.getCode().equals(parentOrder.getSplitStatus())) {
|
|
|
+ throw new ServiceException("该订单已被拆分,不可重复操作");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询所有待分配的商品行(验证存在性 & 所属订单)
|
|
|
+ List<Long> itemIds = rules.stream().map(OrderProductAssignRule::getItemId).collect(Collectors.toList());
|
|
|
+ List<OrderProduct> items = orderProductMapper.selectBatchIds(itemIds);
|
|
|
+ Map<Long, OrderProduct> itemMap = items.stream()
|
|
|
+ .collect(Collectors.toMap(OrderProduct::getId, Function.identity()));
|
|
|
+
|
|
|
+ // 验证:所有商品属于该父订单,且未分配
|
|
|
+ for (OrderProductAssignRule rule : rules) {
|
|
|
+ OrderProduct item = itemMap.get(rule.getItemId());
|
|
|
+ if (item == null || !parentId.equals(item.getOrderId())) {
|
|
|
+ throw new ServiceException("商品行不属于该订单或不存在");
|
|
|
+ }
|
|
|
+ if (OrderAssignStatus.ASSIGNED.getCode().equals(item.getAssignmentStatus())) {
|
|
|
+ throw new ServiceException("商品 [" + item.getProductName() + "] 已分配,不可重复操作");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 按目标平台分组
|
|
|
+ Map<String, List<OrderProductAssignRule>> platformToRules = rules.stream()
|
|
|
+ .collect(Collectors.groupingBy(OrderProductAssignRule::getTargetPlatform));
|
|
|
+ OrderMain childOrder = null;
|
|
|
+ // 4. 为每个平台创建子订单,并迁移商品
|
|
|
+ for (Map.Entry<String, List<OrderProductAssignRule>> entry : platformToRules.entrySet()) {
|
|
|
+ String targetPlatform = entry.getKey();
|
|
|
+ List<OrderProductAssignRule> groupRules = entry.getValue();
|
|
|
+ childOrder = copyParentToChild(parentOrder, targetPlatform);
|
|
|
+ orderMainMapper.insert(childOrder);
|
|
|
+
|
|
|
+ // 迁移商品行:更新 orderId + platform_code + assignment_status
|
|
|
+ List<Long> groupItemIds = groupRules.stream().map(OrderProductAssignRule::getItemId).collect(Collectors.toList());
|
|
|
+ orderProductMapper.updateForSplitAssign(
|
|
|
+ groupItemIds,
|
|
|
+ childOrder.getId(),
|
|
|
+ targetPlatform,
|
|
|
+ OrderAssignStatus.ASSIGNED.getCode()
|
|
|
+ );
|
|
|
+
|
|
|
+ // 插入分配记录(子订单维度)
|
|
|
+ OrderAssignment assignment = new OrderAssignment();
|
|
|
+ assignment.setOrderId(childOrder.getId());
|
|
|
+ assignment.setOrderNo(childOrder.getOrderNo());
|
|
|
+ assignment.setPlatformBefore(parentOrder.getPlatformCode());
|
|
|
+ assignment.setPlatformAfter(targetPlatform);
|
|
|
+ assignment.setAssignedBy(operatorId);
|
|
|
+ assignment.setAssignTime(now);
|
|
|
+ assignment.setAssignType("0"); // 拆单类型
|
|
|
+ assignment.setRemark(bo.getRemark());
|
|
|
+ baseMapper.insert(assignment);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 更新父订单状态:标记为已拆分
|
|
|
+ OrderMain updateParent = new OrderMain();
|
|
|
+ updateParent.setId(parentId);
|
|
|
+ updateParent.setAssignmentStatus(OrderAssignStatus.ASSIGNED.getCode());
|
|
|
+ updateParent.setSplitStatus(OrderSplitStatus.SPLITED.getCode()); // 已拆分
|
|
|
+ // 注意:父订单 platformCode 保持不变(作为入口)
|
|
|
+ orderMainMapper.updateById(updateParent);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private List<Long> parseOrderIds(String orderIdsStr) {
|
|
|
+ if (StringUtils.contains(orderIdsStr, ",")) {
|
|
|
+ return Arrays.stream(orderIdsStr.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(StringUtils::isNotBlank)
|
|
|
+ .map(Long::parseLong)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ } else {
|
|
|
+ return Collections.singletonList(Long.valueOf(orderIdsStr));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private OrderAssignment buildAssignment(OrderAssignmentBo bo, Long orderId,
|
|
|
+ Map<Long, String> orderNoMap, Map<Long, String> platformBeforeMap,
|
|
|
+ Long operatorId, Date now) {
|
|
|
+ OrderAssignment assignment = new OrderAssignment();
|
|
|
+ assignment.setOrderId(orderId);
|
|
|
+ assignment.setOrderNo(orderNoMap.getOrDefault(orderId, ""));
|
|
|
+ assignment.setPlatformBefore(platformBeforeMap.getOrDefault(orderId, ""));
|
|
|
+ assignment.setPlatformAfter(bo.getPlatformAfter());
|
|
|
+ assignment.setAssignedBy(operatorId);
|
|
|
+ assignment.setAssignTime(now);
|
|
|
+ assignment.setAssignType(bo.getAssignType());
|
|
|
+ assignment.setRemark(bo.getRemark());
|
|
|
+ return assignment;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private OrderMain copyParentToChild(OrderMain parent, String targetPlatform) {
|
|
|
+ OrderMain child = new OrderMain();
|
|
|
+ String childSeqKey = "child_order_seq:" + parent.getOrderNo();
|
|
|
+ String paddedSeq = SequenceUtils.nextPaddedIdStr(childSeqKey, Duration.ofDays(90), 2);
|
|
|
+ child.setParentOrderId(parent.getId());
|
|
|
+ child.setIsSplitChild("0");
|
|
|
+ child.setPlatformCode(targetPlatform);
|
|
|
+ child.setOrderNo(parent.getOrderNo() + paddedSeq);
|
|
|
+ child.setCompanyId(parent.getCompanyId());
|
|
|
+ child.setCustomerId(parent.getCustomerId());
|
|
|
+ child.setExpectedDeliveryTime(parent.getExpectedDeliveryTime());
|
|
|
+ child.setShippingAddressId(parent.getShippingAddressId());
|
|
|
+ child.setWarehouseId(parent.getWarehouseId());
|
|
|
+ child.setInvoiceType(parent.getInvoiceType());
|
|
|
+ child.setPayType(parent.getPayType());
|
|
|
+ child.setTotalAmount(parent.getTotalAmount());
|
|
|
+ child.setPayableAmount(parent.getPayableAmount());
|
|
|
+ child.setShippingFee(parent.getShippingFee());
|
|
|
+ child.setOrderSource(parent.getOrderSource());
|
|
|
+ child.setBusinessStaff(parent.getBusinessStaff());
|
|
|
+ child.setBusinessDept(parent.getBusinessDept());
|
|
|
+ child.setPurchaseReason(parent.getPurchaseReason());
|
|
|
+ child.setCreditLimit(parent.getCreditLimit());
|
|
|
+ child.setOrderStatus(parent.getOrderStatus());
|
|
|
+ child.setAssignmentStatus(OrderAssignStatus.ASSIGNED.getCode());
|
|
|
+ child.setSplitStatus("0");
|
|
|
+ child.setRemark(parent.getRemark());
|
|
|
+ child.setCheckStatus(parent.getCheckStatus());
|
|
|
+ child.setCreateTime(new Date());
|
|
|
+ child.setUpdateTime(new Date());
|
|
|
+ child.setDataSource(parent.getDataSource());
|
|
|
+ child.setDeliveryType(parent.getDeliveryType());
|
|
|
+ return child;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改订单分配记录
|
|
|
+ *
|
|
|
+ * @param bo 订单分配记录
|
|
|
+ * @return 是否修改成功
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Boolean updateByBo(OrderAssignmentBo bo) {
|
|
|
+ OrderAssignment update = MapstructUtils.convert(bo, OrderAssignment.class);
|
|
|
+ validEntityBeforeSave(update);
|
|
|
+ return baseMapper.updateById(update) > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存前的数据校验
|
|
|
+ */
|
|
|
+ private void validEntityBeforeSave(OrderAssignment entity) {
|
|
|
+ //TODO 做一些数据校验,如唯一约束
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验并批量删除订单分配记录信息
|
|
|
+ *
|
|
|
+ * @param ids 待删除的主键集合
|
|
|
+ * @param isValid 是否进行有效性校验
|
|
|
+ * @return 是否删除成功
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
|
|
+ if (isValid) {
|
|
|
+ //TODO 做一些业务上的校验,判断是否需要校验
|
|
|
+ }
|
|
|
+ return baseMapper.deleteByIds(ids) > 0;
|
|
|
+ }
|
|
|
+}
|