no message

main
HUOJIN\92525 2025-12-21 17:58:47 +08:00
parent 7d31f04772
commit 32f9edffc3
38 changed files with 840 additions and 711 deletions

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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));

View File

@ -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));

View File

@ -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));

View File

@ -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);

View File

@ -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;
/**
*
*/

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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());

View File

@ -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());

View File

@ -265,4 +265,6 @@ public class AsnController {
return Result.OK("文件导入失败!");
}
}

View File

@ -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;
/**
*
*/

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -13,5 +13,5 @@ public class ReceiveData {
private Asn asn ;
private List<AsnDetail> asnDetails;
private Stock stock;
private Point dstPoint;
private Point point;
}

View File

@ -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;
/**
*
*

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);
}
/**
*
*

View File

@ -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);
}
}
}

View File

@ -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());
}
}
}

View File

@ -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);
/**
* IDMap
*
* @param pickIds ID
* @return Map<Long, Pick>
*/
Map<Long, Pick> queryByPickIdsToMap(List<Long> pickIds);
/**
* IDMap
*
* @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);
/**
* IDMap
*
* @param pickIds ID
* @return Map<Long, Pick>
*/
Map<Long, Pick> queryByPickIdsToMap(List<Long> pickIds);
/**
* IDMap
*
* @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);
}

View File

@ -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);
/**
*
*

View File

@ -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);
}
}
/**
*

View File

@ -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) {

View File

@ -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);
}
}
/**
*
*

View File

@ -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);
}
/**

View File

@ -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);
}
/**

View File

@ -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;

View File

@ -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());

View File

@ -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());