优化
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
package com.baiyue.firstleg.domain;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class ContainerSpecificationCatalogTest {
|
||||
@Test
|
||||
void exposesCanonicalSpecificationsAndRejectsAliases() {
|
||||
var specification = ContainerSpecificationCatalog.requireMatch(
|
||||
"40HC", new BigDecimal("76.000"), new BigDecimal("28000.000"));
|
||||
|
||||
assertThat(specification.containerType()).isEqualTo("40HC");
|
||||
assertThatThrownBy(() -> ContainerSpecificationCatalog.require("40HQ"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("固定规格");
|
||||
assertThatThrownBy(() -> ContainerSpecificationCatalog.requireMatch(
|
||||
"40HC", new BigDecimal("68"), new BigDecimal("28000")))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("容量和限重");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -309,7 +309,7 @@ class OceanBookingServiceTest {
|
||||
new PartyRequest("CONSIGNEE", "收货人", null, null, null),
|
||||
new PartyRequest("NOTIFY_PARTY", "通知人", null, null, null));
|
||||
List<ContainerRequirementRequest> requirements = List.of(
|
||||
new ContainerRequirementRequest("40HQ", "DRY", BigDecimal.ONE, BigDecimal.TEN, 1));
|
||||
new ContainerRequirementRequest("40HC", "DRY", new BigDecimal("76"), new BigDecimal("28000"), 1));
|
||||
return new DraftData(customerId, customerName, "SEA-US", 701L, "深圳仓", "BL-001",
|
||||
81L, "船公司", null, null, "VESSEL", "V001", "CNSZX", "深圳", "USLAX", "洛杉矶",
|
||||
null, serviceTerm, freightTerm, LocalDateTime.of(2026, 9, 1, 0, 0),
|
||||
|
||||
+10
@@ -20,6 +20,16 @@ class ContainerOverviewSqlContractTest {
|
||||
.doesNotContain("SELECT *");
|
||||
}
|
||||
|
||||
@Test void exceptionQueriesSelectEveryExceptionRowConstructorField() throws Exception {
|
||||
for (String method : java.util.List.of("exceptions", "latestException")) {
|
||||
String sql = String.join(" ", ContainerOverviewMapper.class.getDeclaredMethod(method, long.class)
|
||||
.getAnnotation(Select.class).value());
|
||||
assertThat(sql).contains("SELECT id,action,reason", "operator_id operatorId",
|
||||
"operator_name operatorName", "occurred_at occurredAt", "request_hash requestHash")
|
||||
.doesNotContain("SELECT *");
|
||||
}
|
||||
}
|
||||
|
||||
@Test void developmentAndUnifiedSchemasContainImmutableIdempotentExceptionHistory() throws Exception {
|
||||
String development = new ClassPathResource("db/phase3-smart-loading-schema.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
|
||||
@@ -83,10 +83,22 @@ class ContainerServiceTest {
|
||||
assertThat(saved.getChannelName()).isEqualTo("美西海运");
|
||||
assertThat(saved.getWarehouseId()).isEqualTo(101L);
|
||||
assertThat(saved.getWarehouseName()).isEqualTo("上海中转仓");
|
||||
assertThat(saved.getCapacityCbm()).isEqualByComparingTo("68.0000");
|
||||
assertThat(saved.getCapacityCbm()).isEqualByComparingTo("76.0000");
|
||||
assertThat(saved.getPlanStatus()).isEqualTo("WAIT_LOADING");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("新增模拟柜拒绝柜型与固定规格不匹配")
|
||||
void rejectsSimulationWithNonCanonicalSpecification() {
|
||||
SimulationCreateRequest invalid = new SimulationCreateRequest(
|
||||
"SEA-US", 101L, "40HC", new BigDecimal("100"), new BigDecimal("28000"));
|
||||
|
||||
assertThatThrownBy(() -> service.createSimulation(9L, "admin", invalid))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("容量和限重");
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("智能装柜草稿阶段允许完整编辑")
|
||||
void updatesAllFieldsWhileEditing() {
|
||||
@@ -271,12 +283,12 @@ class ContainerServiceTest {
|
||||
@DisplayName("首次关联允许已有预排货的编辑计划且保持内部柜和计划身份")
|
||||
void linksConfirmedBookingAfterPreloading() {
|
||||
ContainerBookingEntity container = booking("EDITING", 2);
|
||||
container.setWarehouseId(101L); container.setChannelCode("SEA-US"); container.setContainerType("40HQ");
|
||||
container.setCapacityCbm(new BigDecimal("68.0000")); container.setMaxWeightKg(new BigDecimal("26000.000"));
|
||||
container.setWarehouseId(101L); container.setChannelCode("SEA-US"); container.setContainerType("40HC");
|
||||
container.setCapacityCbm(new BigDecimal("76.0000")); container.setMaxWeightKg(new BigDecimal("28000.000"));
|
||||
OceanBookingEntity booking = new OceanBookingEntity();
|
||||
booking.setId(21L); booking.setStatus("CONFIRMED"); booking.setWarehouseId(101L); booking.setChannelCode("SEA-US");
|
||||
OceanBookingContainerRequirementEntity requirement = new OceanBookingContainerRequirementEntity();
|
||||
requirement.setId(31L); requirement.setQuantity(1); requirement.setContainerType("40HQ"); requirement.setCapacityCbm(new BigDecimal("68.0000")); requirement.setMaxWeightKg(new BigDecimal("26000.000"));
|
||||
requirement.setId(31L); requirement.setQuantity(1); requirement.setContainerType("40HC"); requirement.setCapacityCbm(new BigDecimal("76.0000")); requirement.setMaxWeightKg(new BigDecimal("28000.000"));
|
||||
when(repository.find(11L)).thenReturn(container);
|
||||
when(oceanBookings.find(21L)).thenReturn(booking);
|
||||
when(oceanBookings.requirement(21L, 31L)).thenReturn(requirement);
|
||||
@@ -323,15 +335,15 @@ class ContainerServiceTest {
|
||||
|
||||
private static SaveRequest request(String cabinetNo) {
|
||||
return new SaveRequest("MSCU1234567", cabinetNo, 101L, "上海仓", "BOL-001", "柏悦轮",
|
||||
"V001", "40HQ", 201L, "船司A", "CNSHA", "上海港", "USLAX", "洛杉矶港",
|
||||
"ONT8", "ONT8", new BigDecimal("68.0000"), new BigDecimal("26000.000"), 202L, "拖车公司A",
|
||||
"V001", "40HC", 201L, "船司A", "CNSHA", "上海港", "USLAX", "洛杉矶港",
|
||||
"ONT8", "ONT8", new BigDecimal("76.0000"), new BigDecimal("28000.000"), 202L, "拖车公司A",
|
||||
LocalDateTime.of(2026, 8, 10, 8, 0), LocalDateTime.of(2026, 8, 12, 8, 0), null,
|
||||
LocalDateTime.of(2026, 8, 25, 8, 0), null,
|
||||
LocalDateTime.of(2026, 8, 27, 8, 0), null);
|
||||
}
|
||||
|
||||
private static SimulationCreateRequest simulation() {
|
||||
return new SimulationCreateRequest("SEA-US", 101L, "40HQ", new BigDecimal("68.0000"), new BigDecimal("26000.000"));
|
||||
return new SimulationCreateRequest("SEA-US", 101L, "40HC", new BigDecimal("76.0000"), new BigDecimal("28000.000"));
|
||||
}
|
||||
|
||||
private static ChannelRow channel() {
|
||||
|
||||
+44
@@ -1,6 +1,7 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.client.WarehousePalletLocationClient;
|
||||
import com.baiyue.firstleg.config.InboundProperties;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
@@ -23,6 +24,7 @@ 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.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -115,6 +117,48 @@ class MeasurementLocationOccupationServiceTest {
|
||||
org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsConfirmedWeightWithoutConfirmationTimeInsteadOfDroppingIt() {
|
||||
InboundWeightResultEntity weight = confirmedWeights().get(0);
|
||||
weight.setConfirmedAt(null);
|
||||
when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound());
|
||||
when(measurements.listWeights(BUSINESS_TENANT, INBOUND)).thenReturn(List.of(weight));
|
||||
|
||||
assertThatThrownBy(() -> service.occupy(BUSINESS_TENANT, INBOUND, OPERATOR, MEASUREMENT, 3))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("缺少确认时间");
|
||||
|
||||
verify(warehouse, never()).reserve(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsConfirmedWeightWithoutNetWeightInsteadOfDroppingIt() {
|
||||
InboundWeightResultEntity weight = confirmedWeights().get(0);
|
||||
weight.setNetWeightKg(null);
|
||||
when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound());
|
||||
when(measurements.listWeights(BUSINESS_TENANT, INBOUND)).thenReturn(List.of(weight));
|
||||
|
||||
assertThatThrownBy(() -> service.occupy(BUSINESS_TENANT, INBOUND, OPERATOR, MEASUREMENT, 3))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("缺少有效净重");
|
||||
|
||||
verify(warehouse, never()).reserve(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsConfirmedWeightWithoutPalletInsteadOfDroppingIt() {
|
||||
InboundWeightResultEntity weight = confirmedWeights().get(0);
|
||||
weight.setPalletId(null);
|
||||
when(workflow.findOwned(BUSINESS_TENANT, INBOUND)).thenReturn(inbound());
|
||||
when(measurements.listWeights(BUSINESS_TENANT, INBOUND)).thenReturn(List.of(weight));
|
||||
|
||||
assertThatThrownBy(() -> service.occupy(BUSINESS_TENANT, INBOUND, OPERATOR, MEASUREMENT, 3))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("缺少有效托盘");
|
||||
|
||||
verify(warehouse, never()).reserve(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void confirmFailureReleasesReservationInResourceTenantAndKeepsOriginalFailure() {
|
||||
properties.setWarehouseResourceTenantId(90001L);
|
||||
|
||||
@@ -81,6 +81,23 @@ class MeasurementReviewServiceTest {
|
||||
assertThat(history.getValue().getToStatus()).isEqualTo("WAIT_SPLIT");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("审核通过使用订单权威货物总重量,不依赖箱规重量")
|
||||
void shouldApproveWithActualGrossWeightWhenCartonWeightIsMissing() {
|
||||
Fixture fixture = fixture(false);
|
||||
InboundMeasurementItemEntity item = new InboundMeasurementItemEntity();
|
||||
item.setPackageCount(5);
|
||||
item.setTotalVolumeCbm(new BigDecimal("0.7480"));
|
||||
when(fixture.repository.listMeasurementItems(10001L, 20L)).thenReturn(List.of(item));
|
||||
when(fixture.repository.transitionReview(10001L, 10L, 9L, 3, true, 20L)).thenReturn(1);
|
||||
when(fixture.repository.transitionMeasurement(10001L, 10L, 20L, "APPROVED")).thenReturn(1);
|
||||
|
||||
fixture.service.approve(10001L, 9L, "审核员", 10L, "approve-authoritative-weight",
|
||||
new MeasurementReviewRequest(20L, 3, null));
|
||||
|
||||
verify(fixture.repository).transitionReview(10001L, 10L, 9L, 3, true, 20L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("确认箱数合计不等于订单总箱数时不能审核通过")
|
||||
void shouldRejectApprovalWhenConfirmedPackageCountDoesNotMatchOrder() {
|
||||
@@ -195,6 +212,7 @@ class MeasurementReviewServiceTest {
|
||||
order.setProcessStatus("MEASURE_PENDING");
|
||||
order.setMeasureReviewStatus("PENDING");
|
||||
order.setTotalPackageCount(5);
|
||||
order.setActualGrossWeightKg(new BigDecimal("11.500"));
|
||||
InboundMeasurementEntity measurement = new InboundMeasurementEntity();
|
||||
measurement.setId(20L);
|
||||
measurement.setStatus("SUBMITTED");
|
||||
|
||||
Reference in New Issue
Block a user