From 2c94e212ca768767e008ac9df259fa5fe542328a Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 4 Sep 2026 14:17:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/openapi/firstleg-v1.yaml | 4 +- ...SmartLoadingProvisionalAdjustmentTest.java | 129 ++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java diff --git a/firstleg/src/main/resources/openapi/firstleg-v1.yaml b/firstleg/src/main/resources/openapi/firstleg-v1.yaml index e239e48b7..eaae32433 100644 --- a/firstleg/src/main/resources/openapi/firstleg-v1.yaml +++ b/firstleg/src/main/resources/openapi/firstleg-v1.yaml @@ -2210,7 +2210,7 @@ components: items: {type: string, pattern: '^[1-9][0-9]*$'} SmartLoadingPlanItem: type: object - required: [id, packageCount, version, pickedPackageCount, minPackageCount, canAdjust, canRemove] + required: [id, packageCount, totalPackageCount, remainingPackageCount, version, pickedPackageCount, minPackageCount, canAdjust, canRemove] properties: id: {type: string} inboundId: {type: string} @@ -2222,6 +2222,8 @@ components: internalRemark: {type: string, nullable: true, readOnly: true, description: 来源为订单最新内部备注,不使用 cargoRemark} warehouseRemark: {type: string, nullable: true, description: 仓库人员逐条维护,可在 EDITING/LOADING 修改} packageCount: {type: integer, minimum: 1} + totalPackageCount: {type: integer, minimum: 1, description: 当前入仓明细可在计划内分配的总箱数,包含已用与未用箱数} + remainingPackageCount: {type: integer, minimum: 0, description: 当前入仓明细尚未分配到本计划的箱数} version: {type: integer, minimum: 0, description: itemVersion,调整/删除写请求使用此值} pickedPackageCount: {type: integer, minimum: 0} minPackageCount: {type: integer, minimum: 1} diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java new file mode 100644 index 000000000..3473c5b34 --- /dev/null +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/SmartLoadingProvisionalAdjustmentTest.java @@ -0,0 +1,129 @@ +package com.baiyue.firstleg.service; + +import com.baiyue.common.core.api.ApiResponse; +import com.baiyue.firstleg.client.OrderCargoClient; +import com.baiyue.firstleg.client.PendingReviewOrderClient; +import com.baiyue.firstleg.dto.OrderApprovedInboundCommand; +import com.baiyue.firstleg.dto.SmartLoadingDtos.AdjustRequest; +import com.baiyue.firstleg.dto.SmartLoadingDtos.Plan; +import com.baiyue.firstleg.entity.ContainerBookingEntity; +import com.baiyue.firstleg.entity.InboundOrderEntity; +import com.baiyue.firstleg.entity.LoadingPlanEntity; +import com.baiyue.firstleg.entity.LoadingPlanItemEntity; +import com.baiyue.firstleg.loading.bridge.service.LoadingModelBridgeService; +import com.baiyue.firstleg.loading.coload.port.ColoadGroupAssignmentPort; +import com.baiyue.firstleg.pricebookquery.application.port.in.PriceBookQueryUseCase; +import com.baiyue.firstleg.repository.SmartLoadingRepository; +import com.baiyue.firstleg.split.service.SplitPreloadService; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class SmartLoadingProvisionalAdjustmentTest { + @Mock private SmartLoadingRepository repository; + @Mock private OrderCargoClient orderCargoClient; + @Mock private PendingReviewOrderClient pendingReviewOrders; + @Mock private InboundOrderCreationService inboundOrderCreationService; + @Mock private LoadingPickService loadingPickService; + @Mock private LoadingModelBridgeService loadingModelBridge; + @Mock private SplitPreloadService splitPreloadService; + @Mock private ColoadGroupAssignmentPort coloadGroups; + @Mock private PriceBookQueryUseCase priceBooks; + @Mock private FirstlegDocumentNumberGenerator documentNumbers; + @Spy private ObjectMapper objectMapper = new ObjectMapper(); + @InjectMocks private SmartLoadingService service; + + private LoadingPlanItemEntity item; + private InboundOrderEntity inbound; + + @BeforeEach + void setUp() { + item = new LoadingPlanItemEntity(); + item.setId(8L); + item.setLoadingPlanId(1L); + item.setAccountId(9L); + item.setInboundId(10L); + item.setInboundDetailId(20L); + item.setOrderId(30L); + item.setInboundCode("I10"); + item.setPackageCount(20); + item.setVersion(0); + + inbound = new InboundOrderEntity(); + inbound.setTenantId(9L); + inbound.setId(10L); + inbound.setProcessStatus("PREPARING"); + + when(loadingPickService.mutationSnapshot(anyLong())).thenReturn( + new LoadingPickService.MutationSnapshot(null, null, null, Map.of())); + } + + @Test + void adjustsProvisionalInboundFromTwentyToFiftyWithinDeclaredHundredBoxes() { + LoadingPlanEntity plan = plan(103); + ContainerBookingEntity booking = booking(); + OrderCargoClient.CargoBinding cargo = new OrderCargoClient.CargoBinding( + 20L, 30L, 1, "货物", 100, new BigDecimal("200"), new BigDecimal("50")); + OrderApprovedInboundCommand snapshot = new OrderApprovedInboundCommand( + 9L, 30L, "O30", "I10", 9L, "客户", 100L, "仓库", + null, null, null, "FIRST_LEG", "FBA", "FBA渠道", null, null, null, + null, null, false, "FBA", 200L, "FBA1", "FBA仓", null, null, null, 100); + + when(repository.plan(1L)).thenReturn(plan, plan(104)); + when(repository.item(1L, 8L)).thenReturn(item); + when(repository.booking(99L)).thenReturn(booking); + when(repository.inbound(9L, 10L)).thenReturn(inbound); + when(orderCargoClient.detail(nullable(String.class), eq(9L), eq(30L), eq(20L))) + .thenReturn(ApiResponse.success(cargo)); + when(orderCargoClient.inboundSnapshot(nullable(String.class), eq(9L), eq(30L))) + .thenReturn(ApiResponse.success(snapshot)); + when(repository.items(1L)).thenReturn(List.of(item)); + when(repository.touch(1L, 103, 7L, "u")).thenReturn(1); + when(repository.update(item)).thenReturn(1); + + Plan result = service.adjust(1L, 8L, + new AdjustRequest(50, 103, 0, "adjust-provisional"), 7L, "u"); + + assertThat(item.getPackageCount()).isEqualTo(50); + assertThat(result.items()).singleElement().satisfies(updated -> { + assertThat(updated.getTotalPackageCount()).isEqualTo(100); + assertThat(updated.getRemainingPackageCount()).isEqualTo(50); + }); + } + + private static LoadingPlanEntity plan(int version) { + LoadingPlanEntity value = new LoadingPlanEntity(); + value.setId(1L); + value.setContainerBookingId(99L); + value.setPlanStatus("EDITING"); + value.setVersion(version); + return value; + } + + private static ContainerBookingEntity booking() { + ContainerBookingEntity value = new ContainerBookingEntity(); + value.setId(99L); + value.setWarehouseId(100L); + value.setChannelCode("FBA"); + value.setDestinationWarehouseCode("FBA1"); + value.setCapacityCbm(new BigDecimal("60")); + value.setMaxWeightKg(new BigDecimal("20000")); + return value; + } +}