发布当前测试版本至临时灰度环境 #19
@@ -690,7 +690,6 @@ public class LoadingPickService {
|
||||
}
|
||||
runCompletionStage("PLAN_COMPLETE", () -> loadingListService.finishFromPda(task.getLoadingPlanId(), taskId,
|
||||
command.getOperatorId(), command.getOperatorName()));
|
||||
repository.syncInboundProjections(taskId, command.getOperatorId(), command.getOperatorName());
|
||||
runCompletionStage("COMPLETED_EVENT", () -> loadingListService.publishCompletedEvent(task.getLoadingPlanId()));
|
||||
for (GroupSnapshot group : taskGroups) {
|
||||
runCompletionStage("COLOAD_CONSUME", () -> coloadGroups.consumeWholeGroup(group.groupId(),
|
||||
@@ -703,6 +702,7 @@ public class LoadingPickService {
|
||||
&& repository.completeAccepted(taskId, command.getOperatorId(), command.getOperatorName()) != 1) {
|
||||
throw new CompletionProcessingException("TASK_FINALIZE", conflict("PDA任务完成状态已变化"));
|
||||
}
|
||||
repository.syncInboundProjections(taskId, command.getOperatorId(), command.getOperatorName());
|
||||
if (!completionCommands.complete(command.getId(), worker)) {
|
||||
throw new CompletionProcessingException("COMMAND_FINALIZE", conflict("装柜完成命令租约已变化"));
|
||||
}
|
||||
|
||||
@@ -1060,6 +1060,41 @@ class LoadingPickServiceTest {
|
||||
verify(completionCommands).complete(900L, "worker-1");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"COMPLETING", "COMPLETED"})
|
||||
void workerRefreshesInboundProgressAfterTaskCompletionIncludingRetry(String initialTaskStatus) {
|
||||
LoadingPickTaskEntity task = task();
|
||||
task.setTaskStatus(initialTaskStatus);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.inboundOwners(20L)).thenReturn(List.of(
|
||||
new LoadingPickItemMapper.InboundOwner(101L, 50L)));
|
||||
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
|
||||
when(repository.approve(20L, 9L, "operator", "checked")).thenReturn(1);
|
||||
when(repository.completeAccepted(20L, 9L, "operator")).thenAnswer(invocation -> {
|
||||
task.setTaskStatus("COMPLETED");
|
||||
return 1;
|
||||
});
|
||||
AtomicReference<String> projectedStatus = new AtomicReference<>();
|
||||
doAnswer(invocation -> {
|
||||
projectedStatus.set("COMPLETED".equals(task.getTaskStatus()) ? "COMPLETED" : "IN_PROGRESS");
|
||||
return null;
|
||||
}).when(repository).syncInboundProjections(20L, 9L, "operator");
|
||||
when(completionCommands.complete(925L, "worker-projection")).thenReturn(true);
|
||||
|
||||
service.processCompletion(completionCommand(925L, "async-projection"), "worker-projection");
|
||||
|
||||
assertThat(projectedStatus.get()).isEqualTo("COMPLETED");
|
||||
verify(repository, times(1)).syncInboundProjections(20L, 9L, "operator");
|
||||
if ("COMPLETING".equals(initialTaskStatus)) {
|
||||
InOrder finalization = inOrder(repository, completionCommands);
|
||||
finalization.verify(repository).completeAccepted(20L, 9L, "operator");
|
||||
finalization.verify(repository).syncInboundProjections(20L, 9L, "operator");
|
||||
finalization.verify(completionCommands).complete(925L, "worker-projection");
|
||||
} else {
|
||||
verify(repository, never()).completeAccepted(anyLong(), anyLong(), anyString());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "truck state {0} never participates in PDA completion")
|
||||
@ValueSource(strings = {"NO_APPOINTMENT", "DRAFT", "IN_PROGRESS", "COMPLETED"})
|
||||
void completionWorkerIsIndependentOfEveryTruckAppointmentState(String truckState) {
|
||||
|
||||
@@ -121,6 +121,8 @@ test('HTTP chain refreshes after stale inventory and keeps one stable PDA identi
|
||||
})
|
||||
|
||||
test('downstream finalizer uses the frozen loading complete contract without truck coupling', () => {
|
||||
assert.match(finalize, /unifiedDetail\?\.summary\?\.loading\?\.status === 'COMPLETED'/)
|
||||
assert.match(finalize, /unifiedRow\?\.loading\?\.status === 'COMPLETED'/)
|
||||
assert.match(convergence, /loadingPlan\?\.status === 'LOADING'/)
|
||||
assert.match(convergence, /!operations\.some\(\(item\) => item\.actionType === 'COMPLETE_LOADING'\)/)
|
||||
assert.match(customs, /\['AWAITING_REVIEW', 'LOADED'\]/)
|
||||
|
||||
@@ -429,6 +429,9 @@ export async function run(context) {
|
||||
id(unifiedDetail?.summary?.orderId) === orderId && unifiedDetail?.summary?.mainStatus === 'LOADED'
|
||||
&& Boolean(orderNo),
|
||||
`orderId=${id(unifiedDetail?.summary?.orderId) || 'missing'}, mainStatus=${unifiedDetail?.summary?.mainStatus || 'missing'}, orderNo=${orderNo || 'missing'}`, OPTIONS)
|
||||
context.assert(MODULE, '装柜完成后订单详情拣货汇总同步完成', unifiedDetailResponse,
|
||||
unifiedDetail?.summary?.loading?.status === 'COMPLETED',
|
||||
`loadingStatus=${unifiedDetail?.summary?.loading?.status || 'missing'}`, OPTIONS)
|
||||
if (id(unifiedDetail?.summary?.orderId) !== orderId || unifiedDetail?.summary?.mainStatus !== 'LOADED' || !orderNo) return
|
||||
const unifiedListPath = `/api/platform/v1/orders?page=1&size=100&tenantId=${encodeURIComponent(tenantId)}&orderNo=${encodeURIComponent(orderNo)}`
|
||||
const unifiedListResponse = await context.request('GET', unifiedListPath)
|
||||
@@ -437,6 +440,9 @@ export async function run(context) {
|
||||
context.assert(MODULE, '统一订单列表投影同一订单为 LOADED', unifiedListResponse,
|
||||
Boolean(unifiedRow) && unifiedRow?.mainStatus === 'LOADED',
|
||||
`orderId=${orderId}, found=${Boolean(unifiedRow)}, mainStatus=${unifiedRow?.mainStatus || 'missing'}`, OPTIONS)
|
||||
context.assert(MODULE, '装柜完成后订单列表拣货汇总同步完成', unifiedListResponse,
|
||||
unifiedRow?.loading?.status === 'COMPLETED',
|
||||
`loadingStatus=${unifiedRow?.loading?.status || 'missing'}`, OPTIONS)
|
||||
|
||||
const evidencePath = `/api/platform/v1/first-leg/pda-loading/tasks/${encodeURIComponent(id(fixture.canonicalPdaTaskId))}/evidence?warehouseId=${encodeURIComponent(id(fixture.warehouseId))}`
|
||||
const immutableEvidenceResponse = await context.request('GET', evidencePath)
|
||||
|
||||
Reference in New Issue
Block a user