package com.vincent.rsf.server.manager.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.common.constant.Constants; import com.vincent.rsf.server.manager.controller.dto.OrderOutItemDto; import com.vincent.rsf.server.manager.controller.params.LocToTaskParams; import com.vincent.rsf.server.manager.controller.params.WaveToLocParams; import com.vincent.rsf.server.manager.enums.*; import com.vincent.rsf.server.manager.entity.*; import com.vincent.rsf.server.manager.mapper.WaveMapper; import com.vincent.rsf.server.manager.service.*; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.vincent.rsf.server.manager.utils.LocManageUtil; import com.vincent.rsf.server.manager.utils.OptimalAlgorithmUtil; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service("waveService") public class WaveServiceImpl extends ServiceImpl implements WaveService { @Autowired private AsnOrderItemService asnOrderItemService; @Autowired private AsnOrderService asnOrderService; @Autowired private WaveItemService waveItemService; @Autowired private TaskService taskService; @Autowired private TaskItemService taskItemService; @Autowired private LocItemService locItemService; @Autowired private LocService locService; @Autowired private OutStockService outStockService; @Autowired private WaveService waveService; @Autowired private WaveRuleServiceImpl waveRuleService; @Autowired private WaveOrderRelaServiceImpl waveOrderRelaService; /** * @param * @param loginUserId * @return * @author Ryan * @description 波次任务下发 * @time 2025/4/25 16:24 */ @Override @Transactional(rollbackFor = Exception.class) public R publicTask(Map map, Long loginUserId) { List itemParams = JSONArray.parseArray(JSON.toJSONString(map.get("waveItem")), WaveItem.class); if (Objects.isNull(itemParams) || itemParams.isEmpty()) { throw new CoolException("参数不能为空!!"); } String waveId = map.get("wave").toString(); Wave waves = this.getById(Long.parseLong(waveId)); if (Objects.isNull(waves)) { throw new CoolException("波次数据不存在!!"); } List waveItems = waveItemService.list(new LambdaQueryWrapper() .eq(WaveItem::getWaveId, waves.getId()) .apply("anfme > work_qty")); if (waveItems.isEmpty()) { throw new CoolException("波次明细不存在!!"); } /**生成出库任务*/ try { List params = new ArrayList<>(); for (WaveItem item : waveItems) { WaveToLocParams locParams = new WaveToLocParams(); BeanUtils.copyProperties(item, locParams); locParams.setBatch(item.getSplrBatch()) .setItemId(item.getId()) .setWaveId(item.getWaveId()); params.add(locParams); } List results = LocManageUtil.getOutOrderList(params, null); generateOutTask(results, loginUserId, waves); } catch (Exception e) { log.error(e.getMessage()); throw new CoolException("出库任务生成失败!!!"); } List orderIds = waveItems.stream().map(WaveItem::getOrderId).collect(Collectors.toList()); /**修改出库单状态*/ if (!asnOrderService.update(new LambdaUpdateWrapper() .set(WkOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val) .in(WkOrder::getId, orderIds))) { throw new CoolException("出库单据状态修改失败!!"); } return R.ok(); } /** * 选择波次明细下发任务 * * @param map * @param loginUserId * @return */ @Override @Transactional(rollbackFor = Exception.class) public R waveToTask(Map map, Long loginUserId) { if (Objects.isNull(map.get("ids"))) { throw new CoolException("参数不能为空!!"); } List WaveIds = JSONArray.parseArray(JSON.toJSONString(map.get("ids")), Long.class); List waves = waveService.listByIds(WaveIds); if (Objects.isNull(waves)) { throw new CoolException("数据错误: 波次不存在!!"); } for (Wave wave : waves) { if (wave.getExceStatus() >= WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val) { throw new CoolException("当前状态无法下发执行!!"); } List items = waveItemService.list(new LambdaQueryWrapper().eq(WaveItem::getWaveId, wave.getId())); if (items.isEmpty()) { throw new CoolException("波次明细不存在!!"); } List ids = items.stream().map(WaveItem::getId).collect(Collectors.toList()); if (!waveItemService.update(new LambdaUpdateWrapper() .set(WaveItem::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val) .in(WaveItem::getId, ids))) { throw new CoolException("执行状态修改失败!!"); } WaveRule waveRule = waveRuleService.getOne(new LambdaQueryWrapper() .eq(WaveRule::getType, WaveRuleType.First_In_First_Out.type)); if (Cools.isEmpty(waveRule)) { throw new CoolException("未找到当前策略"); } List params = new ArrayList<>(); for (WaveItem item : items) { WaveToLocParams locParams = new WaveToLocParams(); BeanUtils.copyProperties(item, locParams); locParams.setBatch(item.getSplrBatch()) .setItemId(item.getId()) .setWaveId(item.getWaveId()); params.add(locParams); } List results = LocManageUtil.getOutOrderList(params, waveRule); if (results.isEmpty()) { wave.setUpdateBy(loginUserId).setUpdateTime(new Date()); if (wave.getAnfme().compareTo(wave.getWorkQty()) == 0) { wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_TASK.val); } else { wave.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val); } wave.setMemo("-->库存不足"); waveService.updateById(wave); return R.ok(); } try { /**生成出库任务*/ generateOutTask(results, loginUserId, wave); } catch (Exception e) { log.error("UNK", e); throw new CoolException(e.getMessage()); } List taskItems = taskItemService.list(new LambdaQueryWrapper() .in(TaskItem::getSource, ids)); if (Cools.isEmpty(taskItems)) { throw new CoolException("暂无合适库存信息!!"); } for (TaskItem item : taskItems) { WaveItem waveItem = waveItemService.getById(item.getSource()); Double workQty = Math.round((waveItem.getWorkQty() + item.getAnfme()) * 10000) / 10000.0; waveItem.setWorkQty(workQty); if (workQty.compareTo(waveItem.getAnfme()) < 0) { waveItem.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val); } else { waveItem.setExceStatus(WaveExceStatus.WAVE_EXCE_STATUS_TASK.val); } if (!waveItemService.update(new LambdaUpdateWrapper() .set(WaveItem::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val) .setSql("work_qty = work_qty + " + item.getAnfme()) .set(WaveItem::getUpdateBy, loginUserId) .set(WaveItem::getUpdateTime, new Date()) .eq(WaveItem::getId, item.getSource()))) { throw new CoolException("下发执行异常,请稍候重试!"); } } if (!waveService.update(new LambdaUpdateWrapper() .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val) .set(Wave::getWorkQty, taskItems.stream().mapToDouble(TaskItem::getAnfme).sum()) .set(Wave::getUpdateBy, loginUserId) .set(Wave::getUpdateTime, new Date()) .eq(Wave::getId, wave.getId()))) { throw new CoolException("波次状态修改失败!!"); } } return R.ok(); } /** * 终止波次下发任务 * * @param id * @return */ @Override @Transactional(rollbackFor = Exception.class) public R stopPubTask(Long id) { Wave wave = this.getById(id); if (Objects.isNull(wave)) { throw new CoolException("波次单不存在!!"); } List taskItems = taskItemService.list(new LambdaQueryWrapper() .eq(TaskItem::getSourceId, wave.getId())); if (!taskItems.isEmpty()) { throw new CoolException("已生成任务不可终止当前波次!!"); } List orderRelas = waveOrderRelaService.list(new LambdaQueryWrapper().eq(WaveOrderRela::getWaveId, id)); if (orderRelas.isEmpty()) { throw new CoolException("无关联明细!!"); } List orderIds = orderRelas.stream().map(WaveOrderRela::getOrderItemId).collect(Collectors.toList()); List orderItems = asnOrderItemService.list(new LambdaQueryWrapper().in(WkOrderItem::getId, orderIds)); orderItems.forEach(asnOrderItem -> { asnOrderItem.setWorkQty(0.0); if (!asnOrderItemService.updateById(asnOrderItem)) { throw new CoolException("单据明细更新失败!!"); } }); List orders = orderRelas.stream().map(WaveOrderRela::getOrderId).collect(Collectors.toList()); if (!asnOrderService.update(new LambdaUpdateWrapper() .set(WkOrder::getWorkQty, 0.0) .set(WkOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val) .in(WkOrder::getId, orders))) { throw new CoolException("单据更新失败!!"); } this.update(new LambdaUpdateWrapper() .eq(Wave::getId, id) .set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK.val)); return R.ok(); } /** * @param * @param loginUserId * @param wave * @return * @author Ryan * @description 生成出库任务 * @time 2025/4/28 14:01 */ @Synchronized @Transactional(rollbackFor = Exception.class) public void generateOutTask(List itemParams, Long loginUserId, Wave wave) throws Exception { for (OrderOutItemDto itemDto : itemParams) { LocToTaskParams taskParams = new LocToTaskParams(); Loc loc = locService.getById(itemDto.getLocId()); if (Objects.isNull(loc)) { continue; } taskParams.setItems(Arrays.asList(itemDto.getLocItem())) .setSiteNo(itemDto.getSiteNo()) .setType(Constants.TASK_TYPE_WAVE_OUT_STOCK) .setSourceId(wave.getId()) .setTarLoc(loc.getCode()); locItemService.generateTask(TaskResouceType.TASK_RESOUCE_WAVE_TYPE.val, taskParams, loginUserId); } } /** * @param * @return * @author Ryan * @description 预览波次下发任务 * @time 2025/4/27 11:09 */ @Override @Transactional(rollbackFor = Exception.class) public List mergeWavePreview(Long waveId) { Wave wave = this.getById(waveId); if (Objects.isNull(wave)) { throw new CoolException("波次不能存在!!"); } List waveItems = waveItemService.list(new LambdaQueryWrapper().eq(WaveItem::getWaveId, waveId)); if (waveItems.isEmpty()) { throw new CoolException("波次明细不存在!!"); } List itemPreview = null; try { itemPreview = getLocs(waveItems); } catch (Exception e) { throw new CoolException("库位获取失败!!!!"); } return itemPreview; } /** * @param * @return * @author Ryan * @description 取消波次 * @time 2025/6/17 10:04 */ @Override @Transactional(rollbackFor = Exception.class) public R cancelWave(List ids) { return null; } /** * @param * @param waveItems * @return * @author Ryan * @description 根据物料编码,批次,动态字段 查询符合的库位,再根据库位中物料的数量选择最适合的库位 * @time 2025/4/27 09:26 */ @Synchronized private List getLocs(List waveItems) throws Exception { //TODO 根据物料编码,批次,动态字段 查询符合的库位,再根据库位中物料的数量选择最适合的库位 waveItems.forEach(waveItem -> { List locItems = locItemService.list(new QueryWrapper() .select("id", "loc_id", "loc_code", "order_id", "SUM(anfme) anfme", "SUM(qty) qty", "SUM(work_qty) work_qty", "splr_batch", "fields_index", "matnr_code") .lambda() .eq(LocItem::getMatnrCode, waveItem.getMatnrCode()) .eq(LocItem::getSplrBatch, waveItem.getSplrBatch()) .eq(StringUtils.isNotBlank(waveItem.getFieldsIndex()), LocItem::getFieldsIndex, waveItem.getFieldsIndex()) .groupBy(LocItem::getMatnrCode, LocItem::getSplrBatch, LocItem::getFieldsIndex, LocItem::getId)); List doubles1 = locItems.stream().map(LocItem::getAnfme).collect(Collectors.toList()); double[] doubles = doubles1.stream().mapToDouble(Double::doubleValue).toArray(); /**使用回溯算法计算,获取符合出库量的最简组合*/ List result = OptimalAlgorithmUtil.findCombination(doubles, waveItem.getAnfme()); String locs = "[]"; if (Objects.isNull(result) || result.isEmpty()) { waveItem.setStockLocs(locs).setStockQty(0.0); } else { /**过滤集合中最简短的组合*/ List locsInfo = result.stream() .filter(i -> i >= 0 && i < locItems.size()) .map(locItems::get).collect(Collectors.toList()); locs = JSONArray.toJSONString(locsInfo); Double sumQty = locsInfo.stream().mapToDouble(LocItem::getAnfme).sum(); Double surQty = locsInfo.stream().mapToDouble(LocItem::getWorkQty).sum(); Double qty = locsInfo.stream().mapToDouble(LocItem::getQty).sum(); Double v = sumQty - surQty - qty; waveItem.setStockLocs(locs).setStockQty(v); } }); return waveItems; } }