no message
parent
7d31f04772
commit
32f9edffc3
|
|
@ -2,6 +2,10 @@ package org.cpte.modules.agvTask.service;
|
|||
|
||||
import org.cpte.modules.agvTask.entity.AgvTask;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.conveyorLine.vo.ScanTrayData;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -40,4 +44,11 @@ public interface IAgvTaskService extends IService<AgvTask> {
|
|||
*/
|
||||
AgvTask bulidAgvTask(Long businessDetailId, String carrierCode, String startCode, String endCode, String taskType, String type, Integer izAll, String agvVendor);
|
||||
|
||||
/**
|
||||
* 处理AGV任务
|
||||
* @param data 扫描数据
|
||||
* @param dstPoint 目标库位
|
||||
*/
|
||||
void processAgvTask(ScanTrayData data, Point dstPoint);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,22 @@ package org.cpte.modules.agvTask.service.impl;
|
|||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.cpte.modules.agvTask.entity.AgvTask;
|
||||
import org.cpte.modules.agvTask.mapper.AgvTaskMapper;
|
||||
import org.cpte.modules.agvTask.service.IAgvTaskService;
|
||||
import org.cpte.modules.constant.enums.AgvStatusEnum;
|
||||
import org.cpte.modules.constant.enums.AgvVendorEnum;
|
||||
import org.cpte.modules.constant.enums.StockTypeEnum;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.enums.*;
|
||||
import org.cpte.modules.conveyorLine.vo.ScanTrayData;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
||||
import org.cpte.modules.receive.mapper.AsnMapper;
|
||||
import org.cpte.modules.shipping.mapper.PickMapper;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -28,9 +37,18 @@ import java.util.List;
|
|||
@Service
|
||||
public class AgvTaskServiceImpl extends ServiceImpl<AgvTaskMapper, AgvTask> implements IAgvTaskService {
|
||||
|
||||
@Autowired
|
||||
private AsnMapper asnMapper;
|
||||
|
||||
@Autowired
|
||||
private AsnDetailMapper asnDetailMapper;
|
||||
|
||||
@Autowired
|
||||
private IPointService pointService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AgvTask createAgvTask(Long businessDetailId, String carrierCode, String startCode, String endCode, String taskType, String type,Integer izAll, String agvVendor) {
|
||||
public AgvTask createAgvTask(Long businessDetailId, String carrierCode, String startCode, String endCode, String taskType, String type, Integer izAll, String agvVendor) {
|
||||
LoginUser sysUser = null;
|
||||
try {
|
||||
sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
|
|
@ -62,7 +80,7 @@ public class AgvTaskServiceImpl extends ServiceImpl<AgvTaskMapper, AgvTask> impl
|
|||
}
|
||||
|
||||
@Override
|
||||
public AgvTask bulidAgvTask(Long businessDetailId, String carrierCode, String startCode, String endCode, String taskType, String type,Integer izAll, String agvVendor) {
|
||||
public AgvTask bulidAgvTask(Long businessDetailId, String carrierCode, String startCode, String endCode, String taskType, String type, Integer izAll, String agvVendor) {
|
||||
LoginUser sysUser = null;
|
||||
try {
|
||||
sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
|
|
@ -92,4 +110,30 @@ public class AgvTaskServiceImpl extends ServiceImpl<AgvTaskMapper, AgvTask> impl
|
|||
.createTime(new Date())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processAgvTask(ScanTrayData data, Point dstPoint) {
|
||||
Asn asn = data.getAsn();
|
||||
asn.setStatus(AsnStatusEnum.SCAN.getValue());
|
||||
asnMapper.updateById(asn);
|
||||
|
||||
//写入工作站和终点库位
|
||||
Point station = data.getStation();
|
||||
List<AsnDetail> asnDetails = data.getAsnDetails();
|
||||
for (AsnDetail asnDetail : data.getAsnDetails()) {
|
||||
asnDetail.setStationId(station.getId());
|
||||
asnDetail.setToPointId(dstPoint.getId());
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(asnDetails)) {
|
||||
asnDetailMapper.updateById(asnDetails);
|
||||
}
|
||||
|
||||
//锁定目标库位
|
||||
pointService.bindPoint(dstPoint);
|
||||
|
||||
//验证通过,生成Tes任务
|
||||
Stock stock = data.getStock();
|
||||
createAgvTask(asn.getId(), stock.getStockCode(), station.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.TES.getValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,11 +55,7 @@ public class AreaController extends JeecgController<Area, IAreaService> {
|
|||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(name = "keyword", required = false) String keyword,
|
||||
HttpServletRequest req) {
|
||||
// 自定义查询规则
|
||||
Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
|
||||
customeRuleMap.put("areaCode", QueryRuleEnum.RIGHT_LIKE);
|
||||
customeRuleMap.put("areaName", QueryRuleEnum.RIGHT_LIKE);
|
||||
QueryWrapper<Area> queryWrapper = QueryGenerator.initQueryWrapper(area, req.getParameterMap(), customeRuleMap);
|
||||
QueryWrapper<Area> queryWrapper = QueryGenerator.initQueryWrapper(area, req.getParameterMap());
|
||||
// 如果提供了 keyword,则同时对 areaCode 和 areaName 进行模糊搜索
|
||||
if (StringUtils.isNotBlank(keyword)) {
|
||||
queryWrapper.and(wrapper -> wrapper.likeRight("area_code", keyword).or().likeRight("area_name", keyword));
|
||||
|
|
|
|||
|
|
@ -72,11 +72,8 @@ public class ItemController extends JeecgController<Item, IItemService> {
|
|||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(name = "keyword", required = false) String keyword,
|
||||
HttpServletRequest req) {
|
||||
// 自定义查询规则
|
||||
Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
|
||||
customeRuleMap.put("itemCode", QueryRuleEnum.RIGHT_LIKE);
|
||||
customeRuleMap.put("itemName", QueryRuleEnum.RIGHT_LIKE);
|
||||
QueryWrapper<Item> queryWrapper = QueryGenerator.initQueryWrapper(item, req.getParameterMap(),customeRuleMap);
|
||||
|
||||
QueryWrapper<Item> queryWrapper = QueryGenerator.initQueryWrapper(item, req.getParameterMap());
|
||||
// 如果提供了 keyword,则同时对 areaCode 和 areaName 进行模糊搜索
|
||||
if (StringUtils.isNotBlank(keyword)) {
|
||||
queryWrapper.and(wrapper -> wrapper.likeRight("item_code", keyword).or().likeRight("item_name", keyword));
|
||||
|
|
|
|||
|
|
@ -70,10 +70,7 @@ public class PointController extends JeecgController<Point, IPointService> {
|
|||
@RequestParam(name = "keyword", required = false) String keyword,
|
||||
HttpServletRequest req) {
|
||||
|
||||
// 自定义查询规则
|
||||
Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
|
||||
customeRuleMap.put("pointCode", QueryRuleEnum.RIGHT_LIKE);
|
||||
QueryWrapper<Point> queryWrapper = QueryGenerator.initQueryWrapper(point, req.getParameterMap(), customeRuleMap);
|
||||
QueryWrapper<Point> queryWrapper = QueryGenerator.initQueryWrapper(point, req.getParameterMap());
|
||||
// 如果提供了 keyword,则同时对 pointCode 模糊搜索
|
||||
if (StringUtils.isNotBlank(keyword)) {
|
||||
queryWrapper.and(wrapper -> wrapper.likeRight("point_code", keyword));
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ import java.io.IOException;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.system.query.QueryRuleEnum;
|
||||
|
|
@ -55,6 +58,9 @@ public class StockController extends JeecgController<Stock, IStockService> {
|
|||
@Autowired
|
||||
private IStockService stockService;
|
||||
|
||||
@Autowired
|
||||
private InventoryMapper inventoryMapper;
|
||||
|
||||
/**
|
||||
* 分页列表查询
|
||||
*
|
||||
|
|
@ -71,15 +77,22 @@ public class StockController extends JeecgController<Stock, IStockService> {
|
|||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(name = "keyword", required = false) String keyword,
|
||||
@RequestParam(name = "izScan", required = false) boolean izScan,
|
||||
HttpServletRequest req) {
|
||||
// 自定义查询规则
|
||||
Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
|
||||
customeRuleMap.put("stockCode", QueryRuleEnum.RIGHT_LIKE);
|
||||
QueryWrapper<Stock> queryWrapper = QueryGenerator.initQueryWrapper(stock, req.getParameterMap(), customeRuleMap);
|
||||
QueryWrapper<Stock> queryWrapper = QueryGenerator.initQueryWrapper(stock, req.getParameterMap());
|
||||
// 如果提供了 keyword,则同时对 pointCode 模糊搜索
|
||||
if (StringUtils.isNotBlank(keyword)) {
|
||||
queryWrapper.and(wrapper -> wrapper.likeRight("stock_code", keyword));
|
||||
}
|
||||
|
||||
//是否扫描
|
||||
if (izScan) {
|
||||
/*List<Inventory> inventories = inventoryMapper.selectList(null);
|
||||
List<Long> stockIds = inventories.stream().map(Inventory::getStockId).distinct().toList();
|
||||
queryWrapper.notIn("id", stockIds);*/
|
||||
queryWrapper.notExists("SELECT 1 FROM data_inventory WHERE stock_id = base_stock.id");
|
||||
}
|
||||
|
||||
queryWrapper.orderByAsc("stock_code");
|
||||
Page<Stock> page = new Page<Stock>(pageNo, pageSize);
|
||||
IPage<Stock> pageList = stockService.page(page, queryWrapper);
|
||||
|
|
|
|||
|
|
@ -40,15 +40,7 @@ public class Stock implements Serializable {
|
|||
@Schema(description = "主键")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private java.lang.Long id;
|
||||
/**
|
||||
* 库位ID
|
||||
*/
|
||||
@Excel(name = "库位ID", width = 15)
|
||||
@Schema(description = "库位ID")
|
||||
@Dict(dictTable = "base_point", dicCode = "id", dicText = "point_code")
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private java.lang.Long pointId;
|
||||
|
||||
/**
|
||||
* 容器编码
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -42,9 +42,8 @@ public interface IStockService extends IService<Stock> {
|
|||
* 绑定容器
|
||||
*
|
||||
* @param stock 容器
|
||||
* @param point 容器位置
|
||||
*/
|
||||
void bindStock(Stock stock, Point point);
|
||||
void bindStock(Stock stock);
|
||||
|
||||
/**
|
||||
* 根据容器编码集合查询容器信息
|
||||
|
|
@ -70,5 +69,11 @@ public interface IStockService extends IService<Stock> {
|
|||
*/
|
||||
Map<Long, Stock> queryByStockIdsToMap(List<Long> stockIds);
|
||||
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param insertToStock 创建的容器
|
||||
* @param updateToStock 更新的容器
|
||||
*/
|
||||
void batchOperation(List<Stock> insertToStock, List<Stock> updateToStock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import com.google.common.collect.Maps;
|
|||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.mapper.PointMapper;
|
||||
import org.cpte.modules.base.service.IAreaService;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.constant.enums.AreaTypeEnum;
|
||||
import org.cpte.modules.constant.enums.CommonStatusEnum;
|
||||
|
|
@ -29,9 +28,6 @@ import java.util.Map;
|
|||
@Service
|
||||
public class PointServiceImpl extends ServiceImpl<PointMapper, Point> implements IPointService {
|
||||
|
||||
@Autowired
|
||||
private IAreaService iAreaService;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,13 @@ import org.cpte.modules.base.service.IStockService;
|
|||
import org.cpte.modules.constant.enums.CommonStatusEnum;
|
||||
import org.cpte.modules.constant.enums.StockTypeEnum;
|
||||
import org.cpte.modules.saiWms.request.SyncStockRequest;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
|
@ -28,6 +31,9 @@ import java.util.*;
|
|||
@Service
|
||||
public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements IStockService {
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtil;
|
||||
|
||||
@Override
|
||||
public Stock buildStocK(SyncStockRequest.StockDTO stockDTO) {
|
||||
LoginUser sysUser = null;
|
||||
|
|
@ -79,8 +85,7 @@ public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void bindStock(Stock stock, Point point) {
|
||||
stock.setPointId(point == null ? null : point.getId());
|
||||
public void bindStock(Stock stock) {
|
||||
stock.setStatus(CommonStatusEnum.USED.getValue());
|
||||
this.baseMapper.updateById(stock);
|
||||
}
|
||||
|
|
@ -134,4 +139,15 @@ public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements
|
|||
}
|
||||
return stockMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperation(List<Stock> insertToStock, List<Stock> updateToStock) {
|
||||
if (CollectionUtils.isNotEmpty(insertToStock)) {
|
||||
batchUtil.saveBatchStock(insertToStock);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToStock)) {
|
||||
batchUtil.batchUpdateStocks(updateToStock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package org.cpte.modules.conveyorLine.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.conveyorLine.request.ScanTrayRequest;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
|
||||
public interface IConveyorLineService {
|
||||
|
||||
|
|
@ -12,5 +15,11 @@ public interface IConveyorLineService {
|
|||
*/
|
||||
void scanTray(ScanTrayRequest scanTrayRequest);
|
||||
|
||||
/**
|
||||
* 显示 输送线大屏显示
|
||||
*
|
||||
* @param conveyorLine conveyorLine
|
||||
*/
|
||||
JSONObject showConveyorLine(String conveyorLine);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package org.cpte.modules.conveyorLine.service.processor;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.agvTask.mapper.AgvTaskMapper;
|
||||
import org.cpte.modules.agvTask.service.IAgvTaskService;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.ItemKey;
|
||||
|
|
@ -26,7 +25,6 @@ import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
|||
import org.cpte.modules.receive.mapper.AsnMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
|
@ -61,9 +59,6 @@ public class ScanTrayProcessor {
|
|||
@Autowired
|
||||
private InventoryMapper inventoryMapper;
|
||||
|
||||
@Autowired
|
||||
private AgvTaskMapper agvTaskMapper;
|
||||
|
||||
@Autowired
|
||||
private IPointService pointService;
|
||||
|
||||
|
|
@ -90,7 +85,7 @@ public class ScanTrayProcessor {
|
|||
Point dstPoint = allocatePoint(data.getItemKeys(), data.getStation(), areaCode);
|
||||
|
||||
// 5.生成TES任务
|
||||
processAgvTask(data.getAsn(), data.getStock(), data.getStation(), dstPoint);
|
||||
agvTaskService.processAgvTask(data, dstPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -157,6 +152,12 @@ public class ScanTrayProcessor {
|
|||
private void validateTray(ScanTrayData data) {
|
||||
Long stockId = data.getStock().getId();
|
||||
String stockCode = data.getStock().getStockCode();
|
||||
Asn asn = data.getAsn();
|
||||
//验证当前托盘是否生成了TES任务
|
||||
if (AsnStatusEnum.SCAN.getValue().equals(asn.getStatus())) {
|
||||
throw new RuntimeException("【" + stockCode + "】托盘已扫描,请勿重复扫描");
|
||||
}
|
||||
|
||||
List<AsnDetail> asnDetails = asnDetailMapper.queryByStockCode(stockId, AsnStatusEnum.CREATED.getValue());
|
||||
if (CollectionUtils.isEmpty(asnDetails)) {
|
||||
throw new RuntimeException("【" + stockCode + "】托盘,无入库任务");
|
||||
|
|
@ -167,10 +168,7 @@ public class ScanTrayProcessor {
|
|||
throw new RuntimeException("【" + stockCode + "】托盘已入库");
|
||||
}
|
||||
|
||||
//验证当前托盘是否生成了TES任务
|
||||
if (agvTaskMapper.existsByStockCode(stockCode, AgvVendorEnum.TES.getValue()) != null) {
|
||||
throw new RuntimeException("【" + stockCode + "】托盘已扫描,请勿重复扫描");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -395,16 +393,4 @@ public class ScanTrayProcessor {
|
|||
// 距离越小分数越高
|
||||
return Math.max(0, 100 - (distance / 100.0));
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processAgvTask(Asn asn, Stock stock, Point station, Point dstPoint) {
|
||||
asn.setStatus(AsnStatusEnum.SCAN.getValue());
|
||||
asnMapper.updateById(asn);
|
||||
//锁定目标库位
|
||||
pointService.bindPoint(dstPoint);
|
||||
|
||||
//验证通过,生成Tes任务
|
||||
agvTaskService.createAgvTask(asn.getId(), stock.getStockCode(), station.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.TES.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,12 +132,6 @@ public class IHikAgvServiceImpl implements IHikAgvService {
|
|||
if (agvTask == null) {
|
||||
throw new RuntimeException("【" + taskReporterRequest.getRobotTaskCode() + "】任务不存在");
|
||||
}
|
||||
Point point = null;
|
||||
Stock stock = stock = iStockService.validateStock(agvTask.getCarrierCode());
|
||||
if (BusinessTypeEnum.INBOUND.getValue().equals(agvTask.getType())) {
|
||||
point = iPointService.validatePoint(agvTask.getEndCode());
|
||||
}
|
||||
|
||||
String status = taskReporterRequest.getExtra().getValues().getMethod();
|
||||
switch (status) {
|
||||
case "outbin":
|
||||
|
|
@ -146,7 +140,7 @@ public class IHikAgvServiceImpl implements IHikAgvService {
|
|||
break;
|
||||
case "end":
|
||||
//任务完成
|
||||
handleEnd(agvTask, stock, point);
|
||||
handleEnd(agvTask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -223,11 +217,7 @@ public class IHikAgvServiceImpl implements IHikAgvService {
|
|||
*
|
||||
* @param agvTask 任务
|
||||
*/
|
||||
private void handleEnd(AgvTask agvTask, Stock stock, Point point) {
|
||||
if (BusinessTypeEnum.INBOUND.getValue().equals(agvTask.getType())) {
|
||||
//绑定容器和点位
|
||||
iStockService.bindStock(stock, point);
|
||||
}
|
||||
private void handleEnd(AgvTask agvTask) {
|
||||
//更新任务状态
|
||||
agvTask.setStatus(AgvStatusEnum.COMPLETED.getValue());
|
||||
agvTask.setEndTime(new Date());
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ public class InventoryLogServiceImpl extends ServiceImpl<InventoryLogMapper, Inv
|
|||
inventoryLog.setChangeQty(BigDecimal.ZERO);
|
||||
inventoryLog.setBeforeAllocatedQty(BigDecimalUtil.subtract(inventory.getQueuedQty(), AllocatedQty, 0));
|
||||
inventoryLog.setAfterAllocatedQty(inventory.getQueuedQty());
|
||||
log.debug("库存分配日志记录成功,变动前分配数量: {}, 变动后分配数量: {}", inventoryLog.getBeforeAllocatedQty(), inventoryLog.getAfterAllocatedQty());
|
||||
addInventoryLog(inventoryLog);
|
||||
}
|
||||
|
||||
|
|
@ -93,8 +92,8 @@ public class InventoryLogServiceImpl extends ServiceImpl<InventoryLogMapper, Inv
|
|||
inventoryLog.setLogType(InventoryLogEnum.UNALLOC.getValue());
|
||||
// 实际数量不变
|
||||
inventoryLog.setChangeQty(BigDecimal.ZERO);
|
||||
inventoryLog.setBeforeAllocatedQty(inventory.getQueuedQty());
|
||||
inventoryLog.setAfterAllocatedQty(BigDecimalUtil.subtract(inventory.getQueuedQty(), cancelQuantity, 0));
|
||||
inventoryLog.setBeforeAllocatedQty(BigDecimalUtil.add(inventory.getQueuedQty(), cancelQuantity, 0));
|
||||
inventoryLog.setAfterAllocatedQty(inventory.getQueuedQty());
|
||||
addInventoryLog(inventoryLog);
|
||||
}
|
||||
|
||||
|
|
@ -105,9 +104,10 @@ public class InventoryLogServiceImpl extends ServiceImpl<InventoryLogMapper, Inv
|
|||
// 拣货类型
|
||||
inventoryLog.setLogType(InventoryLogEnum.OUTBOUND.getValue());
|
||||
// 出库数量为负数
|
||||
inventoryLog.setBeforeQty(inventory.getQuantity());
|
||||
inventoryLog.setChangeQty(changeQty.negate());
|
||||
inventoryLog.setAfterQty(BigDecimalUtil.subtract(inventory.getQuantity(), changeQty, 0));
|
||||
log.info("库存变动日志记录成功,库存数量: {}, 拣货数量: {}", inventory.getQuantity(), changeQty);
|
||||
inventoryLog.setBeforeQty(BigDecimalUtil.add(inventory.getQuantity(), changeQty, 0));
|
||||
inventoryLog.setAfterQty(inventory.getQuantity());
|
||||
inventoryLog.setAfterAllocatedQty(BigDecimal.ZERO);
|
||||
inventoryLog.setBeforeAllocatedQty(BigDecimal.ZERO);
|
||||
inventoryLog.setFromPointId(inventory.getPointId());
|
||||
|
|
|
|||
|
|
@ -265,4 +265,6 @@ public class AsnController {
|
|||
return Result.OK("文件导入失败!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,16 @@ public class AsnDetail implements Serializable {
|
|||
@Schema(description = "起点库位")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private java.lang.Long fromPointId;
|
||||
|
||||
|
||||
/**
|
||||
* 工作站库位
|
||||
*/
|
||||
@Schema(description = "工作站")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private java.lang.Long stationId;
|
||||
|
||||
|
||||
/**
|
||||
* 终点库位
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import org.cpte.modules.base.entity.Item;
|
|||
import org.cpte.modules.base.entity.ItemKey;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventoryLog.entity.InventoryLog;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
|
@ -30,6 +32,24 @@ public interface IAsnDetailService extends IService<AsnDetail> {
|
|||
*/
|
||||
public List<AsnDetail> selectByMainId(Long mainId);
|
||||
|
||||
/**
|
||||
* 保存主表信息
|
||||
*
|
||||
* @param asn 入库单
|
||||
* @param asnDetailList 入库明细
|
||||
*/
|
||||
void processorSaveMain(Asn asn, List<AsnDetail> asnDetailList);
|
||||
|
||||
/**
|
||||
* 入库处理
|
||||
*
|
||||
* @param inboundRequest 入库参数
|
||||
* @param itemMap 物料
|
||||
* @param srcPoint 起点
|
||||
* @param stock 容器
|
||||
*/
|
||||
void processInboundTask(InboundRequest inboundRequest, Map<String, Item> itemMap, Point srcPoint, Stock stock);
|
||||
|
||||
/**
|
||||
* 刷新入库单
|
||||
*
|
||||
|
|
@ -38,6 +58,27 @@ public interface IAsnDetailService extends IService<AsnDetail> {
|
|||
*/
|
||||
void refreshAsn(Asn asn, List<AsnDetail> asnDetails);
|
||||
|
||||
/**
|
||||
* 构建入库单
|
||||
*
|
||||
* @param inboundRequest 入库请求
|
||||
* @return Asn
|
||||
*/
|
||||
Asn buildAsn(InboundRequest inboundRequest);
|
||||
|
||||
/**
|
||||
* 构建入库单明细
|
||||
*
|
||||
* @param inboundDetails 入库单明细
|
||||
* @param itemMap 物料信息
|
||||
* @param stock 容器
|
||||
* @param srcPoint 源库位
|
||||
* @param station 工作站
|
||||
* @return AsnDetail
|
||||
*/
|
||||
List<AsnDetail> buildAsnDetail(List<InboundRequest.InboundDetail> inboundDetails, Map<String, Item> itemMap, Stock stock, Point srcPoint, Point station);
|
||||
|
||||
|
||||
/**
|
||||
* 构建入库记录
|
||||
*
|
||||
|
|
@ -49,5 +90,14 @@ public interface IAsnDetailService extends IService<AsnDetail> {
|
|||
*/
|
||||
ReceiveRecord buildReceiveRecord(AsnDetail asnDetail, BigDecimal receivedQty, ItemKey itemKey, Long dstPointId);
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param updateToAsnDetail 更新入库单明细
|
||||
* @param records 创建收货记录
|
||||
* @param inventoryMap 创建库存
|
||||
* @param inventoryLogs 创建库存日志
|
||||
*/
|
||||
void batchOperation(List<AsnDetail> updateToAsnDetail, List<ReceiveRecord> records, Map<Long, Inventory> inventoryMap, List<InventoryLog> inventoryLogs);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
package org.cpte.modules.receive.service;
|
||||
|
||||
import org.cpte.modules.agvTask.entity.AgvTask;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.ItemKey;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventoryLog.entity.InventoryLog;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
|
@ -54,32 +57,13 @@ public interface IAsnService extends IService<Asn> {
|
|||
*/
|
||||
public void delBatchMain(Collection<? extends Serializable> idList);
|
||||
|
||||
/**
|
||||
* 构建入库单
|
||||
*
|
||||
* @param inboundRequest 入库请求
|
||||
* @return Asn
|
||||
*/
|
||||
Asn buildAsn(InboundRequest inboundRequest);
|
||||
|
||||
/**
|
||||
* 构建入库单明细
|
||||
*
|
||||
* @param inboundDetails 入库单明细
|
||||
* @param itemMap 物料信息
|
||||
* @param stock 容器
|
||||
* @param srcPoint 源库位
|
||||
* @param dstPoint 目标库位
|
||||
* @return AsnDetail
|
||||
*/
|
||||
List<AsnDetail> buildAsnDetail(List<InboundRequest.InboundDetail> inboundDetails, Map<String, Item> itemMap, Stock stock, Point srcPoint, Point dstPoint);
|
||||
|
||||
/**
|
||||
* 收货操作
|
||||
*
|
||||
* @param asnId 入库单ID
|
||||
* @param pointCode 目标库位
|
||||
*/
|
||||
void receiveAsn(Long asnId, String pointCode);
|
||||
void receiveAsn(Long asnId);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,19 @@
|
|||
package org.cpte.modules.receive.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.cpte.modules.agvTask.service.IAgvTaskService;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.ItemKey;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.constant.enums.AsnStatusEnum;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.GeneralConstant;
|
||||
import org.cpte.modules.constant.enums.*;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventoryLog.entity.InventoryLog;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
import org.cpte.modules.receive.entity.ReceiveRecord;
|
||||
|
|
@ -13,7 +21,9 @@ import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
|||
import org.cpte.modules.receive.mapper.AsnMapper;
|
||||
import org.cpte.modules.receive.service.IAsnDetailService;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.cpte.modules.shipping.mapper.PickMapper;
|
||||
import org.cpte.modules.serialNumber.AsnSerialNumberRule;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
|
@ -21,9 +31,11 @@ import java.util.ArrayList;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @Description: 入库明细
|
||||
|
|
@ -37,11 +49,93 @@ public class AsnDetailServiceImpl extends ServiceImpl<AsnDetailMapper, AsnDetail
|
|||
@Autowired
|
||||
private AsnMapper asnMapper;
|
||||
|
||||
@Autowired
|
||||
private IPointService pointService;
|
||||
|
||||
@Autowired
|
||||
private IStockService stockService;
|
||||
|
||||
@Autowired
|
||||
private IAgvTaskService agvTaskService;
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtil;
|
||||
|
||||
@Autowired
|
||||
private AsnSerialNumberRule asnSerialNumberRule;
|
||||
|
||||
@Override
|
||||
public List<AsnDetail> selectByMainId(Long mainId) {
|
||||
return this.baseMapper.selectByMainId(mainId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processorSaveMain(Asn asn, List<AsnDetail> asnDetailList) {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
asn.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
asn.setSysOrgCode(sysUser.getOrgCode());
|
||||
String orderNo = asnSerialNumberRule.generateSerialNumber(GeneralConstant.ASN_ORDER_NO);
|
||||
asn.setOrderNo(orderNo);
|
||||
asnMapper.insert(asn);
|
||||
|
||||
if (asnDetailList == null || asnDetailList.isEmpty()) {
|
||||
throw new RuntimeException("请新增入库明细");
|
||||
}
|
||||
|
||||
AtomicInteger lineNoCounter = new AtomicInteger(1);
|
||||
for (AsnDetail entity : asnDetailList) {
|
||||
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
|
||||
entity.setLineNo(lineNoCounter.getAndIncrement());
|
||||
}
|
||||
entity.setAsnId(asn.getId());
|
||||
entity.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
entity.setSysOrgCode(sysUser.getOrgCode());
|
||||
this.baseMapper.insert(entity);
|
||||
}
|
||||
//刷新入库单
|
||||
refreshAsn(asn, asnDetailList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processInboundTask(InboundRequest inboundRequest, Map<String, Item> itemMap, Point srcPoint, Stock stock) {
|
||||
//1.获取工作站
|
||||
Point station = null;
|
||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType())) {
|
||||
station = getStationPoint(inboundRequest.getType());
|
||||
}
|
||||
|
||||
//2.构建入库单和入库明细
|
||||
Asn asn = buildAsn(inboundRequest);
|
||||
List<AsnDetail> asnDetails = buildAsnDetail(inboundRequest.getDetails(), itemMap, stock, srcPoint, station);
|
||||
processorSaveMain(asn, asnDetails);
|
||||
|
||||
//3.绑定容器
|
||||
stockService.bindStock(stock);
|
||||
|
||||
//4.成品入库,生成AGV任务
|
||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType()) && station != null) {
|
||||
agvTaskService.createAgvTask(asn.getId(), stock.getStockCode(), srcPoint.getPointCode(), station.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.HIK.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作站
|
||||
*
|
||||
* @param orderType 任务类型
|
||||
* @return Point
|
||||
*/
|
||||
private Point getStationPoint(Integer orderType) {
|
||||
Point dstPoint = null;
|
||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(orderType)) {
|
||||
//1.获取入库输送线工作台点位为终点,均衡分配点位-轮询方式
|
||||
dstPoint = pointService.getWorkStationPoint(null, AreaTypeEnum.RK_DOCK.getValue(), GeneralConstant.RK_DOCK_TASK_INDEX);
|
||||
}
|
||||
return dstPoint;
|
||||
}
|
||||
|
||||
|
||||
public void refreshAsn(Asn asn, List<AsnDetail> asnDetails) {
|
||||
|
||||
if (asnDetails == null) {
|
||||
|
|
@ -77,6 +171,45 @@ public class AsnDetailServiceImpl extends ServiceImpl<AsnDetailMapper, AsnDetail
|
|||
asnMapper.updateById(asn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Asn buildAsn(InboundRequest inboundRequest) {
|
||||
return Asn.builder()
|
||||
.thirdOrderNo(inboundRequest.getOrderNo())
|
||||
.no(inboundRequest.getNo())
|
||||
.whCode(inboundRequest.getWhCode())
|
||||
.supplierCode(inboundRequest.getSupplierCode())
|
||||
.orderType(inboundRequest.getType())
|
||||
.status(AsnStatusEnum.CREATED.getValue())
|
||||
.orderDate(new Date())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AsnDetail> buildAsnDetail(List<InboundRequest.InboundDetail> inboundDetails, Map<String, Item> itemMap, Stock stock, Point srcPoint, Point station) {
|
||||
List<AsnDetail> newDetailList = new ArrayList<>();
|
||||
for (InboundRequest.InboundDetail detail : inboundDetails) {
|
||||
AsnDetail asnDetail = AsnDetail.builder()
|
||||
.lineNo(Integer.parseInt(detail.getLineNo()))
|
||||
.itemId(itemMap.get(detail.getItem()).getId())
|
||||
.unit(detail.getUnit())
|
||||
.orderQty(BigDecimal.valueOf(detail.getQty()))
|
||||
.receivedQty(BigDecimal.ZERO)
|
||||
.stockId(stock.getId())
|
||||
.fromPointId(srcPoint == null ? null : srcPoint.getId())
|
||||
.stationId(station== null ? null : station.getId())
|
||||
.status(AsnStatusEnum.CREATED.getValue())
|
||||
.project(detail.getProject())
|
||||
.taskNo(detail.getTaskNo())
|
||||
.propC1(detail.getLotAtt04())
|
||||
.propC3(detail.getLotAtt010())
|
||||
.build();
|
||||
newDetailList.add(asnDetail);
|
||||
}
|
||||
return newDetailList;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ReceiveRecord buildReceiveRecord(AsnDetail asnDetail, BigDecimal receivedQty, ItemKey itemKey, Long dstPointId) {
|
||||
return ReceiveRecord.builder()
|
||||
|
|
@ -96,4 +229,23 @@ public class AsnDetailServiceImpl extends ServiceImpl<AsnDetailMapper, AsnDetail
|
|||
.createTime(new Date())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperation(List<AsnDetail> updateToAsnDetail, List<ReceiveRecord> records,
|
||||
Map<Long, Inventory> inventoryMap, List<InventoryLog> inventoryLogs) {
|
||||
if (CollectionUtils.isNotEmpty(updateToAsnDetail)) {
|
||||
batchUtil.updateBatchAsnDetail(updateToAsnDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(records)) {
|
||||
batchUtil.saveBatchReceiveRecord(records);
|
||||
}
|
||||
if (inventoryMap != null && !inventoryMap.isEmpty()) {
|
||||
List<Inventory> createToInventory = new ArrayList<>(inventoryMap.values());
|
||||
batchUtil.saveBatchInventory(createToInventory);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(inventoryLogs)) {
|
||||
batchUtil.saveBatchInventoryLog(inventoryLogs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ package org.cpte.modules.receive.service.impl;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.cpte.modules.agvTask.entity.AgvTask;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.constant.GeneralConstant;
|
||||
import org.cpte.modules.constant.enums.AsnStatusEnum;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
|
|
@ -16,12 +15,7 @@ import org.cpte.modules.receive.service.IAsnDetailService;
|
|||
import org.cpte.modules.receive.service.IAsnService;
|
||||
import org.cpte.modules.receive.service.processor.ReceiveProcessor;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.cpte.modules.serialNumber.AsnSerialNumberRule;
|
||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||
import org.cpte.modules.utils.SwmsLoginUtil;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiMapper;
|
||||
import org.jeecg.modules.system.mapper.SysDictMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -42,22 +36,13 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
@Slf4j
|
||||
public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnService {
|
||||
|
||||
|
||||
@Autowired
|
||||
private AsnDetailMapper asnDetailMapper;
|
||||
@Autowired
|
||||
private OpenApiMapper openApiMapper;
|
||||
@Autowired
|
||||
private SysDictMapper sysDictMapper;
|
||||
@Autowired
|
||||
private IAsnDetailService asnDetailService;
|
||||
@Autowired
|
||||
private ReceiveProcessor receiveProcessor;
|
||||
@Autowired
|
||||
private SwmsLoginUtil swmsLoginUtil;
|
||||
@Autowired
|
||||
private AsnSerialNumberRule asnSerialNumberRule;
|
||||
@Autowired
|
||||
private RedisDistributedLockUtil redissonLock;
|
||||
|
||||
@Override
|
||||
|
|
@ -69,7 +54,7 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("入库单创建中,请稍后重试");
|
||||
}
|
||||
processorSaveMain(asn, asnDetailList);
|
||||
asnDetailService.processorSaveMain(asn, asnDetailList);
|
||||
} catch (Exception e) {
|
||||
log.error("入库单创建异常", e);
|
||||
throw e;
|
||||
|
|
@ -80,40 +65,6 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存主表信息
|
||||
*
|
||||
* @param asn 入库单
|
||||
* @param asnDetailList 入库明细
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processorSaveMain(Asn asn, List<AsnDetail> asnDetailList) {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
asn.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
asn.setSysOrgCode(sysUser.getOrgCode());
|
||||
String orderNo = asnSerialNumberRule.generateSerialNumber(GeneralConstant.ASN_ORDER_NO);
|
||||
asn.setOrderNo(orderNo);
|
||||
this.baseMapper.insert(asn);
|
||||
|
||||
if (asnDetailList == null || asnDetailList.isEmpty()) {
|
||||
throw new RuntimeException("请新增入库明细");
|
||||
}
|
||||
|
||||
AtomicInteger lineNoCounter = new AtomicInteger(1);
|
||||
for (AsnDetail entity : asnDetailList) {
|
||||
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
|
||||
entity.setLineNo(lineNoCounter.getAndIncrement());
|
||||
}
|
||||
entity.setAsnId(asn.getId());
|
||||
entity.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
entity.setSysOrgCode(sysUser.getOrgCode());
|
||||
asnDetailMapper.insert(entity);
|
||||
}
|
||||
//刷新入库单
|
||||
asnDetailService.refreshAsn(asn, asnDetailList);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateMain(Asn asn, List<AsnDetail> asnDetailList) {
|
||||
|
|
@ -123,10 +74,6 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
throw new RuntimeException("请新增入库明细");
|
||||
}
|
||||
|
||||
if (asnDetailList.size() > 1) {
|
||||
throw new RuntimeException("入库明细只允许新增一条");
|
||||
}
|
||||
|
||||
AtomicInteger lineNoCounter = new AtomicInteger(1);
|
||||
for (AsnDetail entity : asnDetailList) {
|
||||
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
|
||||
|
|
@ -172,47 +119,8 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
throw new RuntimeException("操作失败:【" + orderNoList + "】入库单,非创建状态不允许删除");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Asn buildAsn(InboundRequest inboundRequest) {
|
||||
return Asn.builder()
|
||||
.thirdOrderNo(inboundRequest.getOrderNo())
|
||||
.no(inboundRequest.getNo())
|
||||
.whCode(inboundRequest.getWhCode())
|
||||
.supplierCode(inboundRequest.getSupplierCode())
|
||||
.orderType(inboundRequest.getType())
|
||||
.status(AsnStatusEnum.CREATED.getValue())
|
||||
.orderDate(new Date())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AsnDetail> buildAsnDetail(List<InboundRequest.InboundDetail> inboundDetails, Map<String, Item> itemMap, Stock stock, Point srcPoint, Point dstPoint) {
|
||||
List<AsnDetail> newDetailList = new ArrayList<>();
|
||||
for (InboundRequest.InboundDetail detail : inboundDetails) {
|
||||
AsnDetail asnDetail = AsnDetail.builder()
|
||||
.lineNo(Integer.parseInt(detail.getLineNo()))
|
||||
.itemId(itemMap.get(detail.getItem()).getId())
|
||||
.unit(detail.getUnit())
|
||||
.orderQty(BigDecimal.valueOf(detail.getQty()))
|
||||
.receivedQty(BigDecimal.ZERO)
|
||||
.stockId(stock.getId())
|
||||
.fromPointId(srcPoint == null ? null : srcPoint.getId())
|
||||
.toPointId(dstPoint == null ? null : dstPoint.getId())
|
||||
.status(AsnStatusEnum.CREATED.getValue())
|
||||
.project(detail.getProject())
|
||||
.taskNo(detail.getTaskNo())
|
||||
.propC1(detail.getLotAtt04())
|
||||
.propC3(detail.getLotAtt010())
|
||||
.build();
|
||||
newDetailList.add(asnDetail);
|
||||
}
|
||||
return newDetailList;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveAsn(Long asnId, String pointCode) {
|
||||
public void receiveAsn(Long asnId) {
|
||||
String lockKey = "asn:" + asnId;
|
||||
String lockValue = null;
|
||||
try {
|
||||
|
|
@ -220,7 +128,7 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("收货处理中,请稍后重试");
|
||||
}
|
||||
receiveProcessor.receiveAsn(asnId, pointCode);
|
||||
receiveProcessor.receiveAsn(asnId);
|
||||
} catch (Exception e) {
|
||||
log.error("收货处理异常", e);
|
||||
throw e;
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ import org.cpte.modules.base.entity.Stock;
|
|||
import org.cpte.modules.base.mapper.PointMapper;
|
||||
import org.cpte.modules.base.mapper.StockMapper;
|
||||
import org.cpte.modules.base.service.IItemKeyService;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.enums.AsnStatusEnum;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventory.service.IInventoryService;
|
||||
|
|
@ -22,11 +20,9 @@ import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
|||
import org.cpte.modules.receive.mapper.AsnMapper;
|
||||
import org.cpte.modules.receive.service.IAsnDetailService;
|
||||
import org.cpte.modules.receive.vo.ReceiveData;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.cpte.modules.utils.BigDecimalUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -42,10 +38,10 @@ import java.util.Map;
|
|||
public class ReceiveProcessor {
|
||||
|
||||
@Autowired
|
||||
private StockMapper stockMapper;
|
||||
private PointMapper pointMapper;
|
||||
|
||||
@Autowired
|
||||
private PointMapper pointMapper;
|
||||
private StockMapper stockMapper;
|
||||
|
||||
@Autowired
|
||||
private AsnMapper asnMapper;
|
||||
|
|
@ -53,12 +49,6 @@ public class ReceiveProcessor {
|
|||
@Autowired
|
||||
private AsnDetailMapper asnDetailMapper;
|
||||
|
||||
@Autowired
|
||||
private IStockService stockService;
|
||||
|
||||
@Autowired
|
||||
private IPointService pointService;
|
||||
|
||||
@Autowired
|
||||
private IAsnDetailService asnDetailService;
|
||||
|
||||
|
|
@ -74,18 +64,15 @@ public class ReceiveProcessor {
|
|||
@Autowired
|
||||
private ReceiveBackProcessor receiveBackProcessor;
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtil;
|
||||
|
||||
/**
|
||||
* 收货
|
||||
*
|
||||
* @param asnId 入库单
|
||||
* @param dstPointCode 目标库位
|
||||
* @param asnId 入库单
|
||||
*/
|
||||
public void receiveAsn(Long asnId, String dstPointCode) {
|
||||
public void receiveAsn(Long asnId) {
|
||||
// 1.数据准备
|
||||
ReceiveData data = prepareReceiveData(asnId, dstPointCode);
|
||||
ReceiveData data = prepareReceiveData(asnId);
|
||||
|
||||
//3.创建数据结构
|
||||
List<AsnDetail> updateToAsnDetail = new ArrayList<>();
|
||||
|
|
@ -97,14 +84,11 @@ public class ReceiveProcessor {
|
|||
receive(data, updateToAsnDetail, createRecords, inventoryMap, createInventoryLogs);
|
||||
|
||||
//5.批量操作
|
||||
batchOperation(updateToAsnDetail, createRecords, inventoryMap, createInventoryLogs);
|
||||
asnDetailService.batchOperation(updateToAsnDetail, createRecords, inventoryMap, createInventoryLogs);
|
||||
|
||||
//6.刷新入库
|
||||
refreshData(data);
|
||||
|
||||
//7.更新容器状态和位置
|
||||
updateStockAndPoint(data.getStock(), data.getDstPoint());
|
||||
|
||||
//8.回传
|
||||
receiveBackProcessor.receiveBack(data.getAsn(), data.getStock());
|
||||
}
|
||||
|
|
@ -112,11 +96,10 @@ public class ReceiveProcessor {
|
|||
/**
|
||||
* 数据准备
|
||||
*
|
||||
* @param asnId 入库单
|
||||
* @param dstPointCode 目标库位
|
||||
* @param asnId 入库单
|
||||
* @return ReceiveData
|
||||
*/
|
||||
private ReceiveData prepareReceiveData(Long asnId, String dstPointCode) {
|
||||
private ReceiveData prepareReceiveData(Long asnId) {
|
||||
ReceiveData data = new ReceiveData();
|
||||
Asn asn = asnMapper.selectById(asnId);
|
||||
data.setAsn(asn);
|
||||
|
|
@ -124,13 +107,13 @@ public class ReceiveProcessor {
|
|||
List<AsnDetail> asnDetails = asnDetailMapper.selectByMainId(asnId);
|
||||
if (CollectionUtils.isNotEmpty(asnDetails)) {
|
||||
data.setAsnDetails(asnDetails);
|
||||
|
||||
Stock stock = stockMapper.selectById(asnDetails.get(0).getStockId());
|
||||
data.setStock(stock);
|
||||
|
||||
Point point = pointMapper.selectById(asnDetails.get(0).getToPointId());
|
||||
data.setPoint(point);
|
||||
}
|
||||
|
||||
Point dstPoint = pointMapper.queryByPointCode(dstPointCode);
|
||||
data.setDstPoint(dstPoint);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
@ -149,8 +132,7 @@ public class ReceiveProcessor {
|
|||
Map<Long, Inventory> inventoryMap,
|
||||
List<InventoryLog> inventoryLogs) {
|
||||
Asn asn = data.getAsn();
|
||||
Point dstPoint = data.getDstPoint();
|
||||
Stock stock = data.getStock();
|
||||
|
||||
for (AsnDetail asnDetail : data.getAsnDetails()) {
|
||||
BigDecimal unreceivedQty = BigDecimalUtil.subtract(asnDetail.getOrderQty(), asnDetail.getReceivedQty(), 0);
|
||||
if (unreceivedQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
|
|
@ -170,14 +152,14 @@ public class ReceiveProcessor {
|
|||
ItemKey itemKey = itemKeyService.createItemKey(asnDetail.getItemId(), asn.getWhCode(), asnDetail.getProject(), asnDetail.getTaskNo(), asnDetail.getPropC1(), asnDetail.getPropC3());
|
||||
|
||||
//生成入库记录
|
||||
ReceiveRecord receiveRecord = asnDetailService.buildReceiveRecord(asnDetail, receivedQty, itemKey, dstPoint.getId());
|
||||
ReceiveRecord receiveRecord = asnDetailService.buildReceiveRecord(asnDetail, receivedQty, itemKey, asnDetail.getToPointId());
|
||||
records.add(receiveRecord);
|
||||
|
||||
// 生成库存
|
||||
Inventory inventory = createInventory(asn, receiveRecord, itemKey, stock, receivedQty, inventoryMap);
|
||||
Inventory inventory = createInventory(asn, receiveRecord, itemKey, asnDetail.getStockId(), receivedQty, inventoryMap);
|
||||
|
||||
//添加库存日志
|
||||
InventoryLog inventoryLog = inventoryLogService.buildInboundInventoryLog(inventory, asnDetail.getToPointId(),receivedQty, asn.getThirdOrderNo(), receiveRecord.getId(), receiveRecord.getDescription());
|
||||
InventoryLog inventoryLog = inventoryLogService.buildInboundInventoryLog(inventory, asnDetail.getFromPointId() == null ? asnDetail.getStationId() : asnDetail.getFromPointId(), receivedQty, asn.getThirdOrderNo(), receiveRecord.getId(), receiveRecord.getDescription());
|
||||
inventoryLogs.add(inventoryLog);
|
||||
}
|
||||
}
|
||||
|
|
@ -189,12 +171,12 @@ public class ReceiveProcessor {
|
|||
* @param asn 入库单
|
||||
* @param receiveRecord 收货记录
|
||||
* @param itemKey 物料属性
|
||||
* @param stock 容器
|
||||
* @param stockId 容器
|
||||
* @param receivedQty 收货数量
|
||||
* @param inventoryMap 创建库存
|
||||
*/
|
||||
private Inventory createInventory(Asn asn, ReceiveRecord receiveRecord, ItemKey itemKey, Stock stock, BigDecimal receivedQty, Map<Long, Inventory> inventoryMap) {
|
||||
Inventory inventory = inventoryService.buildInventory(stock.getId(), BigDecimal.ZERO, asn, receiveRecord);
|
||||
private Inventory createInventory(Asn asn, ReceiveRecord receiveRecord, ItemKey itemKey, Long stockId, BigDecimal receivedQty, Map<Long, Inventory> inventoryMap) {
|
||||
Inventory inventory = inventoryService.buildInventory(stockId, BigDecimal.ZERO, asn, receiveRecord);
|
||||
//根据itemKey更新库存
|
||||
Inventory targetInventory = inventoryMap.getOrDefault(itemKey.getId(), inventory);
|
||||
BigDecimal newReceivedQty = BigDecimalUtil.add(targetInventory.getQuantity(), receivedQty, 0);
|
||||
|
|
@ -203,33 +185,6 @@ public class ReceiveProcessor {
|
|||
return targetInventory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param updateToAsnDetail 更新入库单明细
|
||||
* @param records 创建收货记录
|
||||
* @param inventoryMap 创建库存
|
||||
* @param inventoryLogs 创建库存日志
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperation(List<AsnDetail> updateToAsnDetail, List<ReceiveRecord> records,
|
||||
Map<Long, Inventory> inventoryMap, List<InventoryLog> inventoryLogs) {
|
||||
if (CollectionUtils.isNotEmpty(updateToAsnDetail)) {
|
||||
batchUtil.updateBatchAsnDetail(updateToAsnDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(records)) {
|
||||
batchUtil.saveBatchReceiveRecord(records);
|
||||
}
|
||||
if (inventoryMap != null && !inventoryMap.isEmpty()) {
|
||||
List<Inventory> createToInventory = new ArrayList<>(inventoryMap.values());
|
||||
batchUtil.saveBatchInventory(createToInventory);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(inventoryLogs)) {
|
||||
batchUtil.saveBatchInventoryLog(inventoryLogs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新出库单
|
||||
*
|
||||
|
|
@ -239,16 +194,4 @@ public class ReceiveProcessor {
|
|||
asnDetailService.refreshAsn(data.getAsn(), data.getAsnDetails());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新容器状态和位置
|
||||
*
|
||||
* @param stock 托盘
|
||||
* @param dstPoint 目标库位
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateStockAndPoint(Stock stock, Point dstPoint) {
|
||||
//更新容器状态和位置
|
||||
stockService.bindStock(stock, dstPoint);
|
||||
pointService.bindPoint(dstPoint);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ public class ReceiveData {
|
|||
private Asn asn ;
|
||||
private List<AsnDetail> asnDetails;
|
||||
private Stock stock;
|
||||
private Point dstPoint;
|
||||
private Point point;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.cpte.modules.receive.service.IAsnService;
|
||||
import org.cpte.modules.saiWms.request.CallAgvRequest;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
|
|
@ -11,6 +12,7 @@ import org.cpte.modules.saiWms.request.SyncStockRequest;
|
|||
import org.cpte.modules.saiWms.service.ISMOMService;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
import org.jeecg.config.shiro.IgnoreAuth;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
|
@ -26,6 +28,9 @@ public class SaiWmsController {
|
|||
@Autowired
|
||||
private ISMOMService iSaiWmsService;
|
||||
|
||||
@Autowired
|
||||
private IAsnService asnService;
|
||||
|
||||
/**
|
||||
* 容器同步
|
||||
*
|
||||
|
|
|
|||
|
|
@ -36,12 +36,44 @@ public class ISMOMServiceImpl implements ISMOMService {
|
|||
|
||||
@Override
|
||||
public void inBoundTask(InboundRequest inboundRequest) {
|
||||
inBoundTaskProcessor.inBoundTask(inboundRequest);
|
||||
//5.入库处理
|
||||
String lockKey = "inbound:" + inboundRequest.getNo();
|
||||
String lockValue = null;
|
||||
try {
|
||||
lockValue = redissonLock.tryLock(lockKey, 10);
|
||||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("入库单接收中,请稍后重试");
|
||||
}
|
||||
inBoundTaskProcessor.inBoundTask(inboundRequest);
|
||||
} catch (Exception e) {
|
||||
log.error("入库单接收异常", e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (StringUtils.isNotEmpty(lockValue)) {
|
||||
redissonLock.unlock(lockKey, lockValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outBoundTask(OutboundRequest outboundRequest) {
|
||||
outBoundTaskProcessor.outBoundTask(outboundRequest);
|
||||
String lockKey = "outbound:" + outboundRequest.getNo();
|
||||
String lockValue = null;
|
||||
try {
|
||||
lockValue = redissonLock.tryLock(lockKey, 10);
|
||||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("出库单接收中,请稍后重试");
|
||||
}
|
||||
outBoundTaskProcessor.outBoundTask(outboundRequest);
|
||||
} catch (Exception e) {
|
||||
log.error("出库单接收异常", e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (StringUtils.isNotEmpty(lockValue)) {
|
||||
redissonLock.unlock(lockKey, lockValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@ import org.cpte.modules.inventory.mapper.InventoryMapper;
|
|||
import org.cpte.modules.receive.entity.Asn;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
import org.cpte.modules.receive.mapper.AsnMapper;
|
||||
import org.cpte.modules.receive.service.IAsnDetailService;
|
||||
import org.cpte.modules.receive.service.IAsnService;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
|
@ -53,10 +55,7 @@ public class InBoundTaskProcessor {
|
|||
private IPointService pointService;
|
||||
|
||||
@Autowired
|
||||
private IAsnService asnService;
|
||||
|
||||
@Autowired
|
||||
private IAgvTaskService agvTaskService;
|
||||
private IAsnDetailService asnDetailService;
|
||||
|
||||
/**
|
||||
* 接收入库任务
|
||||
|
|
@ -77,34 +76,7 @@ public class InBoundTaskProcessor {
|
|||
Point srcPoint = validateSrcPoint(inboundRequest.getType(), inboundRequest.getLocationFrom());
|
||||
|
||||
//5.入库处理
|
||||
processInboundTask(inboundRequest, itemMap, srcPoint, stock);
|
||||
}
|
||||
|
||||
/**
|
||||
* 入库处理
|
||||
*
|
||||
* @param inboundRequest 入库参数
|
||||
* @param itemMap 物料
|
||||
* @param srcPoint 起点
|
||||
* @param stock 容器
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
private void processInboundTask(InboundRequest inboundRequest, Map<String, Item> itemMap, Point srcPoint, Stock stock) {
|
||||
//1.获取终点
|
||||
Point dstPoint = getDstPoint(inboundRequest.getType());
|
||||
|
||||
//2.构建入库单和入库明细
|
||||
Asn createAsn = asnService.buildAsn(inboundRequest);
|
||||
List<AsnDetail> asnDetails = asnService.buildAsnDetail(inboundRequest.getDetails(), itemMap, stock, srcPoint, dstPoint);
|
||||
asnService.saveMain(createAsn, asnDetails);
|
||||
|
||||
//3.绑定容器和起点
|
||||
stockService.bindStock(stock, srcPoint);
|
||||
|
||||
//4.成品入库,生成AGV任务
|
||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType())) {
|
||||
agvTaskService.createAgvTask(createAsn.getId(), stock.getStockCode(), srcPoint.getPointCode(), dstPoint.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.HIK.getValue());
|
||||
}
|
||||
asnDetailService.processInboundTask(inboundRequest, itemMap, srcPoint, stock);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -229,19 +201,4 @@ public class InBoundTaskProcessor {
|
|||
return srcPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取终点
|
||||
*
|
||||
* @param orderType 任务类型
|
||||
* @return Point
|
||||
*/
|
||||
private Point getDstPoint(Integer orderType) {
|
||||
Point dstPoint = null;
|
||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(orderType)) {
|
||||
//1.获取入库输送线工作台点位为终点,均衡分配点位-轮询方式
|
||||
dstPoint = pointService.getWorkStationPoint(null, AreaTypeEnum.RK_DOCK.getValue(), GeneralConstant.RK_DOCK_TASK_INDEX);
|
||||
}
|
||||
return dstPoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import org.cpte.modules.saiWms.request.OutboundRequest;
|
|||
import org.cpte.modules.shipping.entity.Pick;
|
||||
import org.cpte.modules.shipping.entity.PickDetail;
|
||||
import org.cpte.modules.shipping.mapper.PickMapper;
|
||||
import org.cpte.modules.shipping.service.IPickDetailService;
|
||||
import org.cpte.modules.shipping.service.IPickService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -39,7 +40,7 @@ public class OutBoundTaskProcessor {
|
|||
private IPointService pointService;
|
||||
|
||||
@Autowired
|
||||
private IPickService pickService;
|
||||
private IPickDetailService pickDetailService;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -58,24 +59,9 @@ public class OutBoundTaskProcessor {
|
|||
Map<String, Item> itemMap = validateItem(outboundRequest.getDetails());
|
||||
|
||||
//5.出库处理
|
||||
processOutBoundTask(outboundRequest, itemMap);
|
||||
pickDetailService.processOutBoundTask(outboundRequest, itemMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 出库处理
|
||||
*
|
||||
* @param outboundRequest 出库参数
|
||||
* @param itemMap 物料
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
private void processOutBoundTask(OutboundRequest outboundRequest, Map<String, Item> itemMap) {
|
||||
// 创建出库单和明细
|
||||
Pick createPick = pickService.buildPick(outboundRequest);
|
||||
List<PickDetail> pickDetails = pickService.buildPickDetail(outboundRequest.getDetails(), itemMap);
|
||||
pickService.saveMain(createPick, pickDetails);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 出库参数校验
|
||||
*
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ public class SyncStockProcessor {
|
|||
@Autowired
|
||||
private IStockService stockService;
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtil;
|
||||
|
||||
|
||||
/**
|
||||
* 接收容器同步信息
|
||||
|
|
@ -46,7 +45,7 @@ public class SyncStockProcessor {
|
|||
processStock(syncStockRequest.getStocks(), stockMap, insertToStock, updateToStock);
|
||||
|
||||
//5.批量操作
|
||||
batchOperation(insertToStock, updateToStock);
|
||||
stockService.batchOperation(insertToStock, updateToStock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -125,21 +124,4 @@ public class SyncStockProcessor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param insertToStock 创建的容器
|
||||
* @param updateToStock 更新的容器
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperation(List<Stock> insertToStock, List<Stock> updateToStock) {
|
||||
if (CollectionUtils.isNotEmpty(insertToStock)) {
|
||||
batchUtil.saveBatchStock(insertToStock);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToStock)) {
|
||||
batchUtil.batchUpdateStocks(updateToStock);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.cpte.modules.constant.GeneralConstant;
|
||||
import org.cpte.modules.serialNumber.PickSerialNumberRule;
|
||||
import org.cpte.modules.shipping.entity.Task;
|
||||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
||||
import org.cpte.modules.shipping.service.ITaskService;
|
||||
import org.jeecg.common.system.query.QueryRuleEnum;
|
||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||
|
|
@ -55,6 +56,8 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
|
|||
@RequestMapping("/shipping/pick")
|
||||
@Slf4j
|
||||
public class PickController {
|
||||
@Autowired
|
||||
private TaskMapper taskMapper;
|
||||
@Autowired
|
||||
private IPickService pickService;
|
||||
@Autowired
|
||||
|
|
@ -81,9 +84,7 @@ public class PickController {
|
|||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<Pick> queryWrapper = QueryGenerator.initQueryWrapper(pick, req.getParameterMap());
|
||||
List<String> status = Arrays.stream(req.getParameterMap().get("status[]")).toList();
|
||||
queryWrapper.in("status", status);
|
||||
Page<Pick> page = new Page<Pick>(pageNo, pageSize);
|
||||
Page<Pick> page = new Page<>(pageNo, pageSize);
|
||||
IPage<Pick> pageList = pickService.page(page, queryWrapper);
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
|
@ -280,8 +281,8 @@ public class PickController {
|
|||
return Result.OK("文件导入失败!");
|
||||
}
|
||||
|
||||
@AutoLog(value = "出库分配")
|
||||
@Operation(summary = "出库分配")
|
||||
@AutoLog(value = "批量分配")
|
||||
@Operation(summary = "批量分配")
|
||||
@RequiresPermissions("shipping:data_pick:allocatePick")
|
||||
@GetMapping(value = "/allocatePick")
|
||||
public Result<String> allocatePick(@RequestParam(name = "ids", required = true) String ids) {
|
||||
|
|
@ -304,13 +305,13 @@ public class PickController {
|
|||
}
|
||||
}
|
||||
|
||||
@AutoLog(value = "取消分配")
|
||||
@Operation(summary = "取消分配")
|
||||
@AutoLog(value = "批量取消分配")
|
||||
@Operation(summary = "批量取消分配")
|
||||
@RequiresPermissions("shipping:data_pick:cancelAllocate")
|
||||
@GetMapping(value = "/cancelAllocate")
|
||||
public Result<String> cancelAllocate(@RequestParam(name = "ids", required = true) String ids) {
|
||||
if (StringUtils.isEmpty(ids)) {
|
||||
return Result.error("请选择需要取消的出库单");
|
||||
return Result.error("请选择需取消的出库单");
|
||||
}
|
||||
try {
|
||||
List<String> idsList = Arrays.asList(ids.split(","));
|
||||
|
|
@ -327,4 +328,23 @@ public class PickController {
|
|||
return Result.error("取消异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@AutoLog(value = "批量拣货")
|
||||
@Operation(summary = "批量拣货")
|
||||
@RequiresPermissions("shipping:data_pick:pickTask")
|
||||
@GetMapping(value = "/pickTask")
|
||||
public Result<String> pickTask(@RequestParam(name = "ids", required = true) String ids) {
|
||||
if (StringUtils.isEmpty(ids)) {
|
||||
return Result.error("请选择需要拣货的出库单");
|
||||
}
|
||||
try {
|
||||
List<String> idsList = Arrays.asList(ids.split(","));
|
||||
List<Long> pickIds = idsList.stream().map(Long::parseLong).toList();
|
||||
List<Task> tasks = taskMapper.queryByPickIds(pickIds);
|
||||
pickService.pickTask(tasks);
|
||||
return Result.OK("拣货成功");
|
||||
} catch (Exception e) {
|
||||
return Result.error("拣货异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,119 @@
|
|||
package org.cpte.modules.shipping.service;
|
||||
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.shipping.entity.Pick;
|
||||
import org.cpte.modules.shipping.entity.PickDetail;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.cpte.modules.shipping.entity.Task;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description: 出库明细
|
||||
* @author: cpte
|
||||
* @Date: 2025-11-14
|
||||
* @Date: 2025-11-14
|
||||
* @Version: V1.0
|
||||
*/
|
||||
public interface IPickDetailService extends IService<PickDetail> {
|
||||
|
||||
/**
|
||||
* 通过主表id查询子表数据
|
||||
*
|
||||
* @param mainId 主表id
|
||||
* @return List<PickDetail>
|
||||
*/
|
||||
public List<PickDetail> selectByMainId(Long mainId);
|
||||
/**
|
||||
* 构建出库单
|
||||
*
|
||||
* @param outboundRequest 出库单请求
|
||||
* @return 出库单
|
||||
*/
|
||||
Pick buildPick(OutboundRequest outboundRequest);
|
||||
|
||||
/**
|
||||
* 根据出库单ID查询出库单Map
|
||||
*
|
||||
* @param pickIds 出库单ID集合
|
||||
* @return Map<Long, Pick>
|
||||
*/
|
||||
Map<Long, Pick> queryByPickIdsToMap(List<Long> pickIds);
|
||||
|
||||
/**
|
||||
* 根据出库单明细ID查询出库单明细Map
|
||||
*
|
||||
* @param pickDetailIds 出库单明细ID集合
|
||||
* @return Map<Long, PickDetail>
|
||||
*/
|
||||
Map<Long, PickDetail> queryByPickDetailIdsToMap(List<Long> pickDetailIds);
|
||||
/**
|
||||
* 构建出库单明细
|
||||
*
|
||||
* @param details 出库单明细
|
||||
* @param exitItemMap 物料
|
||||
* @return 出库单明细
|
||||
*/
|
||||
List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap);
|
||||
|
||||
|
||||
/**
|
||||
* 通过主表id查询子表数据
|
||||
*
|
||||
* @param mainId 主表id
|
||||
* @return List<PickDetail>
|
||||
*/
|
||||
public List<PickDetail> selectByMainId(Long mainId);
|
||||
|
||||
/**
|
||||
* 根据出库单ID查询出库单Map
|
||||
*
|
||||
* @param pickIds 出库单ID集合
|
||||
* @return Map<Long, Pick>
|
||||
*/
|
||||
Map<Long, Pick> queryByPickIdsToMap(List<Long> pickIds);
|
||||
|
||||
/**
|
||||
* 根据出库单明细ID查询出库单明细Map
|
||||
*
|
||||
* @param pickDetailIds 出库单明细ID集合
|
||||
* @return Map<Long, PickDetail>
|
||||
*/
|
||||
Map<Long, PickDetail> queryByPickDetailIdsToMap(List<Long> pickDetailIds);
|
||||
|
||||
/**
|
||||
* 保存主表及从表
|
||||
*
|
||||
* @param pick 出库单
|
||||
* @param pickDetailList 出库单明细
|
||||
*/
|
||||
void processorSaveMain(Pick pick, List<PickDetail> pickDetailList);
|
||||
|
||||
/**
|
||||
* 处理出库任务
|
||||
*
|
||||
* @param outboundRequest 出库参数
|
||||
* @param itemMap 物料
|
||||
*/
|
||||
void processOutBoundTask(OutboundRequest outboundRequest, Map<String, Item> itemMap);
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param inventoryUpdateMap 库存更新
|
||||
* @param pickDetailUpdateMap 出库单明细更新
|
||||
* @param createToTask 创建任务
|
||||
*/
|
||||
void batchOperationAllocate(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> createToTask);
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param inventoryUpdateMap 库存更新
|
||||
* @param pickDetailUpdateMap 出库单明细更新
|
||||
* @param deleteToTask 删除任务
|
||||
*/
|
||||
void batchOperationCancel(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> deleteToTask);
|
||||
|
||||
/**
|
||||
* 刷新出库单
|
||||
*
|
||||
* @param pick 出库单
|
||||
* @param pickDetails 出库单明细
|
||||
*/
|
||||
void refreshPick(Pick pick, List<PickDetail> pickDetails);
|
||||
* 批量操作
|
||||
*
|
||||
* @param deleteToInventory 删除库存
|
||||
* @param pickDetailUpdateMap 出库单明细更新
|
||||
* @param updateToTask 更新任务
|
||||
* @param updateToStock 更新库存
|
||||
* @param updateToPoint 更新点位
|
||||
*/
|
||||
void batchOperationPick(List<Inventory> deleteToInventory, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Stock> updateToStock, List<Point> updateToPoint);
|
||||
|
||||
/**
|
||||
* 刷新出库单
|
||||
*
|
||||
* @param pick 出库单
|
||||
* @param pickDetails 出库单明细
|
||||
*/
|
||||
void refreshPick(Pick pick, List<PickDetail> pickDetails);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
package org.cpte.modules.shipping.service;
|
||||
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.shipping.entity.PickDetail;
|
||||
import org.cpte.modules.shipping.entity.Pick;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
|
@ -11,7 +8,6 @@ import org.cpte.modules.shipping.entity.Task;
|
|||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Description: 出库单
|
||||
|
|
@ -51,24 +47,6 @@ public interface IPickService extends IService<Pick> {
|
|||
*/
|
||||
public void delBatchMain(Collection<? extends Serializable> idList);
|
||||
|
||||
/**
|
||||
* 构建出库单
|
||||
*
|
||||
* @param outboundRequest 出库单请求
|
||||
* @return 出库单
|
||||
*/
|
||||
Pick buildPick(OutboundRequest outboundRequest);
|
||||
|
||||
/**
|
||||
* 构建出库单明细
|
||||
*
|
||||
* @param details 出库单明细
|
||||
* @param exitItemMap 物料
|
||||
* @return 出库单明细
|
||||
*/
|
||||
List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap);
|
||||
|
||||
|
||||
/**
|
||||
* 分配出库单
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,19 +1,37 @@
|
|||
package org.cpte.modules.shipping.service.impl;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.GeneralConstant;
|
||||
import org.cpte.modules.constant.enums.PickStatusEnum;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
||||
import org.cpte.modules.inventory.service.IInventoryService;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.serialNumber.PickSerialNumberRule;
|
||||
import org.cpte.modules.shipping.entity.Pick;
|
||||
import org.cpte.modules.shipping.entity.PickDetail;
|
||||
import org.cpte.modules.shipping.entity.Task;
|
||||
import org.cpte.modules.shipping.mapper.PickDetailMapper;
|
||||
import org.cpte.modules.shipping.mapper.PickMapper;
|
||||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
||||
import org.cpte.modules.shipping.service.IPickDetailService;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @Description: 出库明细
|
||||
|
|
@ -26,11 +44,66 @@ public class PickDetailServiceImpl extends ServiceImpl<PickDetailMapper, PickDet
|
|||
@Autowired
|
||||
private PickMapper pickMapper;
|
||||
|
||||
@Autowired
|
||||
private TaskMapper taskMapper;
|
||||
|
||||
@Autowired
|
||||
private InventoryMapper inventoryMapper;
|
||||
|
||||
@Autowired
|
||||
private IStockService stockService;
|
||||
|
||||
@Autowired
|
||||
private IPointService pointService;
|
||||
|
||||
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtil;
|
||||
|
||||
@Autowired
|
||||
private PickSerialNumberRule pickSerialNumberRule;
|
||||
|
||||
@Override
|
||||
public List<PickDetail> selectByMainId(Long mainId) {
|
||||
return this.baseMapper.selectByMainId(mainId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pick buildPick(OutboundRequest outboundRequest) {
|
||||
return Pick.builder()
|
||||
.thirdOrderNo(outboundRequest.getOrderNo())
|
||||
.no(outboundRequest.getNo())
|
||||
.whCode(outboundRequest.getWhCode())
|
||||
.customerCode(outboundRequest.getCustomerCode())
|
||||
.orderType(outboundRequest.getType())
|
||||
.status(PickStatusEnum.CREATED.getValue())
|
||||
.orderDate(new Date())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap) {
|
||||
List<PickDetail> newDetailList = new ArrayList<>();
|
||||
for (OutboundRequest.OutboundDetail detail : details) {
|
||||
PickDetail pickDetail = PickDetail.builder()
|
||||
.lineNo(Integer.parseInt(detail.getLineNo()))
|
||||
.itemId(exitItemMap.get(detail.getItem()).getId())
|
||||
.unit(detail.getUnit())
|
||||
.orderQty(BigDecimal.valueOf(detail.getQty()))
|
||||
.allocatedQty(BigDecimal.ZERO)
|
||||
.pickedQty(BigDecimal.ZERO)
|
||||
.status(PickStatusEnum.CREATED.getValue())
|
||||
.project(detail.getProject())
|
||||
.taskNo(detail.getTaskNo())
|
||||
.propC1(detail.getLotAtt04())
|
||||
.propC3(detail.getLotAtt010())
|
||||
.build();
|
||||
newDetailList.add(pickDetail);
|
||||
}
|
||||
return newDetailList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取出库单Map
|
||||
*
|
||||
|
|
@ -67,6 +140,101 @@ public class PickDetailServiceImpl extends ServiceImpl<PickDetailMapper, PickDet
|
|||
return pickDetailMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processorSaveMain(Pick pick, List<PickDetail> pickDetailList) {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
pick.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
pick.setSysOrgCode(sysUser.getOrgCode());
|
||||
String orderNo = pickSerialNumberRule.generateSerialNumber(GeneralConstant.PICK_ORDER_NO);
|
||||
pick.setOrderNo(orderNo);
|
||||
pickMapper.insert(pick);
|
||||
|
||||
if (pickDetailList == null || pickDetailList.isEmpty()) {
|
||||
throw new RuntimeException("请新增出库明细");
|
||||
}
|
||||
|
||||
// 获取当前出库单下已存在的最大序号
|
||||
Integer maxLineNo = this.baseMapper.queryMaxLineNoByPickId(pick.getId());
|
||||
AtomicInteger lineNoCounter = new AtomicInteger((maxLineNo != null) ? maxLineNo + 1 : 1);
|
||||
|
||||
for (PickDetail entity : pickDetailList) {
|
||||
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
|
||||
entity.setLineNo(lineNoCounter.getAndIncrement());
|
||||
}
|
||||
entity.setPickId(pick.getId());
|
||||
entity.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
entity.setSysOrgCode(sysUser.getOrgCode());
|
||||
this.baseMapper.insert(entity);
|
||||
}
|
||||
//刷新出库单
|
||||
refreshPick(pick, pickDetailList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processOutBoundTask(OutboundRequest outboundRequest, Map<String, Item> itemMap) {
|
||||
// 创建出库单和明细
|
||||
Pick createPick = buildPick(outboundRequest);
|
||||
List<PickDetail> pickDetails = buildPickDetail(outboundRequest.getDetails(), itemMap);
|
||||
processorSaveMain(createPick, pickDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperationAllocate(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> createToTask) {
|
||||
|
||||
List<Inventory> updateToInventory = new ArrayList<>(inventoryUpdateMap.values());
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
||||
if (CollectionUtils.isNotEmpty(updateToInventory)) {
|
||||
batchUtil.updateBatchInventory(updateToInventory);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
|
||||
batchUtil.updateBatchPickDetail(updateToPickDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(createToTask)) {
|
||||
batchUtil.saveBatchTask(createToTask);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperationCancel(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> deleteToTask) {
|
||||
List<Inventory> updateToInventory = new ArrayList<>(inventoryUpdateMap.values());
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
||||
if (CollectionUtils.isNotEmpty(updateToInventory)) {
|
||||
batchUtil.updateBatchInventory(updateToInventory);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
|
||||
batchUtil.updateBatchPickDetail(updateToPickDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(deleteToTask)) {
|
||||
taskMapper.deleteByIds(deleteToTask);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperationPick(List<Inventory> deleteToInventory, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Stock> updateToStock, List<Point> updateToPoint) {
|
||||
if (CollectionUtils.isNotEmpty(deleteToInventory)) {
|
||||
List<Long> deleteToInventoryIds = deleteToInventory.stream().map(Inventory::getId).toList();
|
||||
inventoryMapper.deleteByIds(deleteToInventoryIds);
|
||||
}
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
||||
if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
|
||||
batchUtil.updateBatchPickDetail(updateToPickDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToTask)) {
|
||||
batchUtil.updateBatchTask(updateToTask);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToStock)) {
|
||||
stockService.updateBatchById(updateToStock);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToPoint)) {
|
||||
pointService.updateBatchById(updateToPoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 刷新出库单状态
|
||||
|
|
|
|||
|
|
@ -1,49 +1,27 @@
|
|||
package org.cpte.modules.shipping.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.cpte.modules.constant.GeneralConstant;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.constant.enums.*;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.inventory.service.IInventoryService;
|
||||
import org.cpte.modules.inventoryLog.service.IInventoryLogService;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.saiWms.request.SMOMRequest;
|
||||
import org.cpte.modules.serialNumber.PickSerialNumberRule;
|
||||
import org.cpte.modules.shipping.entity.Pick;
|
||||
import org.cpte.modules.shipping.entity.PickDetail;
|
||||
import org.cpte.modules.shipping.entity.Task;
|
||||
import org.cpte.modules.shipping.mapper.PickDetailMapper;
|
||||
import org.cpte.modules.shipping.mapper.PickMapper;
|
||||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
||||
import org.cpte.modules.shipping.service.processor.AllocateProcessor;
|
||||
import org.cpte.modules.shipping.service.processor.CancelAllocateProcessor;
|
||||
import org.cpte.modules.shipping.service.IPickDetailService;
|
||||
import org.cpte.modules.shipping.service.IPickService;
|
||||
import org.cpte.modules.shipping.service.processor.PickProcessor;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.cpte.modules.utils.BigDecimalUtil;
|
||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||
import org.cpte.modules.utils.SwmsLoginUtil;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.modules.base.service.BaseCommonService;
|
||||
import org.jeecg.modules.openapi.mapper.OpenApiMapper;
|
||||
import org.jeecg.modules.system.mapper.SysDictMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
|
@ -64,8 +42,6 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
@Autowired
|
||||
private BaseCommonService baseCommonService;
|
||||
@Autowired
|
||||
private PickSerialNumberRule pickSerialNumberRule;
|
||||
@Autowired
|
||||
private AllocateProcessor allocateProcessor;
|
||||
@Autowired
|
||||
private CancelAllocateProcessor cancelAllocateProcessor;
|
||||
|
|
@ -84,7 +60,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("出库单创建中,请稍后重试");
|
||||
}
|
||||
processorSaveMain(pick, pickDetailList);
|
||||
pickDetailService.processorSaveMain(pick, pickDetailList);
|
||||
} catch (Exception e) {
|
||||
log.error("出库单创建异常", e);
|
||||
throw e;
|
||||
|
|
@ -95,43 +71,6 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存主表及从表
|
||||
*
|
||||
* @param pick 出库单
|
||||
* @param pickDetailList 出库单明细
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processorSaveMain(Pick pick, List<PickDetail> pickDetailList) {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
pick.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
pick.setSysOrgCode(sysUser.getOrgCode());
|
||||
String orderNo = pickSerialNumberRule.generateSerialNumber(GeneralConstant.PICK_ORDER_NO);
|
||||
pick.setOrderNo(orderNo);
|
||||
this.baseMapper.insert(pick);
|
||||
|
||||
if (pickDetailList == null || pickDetailList.isEmpty()) {
|
||||
throw new RuntimeException("请新增出库明细");
|
||||
}
|
||||
|
||||
// 获取当前出库单下已存在的最大序号
|
||||
Integer maxLineNo = pickDetailMapper.queryMaxLineNoByPickId(pick.getId());
|
||||
AtomicInteger lineNoCounter = new AtomicInteger((maxLineNo != null) ? maxLineNo + 1 : 1);
|
||||
|
||||
for (PickDetail entity : pickDetailList) {
|
||||
if (entity.getLineNo() == null || entity.getLineNo() == 0) {
|
||||
entity.setLineNo(lineNoCounter.getAndIncrement());
|
||||
}
|
||||
entity.setPickId(pick.getId());
|
||||
entity.setTenantId(Long.parseLong(sysUser.getRelTenantIds()));
|
||||
entity.setSysOrgCode(sysUser.getOrgCode());
|
||||
pickDetailMapper.insert(entity);
|
||||
}
|
||||
//刷新出库单
|
||||
pickDetailService.refreshPick(pick, pickDetailList);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateMain(Pick pick, List<PickDetail> pickDetailList) {
|
||||
|
|
@ -206,40 +145,7 @@ public class PickServiceImpl extends ServiceImpl<PickMapper, Pick> implements IP
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pick buildPick(OutboundRequest outboundRequest) {
|
||||
return Pick.builder()
|
||||
.thirdOrderNo(outboundRequest.getOrderNo())
|
||||
.no(outboundRequest.getNo())
|
||||
.whCode(outboundRequest.getWhCode())
|
||||
.customerCode(outboundRequest.getCustomerCode())
|
||||
.orderType(outboundRequest.getType())
|
||||
.status(PickStatusEnum.CREATED.getValue())
|
||||
.orderDate(new Date())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap) {
|
||||
List<PickDetail> newDetailList = new ArrayList<>();
|
||||
for (OutboundRequest.OutboundDetail detail : details) {
|
||||
PickDetail pickDetail = PickDetail.builder()
|
||||
.lineNo(Integer.parseInt(detail.getLineNo()))
|
||||
.itemId(exitItemMap.get(detail.getItem()).getId())
|
||||
.unit(detail.getUnit())
|
||||
.orderQty(BigDecimal.valueOf(detail.getQty()))
|
||||
.allocatedQty(BigDecimal.ZERO)
|
||||
.pickedQty(BigDecimal.ZERO)
|
||||
.status(PickStatusEnum.CREATED.getValue())
|
||||
.project(detail.getProject())
|
||||
.taskNo(detail.getTaskNo())
|
||||
.propC1(detail.getLotAtt04())
|
||||
.propC3(detail.getLotAtt010())
|
||||
.build();
|
||||
newDetailList.add(pickDetail);
|
||||
}
|
||||
return newDetailList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> allocatePick(List<Long> pickIds) {
|
||||
|
|
|
|||
|
|
@ -26,12 +26,10 @@ import org.cpte.modules.shipping.service.ITaskService;
|
|||
import org.cpte.modules.shipping.vo.AllocationData;
|
||||
import org.cpte.modules.shipping.vo.InventoryScore;
|
||||
import org.cpte.modules.shipping.vo.ItemGroupKey;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.cpte.modules.utils.BigDecimalUtil;
|
||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
|
@ -83,9 +81,6 @@ public class AllocateProcessor {
|
|||
@Autowired
|
||||
private MoveSerialNumberRule moveSerialNumberRule;
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtil;
|
||||
|
||||
@Autowired
|
||||
private RedisDistributedLockUtil redissonLock;
|
||||
|
||||
|
|
@ -121,7 +116,7 @@ public class AllocateProcessor {
|
|||
moveTask(createToTask, movePoints);
|
||||
|
||||
//6.批量操作
|
||||
batchOperation(inventoryUpdateMap, pickDetailUpdateMap, createToTask);
|
||||
pickDetailService.batchOperationAllocate(inventoryUpdateMap, pickDetailUpdateMap, createToTask);
|
||||
|
||||
//7.刷新出库单
|
||||
refreshData(data);
|
||||
|
|
@ -261,7 +256,7 @@ public class AllocateProcessor {
|
|||
}
|
||||
|
||||
// 分配库存
|
||||
String lockKey = "allocate:" + pickDetail.getId();
|
||||
String lockKey = "allocate:" + pick.getId();
|
||||
String lockValue = null;
|
||||
try {
|
||||
lockValue = redissonLock.tryLock(lockKey, 10);
|
||||
|
|
@ -271,7 +266,7 @@ public class AllocateProcessor {
|
|||
allocateInventory(pickDetail, item, pick, matchedInventories, inventoryUpdateMap, pickDetailUpdateMap,
|
||||
createToTask, movePoints, data, unAllocatedQty, errorMsgSet);
|
||||
} catch (Exception e) {
|
||||
log.error("分配异常,明细ID: {}", pickDetail.getId(), e);
|
||||
log.error("分配异常,出库单ID: {}", pick.getId(), e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (StringUtils.isNotEmpty(lockValue)) {
|
||||
|
|
@ -279,7 +274,6 @@ public class AllocateProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -339,15 +333,16 @@ public class AllocateProcessor {
|
|||
List<Inventory> matchedInventories, Map<Long, Inventory> inventoryUpdateMap,
|
||||
Map<Long, PickDetail> pickDetailUpdateMap, List<Task> createToTask, List<Point> movePoints,
|
||||
AllocationData data, BigDecimal totalUnAllocatedQty, Set<String> errorMsgSet) {
|
||||
|
||||
// 智能排序库存
|
||||
List<InventoryScore> scoredInventories = scoreInventories(matchedInventories);
|
||||
//未分配数量
|
||||
BigDecimal remainingQty = totalUnAllocatedQty;
|
||||
for (InventoryScore inventoryScore : scoredInventories) {
|
||||
|
||||
if (remainingQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
Inventory inventory = inventoryScore.getInventory();
|
||||
|
||||
// 库存可用数量
|
||||
|
|
@ -363,13 +358,10 @@ public class AllocateProcessor {
|
|||
updatePickDetailAllocation(pickDetail, allocateQty, pickDetailUpdateMap);
|
||||
// 创建任务
|
||||
createPickTask(pickDetail, pick, item, inventory, inventoryScore, allocateQty, createToTask, data);
|
||||
|
||||
// 获取需要移位的库位
|
||||
getMovePoints(inventoryScore, movePoints);
|
||||
|
||||
// 记录分配日志
|
||||
inventoryLogService.addAllocInventoryLog(inventory, inventoryScore.getOutPoint().getId(), allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
|
||||
|
||||
// 更新剩余未分配数量
|
||||
remainingQty = BigDecimalUtil.subtract(remainingQty, allocateQty, 0);
|
||||
|
||||
|
|
@ -378,6 +370,8 @@ public class AllocateProcessor {
|
|||
if (remainingQty.compareTo(BigDecimal.ZERO) > 0) {
|
||||
addInventoryErrorMsg(pick, pickDetail, item, remainingQty, errorMsgSet);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -527,6 +521,7 @@ public class AllocateProcessor {
|
|||
Map<Long, Inventory> inventoryUpdateMap) {
|
||||
Inventory targetInventory = inventoryUpdateMap.getOrDefault(inventory.getId(), inventory);
|
||||
BigDecimal newQueuedQty = BigDecimalUtil.add(targetInventory.getQueuedQty(), allocateQty, 0);
|
||||
log.info("更新库存分配数: {}", newQueuedQty);
|
||||
targetInventory.setQueuedQty(newQueuedQty);
|
||||
targetInventory.setStatus(InventoryStatusEnum.ALLOCATED.getValue());
|
||||
inventoryUpdateMap.put(targetInventory.getId(), targetInventory);
|
||||
|
|
@ -684,7 +679,7 @@ public class AllocateProcessor {
|
|||
.filter(point -> !createTaskIds.contains(point.getId()))
|
||||
.toList();
|
||||
if (CollectionUtils.isNotEmpty(pointsToMove)) {
|
||||
List<Task> moveToTask = bulidMoveTask(pointsToMove);
|
||||
List<Task> moveToTask = buildMoveTask(pointsToMove);
|
||||
if (CollectionUtils.isNotEmpty(moveToTask)) {
|
||||
createToTask.addAll(moveToTask);
|
||||
}
|
||||
|
|
@ -699,7 +694,7 @@ public class AllocateProcessor {
|
|||
* @param movePoints 移位库位
|
||||
* @return 移位任务
|
||||
*/
|
||||
public List<Task> bulidMoveTask(List<Point> movePoints) {
|
||||
public List<Task> buildMoveTask(List<Point> movePoints) {
|
||||
List<Task> moveList = new ArrayList<>();
|
||||
|
||||
//库存
|
||||
|
|
@ -748,30 +743,6 @@ public class AllocateProcessor {
|
|||
return scanTrayProcessor.allocatePoint(itemKeyIds, currentPoint, areaCode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param inventoryUpdateMap 更新库存
|
||||
* @param pickDetailUpdateMap 更新出库明细
|
||||
* @param createToTask 创建出库任务
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperation(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> createToTask) {
|
||||
|
||||
List<Inventory> updateToInventory = new ArrayList<>(inventoryUpdateMap.values());
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
||||
if (CollectionUtils.isNotEmpty(updateToInventory)) {
|
||||
batchUtil.updateBatchInventory(updateToInventory);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
|
||||
batchUtil.updateBatchPickDetail(updateToPickDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(createToTask)) {
|
||||
batchUtil.saveBatchTask(createToTask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新出库单
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package org.cpte.modules.shipping.service.processor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.constant.enums.InventoryStatusEnum;
|
||||
import org.cpte.modules.constant.enums.PickStatusEnum;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
|
|
@ -14,11 +14,10 @@ import org.cpte.modules.shipping.mapper.PickDetailMapper;
|
|||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
||||
import org.cpte.modules.shipping.service.IPickDetailService;
|
||||
import org.cpte.modules.shipping.vo.CancelAllocateData;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.cpte.modules.utils.BigDecimalUtil;
|
||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
|
@ -47,7 +46,7 @@ public class CancelAllocateProcessor {
|
|||
private IInventoryLogService inventoryLogService;
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtils;
|
||||
private RedisDistributedLockUtil redissonLock;
|
||||
|
||||
/**
|
||||
* 取消分配
|
||||
|
|
@ -71,7 +70,7 @@ public class CancelAllocateProcessor {
|
|||
cancelAllocate(data, inventoryUpdateMap, pickDetailUpdateMap, deleteToTask, errorMsgSet);
|
||||
|
||||
//4.批量操作
|
||||
batchOperation(inventoryUpdateMap, pickDetailUpdateMap, deleteToTask);
|
||||
pickDetailService.batchOperationCancel(inventoryUpdateMap, pickDetailUpdateMap, deleteToTask);
|
||||
|
||||
//5.刷新出库单
|
||||
refreshData(data);
|
||||
|
|
@ -125,7 +124,6 @@ public class CancelAllocateProcessor {
|
|||
try {
|
||||
cancelAllocateTask(task, data, inventoryUpdateMap, pickDetailUpdateMap, deleteToTask, errorMsgSet);
|
||||
} catch (Exception e) {
|
||||
log.error("取消任务失败,任务ID: {}", task.getId(), e);
|
||||
errorMsgSet.add(String.format("取消任务失败,任务号:%s,原因:%s",
|
||||
task.getTaskNo(), e.getMessage()));
|
||||
}
|
||||
|
|
@ -145,35 +143,49 @@ public class CancelAllocateProcessor {
|
|||
private void cancelAllocateTask(Task task, CancelAllocateData data, Map<Long, Inventory> inventoryUpdateMap,
|
||||
Map<Long, PickDetail> pickDetailUpdateMap, List<Task> deleteToTask, Set<String> errorMsgSet) {
|
||||
Pick pick = data.getPickMap().get(task.getPickId());
|
||||
PickDetail pickDetail = data.getPickDetailIdMap().get(task.getPickDetailId());
|
||||
if (task.getAgvTaskId() != null) {
|
||||
errorMsgSet.add(String.format("取消失败:【%s】已生成AGV任务", task.getTaskNo()));
|
||||
return;
|
||||
String lockKey = "cancel:" + pick.getId();
|
||||
String lockValue = null;
|
||||
try {
|
||||
lockValue = redissonLock.tryLock(lockKey, 10);
|
||||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("分配处理中,请稍后重试");
|
||||
}
|
||||
PickDetail pickDetail = data.getPickDetailIdMap().get(task.getPickDetailId());
|
||||
if (task.getAgvTaskId() != null) {
|
||||
errorMsgSet.add(String.format("取消失败:【%s】已生成AGV任务", task.getTaskNo()));
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory inventory = data.getInventoryMap().get(task.getInventoryId());
|
||||
if (inventory == null) {
|
||||
errorMsgSet.add(String.format("取消失败:【%s】库存不存在", task.getTaskNo()));
|
||||
return;
|
||||
}
|
||||
if (inventory.getQueuedQty().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
errorMsgSet.add(String.format("取消失败:【%s】库存已取消分配", task.getTaskNo()));
|
||||
return;
|
||||
}
|
||||
BigDecimal cancelQty = task.getPlanQty();
|
||||
|
||||
//更新库存
|
||||
updateInventoryAllocation(inventory, cancelQty, inventoryUpdateMap);
|
||||
|
||||
//更新出库明细
|
||||
updatePickDetailAllocation(pickDetail, cancelQty, pickDetailUpdateMap);
|
||||
|
||||
//删除任务
|
||||
deleteToTask.add(task);
|
||||
|
||||
// 记录取消分配日志
|
||||
inventoryLogService.addUnAllocInventoryLog(inventory, cancelQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
|
||||
} catch (Exception e) {
|
||||
log.error("分配异常,出库单ID: {}", pick.getId(), e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (StringUtils.isNotEmpty(lockValue)) {
|
||||
redissonLock.unlock(lockKey, lockValue);
|
||||
}
|
||||
}
|
||||
|
||||
Inventory inventory = data.getInventoryMap().get(task.getInventoryId());
|
||||
if (inventory == null) {
|
||||
errorMsgSet.add(String.format("取消失败:【%s】库存不存在", task.getTaskNo()));
|
||||
return;
|
||||
}
|
||||
if (inventory.getQueuedQty().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
errorMsgSet.add(String.format("取消失败:【%s】库存已取消分配", task.getTaskNo()));
|
||||
return;
|
||||
}
|
||||
BigDecimal cancelQty = task.getPlanQty();
|
||||
|
||||
//更新库存
|
||||
updateInventoryAllocation(inventory, cancelQty, inventoryUpdateMap);
|
||||
|
||||
//更新出库明细
|
||||
updatePickDetailAllocation(pickDetail, cancelQty, pickDetailUpdateMap);
|
||||
|
||||
//删除任务
|
||||
deleteToTask.add(task);
|
||||
|
||||
// 记录取消分配日志
|
||||
inventoryLogService.addUnAllocInventoryLog(inventory, cancelQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -185,30 +197,13 @@ public class CancelAllocateProcessor {
|
|||
*/
|
||||
private void updateInventoryAllocation(Inventory inventory, BigDecimal cancelQty,
|
||||
Map<Long, Inventory> inventoryUpdateMap) {
|
||||
Inventory targetInventory = inventoryUpdateMap.getOrDefault(inventory.getId(), inventory);
|
||||
|
||||
Inventory inventoryToUpdate = inventoryUpdateMap.computeIfAbsent(
|
||||
inventory.getId(), id -> {
|
||||
// 2. 用Builder实现拷贝
|
||||
return Inventory.builder()
|
||||
.id(inventory.getId())
|
||||
.itemId(inventory.getItemId())
|
||||
.itemKeyId(inventory.getItemKeyId())
|
||||
.pointId(inventory.getPointId())
|
||||
.stockId(inventory.getStockId())
|
||||
.quantity(inventory.getQuantity())
|
||||
.queuedQty(inventory.getQueuedQty())
|
||||
.status(inventory.getStatus())
|
||||
.description(inventory.getDescription())
|
||||
.sysOrgCode(inventory.getSysOrgCode())
|
||||
.tenantId(inventory.getTenantId())
|
||||
.createBy(inventory.getCreateBy())
|
||||
.createTime(inventory.getCreateTime())
|
||||
.build();
|
||||
});
|
||||
BigDecimal newCancelQty = BigDecimalUtil.subtract(inventoryToUpdate.getQueuedQty(), cancelQty, 0);
|
||||
inventoryToUpdate.setQueuedQty(newCancelQty);
|
||||
Integer inv_status = inventoryToUpdate.getQueuedQty().compareTo(BigDecimal.ZERO) > 0 ? InventoryStatusEnum.ALLOCATED.getValue() : InventoryStatusEnum.AVAILABLE.getValue();
|
||||
inventoryToUpdate.setStatus(inv_status);
|
||||
BigDecimal newCancelQty = BigDecimalUtil.subtract(targetInventory.getQueuedQty(), cancelQty, 0);
|
||||
targetInventory.setQueuedQty(newCancelQty);
|
||||
Integer inv_status = targetInventory.getQueuedQty().compareTo(BigDecimal.ZERO) > 0 ? InventoryStatusEnum.ALLOCATED.getValue() : InventoryStatusEnum.AVAILABLE.getValue();
|
||||
targetInventory.setStatus(inv_status);
|
||||
inventoryUpdateMap.put(targetInventory.getId(), targetInventory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -221,65 +216,21 @@ public class CancelAllocateProcessor {
|
|||
private void updatePickDetailAllocation(PickDetail pickDetail, BigDecimal cancelQty,
|
||||
Map<Long, PickDetail> pickDetailUpdateMap) {
|
||||
|
||||
PickDetail detailToUpdate = pickDetailUpdateMap.computeIfAbsent(
|
||||
pickDetail.getId(), id -> {
|
||||
// 2. 用Builder实现拷贝
|
||||
return PickDetail.builder()
|
||||
.id(pickDetail.getId())
|
||||
.pickId(pickDetail.getPickId())
|
||||
.itemId(pickDetail.getItemId())
|
||||
.lineNo(pickDetail.getLineNo())
|
||||
.unit(pickDetail.getUnit())
|
||||
.project(pickDetail.getProject())
|
||||
.taskNo(pickDetail.getTaskNo())
|
||||
.orderQty(pickDetail.getOrderQty())
|
||||
.allocatedQty(pickDetail.getAllocatedQty())
|
||||
.pickedQty(pickDetail.getPickedQty())
|
||||
.status(pickDetail.getStatus())
|
||||
.propC1(pickDetail.getPropC1())
|
||||
.propC3(pickDetail.getPropC3())
|
||||
.description(pickDetail.getDescription())
|
||||
.tenantId(pickDetail.getTenantId())
|
||||
.sysOrgCode(pickDetail.getSysOrgCode())
|
||||
.createBy(pickDetail.getCreateBy())
|
||||
.createTime(pickDetail.getCreateTime())
|
||||
.build();
|
||||
});
|
||||
PickDetail targetPickDetail = pickDetailUpdateMap.getOrDefault(pickDetail.getId(), pickDetail);
|
||||
|
||||
BigDecimal newCancelQty = BigDecimalUtil.subtract(detailToUpdate.getAllocatedQty(), cancelQty, 0);
|
||||
detailToUpdate.setAllocatedQty(newCancelQty);
|
||||
BigDecimal newCancelQty = BigDecimalUtil.subtract(targetPickDetail.getAllocatedQty(), cancelQty, 0);
|
||||
targetPickDetail.setAllocatedQty(newCancelQty);
|
||||
|
||||
// 更新状态
|
||||
Integer status=PickStatusEnum.CREATED.getValue();
|
||||
BigDecimal allocateQty = detailToUpdate.getAllocatedQty();
|
||||
if (detailToUpdate.getOrderQty().compareTo(allocateQty)<=0) {
|
||||
Integer status = PickStatusEnum.CREATED.getValue();
|
||||
BigDecimal allocateQty = targetPickDetail.getAllocatedQty();
|
||||
if (targetPickDetail.getOrderQty().compareTo(allocateQty) <= 0) {
|
||||
status = PickStatusEnum.ASSIGNED.getValue();
|
||||
} else if(detailToUpdate.getOrderQty().compareTo(allocateQty)>0 && allocateQty.compareTo(BigDecimal.ZERO)>0){
|
||||
} else if (targetPickDetail.getOrderQty().compareTo(allocateQty) > 0 && allocateQty.compareTo(BigDecimal.ZERO) > 0) {
|
||||
status = PickStatusEnum.PARTIAL.getValue();
|
||||
}
|
||||
detailToUpdate.setStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param inventoryUpdateMap 更新库存
|
||||
* @param pickDetailUpdateMap 更新出库明细
|
||||
* @param deleteToTask 删除出库任务
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperation(Map<Long, Inventory> inventoryUpdateMap, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> deleteToTask) {
|
||||
List<Inventory> updateToInventory = new ArrayList<>(inventoryUpdateMap.values());
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
||||
if (CollectionUtils.isNotEmpty(updateToInventory)) {
|
||||
batchUtils.updateBatchInventory(updateToInventory);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
|
||||
batchUtils.updateBatchPickDetail(updateToPickDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(deleteToTask)) {
|
||||
taskMapper.deleteByIds(deleteToTask);
|
||||
}
|
||||
targetPickDetail.setStatus(status);
|
||||
pickDetailUpdateMap.put(targetPickDetail.getId(), targetPickDetail);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package org.cpte.modules.shipping.service.processor;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.enums.CommonStatusEnum;
|
||||
import org.cpte.modules.constant.enums.PickStatusEnum;
|
||||
|
|
@ -18,14 +19,12 @@ import org.cpte.modules.shipping.entity.Task;
|
|||
import org.cpte.modules.shipping.mapper.PickDetailMapper;
|
||||
import org.cpte.modules.shipping.service.IPickDetailService;
|
||||
import org.cpte.modules.shipping.vo.PickData;
|
||||
import org.cpte.modules.utils.BatchUtil;
|
||||
import org.cpte.modules.utils.BigDecimalUtil;
|
||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||
import org.jeecg.common.constant.CommonConstant;
|
||||
import org.jeecg.modules.base.service.BaseCommonService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -43,6 +42,9 @@ public class PickProcessor {
|
|||
@Autowired
|
||||
private PickDetailMapper pickDetailMapper;
|
||||
|
||||
@Autowired
|
||||
private IPointService pointService;
|
||||
|
||||
@Autowired
|
||||
private IStockService stockService;
|
||||
|
||||
|
|
@ -58,9 +60,6 @@ public class PickProcessor {
|
|||
@Autowired
|
||||
private BaseCommonService baseCommonService;
|
||||
|
||||
@Autowired
|
||||
private BatchUtil batchUtil;
|
||||
|
||||
@Autowired
|
||||
private PickBackProcessor pickBackProcessor;
|
||||
|
||||
|
|
@ -78,15 +77,17 @@ public class PickProcessor {
|
|||
|
||||
//2.创建数据结构
|
||||
List<Inventory> deleteToInventory = new ArrayList<>();
|
||||
Map<Long, Inventory> inventoryUpdateMap = new HashMap<>();
|
||||
Map<Long, PickDetail> pickDetailUpdateMap = new HashMap<>();
|
||||
List<Task> updateToTask = new ArrayList<>();
|
||||
List<Stock> updateToStock = new ArrayList<>();
|
||||
List<Point> updateToPoint = new ArrayList<>();
|
||||
|
||||
//3.拣货
|
||||
pickTask(data, pickDetailUpdateMap, updateToTask, deleteToInventory, updateToStock);
|
||||
pickTask(data, pickDetailUpdateMap, updateToTask, deleteToInventory,inventoryUpdateMap, updateToStock, updateToPoint);
|
||||
|
||||
//4.批量操作
|
||||
batchOperation(deleteToInventory, pickDetailUpdateMap, updateToTask, updateToStock);
|
||||
pickDetailService.batchOperationPick(deleteToInventory, pickDetailUpdateMap, updateToTask, updateToStock, updateToPoint);
|
||||
|
||||
//5.刷新出库单
|
||||
refreshData(data);
|
||||
|
|
@ -124,6 +125,11 @@ public class PickProcessor {
|
|||
List<Long> stockIds = inventoryMap.values().stream().map(Inventory::getStockId).distinct().toList();
|
||||
Map<Long, Stock> stockMap = stockService.queryByStockIdsToMap(stockIds);
|
||||
data.setStockMap(stockMap);
|
||||
|
||||
//库存点位
|
||||
List<Long> pointIds = inventoryMap.values().stream().map(Inventory::getPointId).distinct().toList();
|
||||
Map<Long, Point> pointMap = pointService.queryByPointIdsToMap(pointIds);
|
||||
data.setPointMap(pointMap);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
@ -132,10 +138,10 @@ public class PickProcessor {
|
|||
*
|
||||
* @param data 数据
|
||||
*/
|
||||
private void pickTask(PickData data, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Inventory> deleteToInventory, List<Stock> updateToStock) {
|
||||
private void pickTask(PickData data, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Inventory> deleteToInventory, Map<Long, Inventory> inventoryUpdateMap, List<Stock> updateToStock, List<Point> updateToPoint) {
|
||||
for (Task task : data.getTasks()) {
|
||||
try {
|
||||
processorTaskLock(data, task, pickDetailUpdateMap, updateToTask, deleteToInventory, updateToStock);
|
||||
processorTaskLock(data, task, pickDetailUpdateMap, updateToTask, deleteToInventory, inventoryUpdateMap,updateToStock, updateToPoint);
|
||||
} catch (Exception e) {
|
||||
log.error("拣货异常", e);
|
||||
//记录拣货异常日志
|
||||
|
|
@ -154,16 +160,17 @@ public class PickProcessor {
|
|||
* @param deleteToInventory 删除库存集合
|
||||
* @param updateToStock 更新容器状态集合
|
||||
*/
|
||||
private void processorTaskLock(PickData data, Task task, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Inventory> deleteToInventory, List<Stock> updateToStock) {
|
||||
private void processorTaskLock(PickData data, Task task, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Inventory> deleteToInventory, Map<Long, Inventory> inventoryUpdateMap, List<Stock> updateToStock, List<Point> updateToPoint) {
|
||||
// 拣货处理
|
||||
String lockKey = "task:" + task.getId();
|
||||
Pick pick = data.getPickMap().get(task.getPickId());
|
||||
String lockKey = "task:" + pick.getId();
|
||||
String lockValue = null;
|
||||
try {
|
||||
lockValue = redissonLock.tryLock(lockKey, 10);
|
||||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("拣货处理中,请稍后重试");
|
||||
}
|
||||
processorTask(data, task, pickDetailUpdateMap, updateToTask, deleteToInventory, updateToStock);
|
||||
processorTask(data, task, pickDetailUpdateMap, updateToTask, deleteToInventory, inventoryUpdateMap, updateToStock, updateToPoint);
|
||||
} catch (Exception e) {
|
||||
log.error("拣货异常", e);
|
||||
throw e;
|
||||
|
|
@ -172,6 +179,7 @@ public class PickProcessor {
|
|||
redissonLock.unlock(lockKey, lockValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -185,7 +193,7 @@ public class PickProcessor {
|
|||
* @param deleteToInventory 删除库存集合
|
||||
* @param updateToStock 更新容器状态集合
|
||||
*/
|
||||
private void processorTask(PickData data, Task task, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Inventory> deleteToInventory, List<Stock> updateToStock) {
|
||||
private void processorTask(PickData data, Task task, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Inventory> deleteToInventory, Map<Long, Inventory> inventoryUpdateMap, List<Stock> updateToStock, List<Point> updateToPoint) {
|
||||
|
||||
BigDecimal pickedQty = BigDecimalUtil.subtract(task.getPlanQty(), task.getMoveQty(), 0);
|
||||
if (pickedQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
|
|
@ -208,8 +216,11 @@ public class PickProcessor {
|
|||
//更新容器状态
|
||||
updateToStock(data, task, updateToStock);
|
||||
|
||||
//更新点位状态
|
||||
updateToPoint(data, task, updateToPoint);
|
||||
|
||||
//添加库存日志
|
||||
addInventoryLog(data, task, pickedQty);
|
||||
addInventoryLog(data, task, pickedQty, inventoryUpdateMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -287,9 +298,23 @@ public class PickProcessor {
|
|||
private void updateToStock(PickData data, Task task, List<Stock> updateToStock) {
|
||||
Stock stock = data.getStockMap().get(task.getStockId());
|
||||
if (!updateToStock.contains(stock)) {
|
||||
stock.setPointId(null);
|
||||
stock.setStatus(CommonStatusEnum.FREE.getValue());
|
||||
updateToStock.add(stock);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新点位状态
|
||||
*
|
||||
* @param data 数据
|
||||
* @param updateToPoint 点位更新集合
|
||||
*/
|
||||
private void updateToPoint(PickData data, Task task, List<Point> updateToPoint) {
|
||||
Point point = data.getPointMap().get(task.getFromPointId());
|
||||
if (!updateToPoint.contains(point)) {
|
||||
point.setStatus(CommonStatusEnum.FREE.getValue());
|
||||
updateToPoint.add(point);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,35 +325,11 @@ public class PickProcessor {
|
|||
* @param task 任务
|
||||
* @param pickedQty 拣货数量
|
||||
*/
|
||||
private void addInventoryLog(PickData data, Task task, BigDecimal pickedQty) {
|
||||
private void addInventoryLog(PickData data, Task task, BigDecimal pickedQty, Map<Long, Inventory> inventoryUpdateMap) {
|
||||
Inventory inventory = data.getInventoryMap().get(task.getInventoryId());
|
||||
updateInventory(inventory, pickedQty, inventoryUpdateMap);
|
||||
Pick pick = data.getPickMap().get(task.getPickId());
|
||||
inventoryLogService.addPickInventoryLog(inventory, task.getToPointId(), pickedQty, pick.getOrderNo(), task.getId(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量操作
|
||||
*
|
||||
* @param deleteToInventory 删除库存
|
||||
* @param pickDetailUpdateMap 更新出库明细
|
||||
* @param updateToTask 创建出库任务
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchOperation(List<Inventory> deleteToInventory, Map<Long, PickDetail> pickDetailUpdateMap, List<Task> updateToTask, List<Stock> updateToStock) {
|
||||
if (CollectionUtils.isNotEmpty(deleteToInventory)) {
|
||||
List<Long> deleteToInventoryIds = deleteToInventory.stream().map(Inventory::getId).toList();
|
||||
inventoryService.removeByIds(deleteToInventoryIds);
|
||||
}
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>(pickDetailUpdateMap.values());
|
||||
if (CollectionUtils.isNotEmpty(updateToPickDetail)) {
|
||||
batchUtil.updateBatchPickDetail(updateToPickDetail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToTask)) {
|
||||
batchUtil.updateBatchTask(updateToTask);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToStock)) {
|
||||
stockService.updateBatchById(updateToStock);
|
||||
}
|
||||
inventoryLogService.addPickInventoryLog(inventoryUpdateMap.get(inventory.getId()), task.getToPointId(), pickedQty, pick.getOrderNo(), task.getId(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package org.cpte.modules.shipping.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.shipping.entity.Pick;
|
||||
|
|
@ -14,6 +15,7 @@ import java.util.Map;
|
|||
public class PickData {
|
||||
private List<Task> tasks;
|
||||
private Map<Long, Stock> stockMap;
|
||||
private Map<Long, Point> pointMap;
|
||||
private Map<Long, Pick> pickMap;
|
||||
private Map<Long, PickDetail> pickDetailMap;
|
||||
private Map<Long, Inventory> inventoryMap;
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ public class ITesAgvServiceImpl implements ITesAgvService {
|
|||
private void handleEnd(Long asnId, AgvTask agvTask) {
|
||||
if (BusinessTypeEnum.INBOUND.getValue().equals(agvTask.getType())) {
|
||||
//收货
|
||||
asnService.receiveAsn(asnId, agvTask.getEndCode());
|
||||
asnService.receiveAsn(asnId);
|
||||
} else if (BusinessTypeEnum.OUTBOUND.getValue().equals(agvTask.getType())) {
|
||||
//拣货
|
||||
List<Task> tasks = taskMapper.queryByAgvTask(agvTask.getId());
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ public class BatchUtil {
|
|||
ps.setLong(2, record.getAsnId());
|
||||
ps.setLong(3, record.getAsnDetailId());
|
||||
ps.setLong(4, record.getStockId());
|
||||
ps.setLong(5, record.getFromPointId());
|
||||
ps.setObject(5, record.getFromPointId());
|
||||
ps.setLong(6, record.getToPointId());
|
||||
ps.setLong(7, record.getItemId());
|
||||
ps.setLong(8, record.getItemKeyId());
|
||||
|
|
|
|||
Loading…
Reference in New Issue