2026-10-09 17:36:24 +08:00
package com.baiyue.lastleg.mapper ;
import com.baomidou.mybatisplus.core.MybatisConfiguration ;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean ;
import org.h2.jdbcx.JdbcDataSource ;
import org.junit.jupiter.api.BeforeEach ;
import org.junit.jupiter.api.Test ;
import org.mybatis.spring.SqlSessionTemplate ;
import org.springframework.jdbc.core.JdbcTemplate ;
import java.util.UUID ;
import static org.assertj.core.api.Assertions.* ;
class CustomerOrderProgressMapperTest {
private JdbcTemplate jdbc ;
private CustomerOrderProgressMapper mapper ;
2026-10-19 17:56:36 +08:00
/** 两客户共用一单一任务,计划和在途均按各自真实明细归属统计。 */
@Test void sharedDispatchAndTaskKeepBothCustomerProgressSeparate () {
jdbc . update ( "INSERT INTO ll_dispatch_item(id,dispatch_order_id,customer_id,plan_pallet_id,overseas_warehouse_id,destination_warehouse_code) VALUES(101,10,'22',501,'W1','FBA2')" );
jdbc . update ( "INSERT INTO ll_inbound_plan_pallet_allocation VALUES(501,1002,30)" );
assertThat ( mapper . sources ( "11" , null )). extracting ( s -> s . scheduledPackages ()). containsExactly ( 10L , 20L );
assertThat ( mapper . sources ( "22" , null )). singleElement (). satisfies ( s -> assertThat ( s . scheduledPackages ()). isEqualTo ( 30 ));
jdbc . update ( "INSERT INTO ll_dispatch_pda_task VALUES(700,10)" );
jdbc . update ( "INSERT INTO ll_dispatch_pda_pick VALUES(600,'11',100,400,4,700),(601,'22',101,401,7,700)" );
jdbc . update ( "INSERT INTO ll_dispatch_pda_pick_order VALUES(900,600,'11',1,4),(901,601,'22',3,7)" );
jdbc . update ( "INSERT INTO ll_outbound_order VALUES(10000,'11','OUTBOUNDED'),(10002,'22','OUTBOUNDED')" );
jdbc . update ( "INSERT INTO ll_delivery_order VALUES(10001,'11',10,10000,'DELIVERING','CODE:FBA1'),(10003,'22',10,10002,'DELIVERING','CODE:FBA2')" );
jdbc . update ( "UPDATE ll_dispatch_order SET stage='DELIVERING',departed_at=CURRENT_TIMESTAMP" );
assertThat ( mapper . sources ( "11" , null )). extracting ( s -> s . deliveringPackages ()). containsExactly ( 4L , 0L );
assertThat ( mapper . sources ( "22" , null )). singleElement (). satisfies ( s -> assertThat ( s . deliveringPackages ()). isEqualTo ( 7 ));
assertThat ( mapper . sources ( "UNRELATED" , null )). isEmpty ();
}
/** 使用无客户头的真实新模型,按明细验证查询归属。 */
2026-10-09 17:36:24 +08:00
@BeforeEach void setup () throws Exception {
var ds = new JdbcDataSource (); ds . setURL ( "jdbc:h2:mem:tail-progress-" + UUID . randomUUID () + ";MODE=MySQL;DB_CLOSE_DELAY=-1" );
jdbc = new JdbcTemplate ( ds );
jdbc . execute ( "CREATE TABLE ll_order(id BIGINT,customer_id VARCHAR,source_order_id VARCHAR,source_inbound_id VARCHAR,source_region VARCHAR,order_type VARCHAR,package_count INT)" );
2026-10-19 17:56:36 +08:00
jdbc . execute ( "CREATE TABLE ll_dispatch_order(id BIGINT,status VARCHAR,stage VARCHAR,departed_at TIMESTAMP)" );
2026-10-09 17:36:24 +08:00
jdbc . execute ( "CREATE TABLE ll_dispatch_item(id BIGINT,dispatch_order_id BIGINT,customer_id VARCHAR,plan_pallet_id BIGINT,warehouse_pallet_id BIGINT,overseas_warehouse_id VARCHAR,destination_type VARCHAR,delivery_address VARCHAR,postal_code VARCHAR,destination_warehouse_code VARCHAR,fba_warehouse_code VARCHAR,destination_warehouse_id VARCHAR)" );
jdbc . execute ( "CREATE TABLE ll_inbound_plan_pallet_allocation(pallet_id BIGINT,line_id BIGINT,planned_package_count INT)" );
jdbc . execute ( "CREATE TABLE ll_inbound_plan_line(id BIGINT,customer_id VARCHAR,order_id BIGINT)" );
jdbc . execute ( "CREATE TABLE ll_inventory_position(id BIGINT,customer_id VARCHAR,pallet_id BIGINT,overseas_warehouse_id VARCHAR,balance_id BIGINT,available_packages INT)" );
jdbc . execute ( "CREATE TABLE ll_inventory_balance(id BIGINT,customer_id VARCHAR,inbound_order_id BIGINT)" );
jdbc . execute ( "CREATE TABLE ll_dispatch_pda_pick(id BIGINT,customer_id VARCHAR,dispatch_item_id BIGINT,inventory_position_id BIGINT,packages INT,task_id BIGINT)" );
jdbc . execute ( "CREATE TABLE ll_dispatch_pda_pick_order(id BIGINT,pick_id BIGINT,customer_id VARCHAR,order_id BIGINT,packages INT)" );
2026-10-19 17:56:36 +08:00
jdbc . execute ( "CREATE TABLE ll_dispatch_pda_task(id BIGINT,dispatch_order_id BIGINT UNIQUE)" );
2026-10-09 17:36:24 +08:00
jdbc . execute ( "CREATE TABLE ll_delivery_order(id BIGINT,customer_id VARCHAR,dispatch_order_id BIGINT,outbound_order_id BIGINT,status VARCHAR,delivery_group_key VARCHAR)" );
jdbc . execute ( "CREATE TABLE ll_outbound_order(id BIGINT,customer_id VARCHAR,status VARCHAR)" );
jdbc . update ( "INSERT INTO ll_order VALUES(1,'11','101','201','FIRSTLEG','FBA',10),(2,'11','102','202','FIRSTLEG','FBA',20),(3,'22','103','203','FIRSTLEG','FBA',30)" );
2026-10-19 17:56:36 +08:00
jdbc . update ( "INSERT INTO ll_dispatch_order VALUES(10,'ACTIVE','BEFORE_LOADING',NULL)" );
2026-10-09 17:36:24 +08:00
jdbc . update ( "INSERT INTO ll_dispatch_item(id,dispatch_order_id,customer_id,plan_pallet_id,overseas_warehouse_id,destination_warehouse_code) VALUES(100,10,'11',500,'W1','FBA1')" );
jdbc . update ( "INSERT INTO ll_inbound_plan_line VALUES(1000,'11',1),(1001,'11',2),(1002,'22',3)" );
jdbc . update ( "INSERT INTO ll_inbound_plan_pallet_allocation VALUES(500,1000,10),(500,1001,20),(500,1002,30)" );
var config = new MybatisConfiguration (); config . setMapUnderscoreToCamelCase ( true ); config . addMapper ( CustomerOrderProgressMapper . class );
var factory = new MybatisSqlSessionFactoryBean (); factory . setDataSource ( ds ); factory . setConfiguration ( config );
mapper = new SqlSessionTemplate ( factory . getObject ()). getMapper ( CustomerOrderProgressMapper . class );
}
2026-10-19 17:56:36 +08:00
/** 计划托盘上的所有本客户来源均计入,取消后不再计入。 */
2026-10-09 17:36:24 +08:00
@Test void plannedSharedPalletIncludesEveryOwnSourceAndExcludesCancellation () {
2026-10-15 19:46:34 +08:00
var sources = mapper . sources ( "11" , null ); assertThat ( sources ). hasSize ( 2 );
2026-10-09 17:36:24 +08:00
assertThat ( sources . get ( 0 ). scheduledPackages ()). isEqualTo ( 10 );
assertThat ( sources . get ( 1 ). scheduledPackages ()). isEqualTo ( 20 );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , java . util . List . of ( "101" ))). containsExactly ( sources . get ( 0 ));
2026-10-09 17:36:24 +08:00
assertThat ( sources ). allMatch ( s -> s . deliveringPackages () == 0 );
jdbc . update ( "UPDATE ll_dispatch_order SET status='CANCELLED'" );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , null )). allMatch ( s -> s . scheduledPackages () == 0 );
assertThat ( mapper . sources ( "22" , null )). hasSize ( 1 ). allMatch ( s -> s . scheduledPackages () == 0 );
2026-10-09 17:36:24 +08:00
}
2026-10-19 17:56:36 +08:00
/** 已收货使用实际库存和扫码,不与计划量重复累计。 */
2026-10-09 17:36:24 +08:00
@Test void receivedPalletUsesInventoryAndActualPicksWithoutCountingBothPlanAndStock () {
jdbc . update ( "UPDATE ll_dispatch_item SET warehouse_pallet_id=800" );
jdbc . update ( "INSERT INTO ll_inventory_balance VALUES(300,'11',1),(301,'11',2)" );
jdbc . update ( "INSERT INTO ll_inventory_position VALUES(400,'11',800,'W1',300,6),(401,'11',800,'W1',301,20)" );
jdbc . update ( "INSERT INTO ll_dispatch_pda_pick VALUES(600,'11',100,400,4,700)" );
2026-10-15 19:46:34 +08:00
var sources = mapper . sources ( "11" , null ); assertThat ( sources . get ( 0 ). scheduledPackages ()). isEqualTo ( 10 );
2026-10-09 17:36:24 +08:00
assertThat ( sources . get ( 1 ). scheduledPackages ()). isEqualTo ( 20 );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , java . util . List . of ( "101" ))). containsExactly ( sources . get ( 0 ));
2026-10-09 17:36:24 +08:00
}
2026-10-19 17:56:36 +08:00
/** 实际发车、出库及目的地须同时成立才计入在途。 */
2026-10-09 17:36:24 +08:00
@Test void deliveryRequiresActualDepartureOutboundAndMatchingDestinationAttribution () {
2026-10-19 17:56:36 +08:00
jdbc . update ( "INSERT INTO ll_dispatch_pda_task VALUES(700,10)" );
2026-10-09 17:36:24 +08:00
jdbc . update ( "INSERT INTO ll_dispatch_pda_pick VALUES(600,'11',100,400,4,700)" );
jdbc . update ( "INSERT INTO ll_dispatch_pda_pick_order VALUES(900,600,'11',1,4)" );
jdbc . update ( "INSERT INTO ll_outbound_order VALUES(10000,'11','WAIT_OUTBOUND')" );
jdbc . update ( "INSERT INTO ll_delivery_order VALUES(10001,'11',10,10000,'DELIVERING','CODE:FBA1')" );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , null )). allMatch ( s -> s . deliveringPackages () == 0 );
2026-10-19 17:56:36 +08:00
jdbc . update ( "UPDATE ll_dispatch_order SET stage='DELIVERING',departed_at=CURRENT_TIMESTAMP" );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , null )). allMatch ( s -> s . deliveringPackages () == 0 );
2026-10-09 17:36:24 +08:00
jdbc . update ( "UPDATE ll_outbound_order SET status='OUTBOUNDED'" );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , null ). get ( 0 ). deliveringPackages ()). isEqualTo ( 4 );
assertThat ( mapper . sources ( "11" , java . util . List . of ( "101" ))). containsExactly ( mapper . sources ( "11" , null ). get ( 0 ));
assertThat ( mapper . sources ( "11" , null ). get ( 1 ). deliveringPackages ()). isZero ();
2026-10-09 17:36:24 +08:00
jdbc . update ( "UPDATE ll_delivery_order SET delivery_group_key='CODE:FBA2'" );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , null )). allMatch ( s -> s . deliveringPackages () == 0 );
2026-10-09 17:36:24 +08:00
jdbc . update ( "UPDATE ll_delivery_order SET delivery_group_key='CODE:FBA1',status='RETURN_PENDING'" );
2026-10-15 19:46:34 +08:00
assertThat ( mapper . sources ( "11" , null )). allMatch ( s -> s . deliveringPackages () == 0 );
2026-10-09 17:36:24 +08:00
}
2026-10-15 19:46:34 +08:00
@Test void exactSourceOrderScopePreservesAllOwnInboundFragmentsAndExcludesForeignOrders () {
jdbc . update ( "INSERT INTO ll_order VALUES(4,'11','101','204','FIRSTLEG','FBA',5)" );
var own = mapper . sources ( "11" , java . util . List . of ( "101" , "103" ));
assertThat ( own ). extracting ( s -> s . orderId ()). containsExactly ( "101" , "101" );
assertThat ( own ). extracting ( s -> s . scheduledPackages ()). containsExactly ( 10L , 0L );
assertThat ( mapper . sources ( "22" , java . util . List . of ( "101" ))). isEmpty ();
assertThat ( mapper . sources ( "11" , java . util . List . of ( "999" ))). isEmpty ();
}
2026-10-09 17:36:24 +08:00
}