2026-10-03 04:18:52 +08:00
package com.baiyue.lastleg.delivery ;
import com.baomidou.mybatisplus.core.MybatisConfiguration ;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean ;
import com.baiyue.lastleg.delivery.mapper.DispatchFeeCargoMapper ;
import org.junit.jupiter.api.BeforeEach ;
import org.junit.jupiter.api.Test ;
import org.mybatis.spring.SqlSessionTemplate ;
import org.springframework.jdbc.core.JdbcTemplate ;
import org.springframework.jdbc.datasource.DriverManagerDataSource ;
import java.util.UUID ;
import static org.assertj.core.api.Assertions.* ;
class DispatchFeeCargoMapperTest {
2026-10-18 16:34:14 +08:00
/** 原退回实收只重派其已冻结货量,不借同托其他货物放大来源。 */
@Test void returnedReceiptRetainsItsExactSourceInsteadOfBecomingAWholePallet () {
var item = new com . baiyue . lastleg . dispatch . entity . DispatchItem (); item . setId ( 201L ); item . setWarehousePalletId ( 501L );
item . setReturnReceiptId ( 701L ); item . setSourceStage ( "RECEIVED" ); item . setInboundCode ( "IN-A" );
item . setPackageCount ( 2 ); item . setDestinationType ( "FBA" ); item . setDestinationWarehouseCode ( "ONT8" );
2026-10-20 10:35:52 +08:00
var query = nativeGateway ( item );
assertThat ( query . sourceCargo ( "DP-1" , "101" )). singleElement (). satisfies ( source -> {
2026-10-18 16:34:14 +08:00
assertThat ( source . inboundCode ()). isEqualTo ( "IN-A" ); assertThat ( source . packages ()). isEqualTo ( 2 );
});
}
/** 展示普通货或外接货均不能改变真实组成;保留同客户、同仓及本次拣货边界。 */
@org.junit.jupiter.params.ParameterizedTest
@org.junit.jupiter.params.provider.ValueSource ( strings = { "IN-A" , "IN-B" })
void actualSourceQueryDoesNotDependOnWhichInboundWasChosenForDisplay ( String displayInbound ) {
jdbc . update ( "UPDATE ll_dispatch_item SET inbound_code=?,plan_pallet_id=801" , displayInbound );
var item = new com . baiyue . lastleg . dispatch . entity . DispatchItem (); item . setId ( 201L ); item . setWarehousePalletId ( 501L );
item . setInboundCode ( displayInbound ); item . setPackageCount ( 20 ); item . setDestinationType ( "FBA" ); item . setDestinationWarehouseCode ( "ONT8" );
2026-10-20 10:35:52 +08:00
var query = nativeGateway ( item );
var sources = query . sourceCargo ( "DP-1" , "101" );
2026-10-18 16:34:14 +08:00
assertThat ( sources ). extracting ( com . baiyue . lastleg . fleet . trip . FleetDispatchGateway . SourceCargo :: inboundCode ). containsExactly ( "IN-A" , "IN-B" );
assertThat ( sources ). extracting ( com . baiyue . lastleg . fleet . trip . FleetDispatchGateway . SourceCargo :: packages ). containsExactly ( 10 , 10 );
item . setPackageCount ( 19 );
2026-10-20 10:35:52 +08:00
assertThatThrownBy (() -> query . sourceCargo ( "DP-1" , "101" )). hasMessageContaining ( "箱数未核平" );
2026-10-18 16:34:14 +08:00
}
2026-10-20 10:35:52 +08:00
/** 使用当前Fleet整车来源入口,隔离无关资源写链,不保留旧客户主单查询类。 */
private com . baiyue . lastleg . dispatch . fleet . DispatchFleetAdapter nativeGateway ( com . baiyue . lastleg . dispatch . entity . DispatchItem item ) {
var aggregates = org . mockito . Mockito . mock ( com . baiyue . lastleg . dispatch . repository . DispatchAggregateRepository . class );
var dispatch = new com . baiyue . lastleg . dispatch . entity . DispatchAggregate ();
dispatch . setId ( 1L ); dispatch . setDispatchNo ( "DP-1" );
item . setCustomerId ( "101" ); item . setDispatchOrderId ( 1L );
org . mockito . Mockito . when ( aggregates . find ( "DP-1" )). thenReturn ( dispatch );
org . mockito . Mockito . when ( aggregates . cargo ( 1L )). thenReturn ( java . util . List . of ( item ));
return new com . baiyue . lastleg . dispatch . fleet . DispatchFleetAdapter ( aggregates , null , null , null ,
new com . baiyue . lastleg . delivery . repository . DispatchCargoSourceRepository ( mapper ), null ,
new com . fasterxml . jackson . databind . ObjectMapper ());
}
2026-10-03 04:18:52 +08:00
JdbcTemplate jdbc ; DispatchFeeCargoMapper mapper ;
@BeforeEach void setup () throws Exception {
var dataSource = new DriverManagerDataSource ( "jdbc:h2:mem:" + UUID . randomUUID () + ";MODE=MySQL;DB_CLOSE_DELAY=-1" , "sa" , "" );
jdbc = new JdbcTemplate ( dataSource );
jdbc . execute ( "CREATE TABLE ll_dispatch_item(id BIGINT,dispatch_order_id BIGINT,customer_id VARCHAR(64),warehouse_pallet_id BIGINT,pallet_no VARCHAR(64),overseas_warehouse_id VARCHAR(64),plan_pallet_id BIGINT,inbound_code VARCHAR(64))" );
jdbc . execute ( "CREATE TABLE ll_inventory_position(id BIGINT,customer_id VARCHAR(64),pallet_id BIGINT,overseas_warehouse_id VARCHAR(64),balance_id BIGINT,available_packages BIGINT)" );
jdbc . execute ( "CREATE TABLE ll_inventory_balance(id BIGINT,customer_id VARCHAR(64),inbound_order_id BIGINT,inbound_code VARCHAR(64))" );
jdbc . execute ( "CREATE TABLE ll_order(id BIGINT,customer_id VARCHAR(64),source_region VARCHAR(32),source_inbound_id VARCHAR(64))" );
2026-10-20 10:35:52 +08:00
jdbc . execute ( "CREATE TABLE ll_dispatch_pda_task(id BIGINT,dispatch_order_id BIGINT UNIQUE)" );
2026-10-03 04:18:52 +08:00
jdbc . execute ( "CREATE TABLE ll_dispatch_pda_pick(task_id BIGINT,customer_id VARCHAR(64),dispatch_item_id BIGINT,inventory_position_id BIGINT,packages BIGINT)" );
jdbc . execute ( "CREATE TABLE ll_inbound_plan_pallet_allocation(pallet_id BIGINT,line_id BIGINT)" );
jdbc . execute ( "CREATE TABLE ll_inbound_plan_line(id BIGINT,customer_id VARCHAR(64),order_id BIGINT)" );
jdbc . update ( "INSERT INTO ll_dispatch_item VALUES(201,1,'101',501,'PLT-501','WH-1',NULL,'IN-A')" );
jdbc . update ( "INSERT INTO ll_inventory_position VALUES(101,'101',501,'WH-1',301,8),(102,'101',501,'WH-1',302,6),(103,'202',501,'WH-1',303,50),(104,'101',501,'WH-2',301,50)" );
jdbc . update ( "INSERT INTO ll_inventory_balance VALUES(301,'101',401,'IN-A'),(302,'101',402,'IN-B'),(303,'202',403,'IN-OTHER')" );
jdbc . update ( "INSERT INTO ll_order VALUES(401,'101','FIRSTLEG','11'),(402,'101','FIRSTLEG','12'),(403,'202','FIRSTLEG','13')" );
2026-10-20 10:35:52 +08:00
jdbc . update ( "INSERT INTO ll_dispatch_pda_task VALUES(601,1),(602,2)" );
2026-10-03 04:18:52 +08:00
jdbc . update ( "INSERT INTO ll_dispatch_pda_pick VALUES(601,'101',201,101,2),(601,'101',201,102,4),(602,'101',201,101,50)" );
var config = new MybatisConfiguration (); config . addMapper ( DispatchFeeCargoMapper . class );
var factory = new MybatisSqlSessionFactoryBean (); factory . setDataSource ( dataSource ); factory . setConfiguration ( config ); factory . afterPropertiesSet ();
mapper = new SqlSessionTemplate ( factory . getObject ()). getMapper ( DispatchFeeCargoMapper . class );
}
@Test void preservesEveryInboundOnSharedPalletAndIncludesOnlyThisDispatchsPickedPackages () {
var rows = mapper . list ( "101" , 1 );
assertThat ( rows ). hasSize ( 2 );
assertThat ( rows ). extracting ( row -> row . sourceInboundId ()). containsExactly ( "11" , "12" );
assertThat ( rows ). extracting ( row -> row . packages ()). containsExactly ( 10L , 10L );
assertThat ( mapper . list ( "202" , 1 )). isEmpty ();
}
2026-10-20 10:35:52 +08:00
/** 同一整车与任务内按真实明细和拣货客户分别统计,不借其他客户货量。 */
@Test void sharedDispatchAndTaskKeepEachCustomersSourcesSeparate () {
jdbc . update ( "INSERT INTO ll_dispatch_item VALUES(202,1,'202',501,'PLT-501','WH-1',NULL,'IN-OTHER')" );
jdbc . update ( "INSERT INTO ll_dispatch_pda_pick VALUES(601,'202',202,103,7)" );
assertThat ( mapper . list ( "101" , 1 )). extracting ( row -> row . packages ()). containsExactly ( 10L , 10L );
assertThat ( mapper . list ( "202" , 1 )). singleElement (). satisfies ( row -> {
assertThat ( row . inboundCode ()). isEqualTo ( "IN-OTHER" );
assertThat ( row . packages ()). isEqualTo ( 57L );
});
assertThat ( mapper . list ( "303" , 1 )). isEmpty ();
}
2026-10-18 16:34:14 +08:00
@Test void aPhysicalSharedPalletIncludesEveryActualSourceRegardlessOfItsDisplayPlan () {
2026-10-03 04:18:52 +08:00
jdbc . update ( "UPDATE ll_dispatch_item SET plan_pallet_id=801" );
jdbc . update ( "INSERT INTO ll_inbound_plan_pallet_allocation VALUES(801,901)" );
jdbc . update ( "INSERT INTO ll_inbound_plan_line VALUES(901,'101',401)" );
2026-10-18 16:34:14 +08:00
assertThat ( mapper . list ( "101" , 1 )). extracting ( row -> row . sourceInboundId ()). containsExactly ( "11" , "12" );
2026-10-03 04:18:52 +08:00
}
}