二期内容提交

This commit is contained in:
2026-08-04 17:18:07 +08:00
parent db72bdf884
commit b7d36d4766
30 changed files with 537 additions and 19 deletions
@@ -0,0 +1,137 @@
package com.baiyue.firstleg.service;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.firstleg.client.WarehousePalletLocationClient;
import com.baiyue.firstleg.config.InboundProperties;
import com.baiyue.firstleg.entity.InboundOrderEntity;
import com.baiyue.firstleg.repository.InboundPalletAllocationRepository;
import com.baiyue.firstleg.repository.InboundWorkflowRepository;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import java.math.BigDecimal;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class MeasurementLocationOccupationServiceTest {
private static final long BUSINESS_TENANT = 10001L;
private static final long RESOURCE_TENANT = 90001L;
private static final long WAREHOUSE = 200L;
private static final long INBOUND = 88L;
private static final long OPERATOR = 9L;
private static final long MEASUREMENT = 30L;
private final WarehousePalletLocationClient warehouse = mock(WarehousePalletLocationClient.class);
private final InboundPalletAllocationRepository allocations = mock(InboundPalletAllocationRepository.class);
private final InboundWorkflowRepository workflow = mock(InboundWorkflowRepository.class);
private final InboundProperties properties = properties();
private final MeasurementLocationOccupationService service =
new MeasurementLocationOccupationService(warehouse, allocations, workflow, properties, "internal-token");
@Test
void sharedWarehouseResourcesUseResourceTenantWhileSnapshotsRemainInBusinessTenant() {
properties.setWarehouseResourceTenantId(RESOURCE_TENANT);
when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound());
when(warehouse.reserve(org.mockito.ArgumentMatchers.eq("internal-token"),
org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(batch("RESERVED")));
when(warehouse.confirm(org.mockito.ArgumentMatchers.eq("internal-token"),
org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(batch("OCCUPIED")));
service.occupy(BUSINESS_TENANT, INBOUND, OPERATOR, MEASUREMENT, 3);
ArgumentCaptor<WarehousePalletLocationClient.ReserveRequest> reserve =
ArgumentCaptor.forClass(WarehousePalletLocationClient.ReserveRequest.class);
verify(warehouse).reserve(org.mockito.ArgumentMatchers.eq("internal-token"), reserve.capture());
assertThat(reserve.getValue().tenantId()).isEqualTo(RESOURCE_TENANT);
assertThat(reserve.getValue().businessId()).isEqualTo(INBOUND);
assertThat(reserve.getValue().idempotencyKey()).isEqualTo("measure-88-30-3");
ArgumentCaptor<WarehousePalletLocationClient.ConfirmRequest> confirm =
ArgumentCaptor.forClass(WarehousePalletLocationClient.ConfirmRequest.class);
verify(warehouse).confirm(org.mockito.ArgumentMatchers.eq("internal-token"), confirm.capture());
assertThat(confirm.getValue().tenantId()).isEqualTo(RESOURCE_TENANT);
assertThat(confirm.getValue().businessId()).isEqualTo(INBOUND);
verify(allocations, times(2)).replace(
org.mockito.ArgumentMatchers.eq(BUSINESS_TENANT),
org.mockito.ArgumentMatchers.eq(INBOUND),
org.mockito.ArgumentMatchers.eq(WAREHOUSE),
org.mockito.ArgumentMatchers.eq(new BigDecimal("1.200000")),
org.mockito.ArgumentMatchers.any());
}
@Test
void zeroResourceTenantFallsBackToBusinessTenant() {
properties.setWarehouseResourceTenantId(0L);
when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound());
when(warehouse.reserve(org.mockito.ArgumentMatchers.eq("internal-token"),
org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(batch("RESERVED")));
when(warehouse.confirm(org.mockito.ArgumentMatchers.eq("internal-token"),
org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(batch("OCCUPIED")));
service.occupy(BUSINESS_TENANT, INBOUND, OPERATOR, MEASUREMENT, 3);
ArgumentCaptor<WarehousePalletLocationClient.ReserveRequest> reserve =
ArgumentCaptor.forClass(WarehousePalletLocationClient.ReserveRequest.class);
verify(warehouse).reserve(org.mockito.ArgumentMatchers.eq("internal-token"), reserve.capture());
assertThat(reserve.getValue().tenantId()).isEqualTo(BUSINESS_TENANT);
ArgumentCaptor<WarehousePalletLocationClient.ConfirmRequest> confirm =
ArgumentCaptor.forClass(WarehousePalletLocationClient.ConfirmRequest.class);
verify(warehouse).confirm(org.mockito.ArgumentMatchers.eq("internal-token"), confirm.capture());
assertThat(confirm.getValue().tenantId()).isEqualTo(BUSINESS_TENANT);
}
@Test
void confirmFailureReleasesReservationInResourceTenantAndKeepsOriginalFailure() {
properties.setWarehouseResourceTenantId(RESOURCE_TENANT);
when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound());
when(warehouse.reserve(org.mockito.ArgumentMatchers.eq("internal-token"),
org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(batch("RESERVED")));
IllegalStateException failure = new IllegalStateException("confirm failed");
when(warehouse.confirm(org.mockito.ArgumentMatchers.eq("internal-token"),
org.mockito.ArgumentMatchers.any())).thenThrow(failure);
when(warehouse.release(org.mockito.ArgumentMatchers.eq("internal-token"),
org.mockito.ArgumentMatchers.any())).thenReturn(ApiResponse.success(List.of()));
assertThatThrownBy(() -> service.occupy(BUSINESS_TENANT, INBOUND, OPERATOR, MEASUREMENT, 3))
.isSameAs(failure);
ArgumentCaptor<WarehousePalletLocationClient.ReleaseRequest> release =
ArgumentCaptor.forClass(WarehousePalletLocationClient.ReleaseRequest.class);
verify(warehouse).release(org.mockito.ArgumentMatchers.eq("internal-token"), release.capture());
assertThat(release.getValue().tenantId()).isEqualTo(RESOURCE_TENANT);
assertThat(release.getValue().businessId()).isEqualTo(INBOUND);
verify(allocations).replace(BUSINESS_TENANT, INBOUND, WAREHOUSE,
new BigDecimal("1.200000"), batch("RESERVED"));
}
private static InboundProperties properties() {
InboundProperties value = new InboundProperties();
value.setDefaultPalletCapacityCbm(new BigDecimal("1.200000"));
return value;
}
private static InboundOrderEntity inbound() {
InboundOrderEntity value = new InboundOrderEntity();
value.setTenantId(BUSINESS_TENANT);
value.setId(INBOUND);
value.setWarehouseId(WAREHOUSE);
value.setInboundCode("RK-001");
value.setActualVolumeCbm(new BigDecimal("1.0000"));
return value;
}
private static WarehousePalletLocationClient.BatchResult batch(String state) {
return new WarehousePalletLocationClient.BatchResult(1, List.of(
new WarehousePalletLocationClient.AllocationResult(
501L, "RES-001", 1, 601L, "PL-001", 701L, "A-001",
new BigDecimal("1.0000"), state)));
}
}