PDA 小件流程支持拣多个箱号,支持人工送料。

main
HUOJIN\92525 2025-03-21 14:34:55 +08:00
parent 8ac180f9e8
commit e413a5f1d9
11 changed files with 317 additions and 79 deletions

View File

@ -14,4 +14,8 @@ public class ReturnTaskVo {
private String srcPointCode;//起始点
private String dstPointCode;//目标点
private Double planQty;//待拣货数量
private String description;//备注;
private String dstStockCode;//目标托盘
}

View File

@ -82,6 +82,19 @@ public class BydAppController {
}
}
@PostMapping("/fbFeed")
@Log("翻包送料")
@ApiOperation("翻包送料")
@AnonymousAccess
public ResponseEntity<Object> fbFeed(@RequestBody FbPick fbPick) {
try {
bydAppService.fbFeed(fbPick.getDstStockCode());
return successResponse("操作成功!", null);
} catch (Exception e) {
return badRequest("拣货失败:" + e.getMessage());
}
}
@PostMapping("/unBindContainer")
@Log("容器解绑")
@ApiOperation("容器解绑")

View File

@ -37,6 +37,14 @@ public interface BydAppService {
*/
void fbPicking(Long taskId, String orderNumber, String dstStockCode ,Double moveQty);
/**
*
*
* @param dstStockCode
*/
void fbFeed(String dstStockCode);
/**
*
* @param stockCode

View File

@ -18,6 +18,7 @@ import com.youchain.exception.BadRequestException;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -188,6 +189,19 @@ public class BydAppServiceImpl implements BydAppService {
if (taskList.isEmpty()) {
throw new BadRequestException("未找到" + stockCode + "托盘的翻包拣货任务!");
}
//推荐目标托盘
Stock stock;
stock = stockService.findByPointCode(stockCode);
if (stock == null) {
stock = stockService.findByCode(stockCode);
}
String pickCode = taskService.findByStockCodeToPick(stock.getCode());
String dstStockCode = taskService.findByPickToStockCode(pickCode);
if (StringUtils.isEmpty(dstStockCode)) {
dstStockCode = "";
}
Task task = taskList.get(0);
ReturnTaskVo returnTaskVo = new ReturnTaskVo();
returnTaskVo.setTaskId(task.getId());
@ -197,6 +211,8 @@ public class BydAppServiceImpl implements BydAppService {
returnTaskVo.setSrcPointCode(task.getSrcPointCode());
returnTaskVo.setDstPointCode(task.getDstPointCode());
returnTaskVo.setPlanQty(task.getPlanQty() - task.getMoveQty());
returnTaskVo.setDescription(String.valueOf(taskList.size()));
returnTaskVo.setDstStockCode(dstStockCode);
return returnTaskVo;
}
@ -218,12 +234,40 @@ public class BydAppServiceImpl implements BydAppService {
//刷新出库单状态
pickService.refreshPickStatus(task.getPickDetail().getPick());
//成品原托盘返库;单品不回库
//生成叫料任务、生成返库任务
Set<String> endPointList = new HashSet<>(Arrays.asList(pick.getCallPoint().split(",")));
if (BaseStatus.GD_TYPE_CT.equals(pick.getOrderType())) {
this.returnXJFBAgvTask(task);
this.returnCTFBAgvTask(pick, task, endPointList);
} else if (BaseStatus.GD_TYPE_DP.equals(pick.getOrderType())) {
this.returnDJFBAgvTask(task);
this.returnDPFBAgvTask(pick, task, endPointList);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void fbFeed(String dstStockCode) {
Stock dstStock = stockService.findByCode(dstStockCode);
if (dstStock == null) {
throw new BadRequestException(dstStockCode + "货架不存在!");
}
if (!agvTaskService.isStockAvailable(dstStockCode, BizStatus.CALL_PICK, "RACK_MOVE")) {
throw new BadRequestException(dstStockCode + "货架已生成叫料任务,请勿重复操作!");
}
List<Task> tasks = taskService.findByStockToTaskList(dstStockCode);
if (CollectionUtils.isEmpty(tasks)) {
throw new BadRequestException(dstStockCode + "货架无翻包拣货任务!");
}
Pick pick = tasks.get(0).getPickDetail().getPick();
Set<String> endPoints = new HashSet<>(Arrays.asList(pick.getCallPoint().split(",")));
if (BaseStatus.GD_TYPE_CT.equals(pick.getOrderType())) {
this.createCTCallTask(pick, tasks, endPoints);
} else if (BaseStatus.GD_TYPE_DP.equals(pick.getOrderType())) {
this.createDPCallTask(pick, tasks, endPoints);
}
}
@Override
@ -405,8 +449,8 @@ public class BydAppServiceImpl implements BydAppService {
if (orderNumber.equals(task.getItemKey().getOrderNumber())) {
return task;
} else {
//重新分配
return taskService.reassignTask(task, orderNumber);
//获取其他箱号的任务
return taskService.findByOrderNumber(orderNumber);
}
}
@ -434,13 +478,17 @@ public class BydAppServiceImpl implements BydAppService {
throw new BadRequestException(dstStockCode + "目标托盘没有在" + areaName);
}
/* if (BizStatus.XJ.equals(task.getItemKey().getItem().getGoodType())) {
//一个工单的物料只能放入同一个货架
if (!dstStockCode.equals(pick.getStock())) {
if (!agvTaskService.isStockAvailable(dstStockCode, BizStatus.CALL_PICK, "RACK_MOVE")) {
throw new BadRequestException(dstStockCode + "货架已生成叫料任务,请绑定其他货架!");
}
throw new BadRequestException(pick.getGdCode() + "工单只能放入同一个货架! 请放入" + pick.getCode() + "货架!");
if (BizStatus.XJ.equals(task.getItemKey().getItem().getGoodType())) {
//一个工单的物料只能放入同一个货架
String stockCode = taskService.findByPickToStockCode(pick.getCode());
if (StringUtils.isNotBlank(stockCode) && !dstStockCode.equals(stockCode)) {
throw new BadRequestException("一个工单的物料只能放入同一个货架! 请放入" + stockCode + "货架!");
}
}*/
}
return dstStock;
}
@ -449,14 +497,11 @@ public class BydAppServiceImpl implements BydAppService {
*
* @param task
*/
private void returnXJFBAgvTask(Task task) {
double planQty = 0;
double moveQty = 0;
private void returnCTFBAgvTask(Pick pick, Task task, Set<String> endPoints) {
//当前AGV任务中的任务
List<Task> taskList = taskService.findTaskByAgvTask(task.getAgvTask().getId());
for (Task task1 : taskList) {
planQty += task1.getPlanQty();
moveQty += task1.getMoveQty();
}
double planQty = taskList.stream().mapToDouble(Task::getPlanQty).sum();
double moveQty = taskList.stream().mapToDouble(Task::getMoveQty).sum();
if (planQty == moveQty) {
//成品当前托盘没有库存则不需要回库;
List<Inventory> inventoryList = inventoryService.findByStockCode(task.getSrcStock().getCode());
@ -469,11 +514,53 @@ public class BydAppServiceImpl implements BydAppService {
return false;
})
.collect(Collectors.toList());
if (!smallAreaInventories.isEmpty()) {
if (CollectionUtils.isNotEmpty(smallAreaInventories)) {
kmReService.returnFBAgvTask(task.getSrcStock().getPoint(), task.getSrcStock(), task.getItem());
}
}
//查询工单中的任务,都拣货完成则生成叫料任务
List<Task> tasks = taskService.findTaskByPick(pick.getId());
double planQty2 = tasks.stream().mapToDouble(Task::getPlanQty).sum();
double moveQty2 = tasks.stream().mapToDouble(Task::getMoveQty).sum();
if (planQty2 == moveQty2) {
createCTCallTask(pick, tasks, endPoints);
}
}
/**
*
*
* @param pick
* @param endPoints
* @param taskList
*/
public void createCTCallTask(Pick pick, List<Task> taskList, Set<String> endPoints) {
//根据目标托盘进行分组,每次最多送两个托盘
Map<String, List<Task>> groupMap = taskList.stream().collect(Collectors.groupingBy(Task::getDstStockCode));
for (Map.Entry<String, List<Task>> entry : groupMap.entrySet()) {
String dstStockCode = entry.getKey();//容器
List<Task> tasks = entry.getValue();//任务
for (String endPointCode : endPoints) {
if (agvTaskService.isStockAvailable(dstStockCode, BizStatus.CALL_PICK, "RACK_MOVE")) {
if (agvTaskService.findByEndSlotCode(endPointCode, BizStatus.CALL_PICK, "RACK_MOVE")) {
Stock stock = stockService.findByCode(dstStockCode);
AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.CALL_PICK, stock, stock.getPoint().getCode(), endPointCode, "RACK_MOVE");
for (Task task : tasks) {
task.setCallAgvTaskId(agvTask.getId());
taskService.update(task);
}
agvTask.setLineSlotCode(pick.getCode());
agvTaskService.update(agvTask);
}
}
}
}
}
/**
@ -481,7 +568,7 @@ public class BydAppServiceImpl implements BydAppService {
*
* @param task
*/
private void returnDJFBAgvTask(Task task) {
private void returnDPFBAgvTask(Pick pick, Task task, Set<String> endPoints) {
double planQty = 0;
double moveQty = 0;
List<Task> taskList = taskService.findTaskByAgvTask(task.getAgvTask().getId());
@ -503,6 +590,25 @@ public class BydAppServiceImpl implements BydAppService {
kmReService.sendAgvTask(agvTask, kmReService.sendAgvTaskCcJson(agvTask));
}
}
//生成叫料任务
createDPCallTask(pick, taskList, endPoints);
}
}
public void createDPCallTask(Pick pick, List<Task> taskList, Set<String> endPoints) {
for (Task task : taskList) {
for (String endPointCode : endPoints) {
if (agvTaskService.isStockAvailable(task.getDstStockCode(), BizStatus.CALL_PICK, "RACK_MOVE")) {
if (agvTaskService.findByEndSlotCode(endPointCode, BizStatus.CALL_PICK, "RACK_MOVE")) {
AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.CALL_PICK, task.getDstStock(), task.getDstPointCode(), endPointCode, "RACK_MOVE");
agvTask.setLineSlotCode(pick.getCode());
agvTaskService.update(agvTask);
task.setCallAgvTaskId(agvTask.getId());
taskService.update(task);
}
}
}
}
}

View File

@ -76,10 +76,7 @@ public class Pick extends BaseEntity implements Serializable {
@ApiModelProperty(value = "状态")
private String status;
@OneToOne
@JoinColumn(name = "`point_id`")
@ApiModelProperty(value = "备料点位")
private Point point;
@Column(name = "`call_point_id`")

View File

@ -18,6 +18,7 @@ package com.youchain.businessdata.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.youchain.base.BaseEntity;
import com.youchain.basicdata.domain.Item;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.modules.system.domain.Dept;
import lombok.Data;
@ -143,6 +144,11 @@ public class PickDetail extends BaseEntity implements Serializable {
@ApiModelProperty(value = "回传状态")
private Long sourceId;/**0失败1成功*/
@OneToOne
@JoinColumn(name = "`point_id`")
@ApiModelProperty(value = "备料点位")
private Point point;
public PickDetail() {
}

View File

@ -37,6 +37,14 @@ public interface TaskRepository extends JpaRepository<Task, Long>, JpaSpecificat
@Query(" from Task t where t.agvTask.id =:agvTaskId ")
List<Task> findTaskByAgvTask(Long agvTaskId);
/**
* IDTask
*
* @param agvTaskId agvId
*/
@Query(" from Task t where t.pickDetail.pick.id =:pickId and t.callAgvTaskId is null ")
List<Task> findTaskByPick(Long pickId);
/**
* agvIDTask
*
@ -88,5 +96,37 @@ public interface TaskRepository extends JpaRepository<Task, Long>, JpaSpecificat
@Query(value = " select count(t.id) FROM Task t WHERE t.pickDetail.pick.code!=:pickCode and t.srcStock.code=:stockCode and t.taskType='PICK' and t.taskStatus not in ('FINISH','CANCEL') ")
int existsByStock(String pickCode, String stockCode);
/**
*
* @param orderNumber
* @return
*/
@Query(value = " from Task t where t.itemKey.orderNumber=:orderNumber and t.planQty-t.moveQty>0 ")
Task findByOrderNumber(String orderNumber);
/**
*
* @param stockCode
* @return
*/
@Query(value = "select max(t.pickDetail.pick.code) from Task t where t.srcStock.code=:stockCode and t.taskType='PICK' and t.planQty-t.moveQty>0 and t.callAgvTaskId is null")
String findByStockCodeToPick(String stockCode);
/**
*
* @param stockCode
* @return
*/
@Query(value = " from Task t where t.dstStock.code=:stockCode and t.taskType='PICK' and t.planQty-t.moveQty=0 and t.callAgvTaskId is null")
List<Task> findByStockToTaskList(String stockCode);
/**
*
* @param pickCode
* @return
*/
@Query(value = "select max(t.dstStock.code) from Task t where t.pickDetail.pick.code=:pickCode and t.taskType='PICK' and t.planQty-t.moveQty=0 and t.callAgvTaskId is null")
String findByPickToStockCode(String pickCode);
}

View File

@ -118,6 +118,13 @@ public interface TaskService {
*/
List<Task> findTaskByAgvTask(Long agvTaskId);
/**
* IDTask
*
* @param pickId pickId
*/
List<Task> findTaskByPick(Long pickId);
/**
* agvIDTask
*
@ -155,6 +162,28 @@ public interface TaskService {
*/
List<Task> findTaskByContains(String taskType, String taskStatus, String srcStockCode);
/**
*
*
* @param stockCode
*/
String findByStockCodeToPick(String stockCode);
/**
*
*
* @param stockCode
*/
List<Task> findByStockToTaskList(String stockCode);
/**
*
*
* @param pickCode
*/
String findByPickToStockCode(String pickCode);
/**
*
@ -209,12 +238,11 @@ public interface TaskService {
/**
*
*
*
* @param task
* @param orderNumber
*/
Task reassignTask(Task task, String orderNumber);
Task findByOrderNumber(String orderNumber);
/**
*

View File

@ -74,11 +74,6 @@ public class PickDto implements Serializable {
*/
private String status;
/**
*
*/
private Point point;
/**
*
*/

View File

@ -41,6 +41,7 @@ import java.util.*;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
/**
@ -139,6 +140,11 @@ public class TaskServiceImpl implements TaskService {
return taskRepository.findTaskByAgvTask(agvTaskId);
}
@Override
public List<Task> findTaskByPick(Long pickId) {
return taskRepository.findTaskByPick(pickId);
}
@Override
public List<Task> findTaskByCallAgvTask(Long callAgvTaskId) {
return taskRepository.findTaskByCallAgvTask(callAgvTaskId);
@ -164,6 +170,22 @@ public class TaskServiceImpl implements TaskService {
return taskRepository.findTaskByContains(taskType, taskStatus, srcStockCode);
}
@Override
public String findByStockCodeToPick(String stockCode) {
return taskRepository.findByStockCodeToPick(stockCode);
}
@Override
public List<Task> findByStockToTaskList(String stockCode) {
return taskRepository.findByStockToTaskList(stockCode);
}
@Override
public String findByPickToStockCode(String pickCode) {
return taskRepository.findByPickToStockCode(pickCode);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void allocatePick(Pick pick) {
@ -224,9 +246,50 @@ public class TaskServiceImpl implements TaskService {
@Override
@Transactional(rollbackFor = Exception.class)
public void callJlTask(Pick pick) {
//绑定任务
//终点
Set<String> endPointList = new HashSet<>(Arrays.asList(pick.getCallPoint().split(",")));
//根据成品和单品分别生成叫料任务
if (BaseStatus.GD_TYPE_DP.equals(pick.getOrderType())) {
callDP(pick, endPointList);
} else {
callCT(pick, endPointList);
}
}
public void callCT(Pick pick, Set<String> endPoints) {
List<Task> taskList = new ArrayList<>();
//根据目标托盘进行分组,每次最多送两个托盘
Map<String, List<Task>> groupMap = taskList.stream().collect(Collectors.groupingBy(Task::getDstStockCode));
for (Map.Entry<String, List<Task>> entry : groupMap.entrySet()) {
String dstStockCode = entry.getKey();//容器
List<Task> tasks = entry.getValue();//任务
for (String endPointCode : endPoints) {
if (agvTaskService.isStockAvailable(dstStockCode, BizStatus.CALL_PICK, "RACK_MOVE")) {
if (agvTaskService.findByEndSlotCode(endPointCode, BizStatus.CALL_PICK, "RACK_MOVE")) {
Stock stock = stockService.findByCode(dstStockCode);
AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.CALL_PICK, stock, stock.getPoint().getCode(), endPointCode, "RACK_MOVE");
for (Task task : tasks) {
task.setCallAgvTaskId(agvTask.getId());
taskRepository.save(task);
}
agvTask.setLineSlotCode(pick.getCode());
agvTaskService.update(agvTask);
}
}
}
}
}
public void callDP(Pick pick, Set<String> endPoints) {
List<Task> taskList = this.findByPickAllTask(pick.getId());
if (taskList.isEmpty()) {
String logMessage = pick.getGdCode() + "工单没有进行翻包!";
@ -236,20 +299,6 @@ public class TaskServiceImpl implements TaskService {
}
return;
}
//工单是否叫料
if (StringUtils.isEmpty(pick.getCallPoint())) {
String logMessage = pick.getGdCode() + "工单没有进行叫料!";
if (!lastPollLogMessages.containsKey(logMessage)) {
logService.saveLogInfo(pick.getGdCode(), pick.getGdCode(), "/pick/callJlTask", logMessage, "生成叫料任务", 200, "info");
addLog(logMessage);
}
return;
}
//终点
Set<String> endPointList = new HashSet<>(Arrays.asList(pick.getCallPoint().split(",")));
Map<String, Point> pointMap = pointService.findByCodes(endPointList);
List<String> endPoints = getValuesFromMap(endPointList, pointMap);
for (Task task : taskList) {
for (String endPointCode : endPoints) {
if (agvTaskService.isStockAvailable(task.getDstStockCode(), BizStatus.CALL_PICK, "RACK_MOVE")) {
@ -265,22 +314,6 @@ public class TaskServiceImpl implements TaskService {
}
}
public static List<String> getValuesFromMap(Set<String> endPointList, Map<String, Point> map) {
List<String> values = new ArrayList<>();
int count = endPointList.size();
int index = 0;
// 遍历 map 的键值对
for (Map.Entry<String, Point> entry : map.entrySet()) {
if (index >= count) {
break;
}
values.add(entry.getKey());
index++;
}
return values;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String allocate(long id, double quantity) {
@ -347,7 +380,17 @@ public class TaskServiceImpl implements TaskService {
}
return logMessage;
}
Point endPoint = pointList.get(0);
Point endPoint = null;
//大件一个明细可以对应多个点位;小件一个明细只能对应一个点位
if (BaseStatus.GD_TYPE_CT.equals(pick.getOrderType())) {
if (pickDetail.getPoint() == null) {
endPoint = pointList.get(0);
} else {
endPoint = pickDetail.getPoint();
}
} else {
endPoint = pointList.get(0);
}
// 起点
Point startPoint = inv.getPoint();
@ -368,6 +411,7 @@ public class TaskServiceImpl implements TaskService {
unQty -= allocateQty;
/* 更新出库单明细状态*/
pickDetail.setAllocatedQty(pickDetail.getAllocatedQty() + allocateQty);
pickDetail.setPoint(endPoint);
pickDetailService.update(pickDetail);
// 生成Task任务
@ -415,13 +459,6 @@ public class TaskServiceImpl implements TaskService {
inventoryService.update(inv);
}
if(task.getAgvTask()!=null){
AgvTask agvTask= agvTaskService.findById(task.getAgvTask().getId());
if(agvTask!=null){
agvTaskService.deleteAll(new Long[]{agvTask.getId()});
}
}
//删除Task
taskRepository.delete(task);
@ -542,9 +579,12 @@ public class TaskServiceImpl implements TaskService {
@Override
@Transactional(rollbackFor = Exception.class)
public Task reassignTask(Task task, String orderNumber) {
Inventory dstinventory = inventoryService.findByOrderNumber(orderNumber, task.getSrcStockCode());
public Task findByOrderNumber(String orderNumber) {
Task task = taskRepository.findByOrderNumber(orderNumber);
if (task == null) {
throw new BadRequestException(orderNumber + "无拣货任务!");
}
/* Inventory dstinventory = inventoryService.findByOrderNumber(orderNumber, task.getSrcStockCode());
if (dstinventory == null) {
throw new BadRequestException(orderNumber + "箱号无库存,请更换箱号!");
}
@ -559,7 +599,7 @@ public class TaskServiceImpl implements TaskService {
inventoryService.update(dstinventory);
task.setInvId(dstinventory.getId());
task.setItemKey(dstinventory.getItemKey());
taskRepository.save(task);
taskRepository.save(task);*/
return task;
}
@ -591,6 +631,7 @@ public class TaskServiceImpl implements TaskService {
//更新Task
double planQty = task.getPlanQty();
String status = task.getTaskStatus();
Stock srcStock = task.getDstStock();//未拣货前的终点。
task.setInvId(inventory == null ? null : inventory.getId());
task.setNewInvId(newInventory == null ? null : newInventory.getId());
task.setMoveQty(task.getMoveQty() + moveQty);
@ -606,9 +647,9 @@ public class TaskServiceImpl implements TaskService {
task.setMoveQty(moveQty);
task.setTaskStatus(BizStatus.FINISH);
// 生成Task任务
Task newTask = this.createTask(task.getItemKey().getItem(), planQty - moveQty, task.getItemKey(), null, BizStatus.PICK, pickDetail, task.getInvId(), task.getSrcStock(), task.getSrcPoint(), task.getDstPoint(), task.getAgvTask());
newTask.setDstStock(dstStock);
newTask.setDstStockCode(dstStock.getCode());
Task newTask = this.createTask(task.getItemKey().getItem(), planQty - moveQty, task.getItemKey(), null, BizStatus.PICK, pickDetail, task.getInvId(), task.getSrcStock(), task.getSrcPoint(), srcStock.getPoint(), task.getAgvTask());
newTask.setDstStock(srcStock);
newTask.setDstStockCode(srcStock.getCode());
newTask.setTaskStatus(status);
taskRepository.save(newTask);
}

View File

@ -69,7 +69,7 @@ public class pickTask {
/**
*
*/
public void createJlTask() {
/* public void createJlTask() {
//查询拣货完成完成的出库单
List<String> statuses = Arrays.asList(BizStatus.PICKUP, BizStatus.PICK_ALL);
List<Pick> pickList = pickService.findByPickStatus(statuses, true);
@ -81,6 +81,6 @@ public class pickTask {
taskService.callJlTask(pick);
}
}
}
}*/
}