This commit is contained in:
2026-09-10 15:14:30 +08:00
parent 2963acc32b
commit a5db6fbbb6
6 changed files with 86 additions and 59 deletions
@@ -139,15 +139,13 @@ public interface LoadingPickItemMapper extends BaseMapper<LoadingPickItemEntity>
JOIN fl_loading_plan_item plan_item ON plan_item.id = pick_item.loading_plan_item_id
JOIN fl_loading_plan plan ON plan.id = plan_item.loading_plan_id
AND plan.id = pick_task.loading_plan_id
JOIN fl_container_booking booking ON booking.id = plan.container_booking_id
JOIN fl_inbound_order inbound_order ON inbound_order.id = plan_item.inbound_id
AND inbound_order.tenant_id = plan_item.account_id AND inbound_order.deleted = 0
WHERE pick_item.pick_task_id = #{taskId} AND booking.warehouse_id = #{warehouseId}
AND plan_item.deleted = 0
WHERE pick_item.pick_task_id = #{taskId} AND plan_item.deleted = 0
ORDER BY pick_item.id ASC
""")
java.util.List<LoadingPickItemEntity> selectTaskItemsWithAccount(@Param("taskId") long taskId,
@Param("warehouseId") long warehouseId);
@Param("warehouseId") long warehouseId);
@Select("""
SELECT pick_item.*
@@ -156,11 +154,10 @@ public interface LoadingPickItemMapper extends BaseMapper<LoadingPickItemEntity>
JOIN fl_loading_plan_item plan_item ON plan_item.id = pick_item.loading_plan_item_id
JOIN fl_loading_plan plan ON plan.id = plan_item.loading_plan_id
AND plan.id = pick_task.loading_plan_id
JOIN fl_container_booking booking ON booking.id = plan.container_booking_id
JOIN fl_inbound_order inbound_order ON inbound_order.id = plan_item.inbound_id
AND inbound_order.tenant_id = plan_item.account_id AND inbound_order.deleted = 0
WHERE pick_item.pick_task_id = #{taskId} AND pick_item.id = #{itemId}
AND booking.warehouse_id = #{warehouseId} AND plan_item.deleted = 0
AND plan_item.deleted = 0
""")
LoadingPickItemEntity selectTaskItemWithAccount(@Param("taskId") long taskId,
@Param("itemId") long itemId,
@@ -174,10 +171,8 @@ public interface LoadingPickItemMapper extends BaseMapper<LoadingPickItemEntity>
version = version + 1
WHERE id = #{id} AND version = #{version}
AND EXISTS (SELECT 1 FROM fl_loading_plan_item plan_item
JOIN fl_loading_plan plan ON plan.id = plan_item.loading_plan_id
JOIN fl_container_booking booking ON booking.id = plan.container_booking_id
WHERE plan_item.id = fl_loading_pick_item.loading_plan_item_id
AND booking.warehouse_id = #{warehouseId} AND plan_item.deleted = 0)
AND plan_item.deleted = 0)
AND picked_package_count + #{count} <= planned_package_count
""")
int pick(@Param("id") long id, @Param("count") int count,
@@ -190,10 +185,8 @@ public interface LoadingPickItemMapper extends BaseMapper<LoadingPickItemEntity>
version = version + 1
WHERE id = #{id} AND version = #{version}
AND EXISTS (SELECT 1 FROM fl_loading_plan_item plan_item
JOIN fl_loading_plan plan ON plan.id = plan_item.loading_plan_id
JOIN fl_container_booking booking ON booking.id = plan.container_booking_id
WHERE plan_item.id = fl_loading_pick_item.loading_plan_item_id
AND booking.warehouse_id = #{warehouseId} AND plan_item.deleted = 0)
AND plan_item.deleted = 0)
AND item_status IN ('PENDING', 'PICKING')
AND picked_package_count < #{finalCount}
AND #{finalCount} < planned_package_count
@@ -207,13 +200,12 @@ public interface LoadingPickItemMapper extends BaseMapper<LoadingPickItemEntity>
SET item_status = 'SKIPPED', version = version + 1
WHERE id = #{id} AND version = #{version}
AND EXISTS (SELECT 1 FROM fl_loading_plan_item plan_item
JOIN fl_loading_plan plan ON plan.id = plan_item.loading_plan_id
JOIN fl_container_booking booking ON booking.id = plan.container_booking_id
WHERE plan_item.id = fl_loading_pick_item.loading_plan_item_id
AND booking.warehouse_id = #{warehouseId} AND plan_item.deleted = 0)
AND plan_item.deleted = 0)
AND item_status = 'PENDING' AND picked_package_count = 0
""")
int skip(@Param("id") long id, @Param("version") int version, @Param("warehouseId") long warehouseId);
int skip(@Param("id") long id, @Param("version") int version,
@Param("warehouseId") long warehouseId);
@Select("""
SELECT COUNT(*)
@@ -50,7 +50,6 @@ public interface LoadingPickTaskMapper extends BaseMapper<LoadingPickTaskEntity>
JOIN fl_container_booking booking ON booking.id = plan.container_booking_id
WHERE booking.container_no = #{containerNo} AND booking.record_status = 'ACTIVE'
AND task.task_status = 'LOADING'
AND booking.warehouse_id = #{warehouseId}
LIMIT 1
""")
LoadingPickTaskEntity selectLoadingByContainerAndAccount(@Param("containerNo") String containerNo,
@@ -59,13 +58,13 @@ public interface LoadingPickTaskMapper extends BaseMapper<LoadingPickTaskEntity>
@Select("SELECT task.* FROM fl_loading_pick_task task JOIN fl_loading_plan plan ON plan.id=task.loading_plan_id "
+ "JOIN fl_container_booking booking ON booking.id=plan.container_booking_id "
+ "WHERE task.task_status='LOADING' AND booking.record_status='ACTIVE' "
+ "AND booking.cabinet_no=#{cabinetNo} AND booking.warehouse_id=#{warehouseId} LIMIT 1")
+ "AND booking.cabinet_no=#{cabinetNo} LIMIT 1")
LoadingPickTaskEntity selectLoadingByCabinet(@Param("cabinetNo") String cabinetNo, @Param("warehouseId") long warehouseId);
@Select("SELECT task.* FROM fl_loading_pick_task task JOIN fl_loading_plan plan ON plan.id=task.loading_plan_id "
+ "JOIN fl_container_booking booking ON booking.id=plan.container_booking_id "
+ "WHERE task.task_status='LOADING' AND booking.record_status='ACTIVE' "
+ "AND task.loading_plan_id=#{loadingPlanId} AND booking.warehouse_id=#{warehouseId} LIMIT 1")
+ "AND task.loading_plan_id=#{loadingPlanId} LIMIT 1")
LoadingPickTaskEntity selectLoadingByPlan(@Param("loadingPlanId") long loadingPlanId, @Param("warehouseId") long warehouseId);
@Select("SELECT booking.* FROM fl_loading_pick_task task "
@@ -242,7 +242,7 @@ public class LoadingPickService {
public InventorySnapshot inventorySnapshot(long taskId, long warehouseId) {
LoadingPickTaskEntity task = requiredTask(taskId);
List<LoadingPickItemEntity> items = warehouseScopedItems(task, warehouseId);
List<LoadingPickItemEntity> items = taskItems(task, warehouseId);
return buildInventorySnapshot(task, warehouseId, items);
}
@@ -322,10 +322,7 @@ public class LoadingPickService {
assertReplay(replay, taskId, itemId, requestHash);
return view(task, request.warehouseId());
}
LoadingPickItemEntity item = repository.item(taskId, itemId, request.warehouseId());
if (item == null) {
throw new BizException(ResultCode.NOT_FOUND, "PDA拣货明细不存在");
}
LoadingPickItemEntity item = requireTaskItem(taskId, itemId, request.warehouseId());
if (repository.pick(itemId, request.pickedPackageCount(), request.version(), request.warehouseId()) != 1) {
throw conflict("拣货数量超过计划箱数或明细版本已变化");
}
@@ -364,7 +361,7 @@ public class LoadingPickService {
assertReplay(replay, taskId, itemId, requestHash);
return view(task, request.warehouseId());
}
requireWarehouseItem(taskId, itemId, request.warehouseId());
requireTaskItem(taskId, itemId, request.warehouseId());
if (repository.partial(itemId, request.finalPickedPackageCount(), request.version(),
request.warehouseId()) != 1) {
throw conflict("部分拣货箱数必须大于已拣箱数且小于计划箱数,或明细版本已变化");
@@ -396,7 +393,7 @@ public class LoadingPickService {
assertReplay(replay, taskId, itemId, requestHash);
return view(task, request.warehouseId());
}
LoadingPickItemEntity item = requireWarehouseItem(taskId, itemId, request.warehouseId());
LoadingPickItemEntity item = requireTaskItem(taskId, itemId, request.warehouseId());
if (repository.hasPickedOrPartialItem(taskId, item.getInboundId())) {
throw conflict("同一入库单已存在已拣或部分拣货明细,不能跳拣并恢复智能装柜候选");
}
@@ -897,10 +894,10 @@ public class LoadingPickService {
return task;
}
private LoadingPickItemEntity requireWarehouseItem(long taskId, long itemId, long warehouseId) {
private LoadingPickItemEntity requireTaskItem(long taskId, long itemId, long warehouseId) {
LoadingPickItemEntity item = repository.item(taskId, itemId, warehouseId);
if (item == null) {
throw new BizException(ResultCode.NOT_FOUND, "PDA拣货明细不存在或不属于当前仓库");
throw new BizException(ResultCode.NOT_FOUND, "PDA拣货明细不存在或不属于当前任务");
}
return item;
}
@@ -910,16 +907,12 @@ public class LoadingPickService {
if (booking == null || !Objects.equals(task.getContainerBookingId(), booking.getId())) {
throw new BizException(ResultCode.NOT_FOUND, "PDA拣货任务不存在或柜次已非有效存续记录");
}
if (warehouseId != null && !Objects.equals(warehouseId, booking.getWarehouseId())) {
throw new BizException(ResultCode.NOT_FOUND, "PDA拣货任务不存在或不属于当前仓库");
}
List<LoadingPickItemEntity> source = warehouseId == null
? repository.items(task.getId()) : repository.items(task.getId(), warehouseId);
Map<Long, List<CartonLabelRow>> cartonsByItem = repository.cartonLabels(task.getId()).stream()
.collect(Collectors.groupingBy(CartonLabelRow::getPickItemId));
Map<Long, Long> tenantByInbound = tenantByInbound(task.getId());
Map<Long, List<InventoryResource>> inventoryByInbound = inventoryByInbound(
booking.getWarehouseId(), source, tenantByInbound);
Map<Long, List<InventoryResource>> inventoryByInbound = inventoryByInbound(source, tenantByInbound);
List<PickItem> items = source.stream().map(item -> {
List<CartonLabelRow> cartons = cartonsByItem.getOrDefault(item.getId(), List.of());
CartonLabelRow first = cartons.isEmpty() ? null : cartons.get(0);
@@ -967,11 +960,11 @@ public class LoadingPickService {
private List<BatchLine> validateBatchLines(LoadingPickTaskEntity task, BatchRequest request) {
long taskId = task.getId();
List<LoadingPickItemEntity> allItems = repository.items(taskId);
List<LoadingPickItemEntity> scopedItems = repository.items(taskId, request.warehouseId());
if (allItems.isEmpty() || scopedItems.size() != allItems.size()) {
throw conflict("PDA任务柜次、仓库或客户归属不一致");
List<LoadingPickItemEntity> taskItems = repository.items(taskId, request.warehouseId());
if (allItems.isEmpty() || taskItems.size() != allItems.size()) {
throw conflict("PDA任务柜次或客户归属不一致");
}
Map<Long, LoadingPickItemEntity> itemsById = scopedItems.stream().collect(Collectors.toMap(
Map<Long, LoadingPickItemEntity> itemsById = taskItems.stream().collect(Collectors.toMap(
LoadingPickItemEntity::getId, item -> item));
Set<Long> unresolvedIds = allItems.stream().filter(item -> !isResolved(item))
.map(LoadingPickItemEntity::getId).collect(Collectors.toSet());
@@ -989,7 +982,7 @@ public class LoadingPickService {
LoadingPickItemEntity item = itemsById.get(requestItem.itemId());
if (item == null || item.getInboundId() == null || item.getLoadingPlanItemId() == null
|| item.getInboundDetailId() == null) {
throw conflict("PDA明细不属于当前任务、柜次、仓库或客户");
throw conflict("PDA明细不属于当前任务、柜次或客户");
}
if (!"SKIP".equals(requestItem.action())) {
inboundHasWork.put(item.getInboundId(), true);
@@ -1041,19 +1034,19 @@ public class LoadingPickService {
return result;
}
private List<LoadingPickItemEntity> warehouseScopedItems(LoadingPickTaskEntity task, long warehouseId) {
private List<LoadingPickItemEntity> taskItems(LoadingPickTaskEntity task, long warehouseId) {
List<LoadingPickItemEntity> allItems = repository.items(task.getId());
List<LoadingPickItemEntity> scopedItems = repository.items(task.getId(), warehouseId);
if (allItems.isEmpty() || scopedItems.size() != allItems.size()) {
throw conflict("PDA任务柜次、仓库或客户归属不一致");
List<LoadingPickItemEntity> taskItems = repository.items(task.getId(), warehouseId);
if (allItems.isEmpty() || taskItems.size() != allItems.size()) {
throw conflict("PDA任务柜次或客户归属不一致");
}
return scopedItems;
return taskItems;
}
private InventorySnapshot buildInventorySnapshot(LoadingPickTaskEntity task, long warehouseId,
List<LoadingPickItemEntity> items) {
Map<Long, List<InventoryResource>> inventoryByInbound = inventoryByInbound(
warehouseId, items, tenantByInbound(task.getId()));
items, tenantByInbound(task.getId()));
List<InboundInventory> inbounds = items.stream().map(LoadingPickItemEntity::getInboundId)
.filter(Objects::nonNull).distinct().sorted().map(inboundId -> {
List<InventoryResource> resources = inventoryByInbound.getOrDefault(inboundId, List.of());
@@ -1077,8 +1070,7 @@ public class LoadingPickService {
}));
}
private Map<Long, List<InventoryResource>> inventoryByInbound(long warehouseId,
List<LoadingPickItemEntity> items,
private Map<Long, List<InventoryResource>> inventoryByInbound(List<LoadingPickItemEntity> items,
Map<Long, Long> tenantByInbound) {
Map<Long, List<InventoryResource>> result = new HashMap<>();
for (Long inboundId : items.stream().map(LoadingPickItemEntity::getInboundId)
@@ -1086,7 +1078,6 @@ public class LoadingPickService {
Long tenantId = tenantByInbound.get(inboundId);
if (tenantId == null) throw conflict("PDA任务缺少入库单客户归属");
List<InventoryResource> resources = palletAllocations.list(tenantId, inboundId).stream()
.filter(resource -> Objects.equals(resource.getWarehouseId(), warehouseId))
.filter(resource -> "CONFIRMED".equals(resource.getAllocationStatus()))
.sorted(Comparator.comparing(InboundPalletAllocationEntity::getBlockId,
Comparator.nullsLast(Long::compareTo))
@@ -1134,7 +1125,7 @@ public class LoadingPickService {
private void validateInventorySnapshot(LoadingPickTaskEntity task, BatchRequest request,
List<BatchLine> lines) {
List<LoadingPickItemEntity> allItems = warehouseScopedItems(task, request.warehouseId());
List<LoadingPickItemEntity> allItems = taskItems(task, request.warehouseId());
InventorySnapshot current = buildInventorySnapshot(task, request.warehouseId(), allItems);
if (!current.snapshotToken().equals(request.inventorySnapshotToken().trim())) {
throw conflict("库存已变化,请刷新后重试");