优化
This commit is contained in:
+1
@@ -20,6 +20,7 @@ final class OwnedBusinessFixtures {
|
||||
/** 装车完成但未发车,证明不依赖DEPART历史。 */
|
||||
static Source source() {
|
||||
var row=new Source();row.setId(1L);row.setDispatchNo("DS-OWN-ONE");row.setStatus("ACTIVE");row.setStage("AFTER_LOADING");
|
||||
row.setPooledCargo(false);
|
||||
row.setRecordVersion(8L);row.setOverseasWarehouseId("9");row.setOverseasWarehouseCode("WH-9");row.setOverseasWarehouseName("测试仓");
|
||||
row.setPlannedDepartureAt(LocalDateTime.parse("2026-10-20T08:00:00"));row.setLoadingCompletedAt(LocalDateTime.parse("2026-10-20T07:30:00"));
|
||||
row.setLoadingCompletionHash("actual-load");row.setOwnedLoadingCompletionHash("actual-load");row.setOwnedLoadingCompletedAt(row.getLoadingCompletedAt());
|
||||
|
||||
+5
-1
@@ -50,8 +50,12 @@ class OwnedBusinessPersistenceTest {
|
||||
customer_name VARCHAR(128),source_key VARCHAR(128),order_no VARCHAR(128),inbound_code VARCHAR(128),
|
||||
pallet_no VARCHAR(128),warehouse_pallet_id BIGINT,destination_type VARCHAR(32),
|
||||
destination_warehouse_code VARCHAR(128),destination_warehouse_name VARCHAR(128),fba_warehouse_code VARCHAR(128),
|
||||
delivery_address VARCHAR(256),postal_code VARCHAR(64),package_count INT)
|
||||
delivery_address VARCHAR(256),postal_code VARCHAR(64),package_count INT,plan_id BIGINT,plan_pallet_id BIGINT)
|
||||
""");
|
||||
jdbc.execute("CREATE TABLE ll_fleet_external_booking(id BIGINT PRIMARY KEY,trip_id BIGINT,dispatch_no VARCHAR(128),customer_id VARCHAR(128),offer_id BIGINT,status VARCHAR(32),incoming_no VARCHAR(128),receipt_json LONGTEXT)");
|
||||
jdbc.execute("CREATE TABLE ll_warehouse_transfer_order(customer_id VARCHAR(128),transfer_no VARCHAR(128),inbound_code VARCHAR(128))");
|
||||
jdbc.execute("CREATE TABLE ll_inbound_plan_line(id BIGINT PRIMARY KEY,plan_id BIGINT,customer_id VARCHAR(128),inbound_code VARCHAR(128))");
|
||||
jdbc.execute("CREATE TABLE ll_inbound_plan_pallet_allocation(pallet_id BIGINT,line_id BIGINT,plan_id BIGINT,customer_id VARCHAR(128))");
|
||||
jdbc.execute("CREATE TABLE ll_dispatch_appointment_allocation(dispatch_id BIGINT,dispatch_item_id BIGINT,customer_id VARCHAR(64),batch_key VARCHAR(128),destination_key VARCHAR(128),package_count INT)");
|
||||
jdbc.execute("CREATE TABLE ll_inbound_fba_appointment(id BIGINT,appointment_no VARCHAR(64),confirmation_no VARCHAR(64),appointment_start_utc DATETIME(3))");
|
||||
jdbc.execute("""
|
||||
|
||||
+4
-3
@@ -41,14 +41,15 @@ class OwnedBusinessQueryTest {
|
||||
assertThrows(BizException.class,()->service.detail(OwnedBusinessFixtures.actor(),"DS-OWN-ONE"));
|
||||
verifyNoInteractions(dispatch);verify(repo,never()).capture(any());assertEquals(8L,source.getRecordVersion());
|
||||
}
|
||||
/** 装车前、非自有归属、失配的原装车hash均不能作为本页可写来源。 */
|
||||
/** 装车前、已实际拼车、失配的装车hash均不可写;未拼车的外配车辆仍属自有业务。 */
|
||||
@Test void stageAndFrozenOwnershipFactsAreBothRequired() {
|
||||
var repo=mock(OwnedBusinessRepository.class);var codec=OwnedBusinessFixtures.codec();
|
||||
var service=new OwnedBusinessQueryService(repo,new OwnedBusinessProjection(codec),codec,mock(DispatchDetailReader.class));
|
||||
var source=OwnedBusinessFixtures.source();when(repo.source("DS-OWN-ONE")).thenReturn(source);
|
||||
source.setStage("LOADING");assertThrows(BizException.class,()->service.requireOwned("DS-OWN-ONE"));
|
||||
source.setStage("AFTER_LOADING");source.setOwnedVehicleOwnership("DISPATCHED");assertThrows(BizException.class,()->service.requireOwned("DS-OWN-ONE"));
|
||||
source.setOwnedVehicleOwnership("OWNED");source.setOwnedLoadingCompletionHash("other");assertThrows(BizException.class,()->service.requireOwned("DS-OWN-ONE"));
|
||||
source.setStage("AFTER_LOADING");source.setOwnedVehicleOwnership("DISPATCHED");assertSame(source,service.requireOwned("DS-OWN-ONE"));
|
||||
source.setPooledCargo(true);assertThrows(BizException.class,()->service.requireOwned("DS-OWN-ONE"));
|
||||
source.setPooledCargo(false);source.setOwnedLoadingCompletionHash("other");assertThrows(BizException.class,()->service.requireOwned("DS-OWN-ONE"));
|
||||
}
|
||||
/** 列表权限不自动授予编辑或上传,不暴露主流程写动作。 */
|
||||
@Test void readOnlyActorHasOnlyReadGates() {
|
||||
|
||||
+58
-2
@@ -75,7 +75,7 @@ class OwnedBusinessScopePersistenceTest {
|
||||
""",id,"DS-OUT-"+id,stage,load,snapshot,"TEST-OUT-"+id);
|
||||
baseline.jdbc.update("""
|
||||
INSERT INTO ll_dispatch_item SELECT id+?, ?,customer_id,customer_name,source_key,order_no,inbound_code,?, ?,destination_type,
|
||||
destination_warehouse_code,destination_warehouse_name,fba_warehouse_code,delivery_address,postal_code,package_count FROM ll_dispatch_item WHERE dispatch_order_id=1
|
||||
destination_warehouse_code,destination_warehouse_name,fba_warehouse_code,delivery_address,postal_code,package_count,NULL,NULL FROM ll_dispatch_item WHERE dispatch_order_id=1
|
||||
""",id*100,id,"PAL-"+(31+id),31+id);
|
||||
var ownership=new OwnedBusinessRows.Ownership();ownership.setDispatchId(id);ownership.setVehicleId(vehicle.vehicleId());
|
||||
ownership.setResourceMode(mode);ownership.setVehicleOwnership("DISPATCHED");ownership.setVehicleRecordVersion(vehicle.vehicleId()==null?null:3L);
|
||||
@@ -83,6 +83,12 @@ class OwnedBusinessScopePersistenceTest {
|
||||
baseline.jdbc.update("INSERT INTO ll_dispatch_history VALUES(?,?,8,'LOADING_COMPLETE','TEST-picker',NULL,'{}',?)",100+id,id,original.getLoadingCompletedAt());
|
||||
if(!"AFTER_LOADING".equals(stage))baseline.jdbc.update("UPDATE ll_dispatch_order SET departed_at=? WHERE id=?",original.getLoadingCompletedAt().plusHours(1),id);
|
||||
if("DELIVERED".equals(stage))baseline.jdbc.update("UPDATE ll_dispatch_order SET delivery_completed_at=? WHERE id=?",original.getLoadingCompletedAt().plusHours(2),id);
|
||||
// 每张外配测试任务真实关联一票拼车来源,车辆归属不再充当分类依据。
|
||||
baseline.jdbc.update("UPDATE ll_dispatch_item SET plan_id=?,plan_pallet_id=? WHERE dispatch_order_id=? AND customer_id='101'",id*1000,id*1000+1,id);
|
||||
baseline.jdbc.update("INSERT INTO ll_inbound_plan_line VALUES(?,?,'101','IN-A')",id*1000+2,id*1000);
|
||||
baseline.jdbc.update("INSERT INTO ll_inbound_plan_pallet_allocation VALUES(?,?,?,'101')",id*1000+1,id*1000+2,id*1000);
|
||||
baseline.jdbc.update("INSERT INTO ll_warehouse_transfer_order VALUES('101',?,'IN-A')","INCOMING-"+id);
|
||||
baseline.jdbc.update("INSERT INTO ll_fleet_external_booking VALUES(?,2,?,'101',9,'BOUND',?,'{}')",id,"DS-OUT-"+id,"INCOMING-"+id);
|
||||
}
|
||||
/** 外配真实三权限,与自有集合完全不相交。 */
|
||||
private OwnedBusinessModels.Actor actor(){return new OwnedBusinessModels.Actor("outsourced-operator","TEST外配操作员",Set.of(OutsourcedBusinessModels.LIST,OutsourcedBusinessModels.EDIT,OutsourcedBusinessModels.UPLOAD));}
|
||||
@@ -101,6 +107,56 @@ class OwnedBusinessScopePersistenceTest {
|
||||
assertEquals(0,outsourced.list(actor(),new OwnedBusinessModels.Query(1,20,null,"2026-10-20T08:00:00Z",null,null,"9")).total());
|
||||
for(var stage:OwnedBusinessModels.Stage.values())assertEquals(1,outsourced.list(actor(),new OwnedBusinessModels.Query(1,20,"2026-10-20T08:00:00Z","2026-10-21T08:00:00Z",null,stage,"9")).total());
|
||||
}
|
||||
/** 四种车辆/拼车组合只按货物分类;临时外配未拼车也可从自有入口登记。 */
|
||||
@Test void classificationIsIndependentOfVehicleOwnershipAndResourceMode() {
|
||||
baseline.jdbc.update("UPDATE ll_fleet_owned_business_ownership SET vehicle_ownership='OWNED' WHERE dispatch_id=2");
|
||||
baseline.jdbc.update("UPDATE ll_fleet_external_booking SET status='RECEIVED',dispatch_no=NULL WHERE id=3");
|
||||
baseline.jdbc.update("UPDATE ll_fleet_owned_business_ownership SET vehicle_ownership='DISPATCHED' WHERE dispatch_id=1");
|
||||
var query=new OwnedBusinessModels.Query(1,20,null,null,null,null,null);
|
||||
assertEquals(2,outsourced.list(actor(),query).total());assertEquals(2,queries.list(OwnedBusinessFixtures.actor(),query).total());
|
||||
assertEquals("OWNED",outsourced.detail(actor(),"DS-OUT-2").row().vehicle().ownership());
|
||||
var external=queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-3");
|
||||
assertNull(external.row().vehicle().vehicleId());assertEquals("DISPATCHED",external.row().vehicle().ownership());
|
||||
var saved=records.save(OwnedBusinessFixtures.actor(),"DS-OUT-3",new OwnedBusinessModels.SaveOperations("0","non-pool-external-save",
|
||||
new OwnedBusinessModels.Operations(new OwnedBusinessModels.Money("USD","0"),null,null,List.of()),null));
|
||||
assertEquals("1",saved.row().recordVersion());
|
||||
var pooled=outsourced.save(actor(),"DS-OUT-2",request("0","pool-owned-save",new OwnedBusinessModels.Money("USD","25"),List.of()));
|
||||
assertEquals("OWNED",pooled.row().vehicle().ownership());assertEquals("25.00",pooled.row().unitPrice());
|
||||
assertThrows(BizException.class,()->queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
assertThrows(BizException.class,()->outsourced.detail(actor(),"DS-OUT-3"));
|
||||
}
|
||||
/** 发布、询价、占位、实收未排入、取消和非池来源均不计拼车,详情与完整统计一致。 */
|
||||
@Test void onlyReceivedPoolCargoBoundToThisDispatchCounts() {
|
||||
var query=new OwnedBusinessModels.Query(1,1,null,null,null,null,null);
|
||||
for(String status:List.of("DRAFT","CONFIRMED","RECEIVED","CANCELLED")) {
|
||||
baseline.jdbc.update("UPDATE ll_fleet_external_booking SET status=? WHERE id=2",status);
|
||||
assertEquals(2,outsourced.list(actor(),query).total());assertEquals(2,queries.list(OwnedBusinessFixtures.actor(),query).total());
|
||||
assertNotNull(queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
assertThrows(BizException.class,()->outsourced.detail(actor(),"DS-OUT-2"));
|
||||
}
|
||||
baseline.jdbc.update("UPDATE ll_fleet_external_booking SET status='BOUND',offer_id=NULL WHERE id=2");
|
||||
assertNotNull(queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
baseline.jdbc.update("UPDATE ll_fleet_external_booking SET offer_id=9,receipt_json=NULL WHERE id=2");
|
||||
assertNotNull(queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
baseline.jdbc.update("UPDATE ll_fleet_external_booking SET receipt_json='{}',trip_id=999 WHERE id=2");
|
||||
assertNotNull(queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
baseline.jdbc.update("UPDATE ll_fleet_external_booking SET trip_id=2,dispatch_no='OTHER' WHERE id=2");
|
||||
assertNotNull(queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
baseline.jdbc.update("UPDATE ll_fleet_external_booking SET dispatch_no='DS-OUT-2',customer_id='102' WHERE id=2");
|
||||
assertNotNull(queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
}
|
||||
/** 用真实计划组成核对来源,展示入仓码不能代替组成;多条有效拼车登记不重复整车。 */
|
||||
@Test void actualCargoSourceIsRequiredAndMultipleBookingsNeverMultiplyStatistics() {
|
||||
baseline.jdbc.update("UPDATE ll_dispatch_item SET inbound_code='DISPLAY-ONLY' WHERE dispatch_order_id=2");
|
||||
assertNotNull(outsourced.detail(actor(),"DS-OUT-2"));
|
||||
baseline.jdbc.update("INSERT INTO ll_fleet_external_booking SELECT 22,trip_id,dispatch_no,customer_id,offer_id,status,incoming_no,receipt_json FROM ll_fleet_external_booking WHERE id=2");
|
||||
var query=new OwnedBusinessModels.Query(1,1,null,null,null,null,null);
|
||||
assertEquals(3,outsourced.list(actor(),query).total());assertEquals(1,outsourced.list(actor(),query).records().size());
|
||||
baseline.jdbc.update("DELETE FROM ll_inbound_plan_pallet_allocation WHERE plan_id=2000");
|
||||
assertNotNull(queries.detail(OwnedBusinessFixtures.actor(),"DS-OUT-2"));
|
||||
assertEquals(2,outsourced.list(actor(),query).total());
|
||||
assertThrows(BizException.class,()->outsourced.detail(actor(),"DS-OUT-2"));
|
||||
}
|
||||
/** 外配档案和临时车辆分别保持真实ID/空ID及原承运商,GET不建记录。 */
|
||||
@Test void masterAndExternalReadOriginalSnapshotWithoutBackfill() {
|
||||
var master=outsourced.detail(actor(),"DS-OUT-2");var external=outsourced.detail(actor(),"DS-OUT-3");
|
||||
@@ -210,7 +266,7 @@ class OwnedBusinessScopePersistenceTest {
|
||||
@Test void roundingUsesActualDistinctPalletsAndZeroDenominatorStaysNull() {
|
||||
String load=baseline.repository.source("DS-OUT-2").getLoadingConfirmationJson().replace("\"pallets\":[", "\"pallets\":[{\"warehousePalletId\":99,\"palletSpaces\":5,\"weightKg\":10,\"volumeCbm\":1,\"deliveryIndex\":1},");
|
||||
baseline.jdbc.update("UPDATE ll_dispatch_order SET loading_confirmation_json=? WHERE id=2",load);
|
||||
baseline.jdbc.update("INSERT INTO ll_dispatch_item SELECT id+1000,dispatch_order_id,customer_id,customer_name,CONCAT(source_key,'-2'),order_no,inbound_code,'PAL-99',99,destination_type,destination_warehouse_code,destination_warehouse_name,fba_warehouse_code,delivery_address,postal_code,package_count FROM ll_dispatch_item WHERE id=211");
|
||||
baseline.jdbc.update("INSERT INTO ll_dispatch_item SELECT id+1000,dispatch_order_id,customer_id,customer_name,CONCAT(source_key,'-2'),order_no,inbound_code,'PAL-99',99,destination_type,destination_warehouse_code,destination_warehouse_name,fba_warehouse_code,delivery_address,postal_code,package_count,plan_id,plan_pallet_id FROM ll_dispatch_item WHERE id=211");
|
||||
var saved=outsourced.save(actor(),"DS-OUT-2",request("0","out-half-up-rounding",new OwnedBusinessModels.Money("USD","10.01"),List.of()));
|
||||
assertEquals(2,saved.row().actualPalletCount());assertEquals(3,saved.cargo().size());assertEquals("5.01",saved.row().unitPrice());
|
||||
var confirmation=baseline.codec.read(load,DispatchContracts.ConfirmedLoad.class);
|
||||
|
||||
Reference in New Issue
Block a user