装柜回归测试
This commit is contained in:
+1
-1
@@ -54,7 +54,7 @@ class InboundOrderControllerContractTest {
|
||||
.contains("[WAIT_MEASURE, WAIT_REVIEW, WAIT_FEE_SEND, INBOUNDED]")
|
||||
.contains("platform:firstleg:inbound:list")
|
||||
.doesNotContain("WAIT_CUSTOMER_CONFIRM")
|
||||
.contains("WAIT_SPLIT");
|
||||
.doesNotContain("WAIT_SPLIT");
|
||||
assertThat(inboundList).contains("#/components/schemas/InboundOrderPageEnvelope");
|
||||
assertThat(taskList).doesNotContain("InboundOrderPageEnvelope");
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class MerchantInboundBillingControllerContractTest {
|
||||
String openapi = new ClassPathResource("openapi/firstleg-v1.yaml")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
assertThat(openapi).contains("/api/merchant/v1/first-leg/orders/{orderId}/inbound-billing:")
|
||||
.contains("仅 WAIT_SPLIT + APPROVED + CONFIRMED 的二期终态可见");
|
||||
.contains("INBOUNDED + APPROVED + CONFIRMED");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+4
-4
@@ -11,18 +11,18 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class InboundStatusUnificationSqlContractTest {
|
||||
@Test
|
||||
void preservesWaitSplitWithoutDataRewrite() throws Exception {
|
||||
void preservesHistoricalWaitSplitWithoutDataRewrite() throws Exception {
|
||||
String module = normalize(new ClassPathResource("db/phase3-inbounded-status-unification.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8)).trim();
|
||||
String unified = normalize(Files.readString(unifiedPath(), StandardCharsets.UTF_8));
|
||||
|
||||
assertThat(module)
|
||||
.contains("CREATE PROCEDURE assert_wait_split_compatibility()")
|
||||
.contains("WAIT_SPLIT 是二期当前有效终点")
|
||||
.contains("CREATE PROCEDURE assert_inbounded_compatibility()")
|
||||
.contains("二、三期对外统一使用 INBOUNDED")
|
||||
.doesNotContain("UPDATE fl_inbound_order")
|
||||
.doesNotContain("UPDATE fl_inbound_status_history");
|
||||
assertThat(unified)
|
||||
.contains("WAIT_SPLIT 是二期当前有效终点;统一迁移不得改写主表或历史状态")
|
||||
.contains("二、三期对外统一使用 INBOUNDED")
|
||||
.doesNotContain("SET process_status = 'INBOUNDED'")
|
||||
.doesNotContain("SET from_status = 'INBOUNDED'")
|
||||
.doesNotContain("SET to_status = 'INBOUNDED'");
|
||||
|
||||
+2
-1
@@ -37,7 +37,8 @@ class LoadingPickItemMapperContractTest {
|
||||
@Test
|
||||
void pdaWritesAndReadsRequireWarehouseScope() throws Exception {
|
||||
Method list = LoadingPickItemMapper.class.getDeclaredMethod("selectTaskItemsWithAccount", long.class, long.class);
|
||||
Method pick = LoadingPickItemMapper.class.getDeclaredMethod("pick", long.class, int.class, int.class, long.class);
|
||||
Method pick = LoadingPickItemMapper.class.getDeclaredMethod("pick", long.class, int.class,
|
||||
String.class, String.class, int.class, long.class);
|
||||
|
||||
assertThat(list.getAnnotation(Select.class).value()[0])
|
||||
.contains("booking.warehouse_id = #{warehouseId}")
|
||||
|
||||
+2
-2
@@ -41,8 +41,8 @@ class InboundOrderQueryServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAcceptCurrentPhase2TerminalStatusFilters() {
|
||||
InboundOrderQuery query = new InboundOrderQuery(null, null, "WAIT_SPLIT", null,
|
||||
void shouldAcceptInboundedAsThePhase2TerminalStatusFilter() {
|
||||
InboundOrderQuery query = new InboundOrderQuery(null, null, "INBOUNDED", null,
|
||||
"APPROVED", "CONFIRMED", null, null, null, null, null, null, null,
|
||||
null, null, null, null, 1, 200);
|
||||
PageResult<InboundOrderSummary> expected = new PageResult<>(List.of(), 1, 200, 0, 0);
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.PickRequest;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.PartialPickRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.SkipRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.PickRequest;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.ReviewRequest;
|
||||
import com.baiyue.firstleg.entity.LoadingPickHistoryEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPickOperationEntity;
|
||||
import com.baiyue.firstleg.dto.LoadingPickDtos.SkipRequest;
|
||||
import com.baiyue.firstleg.entity.LoadingPickAssignmentEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPickHistoryEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPickItemEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPickOperationEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPickTaskEntity;
|
||||
import com.baiyue.firstleg.repository.LoadingPickRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -28,6 +32,8 @@ class LoadingPickServiceTest {
|
||||
private LoadingPickRepository repository;
|
||||
@MockBean
|
||||
private LoadingListService loadingListService;
|
||||
@MockBean
|
||||
private PdaPickSettlementService settlementService;
|
||||
@Resource
|
||||
private LoadingPickService service;
|
||||
|
||||
@@ -35,78 +41,77 @@ class LoadingPickServiceTest {
|
||||
void keepsPlanLoadingWhenItemsRemain() {
|
||||
LoadingPickTaskEntity task = task();
|
||||
LoadingPickItemEntity item = item();
|
||||
when(repository.history("pick-1")).thenReturn(null);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.taskForUpdate(20L)).thenReturn(task);
|
||||
when(repository.assignment(20L)).thenReturn(assignment());
|
||||
when(repository.item(20L, 30L, 101L)).thenReturn(item);
|
||||
when(repository.pick(30L, 2, 0, 101L)).thenReturn(1);
|
||||
when(repository.allPlanItemsPicked(10L)).thenReturn(false);
|
||||
when(repository.touchTask(20L, 0)).thenReturn(1);
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of(item));
|
||||
preparePick(task, item, "pick-1");
|
||||
when(repository.allTaskItemsResolved(20L)).thenReturn(false);
|
||||
|
||||
service.pick(20L, 30L, new PickRequest(101L, 2, List.of(), 0, "pick-1"), 9L, "operator");
|
||||
|
||||
verify(repository).touchTask(20L, 0);
|
||||
verify(repository).syncInboundProjections(20L, 9L, "operator");
|
||||
verify(settlementService, never()).settle(20L, 9L, "operator");
|
||||
verify(loadingListService, never()).finishFromPda(10L, 20L, 9L, "operator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void completesPlanWhenLastItemIsPicked() {
|
||||
void touchesTaskBeforeCompletingLastPickedItem() {
|
||||
LoadingPickTaskEntity task = task();
|
||||
LoadingPickItemEntity item = item();
|
||||
when(repository.history("pick-2")).thenReturn(null);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.taskForUpdate(20L)).thenReturn(task);
|
||||
when(repository.assignment(20L)).thenReturn(assignment());
|
||||
when(repository.item(20L, 30L, 101L)).thenReturn(item);
|
||||
when(repository.pick(30L, 2, 0, 101L)).thenReturn(1);
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of(item));
|
||||
when(repository.touchTask(20L, 0)).thenReturn(1);
|
||||
preparePick(task, item, "pick-2");
|
||||
when(repository.allTaskItemsResolved(20L)).thenReturn(true);
|
||||
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
|
||||
|
||||
service.pick(20L, 30L, new PickRequest(101L, 2, List.of(), 0, "pick-2"), 9L, "operator");
|
||||
|
||||
verify(loadingListService, never()).finishFromPda(10L, 20L, 9L, "operator");
|
||||
InOrder order = inOrder(repository, settlementService, loadingListService);
|
||||
order.verify(repository).touchTask(20L, 0);
|
||||
order.verify(settlementService).settle(20L, 9L, "operator");
|
||||
order.verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
|
||||
order.verify(repository).syncInboundProjections(20L, 9L, "operator");
|
||||
verify(repository).insert(any(LoadingPickHistoryEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void completesPlanWhenLastItemIsPartiallyPicked() {
|
||||
void touchesTaskBeforeCompletingLastPartialItem() {
|
||||
LoadingPickTaskEntity task = task();
|
||||
LoadingPickItemEntity item = item();
|
||||
when(repository.history("partial-1")).thenReturn(null);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.taskForUpdate(20L)).thenReturn(task);
|
||||
when(repository.assignment(20L)).thenReturn(assignment());
|
||||
when(repository.item(20L, 30L, 101L)).thenReturn(item);
|
||||
when(repository.partial(30L, 1, 0, 101L)).thenReturn(1);
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of(item));
|
||||
when(repository.touchTask(20L, 0)).thenReturn(1);
|
||||
preparePartial(task, item, "partial-1");
|
||||
when(repository.allTaskItemsResolved(20L)).thenReturn(true);
|
||||
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
|
||||
|
||||
service.partial(20L, 30L, new PartialPickRequest(101L, 1, List.of(), 0, "partial-1"), 9L, "operator");
|
||||
service.partial(20L, 30L, new PartialPickRequest(101L, 1, List.of(), 0, "partial-1"),
|
||||
9L, "operator");
|
||||
|
||||
verify(loadingListService, never()).finishFromPda(10L, 20L, 9L, "operator");
|
||||
InOrder order = inOrder(repository, settlementService, loadingListService);
|
||||
order.verify(repository).touchTask(20L, 0);
|
||||
order.verify(settlementService).settle(20L, 9L, "operator");
|
||||
order.verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
|
||||
order.verify(repository).syncInboundProjections(20L, 9L, "operator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void completesPlanWhenLastItemIsSkipped() {
|
||||
void rejectsSkipWhenInboundAlreadyHasPickedItem() {
|
||||
LoadingPickTaskEntity task = task();
|
||||
LoadingPickItemEntity item = item();
|
||||
LoadingPickItemEntity skipped = item();
|
||||
LoadingPickItemEntity picked = item();
|
||||
picked.setId(31L);
|
||||
picked.setItemStatus("PICKED");
|
||||
picked.setPickedPackageCount(2);
|
||||
when(repository.history("skip-1")).thenReturn(null);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.taskForUpdate(20L)).thenReturn(task);
|
||||
when(repository.assignment(20L)).thenReturn(assignment());
|
||||
when(repository.item(20L, 30L, 101L)).thenReturn(item);
|
||||
when(repository.skip(30L, 0, 101L)).thenReturn(1);
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of(item));
|
||||
when(repository.touchTask(20L, 0)).thenReturn(1);
|
||||
when(repository.item(20L, 30L, 101L)).thenReturn(skipped);
|
||||
when(repository.hasPickedOrPartialItem(20L, 50L)).thenReturn(true);
|
||||
|
||||
service.skip(20L, 30L, new SkipRequest(101L, 0, "skip-1", "fixture unavailable"), 9L, "operator");
|
||||
assertThatThrownBy(() -> service.skip(20L, 30L,
|
||||
new SkipRequest(101L, 0, "skip-1", "fixture unavailable"), 9L, "operator"))
|
||||
.isInstanceOf(BizException.class);
|
||||
|
||||
verify(loadingListService, never()).finishFromPda(10L, 20L, 9L, "operator");
|
||||
verify(repository, never()).skip(30L, 0, 101L);
|
||||
verify(settlementService, never()).settle(20L, 9L, "operator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void reviewSettlesPartialItemsBeforeCompletingPlan() {
|
||||
void reviewSettlesResolvedItemsAndCompletesPlan() {
|
||||
LoadingPickTaskEntity task = task();
|
||||
LoadingPickItemEntity item = item();
|
||||
item.setPlannedPackageCount(5);
|
||||
@@ -115,6 +120,7 @@ class LoadingPickServiceTest {
|
||||
when(repository.taskForUpdate(20L)).thenReturn(task);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.items(20L)).thenReturn(List.of(item));
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of(item));
|
||||
when(repository.settlePartial(40L, 30L, 3, 5, 9L, "operator")).thenReturn(1);
|
||||
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
|
||||
when(repository.approve(20L, 9L, "operator", "checked")).thenReturn(1);
|
||||
@@ -123,9 +129,32 @@ class LoadingPickServiceTest {
|
||||
|
||||
verify(repository).insert(any(LoadingPickOperationEntity.class));
|
||||
verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
|
||||
verify(settlementService, never()).settle(20L, 9L, "operator");
|
||||
verify(repository).syncInboundProjections(20L, 9L, "operator");
|
||||
}
|
||||
|
||||
private void preparePick(LoadingPickTaskEntity task, LoadingPickItemEntity item, String operationId) {
|
||||
when(repository.history(operationId)).thenReturn(null);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.taskForUpdate(20L)).thenReturn(task);
|
||||
when(repository.assignment(20L)).thenReturn(assignment());
|
||||
when(repository.item(20L, 30L, 101L)).thenReturn(item);
|
||||
when(repository.pick(30L, 2, "MANUAL", "[]", 0, 101L)).thenReturn(1);
|
||||
when(repository.touchTask(20L, 0)).thenReturn(1);
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of(item));
|
||||
}
|
||||
|
||||
private void preparePartial(LoadingPickTaskEntity task, LoadingPickItemEntity item, String operationId) {
|
||||
when(repository.history(operationId)).thenReturn(null);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(repository.taskForUpdate(20L)).thenReturn(task);
|
||||
when(repository.assignment(20L)).thenReturn(assignment());
|
||||
when(repository.item(20L, 30L, 101L)).thenReturn(item);
|
||||
when(repository.partial(30L, 1, "MANUAL", "[]", 0, 101L)).thenReturn(1);
|
||||
when(repository.touchTask(20L, 0)).thenReturn(1);
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of(item));
|
||||
}
|
||||
|
||||
private static LoadingPickTaskEntity task() {
|
||||
LoadingPickTaskEntity task = new LoadingPickTaskEntity();
|
||||
task.setId(20L);
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ class MerchantInboundBillingServiceTest {
|
||||
|
||||
@Test
|
||||
void shouldHandleCase01() {
|
||||
InboundOrderEntity inbound = inbound("WAIT_SPLIT", "APPROVED", "CONFIRMED");
|
||||
InboundOrderEntity inbound = inbound("INBOUNDED", "APPROVED", "CONFIRMED");
|
||||
InboundOrderDetail detail = new InboundOrderDetail(mock(com.baiyue.firstleg.dto.InboundOrderSummary.class),
|
||||
"客户备注", List.of(), List.of(
|
||||
new InboundOrderDetail.FileSummary(1L, "RELATED", "public.pdf", "PUBLIC", 1, 1L, null),
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.firstleg.client.WarehousePalletLocationClient;
|
||||
import com.baiyue.firstleg.entity.InboundPalletAllocationEntity;
|
||||
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.repository.InboundPalletAllocationRepository;
|
||||
import com.baiyue.firstleg.repository.LoadingPickRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(PdaPickSettlementService.class)
|
||||
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
|
||||
class PdaPickSettlementServiceTest {
|
||||
@MockBean private LoadingPickRepository picks;
|
||||
@MockBean private InboundSplitSettlementMapper splits;
|
||||
@MockBean private InboundPalletAllocationRepository allocations;
|
||||
@MockBean private WarehousePalletLocationClient warehouse;
|
||||
@Resource private PdaPickSettlementService service;
|
||||
|
||||
@Test
|
||||
void createsChildForAllUnloadedPackagesAndTransfersRemainingAllocations() {
|
||||
LoadingPickItemEntity item = item(11L, 21L, 31L, 41L, 10, 8, "PARTIAL");
|
||||
resolved(List.of(item));
|
||||
when(splits.lockParent(31L)).thenReturn(parent(20));
|
||||
when(splits.childId(10001L, 31L)).thenReturn(null);
|
||||
when(splits.lockLatestApprovedItemsForInbound(10001L, 31L))
|
||||
.thenReturn(List.of(new MeasurementItemRow(51L, 61L, 41L, 20)));
|
||||
when(allocations.lockConfirmed(10001L, 31L))
|
||||
.thenReturn(List.of(allocation(1L, 1, 501L, 10), allocation(2L, 2, 502L, 10)));
|
||||
when(warehouse.settle(eq("internal-token"), any())).thenReturn(ApiResponse.success(
|
||||
new WarehousePalletLocationClient.SettlementResult(List.of(), List.of(
|
||||
transfer(1, 501L, 2), transfer(2, 502L, 10)))));
|
||||
writes(12, 8);
|
||||
|
||||
service.settle(1L, 9L, "operator");
|
||||
|
||||
verify(splits).cloneChild(eq(10001L), eq(31L), anyLong(), anyString(), eq(12), eq(9L), eq("operator"));
|
||||
verify(splits).updateSourceMeasurementPackageCount(10001L, 31L, 61L, 8);
|
||||
verify(splits).updateSourceMeasurementItemPackageCount(10001L, 61L, 51L, 8);
|
||||
verify(allocations).consume(10001L, 31L, 1L, 8);
|
||||
verify(warehouse).settle(eq("internal-token"), org.mockito.ArgumentMatchers.argThat(request ->
|
||||
request.warehouseId() == 701L && request.sourceBusinessId() == 31L
|
||||
&& request.idempotencyKey().equals("PDA-SETTLE-1-31")
|
||||
&& request.releasedReservationIds().isEmpty()
|
||||
&& request.remainingItems().equals(List.of(new WarehousePalletLocationClient.SettlementTransferItem(91L, 2),
|
||||
new WarehousePalletLocationClient.SettlementTransferItem(92L, 10)))));
|
||||
verify(allocations).copyRemainingToChild(eq(10001L), anyLong(), any());
|
||||
verify(allocations).markTransferred(eq(10001L), eq(31L), any(), eq(List.of()));
|
||||
verify(splits).convergePartialPlanItem(21L, 9L, "operator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void repeatedSettleWithExistingChildDoesNotConsumeOrTransferAgain() {
|
||||
LoadingPickItemEntity item = item(11L, 21L, 31L, 41L, 10, 6, "PARTIAL");
|
||||
resolved(List.of(item));
|
||||
when(splits.lockParent(31L)).thenReturn(parent(10));
|
||||
when(splits.childId(10001L, 31L)).thenReturn(71L);
|
||||
|
||||
service.settle(1L, 9L, "operator");
|
||||
|
||||
verify(warehouse, never()).settle(anyString(), any());
|
||||
verify(splits, never()).convergePartialPlanItem(anyLong(), anyLong(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void releasesFullyPickedAllocationBeforeTransferringChildResources() {
|
||||
LoadingPickItemEntity item = item(11L, 21L, 31L, 41L, 10, 10, "PICKED");
|
||||
resolved(List.of(item));
|
||||
when(splits.lockParent(31L)).thenReturn(parent(20));
|
||||
when(splits.childId(10001L, 31L)).thenReturn(null);
|
||||
when(splits.lockLatestApprovedItemsForInbound(10001L, 31L))
|
||||
.thenReturn(List.of(new MeasurementItemRow(51L, 61L, 41L, 20)));
|
||||
when(allocations.lockConfirmed(10001L, 31L))
|
||||
.thenReturn(List.of(allocation(1L, 1, 501L, 10), allocation(2L, 2, 502L, 10)));
|
||||
when(warehouse.settle(eq("internal-token"), any())).thenReturn(ApiResponse.success(
|
||||
new WarehousePalletLocationClient.SettlementResult(List.of(released(91L, 501L)),
|
||||
List.of(transfer(2, 502L, 10)))));
|
||||
writes(10, 10);
|
||||
|
||||
service.settle(1L, 9L, "operator");
|
||||
|
||||
verify(warehouse).settle(eq("internal-token"), org.mockito.ArgumentMatchers.argThat(request ->
|
||||
request.idempotencyKey().equals("PDA-SETTLE-1-31")
|
||||
&& request.releasedReservationIds().equals(List.of(91L))
|
||||
&& request.remainingItems().equals(List.of(new WarehousePalletLocationClient.SettlementTransferItem(92L, 10)))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void fullyPickedInboundReleasesAllResourcesWithoutCreatingChild() {
|
||||
LoadingPickItemEntity item = item(11L, 21L, 31L, 41L, 20, 20, "PICKED");
|
||||
resolved(List.of(item));
|
||||
when(splits.lockParent(31L)).thenReturn(parent(20));
|
||||
when(splits.childId(10001L, 31L)).thenReturn(null);
|
||||
when(allocations.lockConfirmed(10001L, 31L))
|
||||
.thenReturn(List.of(allocation(1L, 1, 501L, 10), allocation(2L, 2, 502L, 10)));
|
||||
when(warehouse.settle(eq("internal-token"), any())).thenReturn(ApiResponse.success(
|
||||
new WarehousePalletLocationClient.SettlementResult(List.of(released(91L, 501L), released(92L, 502L)),
|
||||
List.of())));
|
||||
|
||||
service.settle(1L, 9L, "operator");
|
||||
|
||||
verify(allocations).consume(10001L, 31L, 1L, 10);
|
||||
verify(allocations).consume(10001L, 31L, 2L, 10);
|
||||
verify(splits, never()).cloneChild(anyLong(), anyLong(), anyLong(), anyString(), anyInt(), anyLong(), anyString());
|
||||
verify(warehouse).settle(eq("internal-token"), org.mockito.ArgumentMatchers.argThat(request ->
|
||||
request.targetBusinessId() == 0L && request.targetPackageCount() == 0
|
||||
&& request.releasedReservationIds().equals(List.of(91L, 92L))
|
||||
&& request.remainingItems().isEmpty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void onlyPureSkippedInboundRestoresCandidate() {
|
||||
LoadingPickItemEntity item = item(12L, 22L, 32L, 42L, 8, 0, "SKIPPED");
|
||||
resolved(List.of(item));
|
||||
when(splits.removeSkippedPlanItem(22L, 9L, "operator")).thenReturn(1);
|
||||
|
||||
service.settle(1L, 9L, "operator");
|
||||
|
||||
verify(splits).removeSkippedPlanItem(22L, 9L, "operator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void mixedSkippedInboundIsNotRestored() {
|
||||
LoadingPickItemEntity picked = item(11L, 21L, 31L, 41L, 8, 8, "PICKED");
|
||||
LoadingPickItemEntity skipped = item(12L, 22L, 31L, 42L, 8, 0, "SKIPPED");
|
||||
|
||||
PdaPickSettlementPlan.Resolution resolution = PdaPickSettlementPlan.resolve(List.of(picked, skipped));
|
||||
|
||||
assertThat(resolution.skippedPlanItemIds()).isEmpty();
|
||||
}
|
||||
|
||||
private void resolved(List<LoadingPickItemEntity> items) {
|
||||
when(picks.allTaskItemsResolved(1L)).thenReturn(true);
|
||||
when(picks.items(1L)).thenReturn(items);
|
||||
}
|
||||
|
||||
private void writes(int childCount, int pickedCount) {
|
||||
when(splits.cloneChild(eq(10001L), eq(31L), anyLong(), anyString(), eq(childCount), eq(9L), eq("operator")))
|
||||
.thenReturn(1);
|
||||
when(splits.insertBatch(anyLong(), eq(10001L), eq(31L), anyString(), anyString(), eq(3),
|
||||
eq(childCount), anyString(), eq(9L), eq("operator"))).thenReturn(1);
|
||||
when(splits.cloneMeasurement(eq(10001L), eq(31L), eq(61L), anyLong(), anyLong(), anyLong(),
|
||||
eq(childCount), eq(9L))).thenReturn(1);
|
||||
when(splits.insertSplitItem(anyLong(), eq(10001L), anyLong(), eq(31L), anyLong(), eq(1),
|
||||
eq(41L), eq(61L), eq(51L), eq(childCount))).thenReturn(1);
|
||||
when(splits.cloneMeasurementItem(eq(10001L), eq(61L), eq(51L), anyLong(), anyLong(), anyLong(),
|
||||
eq(1), eq(childCount))).thenReturn(1);
|
||||
when(splits.updateSourceMeasurementPackageCount(10001L, 31L, 61L, pickedCount)).thenReturn(1);
|
||||
when(splits.updateSourceMeasurementItemPackageCount(10001L, 61L, 51L, pickedCount)).thenReturn(1);
|
||||
when(splits.markParentPartiallySplit(10001L, 31L, childCount, 9L, 3)).thenReturn(1);
|
||||
when(splits.applyBatch(eq(10001L), anyLong())).thenReturn(1);
|
||||
when(splits.insertHistory(anyLong(), eq(10001L), anyLong(), anyString(), anyString(), eq(9L),
|
||||
eq("operator"), anyString())).thenReturn(1);
|
||||
when(splits.convergePartialPlanItem(21L, 9L, "operator")).thenReturn(1);
|
||||
}
|
||||
|
||||
private static ParentRow parent(int packageCount) {
|
||||
return new ParentRow(31L, 10001L, "IN-001", "MASTER", "INBOUNDED", packageCount, packageCount, 3);
|
||||
}
|
||||
|
||||
private static InboundPalletAllocationEntity allocation(long id, int no, long locationId, int allocated) {
|
||||
InboundPalletAllocationEntity value = new InboundPalletAllocationEntity();
|
||||
value.setId(id); value.setAllocationNo(no); value.setLocationId(locationId); value.setWarehouseId(701L);
|
||||
value.setReservationId(90L + no);
|
||||
value.setAllocatedPackageCount(allocated); value.setPickedPackageCount(0);
|
||||
return value;
|
||||
}
|
||||
|
||||
private static WarehousePalletLocationClient.TransferResult transfer(int no, long locationId, int remaining) {
|
||||
return new WarehousePalletLocationClient.TransferResult(90L + no, "RES-" + no, 92L + no, no,
|
||||
0L, 701L, 801L + no, "PALLET-" + no, null, locationId, "L-" + no, null, remaining, "OCCUPIED");
|
||||
}
|
||||
|
||||
private static WarehousePalletLocationClient.SelectiveReleaseResult released(long reservationId, long locationId) {
|
||||
return new WarehousePalletLocationClient.SelectiveReleaseResult(reservationId, 92L, 1, 801L,
|
||||
locationId, "L-1", 10);
|
||||
}
|
||||
|
||||
private static LoadingPickItemEntity item(long id, long planItemId, long inboundId, long detailId,
|
||||
int planned, int picked, String status) {
|
||||
LoadingPickItemEntity value = new LoadingPickItemEntity();
|
||||
value.setId(id); value.setLoadingPlanItemId(planItemId); value.setInboundId(inboundId);
|
||||
value.setInboundDetailId(detailId); value.setPlannedPackageCount(planned);
|
||||
value.setPickedPackageCount(picked); value.setItemStatus(status);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+6
-8
@@ -31,7 +31,7 @@ class UnifiedInboundQueryServiceTest {
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("WAIT_PRICING")).isEqualTo("INBOUNDED");
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("FEE_CONFIRMING")).isEqualTo("INBOUNDED");
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("INBOUNDING")).isEqualTo("INBOUNDED");
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("WAIT_SPLIT")).isEqualTo("WAIT_SPLIT");
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("WAIT_SPLIT")).isEqualTo("INBOUNDED");
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("INBOUNDED")).isEqualTo("INBOUNDED");
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("LOADING")).isEqualTo("LOADING");
|
||||
assertThat(UnifiedInboundQueryService.mainStatus("LOADED")).isEqualTo("LOADED");
|
||||
@@ -51,29 +51,27 @@ class UnifiedInboundQueryServiceTest {
|
||||
assertThat(UnifiedInboundQueryService.nextAction("INBOUNDED", "INBOUNDING", null)).isNull();
|
||||
assertThat(UnifiedInboundQueryService.nextAction("INBOUNDED", "INBOUNDED", "CONFIRMED")).isNull();
|
||||
assertThat(UnifiedInboundQueryService.nextAction("INBOUNDED", "WAIT_SPLIT", null))
|
||||
.isNull();
|
||||
assertThat(UnifiedInboundQueryService.nextAction("WAIT_SPLIT", "WAIT_SPLIT", null)).isNull();
|
||||
.isEqualTo("SMART_SPLIT");
|
||||
assertThat(UnifiedInboundQueryService.nextAction("LOADED", "LOADED", null))
|
||||
.isEqualTo("COMPLETE_DELIVERY");
|
||||
assertThat(UnifiedInboundQueryService.nextAction("DELIVERED", "DELIVERED", null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void waitSplitFilterRemainsSeparateFromInbounded() throws Exception {
|
||||
void inboundedFilterIncludesHistoricalWaitSplitRows() throws Exception {
|
||||
var method = UnifiedInboundQueryService.class.getDeclaredMethod("internalStatuses", String.class);
|
||||
method.setAccessible(true);
|
||||
|
||||
assertThat(method.invoke(new UnifiedInboundQueryService(), "WAIT_SPLIT"))
|
||||
.isEqualTo(java.util.List.of("WAIT_SPLIT"));
|
||||
assertThat(method.invoke(new UnifiedInboundQueryService(), "INBOUNDED"))
|
||||
.isEqualTo(java.util.List.of("WAIT_PRICING", "FEE_CONFIRMING", "INBOUNDING", "INBOUNDED"));
|
||||
.isEqualTo(java.util.List.of("WAIT_PRICING", "FEE_CONFIRMING", "INBOUNDING", "INBOUNDED", "WAIT_SPLIT"));
|
||||
assertThat(method.invoke(new UnifiedInboundQueryService(), "WAIT_SPLIT"))
|
||||
.isEqualTo(java.util.List.of("WAIT_PRICING", "FEE_CONFIRMING", "INBOUNDING", "INBOUNDED", "WAIT_SPLIT"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void phaseTwoMeasurementStatusesDoNotRequireUndeployedPhaseThreeTables() {
|
||||
assertThat(UnifiedInboundQueryService.requiresPhaseThreeSummary("WAIT_MEASURE")).isFalse();
|
||||
assertThat(UnifiedInboundQueryService.requiresPhaseThreeSummary("INBOUNDED")).isFalse();
|
||||
assertThat(UnifiedInboundQueryService.requiresPhaseThreeSummary("WAIT_SPLIT")).isFalse();
|
||||
assertThat(UnifiedInboundQueryService.requiresPhaseThreeSummary("LOADING")).isTrue();
|
||||
assertThat(UnifiedInboundQueryService.requiresPhaseThreeSummary("LOADED")).isTrue();
|
||||
assertThat(UnifiedInboundQueryService.requiresPhaseThreeSummary("DELIVERED")).isTrue();
|
||||
|
||||
Reference in New Issue
Block a user