This commit is contained in:
2026-08-25 15:08:34 +08:00
parent e815abcbd7
commit 44198866d9
64 changed files with 1382 additions and 360 deletions
@@ -21,6 +21,7 @@ class BaiyueFirstlegApplicationContractTest {
.contains("com.baiyue.firstleg.portschedule.mapper")
.contains("com.baiyue.firstleg.customs.mapper")
.contains("com.baiyue.firstleg.customerstatistics.adapter.out.persistence")
.contains("com.baiyue.firstleg.pricebookquery.adapter.out.persistence")
.doesNotContain("com.baiyue.firstleg.customerstatistics.mapper");
}
@@ -6,7 +6,7 @@ import com.baiyue.firstleg.domain.PriceModel;
import com.baiyue.firstleg.domain.PricingTaxMode;
import com.baiyue.firstleg.domain.PricingDestinationType;
import com.baiyue.firstleg.dto.PriceBookDtos;
import com.baiyue.firstleg.mapper.PriceBookQueryMapper;
import com.baiyue.firstleg.pricebookquery.adapter.out.persistence.PriceBookQueryMapper;
import org.apache.ibatis.annotations.Select;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -9,8 +9,8 @@ import com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerRequirementE
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingOperationEntity;
import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository;
import com.baiyue.firstleg.repository.PriceBookQueryRepository;
import com.baiyue.firstleg.repository.PriceBookQueryRows.ChannelRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelRow;
import com.baiyue.firstleg.pricebookquery.application.port.in.PriceBookQueryUseCase;
import com.baiyue.firstleg.service.WarehouseSupplierSnapshotService;
import com.baiyue.firstleg.service.FirstlegDocumentNumberGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,7 +33,7 @@ import static org.mockito.Mockito.*;
class OceanBookingServiceTest {
@Mock private OceanBookingRepository repository;
@Mock private PriceBookQueryRepository priceBooks;
@Mock private PriceBookQueryUseCase priceBooks;
@Mock private WarehouseSupplierSnapshotService suppliers;
@Mock private WarehouseMasterDataClient warehouses;
@Mock private FirstlegDocumentNumberGenerator documentNumbers;
@@ -0,0 +1,67 @@
package com.baiyue.firstleg.pricebookquery;
import com.baiyue.firstleg.pricebookquery.application.port.out.PriceBookQueryReader;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.ImportOption;
import org.junit.jupiter.api.Test;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideInAPackage;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.resideOutsideOfPackage;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
class PriceBookQueryArchitectureTest {
private static final String FIRSTLEG = "com.baiyue.firstleg..";
private static final String SLICE = "com.baiyue.firstleg.pricebookquery..";
private static final String APPLICATION = "com.baiyue.firstleg.pricebookquery.application..";
private static final String INPUT_PORT = "com.baiyue.firstleg.pricebookquery.application.port.in..";
private static final String OUTPUT_PORT = "com.baiyue.firstleg.pricebookquery.application.port.out..";
private static final String MODEL = "com.baiyue.firstleg.pricebookquery.application.model..";
private static final String PERSISTENCE = "com.baiyue.firstleg.pricebookquery.adapter.out.persistence..";
private static final JavaClasses PRODUCTION_CLASSES = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS)
.importPackages("com.baiyue.firstleg");
@Test
void applicationStaysFreeOfWebAndPersistenceFrameworks() {
noClasses().that().resideInAPackage(APPLICATION)
.should().dependOnClassesThat().resideInAnyPackage(
"org.springframework.web..",
"org.apache.ibatis..",
"com.baomidou.mybatisplus..")
.check(PRODUCTION_CLASSES);
}
@Test
void applicationOnlyDependsOnItsOwnSliceWithinFirstleg() {
classes().that().resideInAPackage(APPLICATION)
.should().onlyDependOnClassesThat(
resideOutsideOfPackage(FIRSTLEG).or(resideInAPackage(APPLICATION)))
.check(PRODUCTION_CLASSES);
}
@Test
void persistenceAdapterCollaboratesThroughTheOutputPortAndModel() {
classes().that().resideInAPackage(PERSISTENCE)
.should().onlyDependOnClassesThat(
resideOutsideOfPackage(SLICE)
.or(resideInAPackage(PERSISTENCE))
.or(resideInAPackage(OUTPUT_PORT))
.or(resideInAPackage(MODEL)))
.andShould().beAssignableTo(PriceBookQueryReader.class)
.check(PRODUCTION_CLASSES);
}
@Test
void consumersOnlySeeTheInputPortAndReadModel() {
noClasses().that().resideOutsideOfPackage(SLICE)
.should().dependOnClassesThat(
resideInAPackage(SLICE)
.and(resideOutsideOfPackage(INPUT_PORT))
.and(resideOutsideOfPackage(MODEL)))
.check(PRODUCTION_CLASSES);
}
}
@@ -0,0 +1,46 @@
package com.baiyue.firstleg.pricebookquery;
import com.baiyue.firstleg.pricebookquery.application.PriceBookQueryService;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelPrefixRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelRow;
import com.baiyue.firstleg.pricebookquery.application.port.out.PriceBookQueryReader;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class PriceBookQueryServiceTest {
@Mock private PriceBookQueryReader reader;
@InjectMocks private PriceBookQueryService service;
@Test
void delegatesStableReadOperationsToTheOutputPort() {
ChannelPrefixRow prefix = new ChannelPrefixRow("SEA", "IN", "OUT");
when(reader.findActiveVersionId()).thenReturn(9L);
when(reader.findChannelPrefix("SEA")).thenReturn(prefix);
assertThat(service.activeVersionId()).isEqualTo(9L);
assertThat(service.channelPrefix("SEA")).isSameAs(prefix);
verify(reader).findActiveVersionId();
verify(reader).findChannelPrefix("SEA");
}
@Test
void keepsChannelAvailabilityAsApplicationLogic() {
ChannelRow channel = new ChannelRow();
channel.setChannelCode("SEA");
when(reader.findChannels(9L, 3L)).thenReturn(List.of(channel));
assertThat(service.channelAvailable(9L, 3L, "SEA")).isTrue();
assertThat(service.channelAvailable(9L, 3L, "AIR")).isFalse();
verify(reader, org.mockito.Mockito.times(2)).findChannels(9L, 3L);
}
}
@@ -1,7 +1,7 @@
package com.baiyue.firstleg.pricing;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.repository.PriceBookQueryRows.RateRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.RateRow;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
@@ -1,7 +1,7 @@
package com.baiyue.firstleg.pricing;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.repository.PriceBookQueryRows.RateRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.RateRow;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
@@ -17,8 +17,8 @@ import com.baiyue.firstleg.mapper.ContainerTransportHistoryMapper;
import com.baiyue.firstleg.repository.ContainerRepository;
import com.baiyue.firstleg.repository.LoadingPickRepository;
import com.baiyue.firstleg.repository.SmartLoadingRepository;
import com.baiyue.firstleg.repository.PriceBookQueryRepository;
import com.baiyue.firstleg.repository.PriceBookQueryRows.ChannelRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelRow;
import com.baiyue.firstleg.pricebookquery.application.port.in.PriceBookQueryUseCase;
import com.baiyue.firstleg.oceanbooking.repository.OceanBookingRepository;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity;
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerAllocationEntity;
@@ -51,7 +51,7 @@ class ContainerServiceTest {
@MockBean private SmartLoadingRepository smartLoadingRepository;
@MockBean private LoadingPickRepository loadingPickRepository;
@MockBean private LoadingPickService loadingPickService;
@MockBean private PriceBookQueryRepository priceBooks;
@MockBean private PriceBookQueryUseCase priceBooks;
@MockBean private OceanBookingRepository oceanBookings;
@MockBean private WarehouseSupplierSnapshotService suppliers;
@MockBean private FirstlegDocumentNumberGenerator documentNumbers;
@@ -4,7 +4,7 @@ import com.baiyue.firstleg.domain.CustomerDimensionBoxType;
import com.baiyue.firstleg.entity.CustomerDimensionConfigEntity;
import com.baiyue.firstleg.pricing.FbaWarehouseRateEstimator;
import com.baiyue.firstleg.repository.CustomerDimensionConfigRepository;
import com.baiyue.firstleg.repository.PriceBookQueryRows.RateRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.RateRow;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
@@ -11,7 +11,7 @@ import com.baiyue.firstleg.entity.InboundPricingEntity;
import com.baiyue.firstleg.entity.InboundPricingIdempotencyEntity;
import com.baiyue.firstleg.pricing.ActivePriceBookEstimator;
import com.baiyue.firstleg.repository.FbaPricingRepository;
import com.baiyue.firstleg.repository.PriceBookQueryRows.RateRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.RateRow;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -13,11 +13,11 @@ import com.baiyue.firstleg.pricing.FbaWarehouseRateEstimator;
import com.baiyue.firstleg.pricing.PriceBookWarehouseRegionResolver;
import com.baiyue.firstleg.pricing.PriceRegionResolver;
import com.baiyue.firstleg.pricing.RegionWeightTierEstimator;
import com.baiyue.firstleg.repository.PriceBookQueryRepository;
import com.baiyue.firstleg.repository.PriceBookQueryRows.ChannelRow;
import com.baiyue.firstleg.repository.PriceBookQueryRows.ChannelTaxModeRow;
import com.baiyue.firstleg.repository.PriceBookQueryRows.ChannelPrefixRow;
import com.baiyue.firstleg.repository.PriceBookQueryRows.RateRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelTaxModeRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.ChannelPrefixRow;
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.RateRow;
import com.baiyue.firstleg.pricebookquery.application.port.in.PriceBookQueryUseCase;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
@@ -38,7 +38,7 @@ import static org.mockito.Mockito.when;
PriceBookWarehouseRegionResolver.class})
@TestPropertySource(properties = "baiyue.security.internal-service-token=internal-token")
class MerchantPriceBookServiceTest {
@MockBean private PriceBookQueryRepository repository;
@MockBean private PriceBookQueryUseCase repository;
@MockBean private PriceBookWarehouseClient warehouses;
@Resource private MerchantPriceBookService service;
@@ -5,6 +5,7 @@
"booking-customs-trucking->inbound",
"booking-customs-trucking->measurement-pricing",
"booking-customs-trucking->outbound",
"booking-customs-trucking->pricebook-query",
"booking-customs-trucking->shared-technical",
"booking-customs-trucking->split-loading",
"customer-statistics->shared-technical",
@@ -19,6 +20,7 @@
"measurement-pricing->booking-customs-trucking",
"measurement-pricing->finance-integration",
"measurement-pricing->inbound",
"measurement-pricing->pricebook-query",
"measurement-pricing->shared-technical",
"outbound->booking-customs-trucking",
"outbound->shared-technical",
@@ -35,8 +37,8 @@
"shipping-nodes->split-loading",
"split-loading->booking-customs-trucking",
"split-loading->inbound",
"split-loading->measurement-pricing",
"split-loading->outbound",
"split-loading->pricebook-query",
"split-loading->shared-technical"
],
"requiredClassLocations": {
@@ -44,21 +46,50 @@
"com.baiyue.firstleg.customerstatistics.adapter.out.persistence.CustomerTransitStatisticsMapper": "src/main/java/com/baiyue/firstleg/customerstatistics/adapter/out/persistence/CustomerTransitStatisticsMapper.java",
"com.baiyue.firstleg.customerstatistics.application.CustomerTransitStatisticsService": "src/main/java/com/baiyue/firstleg/customerstatistics/application/CustomerTransitStatisticsService.java",
"com.baiyue.firstleg.customerstatistics.application.model.CustomerTransitStatisticsDtos": "src/main/java/com/baiyue/firstleg/customerstatistics/application/model/CustomerTransitStatisticsDtos.java",
"com.baiyue.firstleg.customerstatistics.application.port.out.CustomerTransitStatisticsReader": "src/main/java/com/baiyue/firstleg/customerstatistics/application/port/out/CustomerTransitStatisticsReader.java"
},
"applicationDependencyRule": {
"packagePrefix": "com.baiyue.firstleg.customerstatistics.application",
"allowedInternalPrefix": "com.baiyue.firstleg.customerstatistics.application",
"forbiddenImportPrefixes": [
"org.springframework.web",
"org.apache.ibatis",
"com.baomidou.mybatisplus"
]
"com.baiyue.firstleg.customerstatistics.application.port.out.CustomerTransitStatisticsReader": "src/main/java/com/baiyue/firstleg/customerstatistics/application/port/out/CustomerTransitStatisticsReader.java",
"com.baiyue.firstleg.pricebookquery.adapter.out.persistence.PriceBookQueryMapper": "src/main/java/com/baiyue/firstleg/pricebookquery/adapter/out/persistence/PriceBookQueryMapper.java",
"com.baiyue.firstleg.pricebookquery.application.PriceBookQueryService": "src/main/java/com/baiyue/firstleg/pricebookquery/application/PriceBookQueryService.java",
"com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows": "src/main/java/com/baiyue/firstleg/pricebookquery/application/model/PriceBookQueryRows.java",
"com.baiyue.firstleg.pricebookquery.application.port.in.PriceBookQueryUseCase": "src/main/java/com/baiyue/firstleg/pricebookquery/application/port/in/PriceBookQueryUseCase.java",
"com.baiyue.firstleg.pricebookquery.application.port.out.PriceBookQueryReader": "src/main/java/com/baiyue/firstleg/pricebookquery/application/port/out/PriceBookQueryReader.java"
},
"applicationDependencyRules": [
{
"packagePrefix": "com.baiyue.firstleg.customerstatistics.application",
"allowedInternalPrefix": "com.baiyue.firstleg.customerstatistics.application",
"forbiddenImportPrefixes": [
"org.springframework.web",
"org.apache.ibatis",
"com.baomidou.mybatisplus"
]
},
{
"packagePrefix": "com.baiyue.firstleg.pricebookquery.application",
"allowedInternalPrefix": "com.baiyue.firstleg.pricebookquery.application",
"forbiddenImportPrefixes": [
"org.springframework.web",
"org.apache.ibatis",
"com.baomidou.mybatisplus"
]
}
],
"sliceExposureRules": [
{
"slicePrefix": "com.baiyue.firstleg.pricebookquery.",
"allowedTargetPrefixes": [
"com.baiyue.firstleg.pricebookquery.application.model.",
"com.baiyue.firstleg.pricebookquery.application.port.in."
]
}
],
"sliceSpecificRules": {
"customer-statistics": {
"allowedOutgoing": ["shared-technical"],
"allowedIncoming": []
},
"pricebook-query": {
"allowedOutgoing": [],
"allowedIncoming": ["booking-customs-trucking", "measurement-pricing", "split-loading"]
}
}
}