package cn.iocoder.yudao.module.mes.service.md.workstation; import cn.hutool.core.collection.CollUtil; 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.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.mes.controller.admin.md.workstation.vo.MesMdWorkstationImportExcelVO; import cn.iocoder.yudao.module.mes.controller.admin.md.workstation.vo.MesMdWorkstationImportRespVO; import cn.iocoder.yudao.module.mes.controller.admin.md.workstation.vo.MesMdWorkstationPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.md.workstation.vo.MesMdWorkstationSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO; 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.md.workstation.MesMdWorkshopMapper; import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkstationMapper; import cn.iocoder.yudao.module.mes.dal.mysql.pro.process.MesProProcessMapper; import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum; import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; 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.mes.service.pro.process.MesProProcessService; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; 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 MesMdWorkstationServiceImpl implements MesMdWorkstationService { @Resource private MesMdWorkstationMapper workstationMapper; @Resource @Lazy private MesMdWorkstationMachineService workstationMachineService; @Resource private MesMdWorkstationToolService workstationToolService; @Resource private MesMdWorkstationWorkerService workstationWorkerService; @Resource private MesMdWorkshopService workshopService; @Resource private MesMdWorkshopMapper workshopMapper; @Resource private MesProProcessMapper processMapper; @Resource private MesWmWarehouseService warehouseService; @Resource private MesWmWarehouseLocationService locationService; @Resource private MesWmWarehouseAreaService areaService; @Resource private MesWmBarcodeService barcodeService; @Resource private MesProProcessService processService; @Override public Long createWorkstation(MesMdWorkstationSaveReqVO createReqVO) { // 校验数据 validateWorkstationSaveData(null, createReqVO); // 插入 MesMdWorkstationDO workstation = BeanUtils.toBean(createReqVO, MesMdWorkstationDO.class); workstationMapper.insert(workstation); // 自动生成条码 barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.WORKSTATION.getValue(), workstation.getId(), workstation.getCode(), workstation.getName()); return workstation.getId(); } @Override public void updateWorkstation(MesMdWorkstationSaveReqVO updateReqVO) { // 校验存在 validateWorkstationExists(updateReqVO.getId()); // 校验数据 validateWorkstationSaveData(updateReqVO.getId(), updateReqVO); // 更新 MesMdWorkstationDO updateObj = BeanUtils.toBean(updateReqVO, MesMdWorkstationDO.class); workstationMapper.updateById(updateObj); } private void validateWorkstationSaveData(Long id, MesMdWorkstationSaveReqVO reqVO) { // 校验编码唯一 validateWorkstationCodeUnique(id, reqVO.getCode()); // 校验名称唯一 validateWorkstationNameUnique(id, reqVO.getName()); // 校验车间存在 validateWorkshopExists(reqVO.getWorkshopId()); // 校验工序存在 processService.validateProcessExistsAndEnable(reqVO.getProcessId()); // 处理仓库层级(未指定仓库时自动设置虚拟线边库) handleWarehouseHierarchy(reqVO); } @Override @Transactional(rollbackFor = Exception.class) public void deleteWorkstation(Long id) { // 校验存在 validateWorkstationExists(id); // 级联删除子资源 workstationMachineService.deleteWorkstationMachineByWorkstationId(id); workstationToolService.deleteWorkstationToolByWorkstationId(id); workstationWorkerService.deleteWorkstationWorkerByWorkstationId(id); // 删除工作站 workstationMapper.deleteById(id); } @Override public MesMdWorkstationDO validateWorkstationExists(Long id) { MesMdWorkstationDO workstation = workstationMapper.selectById(id); if (workstation == null) { throw exception(MD_WORKSTATION_NOT_EXISTS); } return workstation; } @Override public MesMdWorkstationDO validateWorkstationExistsAndEnable(Long id) { MesMdWorkstationDO workstation = validateWorkstationExists(id); if (ObjUtil.notEqual(CommonStatusEnum.ENABLE.getStatus(), workstation.getStatus())) { throw exception(MD_WORKSTATION_IS_DISABLE); } return workstation; } private void validateWorkshopExists(Long workshopId) { MesMdWorkshopDO workshop = workshopService.getWorkshop(workshopId); if (workshop == null) { throw exception(MD_WORKSHOP_NOT_EXISTS); } } /** * 校验并处理仓库层级关系 * * 仓库层级结构:仓库 -> 库区 -> 库位 * 处理规则: * 1. 如果仓库/库区/库位都未填写,则自动设置虚拟线边库 * 2. 如果填写了库区,必须填写仓库,且库区必须属于该仓库 * 3. 如果填写了库位,必须填写库区,且库位必须属于该库区 * * @param reqVO 工作站保存请求对象 */ private void handleWarehouseHierarchy(MesMdWorkstationSaveReqVO reqVO) { // 1.1 获取仓库、库区、库位 ID Long warehouseId = reqVO.getWarehouseId(); Long locationId = reqVO.getLocationId(); Long areaId = reqVO.getAreaId(); // 1.2 如果都为空,则自动设置虚拟线边库 if (warehouseId == null && locationId == null && areaId == null) { MesWmWarehouseDO warehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE); MesWmWarehouseLocationDO location = locationService.getWarehouseLocationByCode( MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION); MesWmWarehouseAreaDO area = areaService.getWarehouseAreaByCode( MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA); reqVO.setWarehouseId(warehouse.getId()); reqVO.setLocationId(location.getId()); reqVO.setAreaId(area.getId()); return; } // 2. 校验仓库是否存在 if (warehouseId != null) { warehouseService.validateWarehouseExists(warehouseId); } // 3. 校验库区:如果填写了库区,必须填写仓库,且库区必须属于该仓库 MesWmWarehouseLocationDO location; if (locationId != null) { // 3.1 校验库区是否存在 location = locationService.validateWarehouseLocationExists(locationId); // 3.2 校验必须填写仓库 if (warehouseId == null) { throw exception(WM_WAREHOUSE_REQUIRED); } // 3.3 校验库区是否属于该仓库 if (ObjUtil.notEqual(location.getWarehouseId(), warehouseId)) { throw exception(WM_WAREHOUSE_LOCATION_RELATION_INVALID); } } // 4. 校验库位:如果填写了库位,必须填写库区,且库位必须属于该库区 if (areaId == null) { return; } // 4.1 校验库位是否存在 MesWmWarehouseAreaDO area = areaService.validateWarehouseAreaExists(areaId); // 4.2 校验必须填写库区 if (locationId == null) { throw exception(WM_WAREHOUSE_LOCATION_REQUIRED); } // 4.3 校验库位是否属于该库区 if (ObjUtil.notEqual(area.getLocationId(), locationId)) { throw exception(WM_WAREHOUSE_AREA_RELATION_INVALID); } } private void validateWorkstationCodeUnique(Long id, String code) { MesMdWorkstationDO workstation = workstationMapper.selectByCode(code); if (workstation == null) { return; } if (ObjUtil.notEqual(workstation.getId(), id)) { throw exception(MD_WORKSTATION_CODE_DUPLICATE); } } private void validateWorkstationNameUnique(Long id, String name) { MesMdWorkstationDO workstation = workstationMapper.selectByName(name); if (workstation == null) { return; } if (ObjUtil.notEqual(workstation.getId(), id)) { throw exception(MD_WORKSTATION_NAME_DUPLICATE); } } @Override public MesMdWorkstationDO getWorkstation(Long id) { return workstationMapper.selectById(id); } @Override public PageResult getWorkstationPage(MesMdWorkstationPageReqVO pageReqVO) { return workstationMapper.selectPage(pageReqVO); } @Override public List getWorkstationListByStatus(Integer status) { return workstationMapper.selectListByStatus(status); } @Override public Long getWorkstationCountByWorkshopId(Long workshopId) { return workstationMapper.selectCountByWorkshopId(workshopId); } @Override public Long getWorkstationCountByWarehouseId(Long warehouseId) { return workstationMapper.selectCountByWarehouseId(warehouseId); } @Override public Long getWorkstationCountByLocationId(Long locationId) { return workstationMapper.selectCountByLocationId(locationId); } @Override public Long getWorkstationCountByAreaId(Long areaId) { return workstationMapper.selectCountByAreaId(areaId); } @Override public List getWorkstationList(Collection ids) { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); } return workstationMapper.selectByIds(ids); } @Override @Transactional(rollbackFor = Exception.class) public MesMdWorkstationImportRespVO importWorkstationList(List importList, boolean updateSupport) { // 1. 校验非空 if (CollUtil.isEmpty(importList)) { throw exception(MD_WORKSTATION_IMPORT_LIST_IS_EMPTY); } // 2. 逐行处理 MesMdWorkstationImportRespVO respVO = MesMdWorkstationImportRespVO.builder() .createCodes(new ArrayList<>()).updateCodes(new ArrayList<>()) .failureCodes(new LinkedHashMap<>()).build(); AtomicInteger index = new AtomicInteger(1); importList.forEach(importItem -> { int currentIndex = index.getAndIncrement(); String key = StrUtil.blankToDefault(importItem.getCode(), "第 " + currentIndex + " 行"); if (StrUtil.isBlank(importItem.getCode())) { respVO.getFailureCodes().put(key, "工作站编码不能为空"); return; } if (StrUtil.isBlank(importItem.getName())) { respVO.getFailureCodes().put(key, "工作站名称不能为空"); return; } // 2.1 解析车间 if (StrUtil.isBlank(importItem.getWorkshopCode())) { respVO.getFailureCodes().put(key, "所在车间编码不能为空"); return; } MesMdWorkshopDO workshop = workshopMapper.selectByCode(importItem.getWorkshopCode()); if (workshop == null) { respVO.getFailureCodes().put(key, "所在车间编码[" + importItem.getWorkshopCode() + "]不存在"); return; } // 2.2 解析工序 if (StrUtil.isBlank(importItem.getProcessCode())) { respVO.getFailureCodes().put(key, "工序编码不能为空"); return; } MesProProcessDO process = processMapper.selectByCode(importItem.getProcessCode()); if (process == null) { respVO.getFailureCodes().put(key, "工序编码[" + importItem.getProcessCode() + "]不存在"); return; } // 2.3 判断:创建 or 更新 MesMdWorkstationDO existWorkstation = workstationMapper.selectByCode(importItem.getCode()); if (existWorkstation == null) { // 2.3.1 新增(复用 create 的仓库层级处理与条码生成逻辑) MesMdWorkstationSaveReqVO reqVO = BeanUtils.toBean(importItem, MesMdWorkstationSaveReqVO.class); reqVO.setWorkshopId(workshop.getId()); reqVO.setProcessId(process.getId()); reqVO.setStatus(ObjUtil.defaultIfNull(importItem.getStatus(), CommonStatusEnum.ENABLE.getStatus())); handleWarehouseHierarchy(reqVO); MesMdWorkstationDO workstation = BeanUtils.toBean(reqVO, MesMdWorkstationDO.class); workstationMapper.insert(workstation); // 自动生成条码 barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.WORKSTATION.getValue(), workstation.getId(), workstation.getCode(), workstation.getName()); respVO.getCreateCodes().add(importItem.getCode()); } else if (updateSupport) { // 2.3.2 更新(保留原有线边库层级) MesMdWorkstationDO updateObj = BeanUtils.toBean(importItem, MesMdWorkstationDO.class); updateObj.setId(existWorkstation.getId()); updateObj.setWorkshopId(workshop.getId()); updateObj.setProcessId(process.getId()); workstationMapper.updateById(updateObj); respVO.getUpdateCodes().add(importItem.getCode()); } else { respVO.getFailureCodes().put(key, "工作站编码已存在"); } }); return respVO; } }