package com.klp.service.impl; import cn.hutool.core.bean.BeanUtil; 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.klp.common.core.domain.PageQuery; import com.klp.common.core.page.TableDataInfo; import com.klp.common.exception.ServiceException; import com.klp.common.utils.StringUtils; import com.klp.domain.WmsFurnace; import com.klp.domain.WmsFurnacePlan; import com.klp.domain.WmsFurnacePlanCoil; import com.klp.domain.WmsMaterialCoil; import com.klp.domain.WmsActualWarehouse; import com.klp.domain.bo.WmsFurnacePlanBo; import com.klp.domain.bo.WmsFurnacePlanCoilBo; import com.klp.domain.vo.WmsFurnacePlanCoilVo; import com.klp.domain.vo.WmsFurnacePlanVo; import com.klp.mapper.WmsActualWarehouseMapper; import com.klp.mapper.WmsFurnaceMapper; import com.klp.mapper.WmsFurnacePlanCoilMapper; import com.klp.mapper.WmsFurnacePlanMapper; import com.klp.mapper.WmsMaterialCoilMapper; import com.klp.service.IWmsFurnacePlanService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.stream.Collectors; /** * 退火计划Service业务层处理 * * @author klp * @date 2026-03-14 */ @RequiredArgsConstructor @Service public class WmsFurnacePlanServiceImpl implements IWmsFurnacePlanService { private final WmsFurnacePlanMapper baseMapper; private final WmsFurnacePlanCoilMapper planCoilMapper; private final WmsFurnaceMapper furnaceMapper; private final WmsMaterialCoilMapper materialCoilMapper; private final WmsActualWarehouseMapper actualWarehouseMapper; @Override public WmsFurnacePlanVo queryById(Long planId) { WmsFurnacePlanVo plan = baseMapper.selectVoById(planId); if (plan != null) { plan.setCoilIds(queryPlanCoils(planId).stream() .map(WmsFurnacePlanCoilVo::getCoilId) .collect(Collectors.toList())); fillFurnaceNames(java.util.Collections.singletonList(plan)); } return plan; } @Override public TableDataInfo queryPageList(WmsFurnacePlanBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); fillFurnaceNames(result.getRecords()); return TableDataInfo.build(result); } @Override public List queryList(WmsFurnacePlanBo bo) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); List list = baseMapper.selectVoList(lqw); fillFurnaceNames(list); return list; } private LambdaQueryWrapper buildQueryWrapper(WmsFurnacePlanBo bo) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.like(StringUtils.isNotBlank(bo.getPlanNo()), WmsFurnacePlan::getPlanNo, bo.getPlanNo()); lqw.eq(bo.getTargetFurnaceId() != null, WmsFurnacePlan::getTargetFurnaceId, bo.getTargetFurnaceId()); lqw.eq(bo.getStatus() != null, WmsFurnacePlan::getStatus, bo.getStatus()); lqw.ge(bo.getPlanStartTime() != null, WmsFurnacePlan::getPlanStartTime, bo.getPlanStartTime()); lqw.orderByDesc(WmsFurnacePlan::getPlanStartTime); return lqw; } private void fillFurnaceNames(List plans) { if (plans == null || plans.isEmpty()) { return; } List furnaceIds = plans.stream() .map(WmsFurnacePlanVo::getTargetFurnaceId) .filter(id -> id != null) .distinct() .collect(Collectors.toList()); if (furnaceIds.isEmpty()) { return; } List furnaces = furnaceMapper.selectBatchIds(furnaceIds); java.util.Map nameMap = furnaces.stream() .collect(Collectors.toMap(WmsFurnace::getFurnaceId, WmsFurnace::getFurnaceName, (a, b) -> a)); plans.forEach(plan -> { if (plan.getTargetFurnaceId() != null) { plan.setTargetFurnaceName(nameMap.get(plan.getTargetFurnaceId())); } }); } @Override public Boolean insertByBo(WmsFurnacePlanBo bo) { WmsFurnacePlan add = BeanUtil.toBean(bo, WmsFurnacePlan.class); validEntityBeforeSave(add, true); boolean flag = baseMapper.insert(add) > 0; if (flag) { bo.setPlanId(add.getPlanId()); } return flag; } @Override public Boolean updateByBo(WmsFurnacePlanBo bo) { WmsFurnacePlan update = BeanUtil.toBean(bo, WmsFurnacePlan.class); validEntityBeforeSave(update, false); return baseMapper.updateById(update) > 0; } private void validEntityBeforeSave(WmsFurnacePlan entity, boolean isNew) { LambdaQueryWrapper planNoQuery = Wrappers.lambdaQuery(); planNoQuery.eq(WmsFurnacePlan::getPlanNo, entity.getPlanNo()); if (!isNew) { planNoQuery.ne(WmsFurnacePlan::getPlanId, entity.getPlanId()); } if (baseMapper.selectCount(planNoQuery) > 0) { throw new ServiceException("计划号已存在"); } WmsFurnace furnace = furnaceMapper.selectById(entity.getTargetFurnaceId()); if (furnace == null || furnace.getDelFlag() != null && furnace.getDelFlag() == 1) { throw new ServiceException("目标炉子不存在"); } } @Override public Boolean updateStatus(Long planId, Integer status) { WmsFurnacePlan plan = baseMapper.selectById(planId); if (plan == null) { throw new ServiceException("计划不存在"); } WmsFurnacePlan update = new WmsFurnacePlan(); update.setPlanId(planId); update.setStatus(status); boolean updated = baseMapper.updateById(update) > 0; if (updated && plan.getTargetFurnaceId() != null) { if (status != null && (status == 2)) { updateFurnaceBusy(plan.getTargetFurnaceId(), 1); } if (status != null && (status == 3 || status == 4)) { updateFurnaceBusy(plan.getTargetFurnaceId(), 0); } } return updated; } @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid && ids != null && !ids.isEmpty()) { for (Long planId : ids) { if (planCoilMapper.selectCount(Wrappers.lambdaQuery() .eq(WmsFurnacePlanCoil::getPlanId, planId)) > 0) { throw new ServiceException("计划下存在钢卷,请先解绑"); } } } return baseMapper.deleteBatchIds(ids) > 0; } @Override public List queryPlanCoils(Long planId) { List list = planCoilMapper.selectVoList(Wrappers.lambdaQuery() .eq(WmsFurnacePlanCoil::getPlanId, planId)); if (list == null || list.isEmpty()) { return list; } List coilIds = list.stream() .map(WmsFurnacePlanCoilVo::getCoilId) .filter(id -> id != null) .distinct() .collect(Collectors.toList()); if (coilIds.isEmpty()) { return list; } List materialCoils = materialCoilMapper.selectBatchIds(coilIds); java.util.Map coilMap = materialCoils.stream() .collect(Collectors.toMap(WmsMaterialCoil::getCoilId, item -> item, (a, b) -> a)); List actualWarehouseIds = materialCoils.stream() .map(WmsMaterialCoil::getActualWarehouseId) .filter(id -> id != null) .distinct() .collect(Collectors.toList()); java.util.Map warehouseMap = actualWarehouseIds.isEmpty() ? java.util.Collections.emptyMap() : actualWarehouseMapper.selectBatchIds(actualWarehouseIds).stream() .collect(Collectors.toMap(WmsActualWarehouse::getActualWarehouseId, WmsActualWarehouse::getActualWarehouseName, (a, b) -> a)); list.forEach(item -> { WmsMaterialCoil coil = coilMap.get(item.getCoilId()); if (coil != null) { item.setEnterCoilNo(coil.getEnterCoilNo()); item.setActualWarehouseId(coil.getActualWarehouseId()); item.setActualWarehouseName(warehouseMap.get(coil.getActualWarehouseId())); } }); return list; } @Override @Transactional(rollbackFor = Exception.class) public Boolean bindPlanCoils(WmsFurnacePlanCoilBo bo) { if (bo.getPlanId() == null) { throw new ServiceException("计划ID不能为空"); } List coilIds = parseCoilIds(bo); if (coilIds.isEmpty()) { throw new ServiceException("请至少选择一条钢卷"); } WmsFurnacePlan plan = ensurePlanExist(bo.getPlanId()); if (plan.getStatus() != null && plan.getStatus() == 2) { throw new ServiceException("计划进行中,无法再领料"); } for (Long coilId : coilIds) { if (planCoilMapper.selectCount(Wrappers.lambdaQuery() .eq(WmsFurnacePlanCoil::getPlanId, bo.getPlanId()) .eq(WmsFurnacePlanCoil::getCoilId, coilId)) > 0) { continue; } WmsFurnacePlanCoil entity = new WmsFurnacePlanCoil(); entity.setPlanId(bo.getPlanId()); entity.setCoilId(coilId); planCoilMapper.insert(entity); } return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean unbindPlanCoil(WmsFurnacePlanCoilBo bo) { if (bo.getPlanId() == null || bo.getCoilId() == null) { throw new ServiceException("计划ID和钢卷ID不能为空"); } return planCoilMapper.delete(Wrappers.lambdaQuery() .eq(WmsFurnacePlanCoil::getPlanId, bo.getPlanId()) .eq(WmsFurnacePlanCoil::getCoilId, bo.getCoilId())) > 0; } @Override @Transactional(rollbackFor = Exception.class) public Boolean inFurnace(Long planId) { WmsFurnacePlan plan = baseMapper.selectById(planId); if (plan == null) { throw new ServiceException("计划不存在"); } if (plan.getActualStartTime() != null) { throw new ServiceException("计划已入炉"); } if (planCoilMapper.selectCount(Wrappers.lambdaQuery() .eq(WmsFurnacePlanCoil::getPlanId, planId)) <= 0) { throw new ServiceException("计划未绑定钢卷"); } Date now = new Date(); Date endTime = new Date(now.getTime() + 48L * 60 * 60 * 1000); WmsFurnacePlan update = new WmsFurnacePlan(); update.setPlanId(planId); update.setActualStartTime(now); update.setEndTime(endTime); update.setStatus(2); baseMapper.updateById(update); updateFurnaceBusy(plan.getTargetFurnaceId(), 1); List coils = queryPlanCoils(planId); for (WmsFurnacePlanCoilVo coil : coils) { releaseActualWarehouse(coil.getCoilId()); } return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean completePlan(Long planId, List locations) { WmsFurnacePlan plan = baseMapper.selectById(planId); if (plan == null) { throw new ServiceException("计划不存在"); } if (plan.getStatus() == null || plan.getStatus() != 2) { throw new ServiceException("计划未进行中,无法完成"); } List coils = queryPlanCoils(planId); if (coils == null || coils.isEmpty()) { throw new ServiceException("计划未绑定钢卷"); } if (locations == null || locations.isEmpty()) { throw new ServiceException("请先分配实际库位"); } java.util.Map locationMap = locations.stream() .collect(Collectors.toMap(com.klp.domain.bo.WmsFurnacePlanLocationItemBo::getCoilId, com.klp.domain.bo.WmsFurnacePlanLocationItemBo::getActualWarehouseId, (a, b) -> a)); for (WmsFurnacePlanCoilVo coil : coils) { Long targetLocation = locationMap.get(coil.getCoilId()); if (targetLocation == null) { throw new ServiceException("钢卷" + coil.getEnterCoilNo() + "未分配库位"); } occupyActualWarehouse(coil.getCoilId(), targetLocation); } Date now = new Date(); WmsFurnacePlan update = new WmsFurnacePlan(); update.setPlanId(planId); update.setStatus(3); update.setEndTime(now); baseMapper.updateById(update); updateFurnaceBusy(plan.getTargetFurnaceId(), 0); return true; } private void releaseActualWarehouse(Long coilId) { WmsMaterialCoil coil = materialCoilMapper.selectById(coilId); if (coil == null) { return; } Long actualWarehouseId = coil.getActualWarehouseId(); if (actualWarehouseId != null) { WmsActualWarehouse warehouse = new WmsActualWarehouse(); warehouse.setActualWarehouseId(actualWarehouseId); warehouse.setIsEnabled(1); actualWarehouseMapper.updateById(warehouse); } materialCoilMapper.update(null, Wrappers.lambdaUpdate() .eq(WmsMaterialCoil::getCoilId, coilId) .set(WmsMaterialCoil::getActualWarehouseId, null) .set(WmsMaterialCoil::getExclusiveStatus, 2)); } private void occupyActualWarehouse(Long coilId, Long actualWarehouseId) { if (actualWarehouseId == null) { throw new ServiceException("实际库位不能为空"); } WmsActualWarehouse warehouse = actualWarehouseMapper.selectById(actualWarehouseId); if (warehouse == null || warehouse.getDelFlag() != null && warehouse.getDelFlag() == 1) { throw new ServiceException("实际库位不存在"); } if (warehouse.getIsEnabled() != null && warehouse.getIsEnabled() == 0) { throw new ServiceException("实际库位已被占用"); } WmsActualWarehouse updateWarehouse = new WmsActualWarehouse(); updateWarehouse.setActualWarehouseId(actualWarehouseId); updateWarehouse.setIsEnabled(0); actualWarehouseMapper.updateById(updateWarehouse); WmsMaterialCoil updateCoil = new WmsMaterialCoil(); updateCoil.setCoilId(coilId); updateCoil.setActualWarehouseId(actualWarehouseId); updateCoil.setExclusiveStatus(0); materialCoilMapper.updateById(updateCoil); } private List parseCoilIds(WmsFurnacePlanCoilBo bo) { List coilIds = new ArrayList<>(); if (bo.getCoilId() != null) { coilIds.add(bo.getCoilId()); } if (StringUtils.isNotBlank(bo.getCoilIds())) { String[] parts = bo.getCoilIds().split(","); for (String part : parts) { if (StringUtils.isNotBlank(part)) { coilIds.add(Long.parseLong(part.trim())); } } } if (StringUtils.isNotBlank(bo.getEnterCoilNos())) { coilIds.addAll(resolveCoilIdsByEnterNos(bo.getEnterCoilNos())); } if (StringUtils.isNotBlank(bo.getCurrentCoilNos())) { coilIds.addAll(resolveCoilIdsByCurrentNos(bo.getCurrentCoilNos())); } return coilIds.stream().distinct().collect(Collectors.toList()); } private List resolveCoilIdsByEnterNos(String enterCoilNos) { List nos = splitCommaValues(enterCoilNos); if (nos.isEmpty()) { return new ArrayList<>(); } return materialCoilMapper.selectList(Wrappers.lambdaQuery() .in(WmsMaterialCoil::getEnterCoilNo, nos) .eq(WmsMaterialCoil::getDelFlag, 0)) .stream() .map(WmsMaterialCoil::getCoilId) .collect(Collectors.toList()); } private List resolveCoilIdsByCurrentNos(String currentCoilNos) { List nos = splitCommaValues(currentCoilNos); if (nos.isEmpty()) { return new ArrayList<>(); } return materialCoilMapper.selectList(Wrappers.lambdaQuery() .in(WmsMaterialCoil::getCurrentCoilNo, nos) .eq(WmsMaterialCoil::getDelFlag, 0)) .stream() .map(WmsMaterialCoil::getCoilId) .collect(Collectors.toList()); } private List splitCommaValues(String values) { List result = new ArrayList<>(); if (StringUtils.isBlank(values)) { return result; } String[] parts = values.split(","); for (String part : parts) { if (StringUtils.isNotBlank(part)) { result.add(part.trim()); } } return result; } private WmsFurnacePlan ensurePlanExist(Long planId) { WmsFurnacePlan plan = baseMapper.selectById(planId); if (plan == null) { throw new ServiceException("计划不存在"); } return plan; } private void updateFurnaceBusy(Long furnaceId, Integer busyFlag) { if (furnaceId == null) { return; } WmsFurnace update = new WmsFurnace(); update.setFurnaceId(furnaceId); update.setBusyFlag(busyFlag); furnaceMapper.updateById(update); } }