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 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.*;
|
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 波次任务下发
|
* @time 2025/4/25 16:24
|
*/
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
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("参数不能为空!!");
|
}
|
String waveId = map.get("wave").toString();
|
Wave waves = this.getById(Long.parseLong(waveId));
|
if (Objects.isNull(waves)) {
|
throw new CoolException("波次数据不存在!!");
|
}
|
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();
|
}
|
|
|
/**
|
* 选择波次明细下发任务
|
*
|
* @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()) {
|
waveService.update(new LambdaUpdateWrapper<Wave>()
|
.set(Wave::getExceStatus, WaveExceStatus.WAVE_EXCE_STATUS_EXCING.val)
|
.set(Wave::getUpdateBy, loginUserId)
|
.set(Wave::getUpdateTime, new Date())
|
.eq(Wave::getId, waveId));
|
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;
|
}
|
}
|