From e4b641e65e49c7854ed11e7822316431f5e0ce1b Mon Sep 17 00:00:00 2001 From: skyouc Date: 星期五, 27 六月 2025 08:36:03 +0800 Subject: [PATCH] 出库单生成波次功能优化 --- rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java | 316 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 292 insertions(+), 24 deletions(-) diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java index d42bfd6..51b885d 100644 --- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java +++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WaveServiceImpl.java @@ -1,64 +1,332 @@ 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.manager.entity.AsnOrder; -import com.vincent.rsf.server.manager.entity.AsnOrderItem; -import com.vincent.rsf.server.manager.enums.WaveExceStatus; +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.entity.Wave; -import com.vincent.rsf.server.manager.service.AsnOrderItemService; -import com.vincent.rsf.server.manager.service.AsnOrderService; -import com.vincent.rsf.server.manager.service.WaveService; +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 com.vincent.rsf.server.system.constant.SerialRuleCode; +import com.vincent.rsf.server.system.utils.SerialRuleUtils; +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.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.stream.Collectors; +@Slf4j @Service("waveService") public class WaveServiceImpl extends ServiceImpl<WaveMapper, Wave> 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; /** + * @param + * @param loginUserId + * @return * @author Ryan * @description 娉㈡浠诲姟涓嬪彂 - * @param - * @return * @time 2025/4/25 16:24 */ @Override @Transactional(rollbackFor = Exception.class) - public R publicTask(Map<String, Object> map) { - List<Long> ids = (List<Long>) map.get("ids"); - if (Objects.isNull(ids) || ids.isEmpty()) { + public R publicTask(Map<String, Object> map, Long loginUserId) { + List<WaveItem> itemParams = JSONArray.parseArray(JSON.toJSONString(map.get("waveItem")), WaveItem.class); + if (Objects.isNull(itemParams) || itemParams.isEmpty()) { throw new CoolException("鍙傛暟涓嶈兘涓虹┖锛侊紒"); } - List<Wave> waves = this.list(new LambdaQueryWrapper<Wave>().in(Wave::getId, ids)); - if (Objects.isNull(waves) || waves.isEmpty()) { + String waveId = map.get("wave").toString(); + Wave waves = this.getById(Long.parseLong(waveId)); + if (Objects.isNull(waves)) { throw new CoolException("娉㈡鏁版嵁涓嶅瓨鍦紒锛�"); } - - List<AsnOrder> orders = asnOrderService.list(new LambdaQueryWrapper<AsnOrder>().eq(AsnOrder::getId, ids)); + List<WaveItem> waveItems = waveItemService.list(new LambdaQueryWrapper<WaveItem>() + .eq(WaveItem::getWaveId, waves.getId()) + .apply("anfme > work_qty")); + if (waveItems.isEmpty()) { + throw new CoolException("娉㈡鏄庣粏涓嶅瓨鍦紒锛�"); + } + /**鐢熸垚鍑哄簱浠诲姟*/ + try { + List<WaveToLocParams> 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<OrderOutItemDto> results = LocManageUtil.getOutOrderList(params, null); + generateOutTask(results, loginUserId, waves); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CoolException("鍑哄簱浠诲姟鐢熸垚澶辫触锛侊紒锛�"); + } + List<Long> orderIds = waveItems.stream().map(WaveItem::getOrderId).collect(Collectors.toList()); + /**淇敼鍑哄簱鍗曠姸鎬�*/ + if (!asnOrderService.update(new LambdaUpdateWrapper<AsnOrder>() + .set(AsnOrder::getExceStatus, AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val) + .in(AsnOrder::getId, orderIds))) { + throw new CoolException("鍑哄簱鍗曟嵁鐘舵�佷慨鏀瑰け璐ワ紒锛�"); + } + return R.ok(); + } - asnOrderItemService.list(new LambdaQueryWrapper<AsnOrderItem>().eq(AsnOrderItem::getAsnId, ids)); - - if (!this.update(new LambdaUpdateWrapper<Wave>().set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_TASK).in(Wave::getId,ids))) { - throw new CoolException("娉㈡鐘舵�佷慨鏀瑰け璐ワ紒锛�"); + /** + * 閫夋嫨娉㈡鏄庣粏涓嬪彂浠诲姟 + * + * @param map + * @param loginUserId + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public R waveToTask(Map<String, Object> map, Long loginUserId) { + if (Objects.isNull(map.get("waveItem"))) { + throw new CoolException("鍙傛暟涓嶈兘涓虹┖锛侊紒"); + } + String waveId = map.get("wave").toString(); + Wave waves = this.getById(Long.parseLong(waveId)); + if (Objects.isNull(waves)) { + throw new CoolException("娉㈡鏁版嵁涓嶅瓨鍦紒锛�"); + } + List<Long> waveItems = JSONArray.parseArray(JSON.toJSONString(map.get("waveItem")), Long.class); + if (waveItems.isEmpty()) { + throw new CoolException("娉㈡鏄庣粏涓嶈兘涓虹┖锛侊紒"); + } + List<WaveItem> items = waveItemService.listByIds(waveItems); + if (items.isEmpty()) { + throw new CoolException("娉㈡鏄庣粏涓嶅瓨鍦紒锛�"); } + if (!waveItemService.update(new LambdaUpdateWrapper<WaveItem>() + .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val) + .in(WaveItem::getId, waveItems))) { + throw new CoolException("鎵ц鐘舵�佷慨鏀瑰け璐ワ紒锛�"); + } + + WaveRule waveRule = waveRuleService.getOne(new LambdaQueryWrapper<WaveRule>() + .eq(WaveRule::getType, WaveRuleType.First_In_First_Out.type)); + if (Cools.isEmpty(waveRule)) { + throw new CoolException("鏈壘鍒板綋鍓嶇瓥鐣�"); + } + + List<WaveToLocParams> 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<OrderOutItemDto> results = LocManageUtil.getOutOrderList(params, waveRule); + if (results.isEmpty()) { + Wave wave = waveService.getById(waveId); + if (Objects.isNull(wave)) { + throw new CoolException("<UNK>"); + } + 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); + } + waveService.updateById(wave); + return R.ok(); + } + try { + /**鐢熸垚鍑哄簱浠诲姟*/ + generateOutTask(results, loginUserId, waves); + } catch (Exception e) { + log.error("UNK", e); + throw new CoolException(e.getMessage()); + } + + List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>() + .in(TaskItem::getSource, waveItems)); + 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(WaveItemExceStatus.WAVE_EXCE_STATUS_ING.val); + } else { + waveItem.setExceStatus(WaveItemExceStatus.WAVE_EXCE_STATUS_PUBD.val); + } + + if (!waveItemService.update(new LambdaUpdateWrapper<WaveItem>() + .set(WaveItem::getExceStatus, WaveItemExceStatus.WAVE_EXCE_STATUS_PUBD.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<Wave>() + .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, waveId))) { + throw new CoolException("娉㈡鐘舵�佷慨鏀瑰け璐ワ紒锛�"); + } 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<OrderOutItemDto> 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<WaveItem> mergeWavePreview(Long waveId) { + Wave wave = this.getById(waveId); + if (Objects.isNull(wave)) { + throw new CoolException("娉㈡涓嶈兘瀛樺湪锛侊紒"); + } + List<WaveItem> waveItems = waveItemService.list(new LambdaQueryWrapper<WaveItem>().eq(WaveItem::getWaveId, waveId)); + if (waveItems.isEmpty()) { + throw new CoolException("娉㈡鏄庣粏涓嶅瓨鍦紒锛�"); + } + List<WaveItem> 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<Long> ids) { + + return null; + } + + /** + * @param + * @param waveItems + * @return + * @author Ryan + * @description 鏍规嵁鐗╂枡缂栫爜锛屾壒娆★紝鍔ㄦ�佸瓧娈� 鏌ヨ绗﹀悎鐨勫簱浣嶏紝鍐嶆牴鎹簱浣嶄腑鐗╂枡鐨勬暟閲忛�夋嫨鏈�閫傚悎鐨勫簱浣� + * @time 2025/4/27 09:26 + */ + @Synchronized + private List<WaveItem> getLocs(List<WaveItem> waveItems) throws Exception { + //TODO 鏍规嵁鐗╂枡缂栫爜锛屾壒娆★紝鍔ㄦ�佸瓧娈� 鏌ヨ绗﹀悎鐨勫簱浣嶏紝鍐嶆牴鎹簱浣嶄腑鐗╂枡鐨勬暟閲忛�夋嫨鏈�閫傚悎鐨勫簱浣� + waveItems.forEach(waveItem -> { + List<LocItem> locItems = locItemService.list(new QueryWrapper<LocItem>() + .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<Double> doubles1 = locItems.stream().map(LocItem::getAnfme).collect(Collectors.toList()); + double[] doubles = doubles1.stream().mapToDouble(Double::doubleValue).toArray(); + + /**浣跨敤鍥炴函绠楁硶璁$畻锛岃幏鍙栫鍚堝嚭搴撻噺鐨勬渶绠�缁勫悎*/ + List<Integer> result = OptimalAlgorithmUtil.findCombination(doubles, waveItem.getAnfme()); + + String locs = "[]"; + if (Objects.isNull(result) || result.isEmpty()) { + waveItem.setStockLocs(locs).setStockQty(0.0); + } else { + /**杩囨护闆嗗悎涓渶绠�鐭殑缁勫悎*/ + List<LocItem> 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; + } } -- Gitblit v1.9.1