package cn.iocoder.yudao.module.mes.service.wm.packages;
|
|
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.packages.vo.line.MesWmPackageLinePageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.packages.vo.line.MesWmPackageLineSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderProcessDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.packages.MesWmPackageLineDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.wm.packages.MesWmPackageLineMapper;
|
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
|
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService;
|
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
|
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
|
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService;
|
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
|
import jakarta.annotation.Resource;
|
import org.springframework.context.annotation.Lazy;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Objects;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
|
/**
|
* MES 装箱明细 Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesWmPackageLineServiceImpl implements MesWmPackageLineService {
|
|
private static final String ASSEMBLY_PROCESS_CODE = "PRO-ASSEMBLY";
|
private static final String ASSEMBLY_PROCESS_NAME = "组装";
|
|
@Resource
|
private MesWmPackageLineMapper packageLineMapper;
|
|
@Resource
|
@Lazy
|
private MesWmPackageService packageService;
|
@Resource
|
private MesMdmItemService mdmItemService;
|
@Resource
|
private MesMdItemService mdItemService;
|
@Resource
|
private MesMdItemTypeService itemTypeService;
|
@Resource
|
private MesProWorkOrderService workOrderService;
|
@Resource
|
private MesProWorkOrderProcessService workOrderProcessService;
|
@Resource
|
private MesProProcessService processService;
|
@Resource
|
private MesProFeedbackMapper feedbackMapper;
|
|
@Override
|
public Long createPackageLine(MesWmPackageLineSaveReqVO createReqVO) {
|
// 校验数据
|
int boxCount = validateLineSaveData(createReqVO);
|
|
// 插入
|
MesWmPackageLineDO line = BeanUtils.toBean(createReqVO, MesWmPackageLineDO.class);
|
line.setBoxCount(boxCount);
|
packageLineMapper.insert(line);
|
return line.getId();
|
}
|
|
@Override
|
public void updatePackageLine(MesWmPackageLineSaveReqVO updateReqVO) {
|
// 校验存在
|
MesWmPackageLineDO line = validatePackageLineExists(updateReqVO.getId());
|
// 校验数据
|
updateReqVO.setPackageId(line.getPackageId());
|
int boxCount = validateLineSaveData(updateReqVO);
|
|
// 更新
|
MesWmPackageLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmPackageLineDO.class);
|
updateObj.setBoxCount(boxCount);
|
packageLineMapper.updateById(updateObj);
|
}
|
|
@Override
|
public void deletePackageLine(Long id) {
|
// 校验存在
|
MesWmPackageLineDO line = validatePackageLineExists(id);
|
// 校验装箱单状态为草稿
|
packageService.validatePackageStatusDraft(line.getPackageId());
|
|
// 删除
|
packageLineMapper.deleteById(id);
|
}
|
|
@Override
|
public MesWmPackageLineDO getPackageLine(Long id) {
|
return packageLineMapper.selectById(id);
|
}
|
|
@Override
|
public PageResult<MesWmPackageLineDO> getPackageLinePage(MesWmPackageLinePageReqVO pageReqVO) {
|
if (pageReqVO.getPackageId() == null) {
|
return PageResult.empty();
|
}
|
List<Long> packageIds = packageService.getPackageAndDescendantIds(pageReqVO.getPackageId());
|
return packageLineMapper.selectPage(pageReqVO, packageIds);
|
}
|
|
@Override
|
public void deletePackageLineByPackageId(Long packageId) {
|
packageLineMapper.deleteByPackageId(packageId);
|
}
|
|
// ========== 校验方法 ==========
|
|
/**
|
* 校验保存时的关联数据,并返回按 数量 / 每箱数量 向上取整计算的箱数
|
*/
|
private int validateLineSaveData(MesWmPackageLineSaveReqVO reqVO) {
|
// 校验装箱单状态为草稿
|
packageService.validatePackageStatusDraft(reqVO.getPackageId());
|
// 校验产品物料存在
|
mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
|
|
// 校验物料档案:必须属于成品分类,且已维护每箱数量
|
MesMdItemDO item = mdItemService.getItem(reqVO.getItemId());
|
if (item == null) {
|
throw exception(WM_PACKAGE_LINE_BOX_QUANTITY_NOT_CONFIGURED, "ID=" + reqVO.getItemId());
|
}
|
String itemName = StrUtil.isNotBlank(item.getName()) ? item.getName() : item.getCode();
|
MesMdItemTypeDO itemType = item.getItemTypeId() != null
|
? itemTypeService.getItemTypeMap(Collections.singleton(item.getItemTypeId()))
|
.get(item.getItemTypeId())
|
: null;
|
if (itemType == null || !Boolean.TRUE.equals(itemType.getFinishedFlag())) {
|
throw exception(WM_PACKAGE_LINE_ITEM_NOT_FINISHED, itemName);
|
}
|
if (item.getBoxQuantity() == null || item.getBoxQuantity().compareTo(BigDecimal.ZERO) <= 0) {
|
throw exception(WM_PACKAGE_LINE_BOX_QUANTITY_NOT_CONFIGURED, itemName);
|
}
|
|
// 校验工单已确认,且装箱物料必须为工单的产品
|
MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderConfirmed(reqVO.getWorkOrderId());
|
if (ObjUtil.notEqual(reqVO.getItemId(), workOrder.getProductId())) {
|
MesMdItemDO product = workOrder.getProductId() != null
|
? mdItemService.getItem(workOrder.getProductId()) : null;
|
String productName = product != null
|
? (StrUtil.isNotBlank(product.getName()) ? product.getName() : product.getCode())
|
: "ID=" + workOrder.getProductId();
|
throw exception(WM_PACKAGE_LINE_WORK_ORDER_PRODUCT_MISMATCH,
|
itemName, workOrder.getCode(), productName);
|
}
|
|
// 校验同一工单累计装箱数量不超过工单数量(草稿与已完成的装箱单都计入)
|
BigDecimal plannedQuantity = packageLineMapper.selectListByWorkOrderId(workOrder.getId()).stream()
|
.filter(line -> ObjUtil.notEqual(line.getId(), reqVO.getId()))
|
.map(MesWmPackageLineDO::getQuantity)
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
BigDecimal totalQuantity = plannedQuantity.add(reqVO.getQuantity());
|
if (workOrder.getQuantity() != null && totalQuantity.compareTo(workOrder.getQuantity()) > 0) {
|
throw exception(WM_PACKAGE_LINE_WORK_ORDER_QUANTITY_EXCEED,
|
workOrder.getCode(), workOrder.getQuantity(), plannedQuantity, reqVO.getQuantity());
|
}
|
|
// 校验组装工序已完成报工:组装合格数量必须覆盖累计装箱数量
|
validateAssemblyCompleted(workOrder, plannedQuantity, reqVO.getQuantity(), totalQuantity);
|
|
// 箱数 = 数量 / 每箱数量,向上取整
|
return reqVO.getQuantity().divide(item.getBoxQuantity(), 0, RoundingMode.CEILING).intValue();
|
}
|
|
/**
|
* 校验工单的【组装】工序已完成报工,且合格数量不少于累计装箱数量
|
*/
|
private void validateAssemblyCompleted(MesProWorkOrderDO workOrder, BigDecimal packedQuantity,
|
BigDecimal currentQuantity, BigDecimal totalQuantity) {
|
List<Long> processIds = workOrderProcessService.getWorkOrderProcessListByWorkOrderId(workOrder.getId())
|
.stream()
|
.map(MesProWorkOrderProcessDO::getProcessId)
|
.filter(Objects::nonNull)
|
.distinct()
|
.toList();
|
List<Long> assemblyProcessIds = processService.getProcessMap(processIds).values().stream()
|
.filter(process -> ASSEMBLY_PROCESS_CODE.equalsIgnoreCase(process.getCode())
|
|| ASSEMBLY_PROCESS_NAME.equals(process.getName()))
|
.map(MesProProcessDO::getId)
|
.toList();
|
if (assemblyProcessIds.isEmpty()) {
|
throw exception(WM_PACKAGE_LINE_ASSEMBLY_PROCESS_NOT_FOUND, workOrder.getCode());
|
}
|
BigDecimal assembledQuantity = feedbackMapper.selectFinishedQualifiedQuantitySum(
|
workOrder.getId(), assemblyProcessIds);
|
if (assembledQuantity.compareTo(totalQuantity) < 0) {
|
throw exception(WM_PACKAGE_LINE_ASSEMBLY_NOT_COMPLETED,
|
workOrder.getCode(), assembledQuantity, totalQuantity, packedQuantity, currentQuantity);
|
}
|
}
|
|
private MesWmPackageLineDO validatePackageLineExists(Long id) {
|
MesWmPackageLineDO line = packageLineMapper.selectById(id);
|
if (line == null) {
|
throw exception(WM_PACKAGE_LINE_NOT_EXISTS);
|
}
|
return line;
|
}
|
|
}
|