fix(lastleg): unblock inbound plan handoff
This commit is contained in:
@@ -125,12 +125,18 @@ public final class LoadingPickDtos {
|
||||
Long operatorId, String operatorName, LocalDateTime createdAt) {
|
||||
}
|
||||
|
||||
public record CompletionCommand(Long id, String operationId, String status, Integer expectedTaskVersion, String remark,
|
||||
Integer attemptCount, LocalDateTime nextRetryAt, String failureStage,
|
||||
String failureCode, String requestId, String traceId,
|
||||
LocalDateTime completedAt) {
|
||||
}
|
||||
|
||||
public record Task(Long id, Long loadingPlanId, Long containerBookingId, Long inboundId,
|
||||
Integer inboundVersion, Integer loadingVersion, String cabinetNo,
|
||||
String currentContainerNo, String sourceType, String recordStatus,
|
||||
Long mergedIntoContainerBookingId, String taskStatus,
|
||||
String workflowStatus, Integer version, Assignment assignment,
|
||||
Review review, List<PickItem> items) {
|
||||
Review review, CompletionCommand completionCommand, List<PickItem> items) {
|
||||
}
|
||||
|
||||
/** PDA 工作台只展示当前作业员可领取或已领取的进行中任务。 */
|
||||
|
||||
@@ -15,6 +15,7 @@ public interface LoadingCompletedEventMapper {
|
||||
@Select("""
|
||||
SELECT p.id AS loading_plan_id, p.plan_no, p.container_booking_id, p.version AS aggregate_version,
|
||||
b.container_no, b.cabinet_no, b.warehouse_id, b.warehouse_name,
|
||||
b.customer_id AS booking_customer_id, b.customer_name,
|
||||
i.account_id, i.inbound_id AS source_inbound_id,
|
||||
COALESCE(o.root_inbound_id, o.id) AS root_inbound_id,
|
||||
o.order_id AS source_order_id, o.order_no AS source_order_no,
|
||||
@@ -79,7 +80,8 @@ public interface LoadingCompletedEventMapper {
|
||||
class Row {
|
||||
private Long loadingPlanId; private String planNo; private Long containerBookingId;
|
||||
private Integer aggregateVersion; private String containerNo; private String cabinetNo;
|
||||
private Long warehouseId; private String warehouseName; private Long accountId;
|
||||
private Long warehouseId; private String warehouseName; private Long bookingCustomerId;
|
||||
private String customerName; private Long accountId;
|
||||
private Long sourceInboundId; private Long rootInboundId; private Long sourceOrderId;
|
||||
private Long loadingPlanItemId;
|
||||
private String sourceOrderNo; private Long rootOrderId; private String inboundCode;
|
||||
|
||||
@@ -33,6 +33,9 @@ public interface LoadingCompletionCommandMapper extends BaseMapper<LoadingComple
|
||||
""")
|
||||
LoadingCompletionCommandEntity findActiveByTask(@Param("taskId") long taskId);
|
||||
|
||||
@Select("SELECT * FROM fl_loading_completion_command WHERE pick_task_id=#{taskId} ORDER BY created_at DESC LIMIT 1")
|
||||
LoadingCompletionCommandEntity findLatestByTask(@Param("taskId") long taskId);
|
||||
|
||||
@Select("""
|
||||
SELECT * FROM fl_loading_completion_command
|
||||
WHERE command_status IN ('PROCESSING','RETRYABLE') AND next_retry_at<=CURRENT_TIMESTAMP(3)
|
||||
|
||||
+1
@@ -15,6 +15,7 @@ public class LoadingCompletionCommandRepository {
|
||||
public int insert(LoadingCompletionCommandEntity command) { return mapper.insertCommand(command); }
|
||||
public LoadingCompletionCommandEntity operation(String operationId) { return mapper.findByOperation(operationId); }
|
||||
public LoadingCompletionCommandEntity active(long taskId) { return mapper.findActiveByTask(taskId); }
|
||||
public LoadingCompletionCommandEntity latest(long taskId) { return mapper.findLatestByTask(taskId); }
|
||||
public List<LoadingCompletionCommandEntity> due(int limit) { return mapper.findDue(limit); }
|
||||
public boolean claim(long id, String worker, LocalDateTime leaseUntil) { return mapper.claim(id, worker, leaseUntil) == 1; }
|
||||
public boolean renew(long id, String worker, LocalDateTime leaseUntil) { return mapper.renew(id, worker, leaseUntil) == 1; }
|
||||
|
||||
+21
-2
@@ -37,7 +37,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/** 在装柜完成事务内按客户写跨区业务 Outbox。 */
|
||||
/** 在装柜完成事务内按客户及可信客户名称快照写跨区业务 Outbox。 */
|
||||
@Service
|
||||
public class LoadingCompletedOutboxService {
|
||||
private static final long HANDOVER_VERSION = 2L;
|
||||
@@ -49,6 +49,7 @@ public class LoadingCompletedOutboxService {
|
||||
public void publish(long planId) {
|
||||
List<Row> rows = snapshotMapper.rows(planId);
|
||||
if (rows.isEmpty()) throw new BizException(ResultCode.CONFLICT, "装柜计划没有最终实装入仓单,不能生成尾程交接事件");
|
||||
validateCustomerSnapshots(rows);
|
||||
Map<Long, List<String>> cartonMarks = cartonLabelPools(rows);
|
||||
List<PalletRow> palletRows = snapshotMapper.palletRows(planId);
|
||||
rows.stream().collect(java.util.stream.Collectors.groupingBy(Row::getAccountId,
|
||||
@@ -104,10 +105,28 @@ public class LoadingCompletedOutboxService {
|
||||
first.getDestinationWarehouseCode(), first.getDestinationWarehouseName(), sumInt(sorted, Row::getPackageCount),
|
||||
sumNullableInt(sorted, Row::getProductQuantity), "ONE_CLICK_DROPSHIP".equals(orderType)
|
||||
? pallets.size() : 0, sum(sorted, Row::getGrossWeightKg), sum(sorted, Row::getNetWeightKg),
|
||||
sum(sorted, Row::getVolumeCbm), items, string(first.getAccountId()), orderType, pallets,
|
||||
sum(sorted, Row::getVolumeCbm), items, string(first.getAccountId()), first.getCustomerName().trim(), orderType, pallets,
|
||||
destinationType(sorted));
|
||||
}
|
||||
|
||||
private void validateCustomerSnapshots(List<Row> rows) {
|
||||
for (Row row : rows) {
|
||||
if (row.getAccountId() == null || !Objects.equals(row.getAccountId(), row.getBookingCustomerId())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "装柜计划客户与柜次客户快照不一致,不能生成尾程交接事件");
|
||||
}
|
||||
if (row.getCustomerName() == null || row.getCustomerName().isBlank()) {
|
||||
throw new BizException(ResultCode.CONFLICT, "柜次缺少客户名称快照,不能生成尾程交接事件");
|
||||
}
|
||||
}
|
||||
rows.stream().collect(java.util.stream.Collectors.groupingBy(Row::getAccountId)).forEach((accountId, values) -> {
|
||||
Set<String> names = values.stream().map(Row::getCustomerName).map(String::trim)
|
||||
.collect(java.util.stream.Collectors.toSet());
|
||||
if (names.size() != 1) {
|
||||
throw new BizException(ResultCode.CONFLICT, "同一客户事件存在多个客户名称快照");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 国内按实装箱数从可用标签池稳定随机抽取箱唛,重复发布同一计划时结果不变。 */
|
||||
private Map<Long, List<String>> cartonLabelPools(List<Row> rows) {
|
||||
Map<Long, List<String>> result = new java.util.LinkedHashMap<>();
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.baiyue.firstleg.dto.LoadingPickDtos.AssignRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.ReviewRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.CompleteLoadingRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.Operation;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.CompletionCommand;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.BatchRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.BatchItemRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.InventoryResource;
|
||||
@@ -837,12 +838,17 @@ public class LoadingPickService {
|
||||
.filter(value -> detailInboundId.equals(value.inboundId())).findFirst().orElse(null);
|
||||
var inbound = owner == null || owner.tenantId() == null || owner.inboundId() == null
|
||||
? null : repository.inbound(owner.tenantId(), owner.inboundId());
|
||||
LoadingCompletionCommandEntity command = completionCommands.latest(task.getId());
|
||||
CompletionCommand completionCommand = command == null ? null : new CompletionCommand(command.getId(),
|
||||
command.getOperationId(), command.getCommandStatus(), command.getExpectedTaskVersion(), command.getRemark(),
|
||||
command.getAttemptCount(), command.getNextRetryAt(), command.getFailureStage(), command.getFailureCode(),
|
||||
command.getFailureRequestId(), command.getFailureTraceId(), command.getCompletedAt());
|
||||
return new Task(task.getId(), task.getLoadingPlanId(), task.getContainerBookingId(),
|
||||
owner == null ? null : owner.inboundId(), inbound == null ? null : inbound.version(),
|
||||
inbound == null ? null : inbound.version(), task.getCabinetNo(),
|
||||
booking.getContainerNo(), booking.getSourceType(), booking.getRecordStatus(),
|
||||
booking.getMergedIntoContainerBookingId(), task.getTaskStatus(),
|
||||
workflowStatus, task.getVersion(), assignment, review, items);
|
||||
workflowStatus, task.getVersion(), assignment, review, completionCommand, items);
|
||||
}
|
||||
|
||||
private List<BatchLine> validateBatchLines(LoadingPickTaskEntity task, BatchRequest request) {
|
||||
|
||||
Reference in New Issue
Block a user