fix(calendar): include dispatch container numbers in calendar
This commit is contained in:
+20
@@ -62,4 +62,24 @@ class FleetTripCalendarMapperTest {
|
||||
bindDispatches(jdbc);
|
||||
assertThat(mapper.calendar(from,to)).hasSize(2001);
|
||||
}
|
||||
/** 实际Mapper批读同单跨客户多柜,排除其他主单与取消主单,不用货物行放大日历。 */
|
||||
@Test void batchReadsEverySourceSnapshotOnlyForTheRequestedActiveDispatches() throws Exception {
|
||||
var ds=new DriverManagerDataSource("jdbc:h2:mem:"+UUID.randomUUID()+";MODE=MySQL;DB_CLOSE_DELAY=-1","sa","");
|
||||
var jdbc=new JdbcTemplate(ds);
|
||||
jdbc.execute("CREATE TABLE ll_dispatch_order(id BIGINT PRIMARY KEY,dispatch_no VARCHAR(80) UNIQUE,status VARCHAR(32))");
|
||||
jdbc.execute("CREATE TABLE ll_dispatch_item(id BIGINT PRIMARY KEY,dispatch_order_id BIGINT,customer_id VARCHAR(64),source_snapshot_json VARCHAR(2000))");
|
||||
jdbc.update("INSERT INTO ll_dispatch_order VALUES(1,'PC-A','ACTIVE'),(2,'PC-B','ACTIVE'),(3,'PC-OTHER','ACTIVE'),(4,'PC-CANCELLED','CANCELLED')");
|
||||
jdbc.update("INSERT INTO ll_dispatch_item VALUES(11,1,'101',?), (12,1,'102',?), (13,1,'101',?), (21,2,'103',?), (31,3,'101',?), (41,4,'101',?)",
|
||||
"{\"containerNo\":\"TSTU1234567\"}","{\"containerNo\":\"TSTU1234567\"}","{\"containerNo\":\"TSTU7654321\"}",
|
||||
"{\"planNo\":\"PLAN-B\"}","{\"containerNo\":\"OTHER-CARGO\"}","{\"containerNo\":\"CANCELLED-CARGO\"}");
|
||||
var config=new MybatisConfiguration();config.setMapUnderscoreToCamelCase(true);config.addMapper(FleetTripMapper.class);
|
||||
var factory=new MybatisSqlSessionFactoryBean();factory.setDataSource(ds);factory.setConfiguration(config);
|
||||
var mapper=new SqlSessionTemplate(factory.getObject()).getMapper(FleetTripMapper.class);
|
||||
var repository=new FleetTripCalendarRepository(mapper);
|
||||
assertThat(repository.sourceSnapshots(List.of())).isEmpty();
|
||||
var rows=repository.sourceSnapshots(List.of("PC-A","PC-B","PC-CANCELLED"));
|
||||
assertThat(rows).extracting(FleetTripCalendarRepository.Source::dispatchNo).containsExactly("PC-A","PC-A","PC-A","PC-B");
|
||||
assertThat(rows).extracting(FleetTripCalendarRepository.Source::sourceSnapshotJson).containsExactly(
|
||||
"{\"containerNo\":\"TSTU1234567\"}","{\"containerNo\":\"TSTU1234567\"}","{\"containerNo\":\"TSTU7654321\"}","{\"planNo\":\"PLAN-B\"}");
|
||||
}
|
||||
}
|
||||
|
||||
+48
-1
@@ -11,7 +11,7 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class FleetTripCalendarServiceTest {
|
||||
final FleetTripMapper trips=mock(FleetTripMapper.class);
|
||||
final FleetTripCalendarRepository trips=mock(FleetTripCalendarRepository.class);
|
||||
final FleetWarehouseClient warehouses=mock(FleetWarehouseClient.class);
|
||||
final FleetTripCalendarService service=new FleetTripCalendarService(trips,warehouses,new ObjectMapper(),"internal-test");
|
||||
final Instant from=Instant.parse("2026-10-01T00:00:00Z"),to=from.plus(Duration.ofDays(44));
|
||||
@@ -107,4 +107,51 @@ class FleetTripCalendarServiceTest {
|
||||
var platform=new com.baiyue.common.security.AuthenticatedUser(1L,0L,0L,1L,"platform","PLATFORM","WEB",Set.of("platform:overseas-warehouse:dispatch:list"));
|
||||
controller.calendar(platform,from,to);verify(calendar).calendar(from,to);
|
||||
}
|
||||
/** 同车全部来源只批读一次,跨客户重复柜号去重,多柜完整保留。 */
|
||||
@Test void readsAllContainerNumbersInOneBatchAndPreservesTheLocalDateFacts() {
|
||||
var first=trip("PC-A",1L);first.setPlannedDepartureAt(LocalDateTime.of(2026,10,22,16,0));
|
||||
when(trips.calendar(any(),any())).thenReturn(List.of(first,trip("PC-B",1L)));
|
||||
when(trips.sourceSnapshots(List.of("PC-A","PC-B"))).thenReturn(List.of(
|
||||
new FleetTripCalendarRepository.Source("PC-A","{\"containerNo\":\" TSTU1234567 \",\"planNo\":\"PLAN-A\"}"),
|
||||
new FleetTripCalendarRepository.Source("PC-A","{\"containerNo\":\"TSTU1234567\"}"),
|
||||
new FleetTripCalendarRepository.Source("PC-A","{\"containerNo\":\"TSTU7654321\"}"),
|
||||
new FleetTripCalendarRepository.Source("PC-A","{\"containerNo\":null}"),
|
||||
new FleetTripCalendarRepository.Source("PC-B","{}"),
|
||||
new FleetTripCalendarRepository.Source("PC-B","{\"containerNo\":\" \"}")));
|
||||
metadata(List.of(warehouse(1,"US","America/Los_Angeles")),List.of());
|
||||
var result=service.calendar(from,to);
|
||||
assertThat(result.records()).hasSize(2);
|
||||
assertThat(result.records().get(0).containerNumbers()).containsExactly("TSTU1234567","TSTU7654321");
|
||||
assertThat(result.records().get(1).containerNumbers()).isEmpty();
|
||||
assertThat(result.records().get(0).plannedDepartureAt()).isEqualTo(Instant.parse("2026-10-22T16:00:00Z"));
|
||||
assertThat(result.records().get(0).originTimezone()).isEqualTo("America/Los_Angeles");
|
||||
assertThat(result.unresolvedRecords()).isEmpty();
|
||||
verify(trips).calendar(any(),any());verify(trips).sourceSnapshots(List.of("PC-A","PC-B"));verifyNoMoreInteractions(trips);
|
||||
verify(warehouses).platformMetadata("internal-test",new FleetWarehouseClient.MetadataRequest(List.of(1L)));
|
||||
verifyNoMoreInteractions(warehouses);
|
||||
}
|
||||
/** 缺时区的主单仍保留真实柜号,不将货物信息丢失误作起运地已核实。 */
|
||||
@Test void keepsKnownContainersOnAnUnresolvedOrigin() {
|
||||
when(trips.calendar(any(),any())).thenReturn(List.of(trip("PC-UNKNOWN",1L)));
|
||||
when(trips.sourceSnapshots(List.of("PC-UNKNOWN"))).thenReturn(List.of(
|
||||
new FleetTripCalendarRepository.Source("PC-UNKNOWN","{\"containerNo\":\"TSTU1234567\"}")));
|
||||
metadata(List.of(warehouse(1,"US",null)),List.of());
|
||||
var result=service.calendar(from,to);assertThat(result.records()).isEmpty();
|
||||
assertThat(result.unresolvedRecords()).singleElement().satisfies(row->{
|
||||
assertThat(row.containerNumbers()).containsExactly("TSTU1234567");
|
||||
assertThat(row.incompleteReasons()).containsExactly("ORIGIN_TIMEZONE_UNKNOWN");
|
||||
});
|
||||
}
|
||||
/** 损坏或非当前正式文本快照明确失败,不伪造空数组或静默隐藏整月。 */
|
||||
@Test void rejectsMalformedOrForeignSourceSnapshotsExplicitly() {
|
||||
when(trips.calendar(any(),any())).thenReturn(List.of(trip("PC-A",1L)));
|
||||
for(var invalid:Arrays.asList(null,"","not-json","null","[]","{\"containerNo\":123}","{\"containerNo\":[\"TSTU1234567\"]}","{} {}")) {
|
||||
when(trips.sourceSnapshots(List.of("PC-A"))).thenReturn(List.of(new FleetTripCalendarRepository.Source("PC-A",invalid)));
|
||||
assertThatThrownBy(()->service.calendar(from,to)).isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("柜号资料暂不可用");
|
||||
}
|
||||
when(trips.sourceSnapshots(List.of("PC-A"))).thenReturn(List.of(new FleetTripCalendarRepository.Source("OTHER-PC","{}")));
|
||||
assertThatThrownBy(()->service.calendar(from,to)).isInstanceOf(ResponseStatusException.class).hasMessageContaining("柜号资料暂不可用");
|
||||
verifyNoInteractions(warehouses);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user