优化
This commit is contained in:
+1
-2
@@ -2,7 +2,6 @@ package com.baiyue.lastleg.inboundplan.pda.dto;
|
|||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Positive;
|
import jakarta.validation.constraints.Positive;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
@@ -13,7 +12,7 @@ public final class ReceivingContainerRequests {
|
|||||||
private ReceivingContainerRequests() { }
|
private ReceivingContainerRequests() { }
|
||||||
|
|
||||||
public record Action(@NotBlank @Size(max = 255) String idempotencyKey) { }
|
public record Action(@NotBlank @Size(max = 255) String idempotencyKey) { }
|
||||||
public record Sign(@Size(min = 3, max = 3) List<@Valid SignedPhoto> photos,
|
public record Sign(@NotNull @Size(min = 3, max = 3) List<@Valid SignedPhoto> photos,
|
||||||
@NotBlank @Size(max = 255) String idempotencyKey) { }
|
@NotBlank @Size(max = 255) String idempotencyKey) { }
|
||||||
public record SignedPhoto(@NotNull ReceivingPhotoRole role, @Positive long fileId) { }
|
public record SignedPhoto(@NotNull ReceivingPhotoRole role, @Positive long fileId) { }
|
||||||
public record CartonResolve(@NotBlank String cartonMark) { }
|
public record CartonResolve(@NotBlank String cartonMark) { }
|
||||||
|
|||||||
+1
@@ -533,6 +533,7 @@ public class ReceivingContainerService {
|
|||||||
.eq(LastlegOrderDetail::getCustomerId, customerId).eq(LastlegOrderDetail::getOrderId, ref.order().getId()));
|
.eq(LastlegOrderDetail::getCustomerId, customerId).eq(LastlegOrderDetail::getOrderId, ref.order().getId()));
|
||||||
Set<String> skuCodes = details.stream().map(LastlegOrderDetail::getSkuCode)
|
Set<String> skuCodes = details.stream().map(LastlegOrderDetail::getSkuCode)
|
||||||
.map(ReceivingContainerService::trim).filter(Objects::nonNull)
|
.map(ReceivingContainerService::trim).filter(Objects::nonNull)
|
||||||
|
.map(value -> value.toUpperCase(java.util.Locale.ROOT))
|
||||||
.collect(Collectors.toCollection(java.util.LinkedHashSet::new));
|
.collect(Collectors.toCollection(java.util.LinkedHashSet::new));
|
||||||
int expected = 0;
|
int expected = 0;
|
||||||
int received = 0;
|
int received = 0;
|
||||||
|
|||||||
+10
-1
@@ -63,6 +63,12 @@ class ReceivingContainerContractTest {
|
|||||||
assertTrue(schema.contains("unique key uk_ll_receiving_active_operator(active_operator_key)"));
|
assertTrue(schema.contains("unique key uk_ll_receiving_active_operator(active_operator_key)"));
|
||||||
assertTrue(schema.contains("unique key uk_ll_receiving_active_container(active_container_key)"));
|
assertTrue(schema.contains("unique key uk_ll_receiving_active_container(active_container_key)"));
|
||||||
assertTrue(schema.contains("create table if not exists ll_receiving_container_operation"));
|
assertTrue(schema.contains("create table if not exists ll_receiving_container_operation"));
|
||||||
|
assertTrue(schema.contains("create table if not exists ll_receiving_sku_receipt"));
|
||||||
|
assertTrue(schema.contains("unique key uk_ll_receiving_sku_pallet (customer_id,line_id,pallet_id,sku_code)"));
|
||||||
|
assertTrue(schema.contains("sign_photos json"));
|
||||||
|
assertFalse(schema.contains("photo_file_ids json"));
|
||||||
|
assertTrue(unified.contains("create table if not exists ll_receiving_sku_receipt"));
|
||||||
|
assertTrue(unified.contains("column_name='sign_photos'"));
|
||||||
assertTrue(schema.contains("wait_sign、signed、receiving、completed"));
|
assertTrue(schema.contains("wait_sign、signed、receiving、completed"));
|
||||||
assertTrue(unified.contains("customer_id is null or l.customer_id=''"));
|
assertTrue(unified.contains("customer_id is null or l.customer_id=''"));
|
||||||
assertTrue(unified.contains("customer_id is null or v.customer_id=''"));
|
assertTrue(unified.contains("customer_id is null or v.customer_id=''"));
|
||||||
@@ -76,16 +82,19 @@ class ReceivingContainerContractTest {
|
|||||||
String prefix = "/api/pda/v1/last-leg/receiving-containers";
|
String prefix = "/api/pda/v1/last-leg/receiving-containers";
|
||||||
assertTrue(yaml.contains(prefix + "/candidates:"));
|
assertTrue(yaml.contains(prefix + "/candidates:"));
|
||||||
assertTrue(yaml.contains(prefix + "/current/receipts/bulk:"));
|
assertTrue(yaml.contains(prefix + "/current/receipts/bulk:"));
|
||||||
|
assertTrue(yaml.contains(prefix + "/current/skus/resolve:"));
|
||||||
assertTrue(yaml.contains(prefix + "/current/receipts/carton:"));
|
assertTrue(yaml.contains(prefix + "/current/receipts/carton:"));
|
||||||
assertTrue(yaml.contains(prefix + "/current/complete:"));
|
assertTrue(yaml.contains(prefix + "/current/complete:"));
|
||||||
assertFalse(yaml.contains("/api/pda/v1/last-leg/receiving-containers/{planNo}"));
|
assertFalse(yaml.contains("/api/pda/v1/last-leg/receiving-containers/{planNo}"));
|
||||||
String receivingPaths = yaml.substring(yaml.indexOf(prefix), yaml.indexOf("/api/platform/v1/last-leg/orders:"));
|
String receivingPaths = yaml.substring(yaml.indexOf(prefix), yaml.indexOf("/api/platform/v1/last-leg/orders:"));
|
||||||
List<String> successResponses = receivingPaths.lines().map(String::trim)
|
List<String> successResponses = receivingPaths.lines().map(String::trim)
|
||||||
.filter(line -> line.startsWith("responses: { '200':")).toList();
|
.filter(line -> line.startsWith("responses: { '200':")).toList();
|
||||||
assertEquals(11, successResponses.size());
|
assertEquals(12, successResponses.size());
|
||||||
assertTrue(successResponses.stream().allMatch(line ->
|
assertTrue(successResponses.stream().allMatch(line ->
|
||||||
line.contains("content: { application/json: { schema: { $ref: '#/components/schemas/Receiving")));
|
line.contains("content: { application/json: { schema: { $ref: '#/components/schemas/Receiving")));
|
||||||
assertTrue(receivingPaths.contains("返回 WAIT_SIGN、SIGNED 或 RECEIVING 当前柜"));
|
assertTrue(receivingPaths.contains("返回 WAIT_SIGN、SIGNED 或 RECEIVING 当前柜"));
|
||||||
|
assertTrue(receivingPaths.contains("LICENSE_PLATE, CONTAINER_SEAL, DOOR_OPEN"));
|
||||||
|
assertFalse(receivingPaths.contains("photoFileIds"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resource(String name) throws IOException {
|
private String resource(String name) throws IOException {
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@ class ReceivingContainerControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
void candidatesDerivesCustomerAndOperatorOnlyFromPdaIdentity() {
|
void candidatesDerivesCustomerAndOperatorOnlyFromPdaIdentity() {
|
||||||
when(service.candidates("100", "42")).thenReturn(List.of(new ReceivingContainerResponses.Candidate(
|
when(service.candidates("100", "42")).thenReturn(List.of(new ReceivingContainerResponses.Candidate(
|
||||||
"CONT-1", "WAIT_SIGN", 2, 2, 20, 0, false)));
|
"CONT-1", "WAIT_SIGN", 2, 2, List.of("ONT8"), 4, 20, 0, false)));
|
||||||
|
|
||||||
controller.candidates(pda());
|
controller.candidates(pda());
|
||||||
|
|
||||||
|
|||||||
+35
@@ -8,7 +8,9 @@ import com.baiyue.lastleg.inboundplan.entity.InboundPlanPallet;
|
|||||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlanPalletAllocation;
|
import com.baiyue.lastleg.inboundplan.entity.InboundPlanPalletAllocation;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.entity.InboundPdaTask;
|
import com.baiyue.lastleg.inboundplan.pda.entity.InboundPdaTask;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.entity.InboundStockReceipt;
|
import com.baiyue.lastleg.inboundplan.pda.entity.InboundStockReceipt;
|
||||||
|
import com.baiyue.lastleg.inboundplan.pda.entity.ReceivingSkuReceipt;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.mapper.InboundStockReceiptMapper;
|
import com.baiyue.lastleg.inboundplan.pda.mapper.InboundStockReceiptMapper;
|
||||||
|
import com.baiyue.lastleg.inboundplan.pda.mapper.ReceivingSkuReceiptMapper;
|
||||||
import com.baiyue.lastleg.inventory.command.dto.InventoryCommandRequests;
|
import com.baiyue.lastleg.inventory.command.dto.InventoryCommandRequests;
|
||||||
import com.baiyue.lastleg.inventory.command.dto.InventoryCommandResponse;
|
import com.baiyue.lastleg.inventory.command.dto.InventoryCommandResponse;
|
||||||
import com.baiyue.lastleg.inventory.command.service.InventoryCommandService;
|
import com.baiyue.lastleg.inventory.command.service.InventoryCommandService;
|
||||||
@@ -45,6 +47,7 @@ class InboundStockReceiptServiceTest {
|
|||||||
@Mock LastlegOrderMapper orders;
|
@Mock LastlegOrderMapper orders;
|
||||||
@Mock LastlegOrderDetailMapper orderDetails;
|
@Mock LastlegOrderDetailMapper orderDetails;
|
||||||
@Mock InboundStockReceiptMapper receipts;
|
@Mock InboundStockReceiptMapper receipts;
|
||||||
|
@Mock ReceivingSkuReceiptMapper receivingSkuReceipts;
|
||||||
@Mock InventoryCommandService inventory;
|
@Mock InventoryCommandService inventory;
|
||||||
@Mock DropshipOrderService dropshipOrders;
|
@Mock DropshipOrderService dropshipOrders;
|
||||||
@Mock LastlegOrderStatusHistoryMapper orderHistories;
|
@Mock LastlegOrderStatusHistoryMapper orderHistories;
|
||||||
@@ -56,10 +59,12 @@ class InboundStockReceiptServiceTest {
|
|||||||
ReflectionTestUtils.setField(service, "orders", orders);
|
ReflectionTestUtils.setField(service, "orders", orders);
|
||||||
ReflectionTestUtils.setField(service, "orderDetails", orderDetails);
|
ReflectionTestUtils.setField(service, "orderDetails", orderDetails);
|
||||||
ReflectionTestUtils.setField(service, "receipts", receipts);
|
ReflectionTestUtils.setField(service, "receipts", receipts);
|
||||||
|
ReflectionTestUtils.setField(service, "receivingSkuReceipts", receivingSkuReceipts);
|
||||||
ReflectionTestUtils.setField(service, "inventory", inventory);
|
ReflectionTestUtils.setField(service, "inventory", inventory);
|
||||||
ReflectionTestUtils.setField(service, "dropshipOrders", dropshipOrders);
|
ReflectionTestUtils.setField(service, "dropshipOrders", dropshipOrders);
|
||||||
ReflectionTestUtils.setField(service, "orderHistories", orderHistories);
|
ReflectionTestUtils.setField(service, "orderHistories", orderHistories);
|
||||||
when(receipts.listTask("100", 2L)).thenReturn(List.of());
|
when(receipts.listTask("100", 2L)).thenReturn(List.of());
|
||||||
|
when(receivingSkuReceipts.listPlan("100", 1L)).thenReturn(List.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -108,6 +113,30 @@ class InboundStockReceiptServiceTest {
|
|||||||
verify(receipts, times(2)).insert(any(InboundStockReceipt.class));
|
verify(receipts, times(2)).insert(any(InboundStockReceipt.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void exactFbaSkuReceiptsPreserveSkuToPalletAttribution() {
|
||||||
|
Fixture fixture = fixture(10, 5, 5, 10);
|
||||||
|
fixture.detail.setPackageCount(5);
|
||||||
|
LastlegOrderDetail second = detail(202L, "SKU-2", 5, 7);
|
||||||
|
when(orderDetails.selectList(any())).thenReturn(List.of(fixture.detail, second));
|
||||||
|
InboundPlanPallet secondPallet = pallet(22L, 2002L);
|
||||||
|
InboundPlanPalletAllocation secondAllocation = allocation(32L, 12L, 22L, 5);
|
||||||
|
ReceivingSkuReceipt first = skuReceipt(12L, 21L, "SKU-1", 5);
|
||||||
|
ReceivingSkuReceipt secondReceipt = skuReceipt(12L, 22L, "SKU-2", 5);
|
||||||
|
when(receivingSkuReceipts.listPlan("100", 1L)).thenReturn(List.of(first, secondReceipt));
|
||||||
|
when(orders.selectBatchIds(any())).thenReturn(List.of(fixture.order));
|
||||||
|
when(inventory.stockIn(eq("100"), eq("operator"), any(InventoryCommandRequests.StockIn.class)))
|
||||||
|
.thenReturn(new InventoryCommandResponse(8L, "STOCK_IN", 9L, 10L, 5, 0, 0, 0, false, false));
|
||||||
|
|
||||||
|
service.stockIn("100", fixture.plan, fixture.task, List.of(fixture.line),
|
||||||
|
List.of(fixture.allocation, secondAllocation), List.of(fixture.pallet, secondPallet), LocalDateTime.now());
|
||||||
|
|
||||||
|
ArgumentCaptor<InventoryCommandRequests.StockIn> requests = ArgumentCaptor.forClass(InventoryCommandRequests.StockIn.class);
|
||||||
|
verify(inventory, times(2)).stockIn(eq("100"), eq("operator"), requests.capture());
|
||||||
|
assertEquals(List.of("SKU-1:2001", "SKU-2:2002"), requests.getAllValues().stream()
|
||||||
|
.map(value -> value.skuCode() + ":" + value.warehousePalletId()).toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void conservesSingleSkuPackagesAndQuantityAcrossPallets() {
|
void conservesSingleSkuPackagesAndQuantityAcrossPallets() {
|
||||||
Fixture fixture = fixture(5, 2, 2, 11);
|
Fixture fixture = fixture(5, 2, 2, 11);
|
||||||
@@ -216,6 +245,12 @@ class InboundStockReceiptServiceTest {
|
|||||||
allocation.setPlannedPackageCount(picked); allocation.setPickedPackageCount(picked); return allocation;
|
allocation.setPlannedPackageCount(picked); allocation.setPickedPackageCount(picked); return allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReceivingSkuReceipt skuReceipt(long lineId, long palletId, String skuCode, int packages) {
|
||||||
|
ReceivingSkuReceipt receipt = new ReceivingSkuReceipt(); receipt.setLineId(lineId); receipt.setPalletId(palletId);
|
||||||
|
receipt.setSkuCode(skuCode); receipt.setProductName(skuCode + " name"); receipt.setReceivedPackages(packages);
|
||||||
|
return receipt;
|
||||||
|
}
|
||||||
|
|
||||||
private record Fixture(InboundPlan plan, InboundPdaTask task, InboundPlanLine line, LastlegOrder order,
|
private record Fixture(InboundPlan plan, InboundPdaTask task, InboundPlanLine line, LastlegOrder order,
|
||||||
LastlegOrderDetail detail, InboundPlanPalletAllocation allocation,
|
LastlegOrderDetail detail, InboundPlanPalletAllocation allocation,
|
||||||
InboundPlanPallet pallet) {}
|
InboundPlanPallet pallet) {}
|
||||||
|
|||||||
+64
-4
@@ -1,6 +1,7 @@
|
|||||||
package com.baiyue.lastleg.inboundplan.pda.service;
|
package com.baiyue.lastleg.inboundplan.pda.service;
|
||||||
|
|
||||||
import com.baiyue.lastleg.entity.LastlegOrder;
|
import com.baiyue.lastleg.entity.LastlegOrder;
|
||||||
|
import com.baiyue.lastleg.entity.LastlegOrderDetail;
|
||||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlan;
|
import com.baiyue.lastleg.inboundplan.entity.InboundPlan;
|
||||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlanCarton;
|
import com.baiyue.lastleg.inboundplan.entity.InboundPlanCarton;
|
||||||
import com.baiyue.lastleg.inboundplan.entity.InboundPlanLine;
|
import com.baiyue.lastleg.inboundplan.entity.InboundPlanLine;
|
||||||
@@ -12,12 +13,15 @@ import com.baiyue.lastleg.inboundplan.mapper.InboundPlanMapper;
|
|||||||
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletAllocationMapper;
|
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletAllocationMapper;
|
||||||
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletMapper;
|
import com.baiyue.lastleg.inboundplan.mapper.InboundPlanPalletMapper;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.dto.ReceivingContainerRequests;
|
import com.baiyue.lastleg.inboundplan.pda.dto.ReceivingContainerRequests;
|
||||||
|
import com.baiyue.lastleg.inboundplan.pda.dto.ReceivingPhotoRole;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.entity.ReceivingContainerOperation;
|
import com.baiyue.lastleg.inboundplan.pda.entity.ReceivingContainerOperation;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.entity.ReceivingContainerSession;
|
import com.baiyue.lastleg.inboundplan.pda.entity.ReceivingContainerSession;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.gateway.UnloadPhotoFileGateway;
|
import com.baiyue.lastleg.inboundplan.pda.gateway.UnloadPhotoFileGateway;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
|
import com.baiyue.lastleg.inboundplan.pda.gateway.WarehouseResourceGateway;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.mapper.ReceivingContainerOperationMapper;
|
import com.baiyue.lastleg.inboundplan.pda.mapper.ReceivingContainerOperationMapper;
|
||||||
import com.baiyue.lastleg.inboundplan.pda.mapper.ReceivingContainerSessionMapper;
|
import com.baiyue.lastleg.inboundplan.pda.mapper.ReceivingContainerSessionMapper;
|
||||||
|
import com.baiyue.lastleg.inboundplan.pda.mapper.ReceivingSkuReceiptMapper;
|
||||||
|
import com.baiyue.lastleg.mapper.LastlegOrderDetailMapper;
|
||||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@@ -48,8 +52,10 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
@Mock InboundPlanPalletAllocationMapper allocations;
|
@Mock InboundPlanPalletAllocationMapper allocations;
|
||||||
@Mock InboundPlanCartonMapper cartons;
|
@Mock InboundPlanCartonMapper cartons;
|
||||||
@Mock LastlegOrderMapper orders;
|
@Mock LastlegOrderMapper orders;
|
||||||
|
@Mock LastlegOrderDetailMapper orderDetails;
|
||||||
@Mock ReceivingContainerSessionMapper sessions;
|
@Mock ReceivingContainerSessionMapper sessions;
|
||||||
@Mock ReceivingContainerOperationMapper operations;
|
@Mock ReceivingContainerOperationMapper operations;
|
||||||
|
@Mock ReceivingSkuReceiptMapper skuReceipts;
|
||||||
@Mock WarehouseResourceGateway warehouse;
|
@Mock WarehouseResourceGateway warehouse;
|
||||||
@Mock UnloadPhotoFileGateway unloadPhotos;
|
@Mock UnloadPhotoFileGateway unloadPhotos;
|
||||||
@Mock InboundPdaWorkflowService workflow;
|
@Mock InboundPdaWorkflowService workflow;
|
||||||
@@ -64,8 +70,10 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
ReflectionTestUtils.setField(service, "allocations", allocations);
|
ReflectionTestUtils.setField(service, "allocations", allocations);
|
||||||
ReflectionTestUtils.setField(service, "cartons", cartons);
|
ReflectionTestUtils.setField(service, "cartons", cartons);
|
||||||
ReflectionTestUtils.setField(service, "orders", orders);
|
ReflectionTestUtils.setField(service, "orders", orders);
|
||||||
|
ReflectionTestUtils.setField(service, "orderDetails", orderDetails);
|
||||||
ReflectionTestUtils.setField(service, "sessions", sessions);
|
ReflectionTestUtils.setField(service, "sessions", sessions);
|
||||||
ReflectionTestUtils.setField(service, "operations", operations);
|
ReflectionTestUtils.setField(service, "operations", operations);
|
||||||
|
ReflectionTestUtils.setField(service, "skuReceipts", skuReceipts);
|
||||||
ReflectionTestUtils.setField(service, "warehouse", warehouse);
|
ReflectionTestUtils.setField(service, "warehouse", warehouse);
|
||||||
ReflectionTestUtils.setField(service, "unloadPhotos", unloadPhotos);
|
ReflectionTestUtils.setField(service, "unloadPhotos", unloadPhotos);
|
||||||
ReflectionTestUtils.setField(service, "workflow", workflow);
|
ReflectionTestUtils.setField(service, "workflow", workflow);
|
||||||
@@ -116,7 +124,7 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
void destinationModesAreHardRejectedBeforeWarehouseCalls() {
|
void destinationModesAreHardRejectedBeforeWarehouseCalls() {
|
||||||
stubCurrent("OVERSEAS", "CONT-A");
|
stubCurrent("OVERSEAS", "CONT-A");
|
||||||
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
||||||
new ReceivingContainerRequests.BulkReceive("IN-1", "PAL-1", 1, "bulk-key")))
|
new ReceivingContainerRequests.BulkReceive("IN-1", "SKU-1", "PAL-1", 1, "bulk-key")))
|
||||||
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("409");
|
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("409");
|
||||||
verifyNoInteractions(warehouse);
|
verifyNoInteractions(warehouse);
|
||||||
|
|
||||||
@@ -141,9 +149,10 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
|
|
||||||
org.mockito.Mockito.reset(plans, lines, orders, sessions, operations, cartons, warehouse, pallets, workflow);
|
org.mockito.Mockito.reset(plans, lines, orders, sessions, operations, cartons, warehouse, pallets, workflow);
|
||||||
stubCurrent("FBA", "CONT-A");
|
stubCurrent("FBA", "CONT-A");
|
||||||
|
stubSku();
|
||||||
when(warehouse.resolvePallet("PAL-1")).thenReturn(resource(101L, "FBA-1"));
|
when(warehouse.resolvePallet("PAL-1")).thenReturn(resource(101L, "FBA-1"));
|
||||||
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
||||||
new ReceivingContainerRequests.BulkReceive("IN-1", "PAL-1", 1, "pallet-key")))
|
new ReceivingContainerRequests.BulkReceive("IN-1", "SKU-1", "PAL-1", 1, "pallet-key")))
|
||||||
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("409");
|
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("409");
|
||||||
verify(workflow, never()).assignResolvedPallet(any(), any(), any(), any());
|
verify(workflow, never()).assignResolvedPallet(any(), any(), any(), any());
|
||||||
}
|
}
|
||||||
@@ -151,12 +160,13 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
@Test
|
@Test
|
||||||
void overReceiptAndDuplicateCartonFailBeforeRemoteReservation() {
|
void overReceiptAndDuplicateCartonFailBeforeRemoteReservation() {
|
||||||
stubCurrent("FBA", "CONT-A");
|
stubCurrent("FBA", "CONT-A");
|
||||||
|
stubSku();
|
||||||
when(warehouse.resolvePallet("PAL-1")).thenReturn(resource(100L, "FBA-1"));
|
when(warehouse.resolvePallet("PAL-1")).thenReturn(resource(100L, "FBA-1"));
|
||||||
when(pallets.selectList(any())).thenReturn(List.of(planPallet()));
|
when(pallets.selectList(any())).thenReturn(List.of(planPallet()));
|
||||||
doThrow(new ResponseStatusException(org.springframework.http.HttpStatus.CONFLICT, "over receipt"))
|
doThrow(new ResponseStatusException(org.springframework.http.HttpStatus.CONFLICT, "over receipt"))
|
||||||
.when(workflow).validateBulkResolved(any(), any(), any(), anyInt());
|
.when(workflow).validateBulkResolved(any(), any(), any(), anyInt());
|
||||||
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
||||||
new ReceivingContainerRequests.BulkReceive("IN-1", "PAL-1", 9, "over-key")))
|
new ReceivingContainerRequests.BulkReceive("IN-1", "SKU-1", "PAL-1", 9, "over-key")))
|
||||||
.isInstanceOf(ResponseStatusException.class);
|
.isInstanceOf(ResponseStatusException.class);
|
||||||
verify(workflow, never()).assignResolvedPallet(any(), any(), any(), any());
|
verify(workflow, never()).assignResolvedPallet(any(), any(), any(), any());
|
||||||
|
|
||||||
@@ -176,6 +186,7 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
@Test
|
@Test
|
||||||
void containerCompletionRequiresEveryInboundCodeToBalanceExactly() {
|
void containerCompletionRequiresEveryInboundCodeToBalanceExactly() {
|
||||||
stubCurrent("FBA", "CONT-A");
|
stubCurrent("FBA", "CONT-A");
|
||||||
|
stubSku();
|
||||||
InboundPlanPalletAllocation partial = new InboundPlanPalletAllocation();
|
InboundPlanPalletAllocation partial = new InboundPlanPalletAllocation();
|
||||||
partial.setLineId(10L); partial.setPickedPackageCount(1);
|
partial.setLineId(10L); partial.setPickedPackageCount(1);
|
||||||
when(allocations.selectList(any())).thenReturn(List.of(partial));
|
when(allocations.selectList(any())).thenReturn(List.of(partial));
|
||||||
@@ -194,11 +205,48 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
doThrow(failure).when(workflow).receiveBulkResolved(any(), any(), any(), any(), anyInt(), any(), any());
|
doThrow(failure).when(workflow).receiveBulkResolved(any(), any(), any(), any(), anyInt(), any(), any());
|
||||||
|
|
||||||
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
||||||
new ReceivingContainerRequests.BulkReceive("IN-1", "PAL-1", 1, "compensate-key")))
|
new ReceivingContainerRequests.BulkReceive("IN-1", "SKU-1", "PAL-1", 1, "compensate-key")))
|
||||||
.isSameAs(failure);
|
.isSameAs(failure);
|
||||||
verify(workflow).compensateReservation("100", 55L, failure);
|
verify(workflow).compensateReservation("100", 55L, failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void signRequiresEachTypedPhotoExactlyOnceAndRestoresRoles() {
|
||||||
|
when(sessions.lockActiveByOperator("100", "100:7")).thenReturn(session("CONT-A", "WAIT_SIGN"));
|
||||||
|
when(plans.selectList(any())).thenReturn(List.of(plan("CONT-A")));
|
||||||
|
when(lines.selectList(any())).thenReturn(List.of());
|
||||||
|
when(sessions.updateById(any(ReceivingContainerSession.class))).thenReturn(1);
|
||||||
|
when(operations.insert(any(ReceivingContainerOperation.class))).thenReturn(1);
|
||||||
|
ReceivingContainerRequests.Sign request = new ReceivingContainerRequests.Sign(List.of(
|
||||||
|
new ReceivingContainerRequests.SignedPhoto(ReceivingPhotoRole.DOOR_OPEN, 3L),
|
||||||
|
new ReceivingContainerRequests.SignedPhoto(ReceivingPhotoRole.LICENSE_PLATE, 1L),
|
||||||
|
new ReceivingContainerRequests.SignedPhoto(ReceivingPhotoRole.CONTAINER_SEAL, 2L)), "sign-key");
|
||||||
|
|
||||||
|
var response = service.sign("100", "7", "receiver", request);
|
||||||
|
|
||||||
|
org.assertj.core.api.Assertions.assertThat(response.photos()).extracting("role")
|
||||||
|
.containsExactly(ReceivingPhotoRole.LICENSE_PLATE, ReceivingPhotoRole.CONTAINER_SEAL,
|
||||||
|
ReceivingPhotoRole.DOOR_OPEN);
|
||||||
|
verify(unloadPhotos).validate("100", 8L, 1L);
|
||||||
|
verify(unloadPhotos).validate("100", 8L, 2L);
|
||||||
|
verify(unloadPhotos).validate("100", 8L, 3L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bulkRejectsSkuOverReceiptBeforeWarehouseLookup() {
|
||||||
|
stubCurrent("FBA", "CONT-A");
|
||||||
|
stubSku();
|
||||||
|
com.baiyue.lastleg.inboundplan.pda.entity.ReceivingSkuReceipt received =
|
||||||
|
new com.baiyue.lastleg.inboundplan.pda.entity.ReceivingSkuReceipt();
|
||||||
|
received.setReceivedPackages(2);
|
||||||
|
when(skuReceipts.listLineSku("100", 10L, "SKU-1")).thenReturn(List.of(received));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> service.receiveBulk("100", "7", "receiver",
|
||||||
|
new ReceivingContainerRequests.BulkReceive("IN-1", "SKU-1", "PAL-1", 1, "sku-over")))
|
||||||
|
.isInstanceOf(ResponseStatusException.class).hasMessageContaining("409");
|
||||||
|
verifyNoInteractions(warehouse);
|
||||||
|
}
|
||||||
|
|
||||||
private void stubCurrent(String destinationType, String containerNo) {
|
private void stubCurrent(String destinationType, String containerNo) {
|
||||||
InboundPlan plan = plan(containerNo);
|
InboundPlan plan = plan(containerNo);
|
||||||
InboundPlanLine line = line(destinationType);
|
InboundPlanLine line = line(destinationType);
|
||||||
@@ -209,6 +257,11 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
when(orders.selectById(1L)).thenReturn(order);
|
when(orders.selectById(1L)).thenReturn(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void stubSku() {
|
||||||
|
when(orderDetails.selectList(any())).thenReturn(List.of(detail("SKU-1", 2)));
|
||||||
|
when(skuReceipts.listLineSku("100", 10L, "SKU-1")).thenReturn(List.of());
|
||||||
|
}
|
||||||
|
|
||||||
private static InboundPlan plan(String containerNo) {
|
private static InboundPlan plan(String containerNo) {
|
||||||
InboundPlan value = new InboundPlan();
|
InboundPlan value = new InboundPlan();
|
||||||
value.setId(2L); value.setPlanNo("PLAN-1"); value.setCustomerId("100"); value.setContainerNo(containerNo);
|
value.setId(2L); value.setPlanNo("PLAN-1"); value.setCustomerId("100"); value.setContainerNo(containerNo);
|
||||||
@@ -232,6 +285,13 @@ class ReceivingContainerServiceBehaviorTest {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static LastlegOrderDetail detail(String skuCode, int packages) {
|
||||||
|
LastlegOrderDetail value = new LastlegOrderDetail();
|
||||||
|
value.setId(11L); value.setCustomerId("100"); value.setOrderId(1L);
|
||||||
|
value.setSkuCode(skuCode); value.setProductNameZh("产品一"); value.setPackageCount(packages);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private static ReceivingContainerSession session(String containerNo, String status) {
|
private static ReceivingContainerSession session(String containerNo, String status) {
|
||||||
ReceivingContainerSession value = new ReceivingContainerSession();
|
ReceivingContainerSession value = new ReceivingContainerSession();
|
||||||
value.setId(8L); value.setCustomerId("100"); value.setContainerNo(containerNo); value.setOperatorKey("7");
|
value.setId(8L); value.setCustomerId("100"); value.setContainerNo(containerNo); value.setOperatorKey("7");
|
||||||
|
|||||||
Reference in New Issue
Block a user