package cn.iocoder.yudao.module.mes.service.wm.sorting;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.salesnotice.vo.MesWmSalesNoticePageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.sorting.vo.MesWmSortPendingNoticeRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.sorting.vo.MesWmSortProductionRequestRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.sorting.vo.MesWmSortTaskPageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.sorting.vo.MesWmSortTaskRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.sorting.vo.MesWmSortTaskScanReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.salesnotice.MesWmSalesNoticeLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sorting.MesWmSortTaskDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sorting.MesWmSortTaskLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.wm.sorting.MesWmSortTaskLineMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.wm.sorting.MesWmSortTaskMapper;
|
import cn.iocoder.yudao.module.mes.enums.wm.MesWmSalesNoticeStatusEnum;
|
import cn.iocoder.yudao.module.mes.enums.wm.MesWmSortTaskStatusEnum;
|
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
|
import cn.iocoder.yudao.module.mes.service.pro.mps.MesProMpsService;
|
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
|
import cn.iocoder.yudao.module.mes.service.wm.salesnotice.MesWmSalesNoticeLineService;
|
import cn.iocoder.yudao.module.mes.service.wm.salesnotice.MesWmSalesNoticeService;
|
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
|
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
|
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import jakarta.annotation.Resource;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
|
/**
|
* MES 分拣任务 Service 实现类
|
*/
|
@Service
|
@Validated
|
@Slf4j
|
public class MesWmSortTaskServiceImpl implements MesWmSortTaskService {
|
|
private static final DateTimeFormatter CODE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
@Resource
|
private MesWmSortTaskMapper sortTaskMapper;
|
@Resource
|
private MesWmSortTaskLineMapper sortTaskLineMapper;
|
|
@Resource
|
private MesWmSalesNoticeService salesNoticeService;
|
@Resource
|
private MesWmSalesNoticeLineService salesNoticeLineService;
|
@Resource
|
private MesWmMaterialStockService materialStockService;
|
@Resource
|
private MesWmProductSalesMapper productSalesMapper;
|
@Resource
|
private MesMdmItemService mdmItemService;
|
@Resource
|
private MesWmWarehouseService warehouseService;
|
@Resource
|
private MesWmWarehouseAreaService areaService;
|
@Resource
|
private MesWmWarehouseLocationService locationService;
|
@Resource
|
private AdminUserApi adminUserApi;
|
@Resource
|
private MesProMpsService mpsService;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Long createSortTaskFromNotice(Long noticeId) {
|
// 1. 校验发货通知单:必须存在且为「待出库」
|
MesWmSalesNoticeDO notice = salesNoticeService.validateSalesNoticeExists(noticeId);
|
if (!MesWmSalesNoticeStatusEnum.APPROVED.getStatus().equals(notice.getStatus())) {
|
throw new ServiceException(WM_SORT_TASK_NOT_PENDING.getCode(),
|
"发货通知单[" + notice.getCode() + "]当前状态为["
|
+ MesWmSalesNoticeStatusEnum.valueOf(notice.getStatus()).getName()
|
+ "],只有「待出库」的发货通知单才能生成分拣任务,请先提交该发货通知单。");
|
}
|
// 2. 防止重复生成
|
MesWmSortTaskDO exists = sortTaskMapper.selectByNoticeId(noticeId);
|
if (exists != null) {
|
throw new ServiceException(WM_SORT_TASK_NOTICE_EXISTS.getCode(),
|
"发货通知单[" + notice.getCode() + "]已存在分拣任务[" + exists.getCode()
|
+ "],请直接在该任务上执行分拣,或先取消原任务。");
|
}
|
// 3. 发货明细 + 分配货位
|
List<MesWmSalesNoticeLineDO> noticeLines = salesNoticeLineService.getSalesNoticeLineListByNoticeId(noticeId);
|
if (CollUtil.isEmpty(noticeLines)) {
|
throw new ServiceException(WM_SORT_TASK_NO_STOCK.getCode(),
|
"发货通知单[" + notice.getCode() + "]没有发货明细,无法分拣,请先补全发货明细。");
|
}
|
List<MesWmSortTaskLineDO> lines = allocateStock(notice, noticeLines);
|
// 4. 插入任务
|
MesWmSortTaskDO task = MesWmSortTaskDO.builder()
|
.code(generateCode())
|
.noticeId(notice.getId()).noticeCode(notice.getCode())
|
.saleOrderId(notice.getSaleOrderId()).saleOrderCode(notice.getSaleOrderCode())
|
.clientId(notice.getClientId())
|
.recipientName(notice.getRecipientName()).recipientTelephone(notice.getRecipientTelephone())
|
.recipientAddress(notice.getRecipientAddress())
|
.status(MesWmSortTaskStatusEnum.PENDING.getStatus())
|
.printCount(0)
|
.build();
|
sortTaskMapper.insert(task);
|
lines.forEach(line -> line.setTaskId(task.getId()));
|
lines.forEach(sortTaskLineMapper::insert);
|
return task.getId();
|
}
|
|
/**
|
* 按发货明细分配合格库存:同物料优先按入库时间 FIFO,可跨库位拆分
|
*/
|
private List<MesWmSortTaskLineDO> allocateStock(MesWmSalesNoticeDO notice,
|
List<MesWmSalesNoticeLineDO> noticeLines) {
|
List<MesWmSortTaskLineDO> result = new ArrayList<>();
|
for (MesWmSalesNoticeLineDO noticeLine : noticeLines) {
|
BigDecimal remaining = noticeLine.getQuantity() != null ? noticeLine.getQuantity() : BigDecimal.ZERO;
|
if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
|
continue;
|
}
|
// 查询该物料可用库存(按批次过滤,若有)
|
MesWmMaterialStockListReqVO stockQuery = new MesWmMaterialStockListReqVO();
|
stockQuery.setItemId(noticeLine.getItemId());
|
stockQuery.setBatchId(noticeLine.getBatchId());
|
List<MesWmMaterialStockDO> stocks = materialStockService.getMaterialStockList(stockQuery);
|
stocks = stocks.stream()
|
.filter(stock -> stock.getQuantity() != null && stock.getQuantity().compareTo(BigDecimal.ZERO) > 0
|
&& !Boolean.TRUE.equals(stock.getFrozen()))
|
.sorted(Comparator.comparing(MesWmMaterialStockDO::getReceiptTime,
|
Comparator.nullsLast(Comparator.naturalOrder())))
|
.collect(Collectors.toList());
|
BigDecimal available = stocks.stream()
|
.map(stock -> stock.getQuantity() != null ? stock.getQuantity() : BigDecimal.ZERO)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
MesMdmItemDO item = mdmItemService.getItemMap(Collections.singletonList(noticeLine.getItemId()))
|
.get(noticeLine.getItemId());
|
String itemName = item != null ? item.getName() : "ID=" + noticeLine.getItemId();
|
if (available.compareTo(remaining) < 0) {
|
throw new ServiceException(WM_SORT_TASK_NO_STOCK.getCode(),
|
"物料[" + itemName + "]在库位上的可用库存为[" + available.stripTrailingZeros().toPlainString()
|
+ "],发货通知单需要[" + remaining.stripTrailingZeros().toPlainString()
|
+ "],库存不足,请先补货入库或调整发货数量后再生成分拣任务。");
|
}
|
for (MesWmMaterialStockDO stock : stocks) {
|
if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
|
break;
|
}
|
BigDecimal stockQuantity = stock.getQuantity() != null ? stock.getQuantity() : BigDecimal.ZERO;
|
BigDecimal allocate = stockQuantity.min(remaining);
|
result.add(MesWmSortTaskLineDO.builder()
|
.noticeLineId(noticeLine.getId())
|
.itemId(noticeLine.getItemId())
|
.batchId(stock.getBatchId()).batchCode(stock.getBatchCode())
|
.materialStockId(stock.getId())
|
.warehouseId(stock.getWarehouseId()).areaId(stock.getAreaId()).locationId(stock.getLocationId())
|
.planQuantity(allocate).sortedQuantity(BigDecimal.ZERO)
|
.scanned(false)
|
.build());
|
remaining = remaining.subtract(allocate);
|
}
|
}
|
return result;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void scanLine(MesWmSortTaskScanReqVO scanReqVO) {
|
MesWmSortTaskDO task = validateTaskExists(scanReqVO.getTaskId());
|
validateTaskPending(task);
|
MesWmSortTaskLineDO line = sortTaskLineMapper.selectById(scanReqVO.getLineId());
|
if (line == null || !ObjUtil.equal(line.getTaskId(), task.getId())) {
|
throw exception(WM_SORT_TASK_LINE_NOT_EXISTS);
|
}
|
if (MesWmSortTaskStatusEnum.FINISHED.getStatus().equals(task.getStatus())) {
|
throw new ServiceException(WM_SORT_TASK_LINE_ALREADY_SORTED.getCode(),
|
"分拣任务[" + task.getCode() + "]已完成,不能再扫码分拣。");
|
}
|
// 扫码校验:物料条码 或 批次号 匹配即可
|
MesMdmItemDO item = mdmItemService.getItemMap(Collections.singletonList(line.getItemId()))
|
.get(line.getItemId());
|
String barcode = StrUtil.trim(scanReqVO.getBarcode());
|
boolean matched = (item != null && StrUtil.equalsIgnoreCase(barcode, StrUtil.trim(item.getBarCode())))
|
|| StrUtil.equalsIgnoreCase(barcode, StrUtil.trim(line.getBatchCode()));
|
if (!matched) {
|
throw new ServiceException(WM_SORT_TASK_SCAN_MISMATCH.getCode(),
|
"扫码内容[" + barcode + "]与分拣明细[" + (item != null ? item.getName() : "ID=" + line.getItemId())
|
+ "]不匹配:明细要求的物料条码为[" + (item != null && StrUtil.isNotBlank(item.getBarCode())
|
? item.getBarCode() : "未维护")
|
+ "],批次号为[" + StrUtil.blankToDefault(line.getBatchCode(), "无批次") + "]。"
|
+ "请核对货品后重新扫码。");
|
}
|
BigDecimal quantity = scanReqVO.getQuantity() != null ? scanReqVO.getQuantity() : line.getPlanQuantity();
|
if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
|
quantity = line.getPlanQuantity();
|
}
|
// 更新明细:累加分拣数量,但不超过计划数量
|
BigDecimal sorted = line.getSortedQuantity() != null ? line.getSortedQuantity() : BigDecimal.ZERO;
|
BigDecimal newSorted = sorted.add(quantity).min(Objects.requireNonNullElse(line.getPlanQuantity(), quantity));
|
sortTaskLineMapper.updateById(MesWmSortTaskLineDO.builder()
|
.id(line.getId()).sortedQuantity(newSorted).scanned(true).build());
|
// 任务进入分拣中
|
if (MesWmSortTaskStatusEnum.PENDING.getStatus().equals(task.getStatus())) {
|
sortTaskMapper.updateById(MesWmSortTaskDO.builder()
|
.id(task.getId()).status(MesWmSortTaskStatusEnum.SORTING.getStatus())
|
.sortUserId(getCurrentUserId()).build());
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void finishSortTask(Long id, String carrier, String shippingNumber, String remark) {
|
MesWmSortTaskDO task = validateTaskExists(id);
|
validateTaskPending(task);
|
// 1. 校验所有明细已扫码且分拣数量完整
|
List<MesWmSortTaskLineDO> lines = sortTaskLineMapper.selectListByTaskId(id);
|
if (CollUtil.isEmpty(lines)) {
|
throw new ServiceException(WM_SORT_TASK_NO_STOCK.getCode(),
|
"分拣任务[" + task.getCode() + "]没有分拣明细,无法完成分拣。");
|
}
|
List<String> unscanned = new ArrayList<>();
|
Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap(convertSet(lines, MesWmSortTaskLineDO::getItemId));
|
for (MesWmSortTaskLineDO line : lines) {
|
BigDecimal sorted = line.getSortedQuantity() != null ? line.getSortedQuantity() : BigDecimal.ZERO;
|
BigDecimal plan = line.getPlanQuantity() != null ? line.getPlanQuantity() : BigDecimal.ZERO;
|
if (!Boolean.TRUE.equals(line.getScanned()) || sorted.compareTo(plan) < 0) {
|
MesMdmItemDO item = itemMap.get(line.getItemId());
|
unscanned.add((item != null ? item.getName() : "ID=" + line.getItemId())
|
+ "(计划 " + plan.stripTrailingZeros().toPlainString()
|
+ ",已分拣 " + sorted.stripTrailingZeros().toPlainString() + ")");
|
}
|
}
|
if (!unscanned.isEmpty()) {
|
throw new ServiceException(WM_SORT_TASK_NOT_PENDING.getCode(),
|
"分拣任务[" + task.getCode() + "]还有未完成扫码的明细:" + String.join(";", unscanned)
|
+ "。请对上述明细逐条扫码至计划数量后再完成分拣。");
|
}
|
// 2. 触发配送:发货通知单尚未生成销售出库单时自动生成
|
if (productSalesMapper.selectByNoticeId(task.getNoticeId()) == null) {
|
salesNoticeService.generateProductSalesFromNotice(task.getNoticeId());
|
}
|
// 3. 更新任务为已完成并记录承运信息
|
sortTaskMapper.updateById(MesWmSortTaskDO.builder()
|
.id(id).status(MesWmSortTaskStatusEnum.FINISHED.getStatus())
|
.carrier(carrier).shippingNumber(shippingNumber)
|
.sortUserId(getCurrentUserId()).sortTime(LocalDateTime.now())
|
.remark(StrUtil.isBlank(remark) ? null : remark).build());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void cancelSortTask(Long id) {
|
MesWmSortTaskDO task = validateTaskExists(id);
|
if (MesWmSortTaskStatusEnum.FINISHED.getStatus().equals(task.getStatus())) {
|
throw new ServiceException(WM_SORT_TASK_NOT_PENDING.getCode(),
|
"分拣任务[" + task.getCode() + "]已完成,不能取消。");
|
}
|
sortTaskMapper.updateById(MesWmSortTaskDO.builder()
|
.id(id).status(MesWmSortTaskStatusEnum.CANCELED.getStatus()).build());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteSortTask(Long id) {
|
MesWmSortTaskDO task = validateTaskExists(id);
|
if (!MesWmSortTaskStatusEnum.PENDING.getStatus().equals(task.getStatus())
|
&& !MesWmSortTaskStatusEnum.CANCELED.getStatus().equals(task.getStatus())) {
|
throw new ServiceException(WM_SORT_TASK_NOT_PENDING.getCode(),
|
"只有「待分拣」或「已取消」的分拣任务才能删除,任务[" + task.getCode() + "]当前为["
|
+ MesWmSortTaskStatusEnum.valueOf(task.getStatus()).getName()
|
+ "],请先取消任务。");
|
}
|
sortTaskMapper.deleteById(id);
|
sortTaskLineMapper.deleteByTaskId(id);
|
}
|
|
@Override
|
public void updatePrintCount(Long id) {
|
MesWmSortTaskDO task = validateTaskExists(id);
|
sortTaskMapper.updateById(MesWmSortTaskDO.builder()
|
.id(id).printCount((task.getPrintCount() != null ? task.getPrintCount() : 0) + 1).build());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public MesWmSortProductionRequestRespVO submitProductionRequest(Long id) {
|
MesWmSortTaskDO task = validateTaskExists(id);
|
MesWmSalesNoticeDO notice = salesNoticeService.validateSalesNoticeExists(task.getNoticeId());
|
List<MesWmSalesNoticeLineDO> noticeLines =
|
salesNoticeLineService.getSalesNoticeLineListByNoticeId(task.getNoticeId());
|
MesWmSortProductionRequestRespVO result = new MesWmSortProductionRequestRespVO();
|
if (CollUtil.isEmpty(noticeLines)) {
|
result.getFailures().add("分拣任务[" + task.getCode() + "]对应的发货通知单没有明细,无法提交生产申请");
|
return result;
|
}
|
Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap(
|
convertSet(noticeLines, MesWmSalesNoticeLineDO::getItemId));
|
String requestDate = notice.getSalesDate() != null
|
? notice.getSalesDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) : null;
|
for (MesWmSalesNoticeLineDO noticeLine : noticeLines) {
|
MesMdmItemDO item = itemMap.get(noticeLine.getItemId());
|
String itemName = item != null ? item.getName() : "ID=" + noticeLine.getItemId();
|
if (noticeLine.getSaleOrderItemId() == null) {
|
result.getFailures().add(itemName + ":发货明细未关联销售订单明细,无法提交生产申请");
|
continue;
|
}
|
// 已存在生产申请(MPS)时跳过,避免重复提交
|
if (mpsService.getMpsBySaleOrderItemId(noticeLine.getSaleOrderItemId()) != null) {
|
result.setSkippedCount(result.getSkippedCount() + 1);
|
continue;
|
}
|
try {
|
mpsService.createMps(notice.getSaleOrderId(), notice.getSaleOrderCode(),
|
noticeLine.getSaleOrderItemId(), noticeLine.getItemId(), itemName,
|
noticeLine.getQuantity(), notice.getClientId(), requestDate,
|
"由分拣任务[" + task.getCode() + "]提交生产申请");
|
result.setCreatedCount(result.getCreatedCount() + 1);
|
} catch (ServiceException ex) {
|
result.getFailures().add(itemName + ":" + ex.getMessage());
|
}
|
}
|
return result;
|
}
|
|
@Override
|
public MesWmSortTaskRespVO getSortTask(Long id) {
|
MesWmSortTaskDO task = validateTaskExists(id);
|
return buildRespList(Collections.singletonList(task)).get(0);
|
}
|
|
@Override
|
public PageResult<MesWmSortTaskRespVO> getSortTaskPage(MesWmSortTaskPageReqVO pageReqVO) {
|
PageResult<MesWmSortTaskDO> pageResult = sortTaskMapper.selectPage(pageReqVO);
|
if (CollUtil.isEmpty(pageResult.getList())) {
|
return PageResult.empty(pageResult.getTotal());
|
}
|
return new PageResult<>(buildRespList(pageResult.getList()), pageResult.getTotal());
|
}
|
|
@Override
|
public List<MesWmSortPendingNoticeRespVO> getPendingNoticeList(String noticeCode) {
|
// 1. 查询待出库的发货通知单
|
MesWmSalesNoticePageReqVO pageReqVO = new MesWmSalesNoticePageReqVO();
|
pageReqVO.setCode(noticeCode);
|
pageReqVO.setStatus(MesWmSalesNoticeStatusEnum.APPROVED.getStatus());
|
pageReqVO.setPageSize(cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE);
|
List<MesWmSalesNoticeDO> notices = salesNoticeService.getSalesNoticePage(pageReqVO).getList();
|
if (CollUtil.isEmpty(notices)) {
|
return Collections.emptyList();
|
}
|
// 2. 剔除已存在未完成分拣任务的通知单
|
Set<Long> taskNoticeIds = sortTaskMapper.selectList(new LambdaQueryWrapperX<MesWmSortTaskDO>()
|
.in(MesWmSortTaskDO::getNoticeId, convertSet(notices, MesWmSalesNoticeDO::getId))
|
.ne(MesWmSortTaskDO::getStatus, MesWmSortTaskStatusEnum.CANCELED.getStatus()))
|
.stream().map(MesWmSortTaskDO::getNoticeId).collect(Collectors.toSet());
|
return notices.stream().filter(notice -> !taskNoticeIds.contains(notice.getId()))
|
.map(notice -> new MesWmSortPendingNoticeRespVO()
|
.setNoticeId(notice.getId()).setNoticeCode(notice.getCode())
|
.setSaleOrderCode(notice.getSaleOrderCode())
|
.setRecipientName(notice.getRecipientName())
|
.setRecipientTelephone(notice.getRecipientTelephone())
|
.setRecipientAddress(notice.getRecipientAddress())
|
.setDeliveryDate(notice.getSalesDate())
|
.setOutStatus(notice.getOutStatus()))
|
.collect(Collectors.toList());
|
}
|
|
// ==================== 私有方法 ====================
|
|
private String generateCode() {
|
String prefix = "SORT" + LocalDateTime.now().format(CODE_DATE_FORMAT);
|
long count = sortTaskMapper.selectCount(new LambdaQueryWrapperX<MesWmSortTaskDO>()
|
.likeRight(MesWmSortTaskDO::getCode, prefix)) + 1;
|
String code = prefix + String.format("%03d", count);
|
while (sortTaskMapper.selectByCode(code) != null) {
|
count++;
|
code = prefix + String.format("%03d", count);
|
}
|
return code;
|
}
|
|
private MesWmSortTaskDO validateTaskExists(Long id) {
|
MesWmSortTaskDO task = id != null ? sortTaskMapper.selectById(id) : null;
|
if (task == null) {
|
throw exception(WM_SORT_TASK_NOT_EXISTS);
|
}
|
return task;
|
}
|
|
private void validateTaskPending(MesWmSortTaskDO task) {
|
if (!MesWmSortTaskStatusEnum.PENDING.getStatus().equals(task.getStatus())
|
&& !MesWmSortTaskStatusEnum.SORTING.getStatus().equals(task.getStatus())) {
|
String statusName = MesWmSortTaskStatusEnum.valueOf(task.getStatus()) != null
|
? MesWmSortTaskStatusEnum.valueOf(task.getStatus()).getName() : String.valueOf(task.getStatus());
|
throw new ServiceException(WM_SORT_TASK_NOT_PENDING.getCode(),
|
"分拣任务[" + task.getCode() + "]当前状态为[" + statusName + "],只有「待分拣」或「分拣中」的任务才能扫码/完成分拣。");
|
}
|
}
|
|
private List<MesWmSortTaskRespVO> buildRespList(List<MesWmSortTaskDO> list) {
|
List<MesWmSortTaskLineDO> allLines = sortTaskLineMapper.selectListByTaskIds(
|
convertSet(list, MesWmSortTaskDO::getId));
|
Map<Long, List<MesWmSortTaskLineDO>> lineMap = allLines.stream()
|
.collect(Collectors.groupingBy(MesWmSortTaskLineDO::getTaskId));
|
// 关联名称
|
Map<Long, MesMdmItemDO> itemMap = mdmItemService.getItemMap(convertSet(allLines, MesWmSortTaskLineDO::getItemId));
|
Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
|
convertSet(allLines, MesWmSortTaskLineDO::getWarehouseId));
|
Map<Long, MesWmWarehouseAreaDO> areaMap = areaService.getWarehouseAreaMap(
|
convertSet(allLines, MesWmSortTaskLineDO::getAreaId));
|
Map<Long, MesWmWarehouseLocationDO> locationMap = locationService.getWarehouseLocationMap(
|
convertSet(allLines, MesWmSortTaskLineDO::getLocationId));
|
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
convertSet(list, MesWmSortTaskDO::getSortUserId));
|
List<MesWmSortTaskRespVO> result = new ArrayList<>(list.size());
|
for (MesWmSortTaskDO task : list) {
|
MesWmSortTaskRespVO vo = new MesWmSortTaskRespVO();
|
vo.setId(task.getId()).setCode(task.getCode())
|
.setNoticeId(task.getNoticeId()).setNoticeCode(task.getNoticeCode())
|
.setSaleOrderId(task.getSaleOrderId()).setSaleOrderCode(task.getSaleOrderCode())
|
.setClientId(task.getClientId())
|
.setRecipientName(task.getRecipientName())
|
.setRecipientTelephone(task.getRecipientTelephone())
|
.setRecipientAddress(task.getRecipientAddress())
|
.setCarrier(task.getCarrier()).setShippingNumber(task.getShippingNumber())
|
.setStatus(task.getStatus()).setSortUserId(task.getSortUserId())
|
.setSortTime(task.getSortTime()).setPrintCount(task.getPrintCount())
|
.setRemark(task.getRemark()).setCreateTime(task.getCreateTime());
|
AdminUserRespDTO user = userMap.get(task.getSortUserId());
|
if (user != null) {
|
vo.setSortUserName(user.getNickname());
|
}
|
List<MesWmSortTaskLineDO> lines = lineMap.getOrDefault(task.getId(), Collections.emptyList());
|
BigDecimal totalPlan = BigDecimal.ZERO;
|
BigDecimal totalSorted = BigDecimal.ZERO;
|
List<MesWmSortTaskRespVO.Line> lineVOs = new ArrayList<>(lines.size());
|
for (MesWmSortTaskLineDO line : lines) {
|
MesWmSortTaskRespVO.Line lineVO = new MesWmSortTaskRespVO.Line();
|
lineVO.setId(line.getId()).setNoticeLineId(line.getNoticeLineId())
|
.setItemId(line.getItemId()).setBatchCode(line.getBatchCode())
|
.setMaterialStockId(line.getMaterialStockId())
|
.setWarehouseId(line.getWarehouseId()).setAreaId(line.getAreaId())
|
.setLocationId(line.getLocationId())
|
.setPlanQuantity(line.getPlanQuantity()).setSortedQuantity(line.getSortedQuantity())
|
.setScanned(line.getScanned()).setRemark(line.getRemark());
|
MesMdmItemDO item = itemMap.get(line.getItemId());
|
if (item != null) {
|
lineVO.setItemCode(item.getCode()).setItemName(item.getName()).setItemBarCode(item.getBarCode());
|
}
|
MesWmWarehouseDO warehouse = warehouseMap.get(line.getWarehouseId());
|
if (warehouse != null) {
|
lineVO.setWarehouseName(warehouse.getName());
|
}
|
MesWmWarehouseAreaDO area = areaMap.get(line.getAreaId());
|
if (area != null) {
|
lineVO.setAreaName(area.getName());
|
}
|
MesWmWarehouseLocationDO location = locationMap.get(line.getLocationId());
|
if (location != null) {
|
lineVO.setLocationName(location.getName());
|
}
|
totalPlan = totalPlan.add(line.getPlanQuantity() != null ? line.getPlanQuantity() : BigDecimal.ZERO);
|
totalSorted = totalSorted.add(line.getSortedQuantity() != null ? line.getSortedQuantity() : BigDecimal.ZERO);
|
lineVOs.add(lineVO);
|
}
|
vo.setLines(lineVOs).setTotalPlanQuantity(totalPlan).setTotalSortedQuantity(totalSorted);
|
result.add(vo);
|
}
|
return result;
|
}
|
|
private Long getCurrentUserId() {
|
try {
|
return cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId();
|
} catch (Exception ex) {
|
return null;
|
}
|
}
|
|
}
|