fix: 按物理箱贯通一件代发履约箱数
This commit is contained in:
+44
-12
@@ -21,18 +21,44 @@ public interface LoadingModelBridgeMapper extends BaseMapper<PreloadLoadingPlanL
|
||||
+ "ON b.id=p.container_booking_id WHERE p.id=#{loadingPlanId}")
|
||||
LoadingPlanSnapshot loadingPlan(@Param("loadingPlanId") long loadingPlanId);
|
||||
|
||||
@Select("SELECT COALESCE(SUM(package_count),0) FROM fl_loading_plan_item "
|
||||
+ "WHERE loading_plan_id=#{loadingPlanId} AND account_id=#{tenantId} "
|
||||
+ "AND inbound_id=#{inboundId} AND deleted=0")
|
||||
@Select("""
|
||||
SELECT COALESCE(SUM(CASE WHEN item.pallet_id IS NULL THEN item.package_count ELSE 0 END),0)
|
||||
+ COALESCE((SELECT COUNT(DISTINCT carton.id)
|
||||
FROM fl_dropship_pallet_carton carton
|
||||
WHERE carton.tenant_id=#{tenantId} AND carton.inbound_id=#{inboundId}
|
||||
AND EXISTS (SELECT 1 FROM fl_loading_plan_item pallet_item
|
||||
WHERE pallet_item.loading_plan_id=#{loadingPlanId}
|
||||
AND pallet_item.account_id=#{tenantId}
|
||||
AND pallet_item.inbound_id=#{inboundId}
|
||||
AND pallet_item.pallet_id=carton.pallet_id
|
||||
AND pallet_item.deleted=0)),0)
|
||||
FROM fl_loading_plan_item item
|
||||
WHERE item.loading_plan_id=#{loadingPlanId} AND item.account_id=#{tenantId}
|
||||
AND item.inbound_id=#{inboundId} AND item.deleted=0
|
||||
""")
|
||||
int allocatedPackages(@Param("tenantId") long tenantId, @Param("inboundId") long inboundId,
|
||||
@Param("loadingPlanId") long loadingPlanId);
|
||||
|
||||
@Select("SELECT item.account_id tenantId,item.inbound_id inboundId,"
|
||||
+ "COALESCE(SUM(item.package_count),0) allocatedPackageCount,MAX(inbound.process_status) processStatus "
|
||||
+ "FROM fl_loading_plan_item item JOIN fl_inbound_order inbound "
|
||||
+ "ON inbound.tenant_id=item.account_id AND inbound.id=item.inbound_id AND inbound.deleted=0 "
|
||||
+ "WHERE item.loading_plan_id=#{loadingPlanId} AND item.deleted=0 "
|
||||
+ "GROUP BY item.account_id,item.inbound_id HAVING SUM(item.package_count)>0")
|
||||
@Select("""
|
||||
SELECT item.account_id tenantId,item.inbound_id inboundId,
|
||||
COALESCE(SUM(CASE WHEN item.pallet_id IS NULL THEN item.package_count ELSE 0 END),0)
|
||||
+ COALESCE((SELECT COUNT(DISTINCT carton.id)
|
||||
FROM fl_dropship_pallet_carton carton
|
||||
WHERE carton.tenant_id=item.account_id AND carton.inbound_id=item.inbound_id
|
||||
AND EXISTS (SELECT 1 FROM fl_loading_plan_item pallet_item
|
||||
WHERE pallet_item.loading_plan_id=#{loadingPlanId}
|
||||
AND pallet_item.account_id=item.account_id
|
||||
AND pallet_item.inbound_id=item.inbound_id
|
||||
AND pallet_item.pallet_id=carton.pallet_id
|
||||
AND pallet_item.deleted=0)),0) allocatedPackageCount,
|
||||
MAX(inbound.process_status) processStatus
|
||||
FROM fl_loading_plan_item item
|
||||
JOIN fl_inbound_order inbound ON inbound.tenant_id=item.account_id
|
||||
AND inbound.id=item.inbound_id AND inbound.deleted=0
|
||||
WHERE item.loading_plan_id=#{loadingPlanId} AND item.deleted=0
|
||||
GROUP BY item.account_id,item.inbound_id
|
||||
HAVING allocatedPackageCount>0
|
||||
""")
|
||||
List<AllocationScope> allocatedScopes(@Param("loadingPlanId") long loadingPlanId);
|
||||
|
||||
@Update("UPDATE fl_preload_plan SET updated_by=#{operatorId},updated_by_name=#{operatorName},"
|
||||
@@ -76,9 +102,15 @@ public interface LoadingModelBridgeMapper extends BaseMapper<PreloadLoadingPlanL
|
||||
preload.version preloadVersion,link.loading_plan_id loadingPlanId,
|
||||
plan.container_booking_id containerBookingId,booking.container_no containerNo,
|
||||
plan.plan_status loadingPlanStatus,plan.version loadingPlanVersion,
|
||||
COALESCE((SELECT SUM(item.package_count) FROM fl_loading_plan_item item
|
||||
WHERE item.loading_plan_id=link.loading_plan_id AND item.account_id=link.tenant_id
|
||||
AND item.inbound_id=link.inbound_id AND item.deleted=0),0) allocatedPackageCount,
|
||||
COALESCE((SELECT SUM(CASE WHEN item.pallet_id IS NULL THEN item.package_count ELSE 0 END)
|
||||
FROM fl_loading_plan_item item WHERE item.loading_plan_id=link.loading_plan_id
|
||||
AND item.account_id=link.tenant_id AND item.inbound_id=link.inbound_id AND item.deleted=0),0)
|
||||
+ COALESCE((SELECT COUNT(DISTINCT carton.id) FROM fl_dropship_pallet_carton carton
|
||||
WHERE carton.tenant_id=link.tenant_id AND carton.inbound_id=link.inbound_id
|
||||
AND EXISTS (SELECT 1 FROM fl_loading_plan_item pallet_item
|
||||
WHERE pallet_item.loading_plan_id=link.loading_plan_id
|
||||
AND pallet_item.account_id=link.tenant_id AND pallet_item.inbound_id=link.inbound_id
|
||||
AND pallet_item.pallet_id=carton.pallet_id AND pallet_item.deleted=0)),0) allocatedPackageCount,
|
||||
link.created_at linkedAt
|
||||
FROM fl_preload_loading_plan_link link
|
||||
JOIN fl_preload_plan preload ON preload.id=link.preload_plan_id
|
||||
|
||||
@@ -83,15 +83,19 @@ public interface LoadingCompletedEventMapper {
|
||||
SELECT carton.tenant_id AS account_id,carton.inbound_id AS source_inbound_id,
|
||||
pallet.id AS pallet_id,1 AS actual_binding,
|
||||
pallet.pallet_no AS pallet_code,NULL AS allocation_no,
|
||||
COUNT(*) OVER (PARTITION BY pallet.id,carton.tenant_id,carton.inbound_id) AS allocated_package_count,
|
||||
carton.inbound_detail_id AS source_inbound_detail_id,carton.sku_code,
|
||||
(SELECT COUNT(*) FROM fl_dropship_pallet_carton physical
|
||||
WHERE physical.pallet_id=pallet.id AND physical.tenant_id=carton.tenant_id
|
||||
AND physical.inbound_id=carton.inbound_id) AS allocated_package_count,
|
||||
COALESCE(carton_sku.inbound_detail_id,carton.inbound_detail_id) AS source_inbound_detail_id,
|
||||
COALESCE(carton_sku.sku_code,carton.sku_code) AS sku_code,
|
||||
item.product_name_zh,item.package_count,item.product_quantity,carton.box_code,
|
||||
carton.actual_sku_quantity
|
||||
COALESCE(carton_sku.actual_quantity,carton.actual_sku_quantity) AS actual_sku_quantity
|
||||
FROM fl_dropship_pallet pallet
|
||||
JOIN fl_dropship_pallet_carton carton ON carton.pallet_id=pallet.id
|
||||
LEFT JOIN fl_dropship_pallet_carton_sku carton_sku ON carton_sku.carton_id=carton.id
|
||||
JOIN fl_loading_plan_item item ON item.loading_plan_id=#{planId}
|
||||
AND item.account_id=carton.tenant_id AND item.inbound_id=carton.inbound_id
|
||||
AND item.inbound_detail_id=carton.inbound_detail_id
|
||||
AND item.inbound_detail_id=COALESCE(carton_sku.inbound_detail_id,carton.inbound_detail_id)
|
||||
AND item.pallet_id=pallet.id AND item.deleted=0
|
||||
WHERE pallet.pallet_status='SEALED'
|
||||
ORDER BY carton.tenant_id,carton.inbound_id,pallet.id,item.inbound_detail_id,carton.id
|
||||
|
||||
@@ -83,14 +83,34 @@ public interface LoadingPickItemMapper extends BaseMapper<LoadingPickItemEntity>
|
||||
@Param("operatorName") String operatorName);
|
||||
|
||||
@Select("""
|
||||
SELECT COALESCE(SUM(CASE
|
||||
SELECT COALESCE(SUM(CASE WHEN plan_item.pallet_id IS NOT NULL THEN 0
|
||||
WHEN pick_item.item_status='SKIPPED' AND pick_item.picked_package_count=0 THEN 0
|
||||
WHEN pick_item.item_status='PARTIAL' AND pick_item.picked_package_count>0
|
||||
AND pick_item.picked_package_count<=plan_item.package_count
|
||||
THEN pick_item.picked_package_count
|
||||
ELSE plan_item.package_count
|
||||
END),0) expectedCount,
|
||||
COALESCE(SUM(pick_item.picked_package_count),0) pickedCount,
|
||||
END),0)
|
||||
+ COALESCE((SELECT COUNT(DISTINCT carton.id)
|
||||
FROM fl_dropship_pallet_carton carton
|
||||
WHERE carton.tenant_id=#{tenantId} AND carton.inbound_id=#{inboundId}
|
||||
AND EXISTS (SELECT 1 FROM fl_loading_plan_item pallet_plan
|
||||
WHERE pallet_plan.account_id=#{tenantId}
|
||||
AND pallet_plan.inbound_id=#{inboundId}
|
||||
AND pallet_plan.pallet_id=carton.pallet_id
|
||||
AND pallet_plan.deleted=0)),0) expectedCount,
|
||||
COALESCE(SUM(CASE WHEN plan_item.pallet_id IS NULL
|
||||
THEN pick_item.picked_package_count ELSE 0 END),0)
|
||||
+ COALESCE((SELECT COUNT(DISTINCT carton.id)
|
||||
FROM fl_dropship_pallet_carton carton
|
||||
WHERE carton.tenant_id=#{tenantId} AND carton.inbound_id=#{inboundId}
|
||||
AND EXISTS (SELECT 1 FROM fl_loading_plan_item picked_plan
|
||||
JOIN fl_loading_pick_item picked_item
|
||||
ON picked_item.loading_plan_item_id=picked_plan.id
|
||||
WHERE picked_plan.account_id=#{tenantId}
|
||||
AND picked_plan.inbound_id=#{inboundId}
|
||||
AND picked_plan.pallet_id=carton.pallet_id
|
||||
AND picked_plan.deleted=0
|
||||
AND picked_item.item_status='PICKED')),0) pickedCount,
|
||||
COUNT(DISTINCT pick_task.id) taskCount,
|
||||
COUNT(DISTINCT CASE WHEN pick_task.task_status='COMPLETED' THEN pick_task.id END) completedTaskCount,
|
||||
SUM(CASE
|
||||
|
||||
@@ -88,16 +88,23 @@ public interface LoadingPickTaskMapper extends BaseMapper<LoadingPickTaskEntity>
|
||||
WHEN task.task_status = 'COMPLETING' THEN 'PROCESSING'
|
||||
WHEN task.task_status = 'COMPLETION_FAILED' THEN 'COMPLETION_FAILED'
|
||||
WHEN assignment.pick_task_id IS NULL THEN 'UNASSIGNED'
|
||||
WHEN SUM(CASE WHEN pick_item.item_status IN ('PENDING', 'PICKING') THEN 1 ELSE 0 END) = 0
|
||||
WHEN COUNT(DISTINCT CASE WHEN pick_item.item_status IN ('PENDING', 'PICKING')
|
||||
THEN CASE WHEN plan_item.pallet_id IS NULL THEN CONCAT('I:',pick_item.id)
|
||||
ELSE CONCAT('P:',plan_item.pallet_id) END END) = 0
|
||||
THEN 'AWAITING_REVIEW'
|
||||
ELSE 'IN_PROGRESS' END AS workflowStatus,
|
||||
task.version AS version, COALESCE(assignment.version, 0) AS assignmentVersion,
|
||||
COUNT(pick_item.id) AS itemCount,
|
||||
SUM(CASE WHEN pick_item.item_status IN ('PENDING', 'PICKING') THEN 1 ELSE 0 END) AS pendingItemCount
|
||||
COUNT(DISTINCT CASE WHEN plan_item.pallet_id IS NULL THEN CONCAT('I:',pick_item.id)
|
||||
ELSE CONCAT('P:',plan_item.pallet_id) END) AS itemCount,
|
||||
COUNT(DISTINCT CASE WHEN pick_item.item_status IN ('PENDING', 'PICKING')
|
||||
THEN CASE WHEN plan_item.pallet_id IS NULL THEN CONCAT('I:',pick_item.id)
|
||||
ELSE CONCAT('P:',plan_item.pallet_id) END END) AS pendingItemCount
|
||||
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
|
||||
JOIN fl_loading_pick_item pick_item ON pick_item.pick_task_id = task.id
|
||||
JOIN fl_loading_plan_item plan_item ON plan_item.id=pick_item.loading_plan_item_id
|
||||
AND plan_item.loading_plan_id=plan.id AND plan_item.deleted=0
|
||||
LEFT JOIN fl_loading_pick_assignment assignment ON assignment.pick_task_id = task.id
|
||||
WHERE task.task_status IN ('LOADING','COMPLETING','COMPLETION_FAILED') AND booking.record_status = 'ACTIVE'
|
||||
AND booking.warehouse_id = #{warehouseId}
|
||||
|
||||
+16
-6
@@ -175,10 +175,12 @@ public class LoadingCompletedOutboxService {
|
||||
}
|
||||
Integer frozenPalletCount = dropship(fulfillmentType) || standardLabels.isEmpty()
|
||||
? actualPalletCount(palletRows) : Integer.valueOf(standardLabels.size());
|
||||
int physicalPackageCount = dropship(fulfillmentType)
|
||||
? physicalPackageCount(palletRows) : sumInt(sorted, Row::getPackageCount);
|
||||
return new FirstLegLoadingPlanCompletedV2.Order(string(first.getSourceInboundId()),
|
||||
string(first.getRootInboundId()), string(first.getSourceOrderId()), first.getSourceOrderNo(),
|
||||
string(first.getRootOrderId()), first.getInboundCode(), string(first.getDestinationWarehouseId()),
|
||||
first.getDestinationWarehouseCode(), first.getDestinationWarehouseName(), sumInt(sorted, Row::getPackageCount),
|
||||
first.getDestinationWarehouseCode(), first.getDestinationWarehouseName(), physicalPackageCount,
|
||||
sumNullableInt(sorted, Row::getProductQuantity), frozenPalletCount,
|
||||
sum(sorted, Row::getGrossWeightKg), sum(sorted, Row::getNetWeightKg),
|
||||
sum(sorted, Row::getVolumeCbm), sum(sorted, Row::getDimensionalWeightKg), items,
|
||||
@@ -346,7 +348,7 @@ public class LoadingCompletedOutboxService {
|
||||
Map<String, List<PalletRow>> byPallet = source.stream().collect(java.util.stream.Collectors.groupingBy(
|
||||
PalletRow::getPalletCode, LinkedHashMap::new, java.util.stream.Collectors.toList()));
|
||||
List<FirstLegLoadingPlanCompletedV2.PalletSnapshot> result = new ArrayList<>();
|
||||
int actualPackages = 0;
|
||||
Set<String> actualPackages = new HashSet<>();
|
||||
for (Map.Entry<String, List<PalletRow>> pallet : byPallet.entrySet()) {
|
||||
Map<Long, List<PalletRow>> byDetail = pallet.getValue().stream().collect(
|
||||
java.util.stream.Collectors.groupingBy(PalletRow::getSourceInboundDetailId,
|
||||
@@ -365,14 +367,14 @@ public class LoadingCompletedOutboxService {
|
||||
if (quantity <= 0) throw new BizException(ResultCode.CONFLICT, "一件代发现场托盘缺少实点 SKU 数量");
|
||||
skus.add(new FirstLegLoadingPlanCompletedV2.SkuPackageSnapshot(detail.getSourceInboundDetailId().toString(), detail.getSkuCode(),
|
||||
detail.getProductNameZh(), marks.size(), quantity, marks, cartonQuantities(detailRows.getValue(), marks)));
|
||||
actualPackages += marks.size();
|
||||
marks.forEach(mark -> actualPackages.add(pallet.getKey() + '|' + mark));
|
||||
}
|
||||
PalletManifest manifest = manifests.get(pallet.getKey());
|
||||
if (manifest == null) throw new BizException(ResultCode.CONFLICT, "一件代发托盘缺少完整清单摘要");
|
||||
result.add(new FirstLegLoadingPlanCompletedV2.PalletSnapshot(pallet.getKey(), skus,
|
||||
manifest.version(), manifest.packageCount(), manifest.fragmentCount(), manifest.hash()));
|
||||
}
|
||||
if (actualPackages != sumInt(values, Row::getPackageCount)) {
|
||||
if (actualPackages.size() != physicalPackageCount(source)) {
|
||||
throw new BizException(ResultCode.CONFLICT, "一件代发现场托盘箱唛数与实装箱数不一致");
|
||||
}
|
||||
return result;
|
||||
@@ -390,13 +392,21 @@ public class LoadingCompletedOutboxService {
|
||||
String canonical = sorted.stream().map(value -> value.getAccountId() + "|" + value.getSourceInboundId()
|
||||
+ "|" + value.getSourceInboundDetailId() + "|" + value.getSkuCode() + "|" + value.getBoxCode()
|
||||
+ "|" + value.getActualSkuQuantity()).collect(java.util.stream.Collectors.joining("\n"));
|
||||
int fragments = (int) sorted.stream().map(PalletRow::getAccountId).distinct().count();
|
||||
result.put(palletNo, new PalletManifest(1, sorted.size(), fragments,
|
||||
int fragments = (int) sorted.stream().map(value -> value.getAccountId() + ":" + value.getSourceInboundId())
|
||||
.distinct().count();
|
||||
int packages = (int) sorted.stream().map(PalletRow::getBoxCode)
|
||||
.filter(Objects::nonNull).distinct().count();
|
||||
result.put(palletNo, new PalletManifest(1, packages, fragments,
|
||||
manifestHash(canonical)));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int physicalPackageCount(List<PalletRow> rows) {
|
||||
return (int) rows.stream().map(row -> row.getPalletCode() + '|' + row.getBoxCode())
|
||||
.distinct().count();
|
||||
}
|
||||
|
||||
private String manifestHash(String canonical) {
|
||||
String value = EventPayloadHash.sha256(canonical.getBytes(StandardCharsets.UTF_8));
|
||||
return value.substring("sha256:".length());
|
||||
|
||||
@@ -961,19 +961,7 @@ public class LoadingPickService {
|
||||
.collect(Collectors.groupingBy(CartonLabelRow::getPickItemId));
|
||||
Map<Long, Long> tenantByInbound = tenantByInbound(task.getId());
|
||||
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);
|
||||
Long tenantId = first == null ? tenantByInbound.get(item.getInboundId()) : first.getTenantId();
|
||||
return new PickItem(item.getId(), item.getLoadingPlanItemId(), tenantId,
|
||||
item.getInboundId(),
|
||||
item.getInboundDetailId(), item.getUnitType(), item.getPalletId(), item.getPalletNo(), item.getIndivisible(),
|
||||
first == null ? null : first.getOrderNo(),
|
||||
first == null ? null : first.getInboundCode(), first == null ? null : first.getCargoName(),
|
||||
cartons.stream().map(CartonLabelRow::getBoxCode).toList(),
|
||||
inventoryByInbound.getOrDefault(item.getInboundId(), List.of()), item.getPlannedPackageCount(),
|
||||
item.getPickedPackageCount(), item.getItemStatus(), item.getVersion());
|
||||
}).toList();
|
||||
List<PickItem> items = pickItems(source, cartonsByItem, tenantByInbound, inventoryByInbound);
|
||||
LoadingPickAssignmentEntity assigned = repository.assignment(task.getId());
|
||||
LoadingPickReviewEntity reviewed = repository.review(task.getId());
|
||||
Assignment assignment = assigned == null ? null : new Assignment(assigned.getAssigneeId(),
|
||||
@@ -1006,6 +994,71 @@ public class LoadingPickService {
|
||||
workflowStatus, task.getVersion(), assignment, review, completionCommand, items);
|
||||
}
|
||||
|
||||
/** One sealed pallet is one physical PDA work unit even when its cartons contain several SKU snapshots. */
|
||||
private List<PickItem> pickItems(List<LoadingPickItemEntity> source,
|
||||
Map<Long, List<CartonLabelRow>> cartonsByItem,
|
||||
Map<Long, Long> tenantByInbound,
|
||||
Map<Long, List<InventoryResource>> inventoryByInbound) {
|
||||
Map<String, List<LoadingPickItemEntity>> units = source.stream().collect(Collectors.groupingBy(
|
||||
item -> "SEALED_PALLET".equals(item.getUnitType()) && item.getPalletId() != null
|
||||
? "P:" + item.getPalletId() : "I:" + item.getId(),
|
||||
LinkedHashMap::new, Collectors.toList()));
|
||||
Set<Long> palletIds = units.values().stream().map(items -> items.get(0))
|
||||
.filter(item -> "SEALED_PALLET".equals(item.getUnitType()) && item.getPalletId() != null)
|
||||
.map(LoadingPickItemEntity::getPalletId).collect(Collectors.toSet());
|
||||
Map<Long, com.baiyue.firstleg.mapper.DropshipPalletizationMapper.PalletMetrics> physical =
|
||||
palletIds.isEmpty() ? Map.of() : dropshipPalletizationMapper.physicalMetricsByPalletIds(palletIds).stream()
|
||||
.collect(Collectors.toMap(
|
||||
com.baiyue.firstleg.mapper.DropshipPalletizationMapper.PalletMetrics::palletId,
|
||||
java.util.function.Function.identity()));
|
||||
List<PickItem> result = new ArrayList<>();
|
||||
for (List<LoadingPickItemEntity> members : units.values()) {
|
||||
LoadingPickItemEntity firstItem = members.get(0);
|
||||
List<CartonLabelRow> cartons = members.stream()
|
||||
.flatMap(item -> cartonsByItem.getOrDefault(item.getId(), List.of()).stream()).toList();
|
||||
CartonLabelRow firstCarton = cartons.isEmpty() ? null : cartons.get(0);
|
||||
Long tenantId = firstCarton == null ? tenantByInbound.get(firstItem.getInboundId())
|
||||
: firstCarton.getTenantId();
|
||||
List<String> boxCodes = cartons.stream().map(CartonLabelRow::getBoxCode)
|
||||
.filter(StringUtils::hasText).distinct().toList();
|
||||
List<InventoryResource> inventory = members.stream()
|
||||
.flatMap(item -> inventoryByInbound.getOrDefault(item.getInboundId(), List.of()).stream())
|
||||
.collect(Collectors.collectingAndThen(Collectors.toMap(
|
||||
resource -> resource.reservationId() == null ? "L:" + resource.locationId()
|
||||
: "R:" + resource.reservationId(),
|
||||
java.util.function.Function.identity(), (left, right) -> left, LinkedHashMap::new),
|
||||
values -> List.copyOf(values.values())));
|
||||
if (!"SEALED_PALLET".equals(firstItem.getUnitType()) || firstItem.getPalletId() == null) {
|
||||
result.add(new PickItem(firstItem.getId(), firstItem.getLoadingPlanItemId(), tenantId,
|
||||
firstItem.getInboundId(), firstItem.getInboundDetailId(), firstItem.getUnitType(),
|
||||
firstItem.getPalletId(), firstItem.getPalletNo(), firstItem.getIndivisible(),
|
||||
firstCarton == null ? null : firstCarton.getOrderNo(),
|
||||
firstCarton == null ? null : firstCarton.getInboundCode(),
|
||||
firstCarton == null ? null : firstCarton.getCargoName(), boxCodes, inventory,
|
||||
firstItem.getPlannedPackageCount(), firstItem.getPickedPackageCount(),
|
||||
firstItem.getItemStatus(), firstItem.getVersion()));
|
||||
continue;
|
||||
}
|
||||
var metrics = physical.get(firstItem.getPalletId());
|
||||
if (metrics == null || count(metrics.cartonCount()) < 1) {
|
||||
throw conflict("托盘缺少物理箱明细,不能生成PDA整托任务");
|
||||
}
|
||||
boolean picked = members.stream().allMatch(item -> "PICKED".equals(item.getItemStatus()));
|
||||
boolean pending = members.stream().allMatch(item -> "PENDING".equals(item.getItemStatus())
|
||||
&& count(item.getPickedPackageCount()) == 0);
|
||||
String status = picked ? "PICKED" : pending ? "PENDING" : "PICKING";
|
||||
int version = members.stream().map(LoadingPickItemEntity::getVersion).filter(Objects::nonNull)
|
||||
.max(Integer::compareTo).orElse(0);
|
||||
result.add(new PickItem(firstItem.getId(), firstItem.getLoadingPlanItemId(), tenantId,
|
||||
firstItem.getInboundId(), firstItem.getInboundDetailId(), "SEALED_PALLET",
|
||||
firstItem.getPalletId(), firstItem.getPalletNo(), true,
|
||||
firstCarton == null ? null : firstCarton.getOrderNo(),
|
||||
firstCarton == null ? null : firstCarton.getInboundCode(), null, boxCodes, inventory,
|
||||
metrics.cartonCount(), picked ? metrics.cartonCount() : 0, status, version));
|
||||
}
|
||||
return List.copyOf(result);
|
||||
}
|
||||
|
||||
private List<BatchLine> validateBatchLines(LoadingPickTaskEntity task, BatchRequest request) {
|
||||
long taskId = task.getId();
|
||||
List<LoadingPickItemEntity> allItems = repository.items(taskId);
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.baiyue.firstleg.entity.LoadingPickItemEntity;
|
||||
import com.baiyue.firstleg.mapper.InboundSplitSettlementMapper;
|
||||
import com.baiyue.firstleg.mapper.InboundSplitSettlementMapper.MeasurementItemRow;
|
||||
import com.baiyue.firstleg.mapper.InboundSplitSettlementMapper.ParentRow;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper;
|
||||
import com.baiyue.firstleg.repository.InboundPalletAllocationRepository;
|
||||
import com.baiyue.firstleg.repository.LoadingPickRepository;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
@@ -50,6 +51,8 @@ public class PdaPickSettlementService {
|
||||
private OrderFulfillmentSplitClient orderSplits;
|
||||
@Resource
|
||||
private InboundHoldGuard inboundHoldGuard;
|
||||
@Resource
|
||||
private DropshipPalletizationMapper dropshipPallets;
|
||||
@Value("${baiyue.security.internal-service-token}")
|
||||
private String internalToken;
|
||||
|
||||
@@ -173,13 +176,14 @@ public class PdaPickSettlementService {
|
||||
if (measurements.stream().anyMatch(item -> !Objects.equals(sourceMeasurementId, item.measurementId()))) {
|
||||
throw conflict("主入库单存在多个已审核测量批次,不能自动拆分");
|
||||
}
|
||||
Map<Long, Integer> pickedByDetail = pickedByDetail(taskItems, parentInboundId);
|
||||
int pickedByMeasurement = pickedByDetail.values().stream().mapToInt(Integer::intValue).sum();
|
||||
if (pickedByMeasurement != pickedPackageCount) {
|
||||
throw conflict("PDA 已拣明细与入库单已拣箱数不一致");
|
||||
}
|
||||
boolean dropshipWholePallet = "ONE_CLICK_DROPSHIP".equals(
|
||||
splits.fulfillmentType(parent.tenantId(), parentInboundId));
|
||||
Map<Long, Integer> pickedByDetail = dropshipWholePallet
|
||||
? Map.of() : pickedByDetail(taskItems, parentInboundId);
|
||||
if (!dropshipWholePallet
|
||||
&& pickedByDetail.values().stream().mapToInt(Integer::intValue).sum() != pickedPackageCount) {
|
||||
throw conflict("PDA 已拣明细与入库单已拣箱数不一致");
|
||||
}
|
||||
if (dropshipWholePallet && childPackageCount != 0) {
|
||||
throw conflict("一件代发现场托盘必须整票装柜,不能生成余量分片");
|
||||
}
|
||||
@@ -192,8 +196,7 @@ public class PdaPickSettlementService {
|
||||
}
|
||||
|
||||
if (root == null || !"MASTER".equals(root.inboundRole())) throw conflict("根主入库单不存在");
|
||||
Map<Long, Integer> orderQuantities = dropshipWholePallet
|
||||
? new LinkedHashMap<>(pickedByDetail) : measurementQuantities(measurementLines);
|
||||
Map<Long, Integer> orderQuantities = measurementQuantities(measurementLines);
|
||||
OrderFulfillmentSplitClient.Response orderSplit = createOrderSplit(parent, root, orderQuantities,
|
||||
pickedPackageCount, childPackageCount, loadingPlanId, containerBookingId, operationId,
|
||||
"pda-task-" + taskId, operatorId, operatorName);
|
||||
@@ -337,11 +340,35 @@ public class PdaPickSettlementService {
|
||||
&& Objects.equals(child.containerBookingId(), containerBookingId);
|
||||
}
|
||||
|
||||
private static Map<Long, Integer> pickedByInbound(List<LoadingPickItemEntity> taskItems) {
|
||||
return taskItems.stream().filter(item -> "PICKED".equals(item.getItemStatus())
|
||||
|| "PARTIAL".equals(item.getItemStatus()))
|
||||
.collect(Collectors.groupingBy(LoadingPickItemEntity::getInboundId,
|
||||
Collectors.summingInt(item -> count(item.getPickedPackageCount(), "PDA已拣箱数"))));
|
||||
private Map<Long, Integer> pickedByInbound(List<LoadingPickItemEntity> taskItems) {
|
||||
Map<Long, Integer> result = new HashMap<>();
|
||||
Set<Long> pickedPalletIds = new java.util.LinkedHashSet<>();
|
||||
for (LoadingPickItemEntity item : taskItems) {
|
||||
if (!("PICKED".equals(item.getItemStatus()) || "PARTIAL".equals(item.getItemStatus()))) continue;
|
||||
if ("SEALED_PALLET".equals(item.getUnitType()) && item.getPalletId() != null) {
|
||||
pickedPalletIds.add(item.getPalletId());
|
||||
} else {
|
||||
result.merge(item.getInboundId(), count(item.getPickedPackageCount(), "PDA已拣箱数"), Integer::sum);
|
||||
}
|
||||
}
|
||||
if (pickedPalletIds.isEmpty()) return result;
|
||||
Map<Long, List<LoadingPickItemEntity>> palletItems = taskItems.stream()
|
||||
.filter(item -> item.getPalletId() != null && pickedPalletIds.contains(item.getPalletId()))
|
||||
.collect(Collectors.groupingBy(LoadingPickItemEntity::getPalletId));
|
||||
if (palletItems.values().stream().anyMatch(items -> items.stream()
|
||||
.anyMatch(item -> !"PICKED".equals(item.getItemStatus())))) {
|
||||
throw conflict("一件代发整托存在未完成的 SKU 明细,不能结算物理箱数");
|
||||
}
|
||||
List<DropshipPalletizationMapper.PlanPalletMemberRow> physical =
|
||||
dropshipPallets.palletInboundMembersByPalletIds(pickedPalletIds);
|
||||
Set<Long> resolvedPallets = physical.stream().map(DropshipPalletizationMapper.PlanPalletMemberRow::getPalletId)
|
||||
.collect(Collectors.toSet());
|
||||
if (!resolvedPallets.equals(pickedPalletIds)) {
|
||||
throw conflict("一件代发托盘缺少物理箱明细,不能完成装柜结算");
|
||||
}
|
||||
physical.forEach(row -> result.merge(row.getInboundId(),
|
||||
count(row.getAvailablePackageCount(), "托盘物理箱数"), Integer::sum));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Map<Long, Integer> pickedByDetail(List<LoadingPickItemEntity> taskItems, long inboundId) {
|
||||
|
||||
Reference in New Issue
Block a user