feat: support shared FBA appointments and arrival calendar
This commit is contained in:
+5
-3
@@ -26,10 +26,12 @@ class InboundPlanSchemaContractTest {
|
||||
assertTrue(schema.contains("create table if not exists ll_inbound_pda_operation"));
|
||||
assertTrue(schema.contains("create table if not exists ll_inbound_pallet_merge"));
|
||||
assertTrue(schema.contains("create table if not exists ll_inbound_fba_appointment"));
|
||||
assertTrue(schema.contains("unique key uk_ll_fba_appointment_no (customer_id, appointment_no)"));
|
||||
assertTrue(schema.contains("unique key uk_ll_fba_appointment_no (appointment_no)"));
|
||||
assertTrue(schema.contains("expected_loading_at"));
|
||||
assertTrue(schema.contains("change column tenant_id customer_id"));
|
||||
assertTrue(schema.contains("set expected_loading_at=appointment_at"));
|
||||
String appointment = schema.substring(schema.indexOf("create table if not exists ll_inbound_fba_appointment ("), schema.indexOf("create table if not exists ll_inbound_fba_appointment_item ("));
|
||||
assertFalse(appointment.contains("customer_id"));
|
||||
String items = schema.substring(schema.indexOf("create table if not exists ll_inbound_fba_appointment_item ("));
|
||||
assertTrue(items.substring(0, items.indexOf("engine=innodb")).contains("customer_id varchar(128) not null"));
|
||||
assertTrue(schema.contains("planned_arrival_date"));
|
||||
assertTrue(schema.contains("creation_mode varchar(32)"));
|
||||
assertTrue(schema.contains("modify column creation_mode varchar(32)"));
|
||||
|
||||
+15
-4
@@ -53,14 +53,14 @@ class InboundPlanControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformAppointmentUpdateUsesExplicitCustomerScope() {
|
||||
UpdateFbaAppointmentRequest request = new UpdateFbaAppointmentRequest("100",
|
||||
void platformAppointmentUpdateUsesSharedAppointmentNumber() {
|
||||
UpdateFbaAppointmentRequest request = new UpdateFbaAppointmentRequest(
|
||||
LocalDateTime.of(2026, 8, 20, 10, 30), LocalDateTime.of(2026, 8, 21, 8, 0),
|
||||
"PENDING", "dock");
|
||||
"PENDING", "dock", null, 0);
|
||||
|
||||
controller.updateFbaAppointment(platform(), "APT-1", request);
|
||||
|
||||
verify(appointmentService).update("100", "APT-1", request);
|
||||
verify(appointmentService).update("APT-1", request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -98,6 +98,17 @@ class InboundPlanControllerTest {
|
||||
org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void merchantCannotReadOrChangeACrossCustomerAppointment() {
|
||||
var customer = new AuthenticatedUser(8L, 100L, 100L, 9L, "customer", "MERCHANT", "WEB", Set.of());
|
||||
assertThatThrownBy(() -> controller.fbaAppointmentDetail(customer, "APT-1"))
|
||||
.isInstanceOf(ResponseStatusException.class);
|
||||
assertThatThrownBy(() -> controller.fbaAppointmentCalendar(customer,
|
||||
java.time.LocalDate.of(2026, 10, 1), java.time.LocalDate.of(2026, 11, 1)))
|
||||
.isInstanceOf(ResponseStatusException.class);
|
||||
verify(appointmentService, never()).detail(org.mockito.ArgumentMatchers.any());
|
||||
}
|
||||
|
||||
private static AuthenticatedUser platform() {
|
||||
return new AuthenticatedUser(7L, 0L, 0L, 8L, "operator", "PLATFORM", "WEB",
|
||||
Set.of("platform:overseas-warehouse:inbound-order:list"));
|
||||
|
||||
+5
-1
@@ -23,11 +23,15 @@ class InboundPlanPermissionContractTest {
|
||||
Map<String, Method> methods = Arrays.stream(InboundPlanController.class.getDeclaredMethods())
|
||||
.collect(Collectors.toMap(Method::getName, method -> method));
|
||||
|
||||
for (String name : new String[] {"page", "detail", "fbaAppointmentDetail"}) {
|
||||
for (String name : new String[] {"page", "detail"}) {
|
||||
Method method = methods.get(name);
|
||||
assertEquals("hasAuthority('" + LIST + "')", method.getAnnotation(PreAuthorize.class).value());
|
||||
assertEquals("Required authority: " + LIST, method.getAnnotation(Operation.class).description());
|
||||
}
|
||||
assertEquals("hasAnyAuthority('" + LIST + "','platform:appointment:list')",
|
||||
methods.get("fbaAppointmentDetail").getAnnotation(PreAuthorize.class).value());
|
||||
assertEquals("hasAuthority('platform:appointment:list')",
|
||||
methods.get("fbaAppointmentCalendar").getAnnotation(PreAuthorize.class).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+19
-2
@@ -25,8 +25,8 @@ class InboundPlanDispatchStatusPersistenceTest {
|
||||
db.execute("CREATE TABLE ll_inbound_plan(id BIGINT,plan_no VARCHAR(50),customer_id VARCHAR(20),overseas_warehouse_id BIGINT,assigned_flag BOOLEAN,merge_required BOOLEAN,urgent_flag BOOLEAN,status VARCHAR(30),created_at TIMESTAMP,version INT)");
|
||||
db.execute("CREATE TABLE ll_inbound_plan_line(id BIGINT,plan_id BIGINT,order_id BIGINT,inbound_code VARCHAR(50),destination_warehouse_id VARCHAR(30),destination_warehouse_code VARCHAR(30),destination_warehouse_name VARCHAR(50),fba_warehouse_code VARCHAR(30),required_package_count INT,volume_cbm DECIMAL(18,3),planned_pallet_count INT)");
|
||||
db.execute("CREATE TABLE ll_order(id BIGINT,customer_id VARCHAR(20),lx_code VARCHAR(50),order_type VARCHAR(30),overseas_warehouse_code VARCHAR(30),overseas_warehouse_name VARCHAR(50),customer_name VARCHAR(50))");
|
||||
db.execute("CREATE TABLE ll_inbound_fba_appointment_item(id BIGINT,line_id BIGINT,appointment_id BIGINT)");
|
||||
db.execute("CREATE TABLE ll_inbound_fba_appointment(id BIGINT,customer_id VARCHAR(20),created_at TIMESTAMP,appointment_no VARCHAR(50),appointment_status VARCHAR(30),appointment_at TIMESTAMP,expected_loading_at TIMESTAMP)");
|
||||
db.execute("CREATE TABLE ll_inbound_fba_appointment_item(id BIGINT,line_id BIGINT,appointment_id BIGINT,customer_id VARCHAR(20))");
|
||||
db.execute("CREATE TABLE ll_inbound_fba_appointment(id BIGINT,created_at TIMESTAMP,appointment_no VARCHAR(50),appointment_status VARCHAR(30),appointment_at TIMESTAMP,expected_loading_at TIMESTAMP)");
|
||||
db.execute("CREATE TABLE ll_inbound_plan_pallet_allocation(line_id BIGINT,picked_package_count INT)");
|
||||
db.execute("CREATE TABLE ll_order_detail(order_id BIGINT,customer_id VARCHAR(20),gross_weight_kg DECIMAL(18,3),net_weight_kg DECIMAL(18,3))");
|
||||
db.execute("CREATE TABLE ll_inbound_order(id BIGINT,customer_id VARCHAR(20),gross_weight_kg DECIMAL(18,3),net_weight_kg DECIMAL(18,3))");
|
||||
@@ -78,6 +78,23 @@ class InboundPlanDispatchStatusPersistenceTest {
|
||||
assertThat(mapper.count("B", query(null))).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void sharedAppointmentAppearsForBothCustomersWithoutExposingOtherCustomersInboundRows() {
|
||||
db.update("INSERT INTO ll_inbound_plan VALUES(4,'LIP-2','B',90,TRUE,FALSE,FALSE,'RECEIVED',CURRENT_TIMESTAMP,0)");
|
||||
db.update("INSERT INTO ll_inbound_plan_line VALUES(5,4,6,'IN-2','91','ABE4','ABE4','ABE4',1,1,1)");
|
||||
db.update("INSERT INTO ll_order VALUES(6,'B','LX-2','FIRST_LEG','LA','洛杉矶仓','客户B')");
|
||||
db.update("INSERT INTO ll_inbound_fba_appointment VALUES(7,CURRENT_TIMESTAMP,'APT-SHARED','SUCCESS',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)");
|
||||
db.update("INSERT INTO ll_inbound_fba_appointment_item VALUES(8,2,7,'A'),(9,5,7,'B')");
|
||||
assertThat(mapper.rows(null, query(null), 0, 20)).hasSize(2)
|
||||
.extracting(InboundPlanListResponse::appointmentNo).containsOnly("APT-SHARED");
|
||||
for (String customer : new String[]{"A", "B"}) {
|
||||
var rows = mapper.rows(customer, query(null), 0, 20);
|
||||
assertThat(rows).hasSize(1);
|
||||
assertThat(rows.get(0).customerId()).isEqualTo(customer);
|
||||
assertThat(rows.get(0).appointmentNo()).isEqualTo("APT-SHARED");
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatch(long id, String owner, String status, String itemOwner) {
|
||||
db.update("INSERT INTO ll_dispatch_order VALUES(?,?,?)", id, owner, status);
|
||||
db.update("INSERT INTO ll_dispatch_item VALUES(?,?,?,3)", id, itemOwner, id);
|
||||
|
||||
+124
-23
@@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -46,49 +47,54 @@ class InboundFbaAppointmentServiceTest {
|
||||
ReflectionTestUtils.setField(service, "itemMapper", itemMapper);
|
||||
ReflectionTestUtils.setField(service, "queryMapper", queryMapper);
|
||||
lenient().when(itemMapper.selectList(any())).thenReturn(List.of());
|
||||
lenient().when(appointmentMapper.update(any(InboundFbaAppointment.class), any())).thenReturn(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsOneBatchForSelectedLinesAndFreezesFbaWarehouse() throws Exception {
|
||||
assertEquals(true, InboundFbaAppointmentService.class
|
||||
.getMethod("batchCreate", String.class, String.class, BatchFbaAppointmentRequest.class)
|
||||
.getMethod("batchCreate", String.class, BatchFbaAppointmentRequest.class)
|
||||
.getAnnotation(Transactional.class) != null);
|
||||
when(queryMapper.lockLines("100", List.of(11L, 12L))).thenReturn(List.of(
|
||||
when(queryMapper.lockLines(List.of(11L, 12L))).thenReturn(List.of(
|
||||
line(11L, "IN-11", "ONT8"), line(12L, "IN-12", "ONT8")));
|
||||
|
||||
var result = service.batchCreate("100", "7", request(List.of(11L, 12L), "APT-1"));
|
||||
var result = service.batchCreate("7", request(List.of(11L, 12L), "APT-1"));
|
||||
|
||||
assertEquals("APT-1", result.appointmentNo());
|
||||
assertEquals("ONT8", result.fbaWarehouseCode());
|
||||
assertEquals(expectedLoadingAt, result.expectedLoadingAt());
|
||||
assertEquals(2, result.selectedCount());
|
||||
var captured = org.mockito.ArgumentCaptor.forClass(InboundFbaAppointmentItem.class);
|
||||
verify(itemMapper, org.mockito.Mockito.times(2)).insert(captured.capture());
|
||||
assertEquals(List.of("CUSTOMER-11", "CUSTOMER-12"), captured.getAllValues().stream()
|
||||
.map(InboundFbaAppointmentItem::getCustomerId).toList());
|
||||
verify(appointmentMapper).insert(any(InboundFbaAppointment.class));
|
||||
verify(itemMapper, org.mockito.Mockito.times(2)).insert(any(InboundFbaAppointmentItem.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsMixedFbaWarehouses() {
|
||||
when(queryMapper.lockLines("100", List.of(11L, 12L))).thenReturn(List.of(
|
||||
when(queryMapper.lockLines(List.of(11L, 12L))).thenReturn(List.of(
|
||||
line(11L, "IN-11", "ONT8"), line(12L, "IN-12", "LAX9")));
|
||||
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> service.batchCreate("100", "7", request(List.of(11L, 12L), "APT-1")));
|
||||
() -> service.batchCreate("7", request(List.of(11L, 12L), "APT-1")));
|
||||
verify(appointmentMapper, never()).insert(any(InboundFbaAppointment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsMissingLineFromAnotherTenant() {
|
||||
when(queryMapper.lockLines("100", List.of(11L, 12L))).thenReturn(List.of(line(11L, "IN-11", "ONT8")));
|
||||
void rejectsMissingSelectedLine() {
|
||||
when(queryMapper.lockLines(List.of(11L, 12L))).thenReturn(List.of(line(11L, "IN-11", "ONT8")));
|
||||
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> service.batchCreate("100", "7", request(List.of(11L, 12L), "APT-1")));
|
||||
() -> service.batchCreate("7", request(List.of(11L, 12L), "APT-1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void duplicateLineIdsAreRejectedBeforeDatabaseAccess() {
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> service.batchCreate("100", "7", request(List.of(11L, 11L), "APT-1")));
|
||||
verify(queryMapper, never()).lockLines(any(), any());
|
||||
() -> service.batchCreate("7", request(List.of(11L, 11L), "APT-1")));
|
||||
verify(queryMapper, never()).lockLines(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,7 +107,7 @@ class InboundFbaAppointmentServiceTest {
|
||||
when(appointmentMapper.selectOne(any())).thenReturn(existing);
|
||||
when(itemMapper.selectList(any())).thenReturn(List.of(item));
|
||||
|
||||
var result = service.batchCreate("100", "7", request(List.of(11L), "APT-1"));
|
||||
var result = service.batchCreate("7", request(List.of(11L), "APT-1"));
|
||||
|
||||
assertEquals(99L, result.id());
|
||||
verify(appointmentMapper, never()).insert(any(InboundFbaAppointment.class));
|
||||
@@ -115,7 +121,7 @@ class InboundFbaAppointmentServiceTest {
|
||||
when(itemMapper.selectList(any())).thenReturn(List.of(item));
|
||||
|
||||
assertThrows(ResponseStatusException.class,
|
||||
() -> service.batchCreate("100", "7", request(List.of(12L), "APT-1")));
|
||||
() -> service.batchCreate("7", request(List.of(12L), "APT-1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -124,17 +130,17 @@ class InboundFbaAppointmentServiceTest {
|
||||
InboundFbaAppointmentItem item = new InboundFbaAppointmentItem();
|
||||
item.setLineId(11L);
|
||||
when(itemMapper.selectList(any())).thenReturn(List.of(item));
|
||||
BatchFbaAppointmentRequest changed = new BatchFbaAppointmentRequest("100", List.of(11L), "APT-1",
|
||||
appointmentAt, expectedLoadingAt.plusHours(1), "SUCCESS", "dock");
|
||||
BatchFbaAppointmentRequest changed = new BatchFbaAppointmentRequest(List.of(11L), "APT-1",
|
||||
appointmentAt, expectedLoadingAt.plusHours(1), "SUCCESS", "dock", null);
|
||||
|
||||
ResponseStatusException exception = assertThrows(ResponseStatusException.class,
|
||||
() -> service.batchCreate("100", "7", changed));
|
||||
() -> service.batchCreate("7", changed));
|
||||
assertEquals(409, exception.getStatusCode().value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void stringSnowflakeLineIdsDeserializeWithoutPrecisionLoss() throws Exception {
|
||||
String json = "{\"customerId\":\"100\",\"lineIds\":[\"9007199254740993\"],"
|
||||
String json = "{\"lineIds\":[\"9007199254740993\"],"
|
||||
+ "\"appointmentNo\":\"APT-1\",\"appointmentAt\":\"2026-08-20T10:30:00\","
|
||||
+ "\"expectedLoadingAt\":\"2026-08-21T08:00:00\",\"appointmentStatus\":\"PENDING\"}";
|
||||
|
||||
@@ -151,28 +157,122 @@ class InboundFbaAppointmentServiceTest {
|
||||
when(appointmentMapper.selectOne(any())).thenReturn(existing);
|
||||
LocalDateTime loadingAt = expectedLoadingAt.plusHours(2);
|
||||
|
||||
var result = service.update("100", "APT-1", new UpdateFbaAppointmentRequest(
|
||||
"100", appointmentAt.plusDays(1), loadingAt, "PENDING", "updated"));
|
||||
var result = service.update("APT-1", new UpdateFbaAppointmentRequest(
|
||||
appointmentAt.plusDays(1), loadingAt, "PENDING", "updated", null, 0));
|
||||
|
||||
assertEquals(loadingAt, result.expectedLoadingAt());
|
||||
assertEquals("PENDING", result.appointmentStatus());
|
||||
verify(appointmentMapper).updateById(existing);
|
||||
verify(appointmentMapper).update(org.mockito.ArgumentMatchers.eq(existing), any());
|
||||
verify(itemMapper, never()).insert(any(InboundFbaAppointmentItem.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void preventsAssigningTheSameCargoToTwoActiveAppointments() {
|
||||
when(queryMapper.lockLines(List.of(11L))).thenReturn(List.of(line(11L, "IN-11", "ONT8")));
|
||||
when(queryMapper.countActiveAppointments(List.of(11L), null)).thenReturn(1L);
|
||||
var exception = assertThrows(ResponseStatusException.class,
|
||||
() -> service.batchCreate("7", request(List.of(11L), "SECOND-APT")));
|
||||
assertEquals(409, exception.getStatusCode().value());
|
||||
verify(appointmentMapper, never()).insert(any(InboundFbaAppointment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelledAppointmentCannotBeReactivatedAfterItsCargoWasBookedElsewhere() {
|
||||
InboundFbaAppointment existing = appointment(99L, "APT-1", "ONT8");
|
||||
existing.setAppointmentStatus("CANCELLED");
|
||||
when(appointmentMapper.selectOne(any())).thenReturn(existing);
|
||||
InboundFbaAppointmentItem item = new InboundFbaAppointmentItem();
|
||||
item.setLineId(11L);
|
||||
when(itemMapper.selectList(any())).thenReturn(List.of(item));
|
||||
when(queryMapper.countActiveAppointments(List.of(11L), 99L)).thenReturn(1L);
|
||||
assertThrows(ResponseStatusException.class, () -> service.update("APT-1",
|
||||
new UpdateFbaAppointmentRequest(appointmentAt, expectedLoadingAt, "SUCCESS", "", null, 0)));
|
||||
verify(queryMapper).lockLines(List.of(11L));
|
||||
verify(appointmentMapper, never()).update(any(InboundFbaAppointment.class), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAnAppointmentWindowWhoseEndIsNotAfterItsStart() {
|
||||
var request = new BatchFbaAppointmentRequest(List.of(11L), "BAD-WINDOW", appointmentAt,
|
||||
expectedLoadingAt, "PENDING", "", appointmentAt.minusMinutes(1));
|
||||
assertThrows(ResponseStatusException.class, () -> service.batchCreate("7", request));
|
||||
verify(queryMapper, never()).lockLines(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsStaleEditBeforeWritingTheSharedAppointment() {
|
||||
var existing = appointment(99L, "APT-1", "ONT8");
|
||||
existing.setVersion(3);
|
||||
when(appointmentMapper.selectOne(any())).thenReturn(existing);
|
||||
var request = new UpdateFbaAppointmentRequest(appointmentAt, expectedLoadingAt,
|
||||
"PENDING", "", appointmentAt.plusHours(2), 2);
|
||||
var error = assertThrows(ResponseStatusException.class, () -> service.update("APT-1", request));
|
||||
assertEquals(409, error.getStatusCode().value());
|
||||
verify(appointmentMapper, never()).update(any(InboundFbaAppointment.class), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void cannotDeleteAnAppointmentWhoseGoodsAlreadyHaveAnActiveDispatch() {
|
||||
when(appointmentMapper.selectOne(any())).thenReturn(appointment(99L, "APT-1", "ONT8"));
|
||||
when(queryMapper.countActiveDispatches(99L)).thenReturn(1L);
|
||||
assertThrows(ResponseStatusException.class, () -> service.delete("APT-1", 0));
|
||||
verify(appointmentMapper, never()).delete(any(com.baomidou.mybatisplus.core.conditions.Wrapper.class));
|
||||
verify(itemMapper, never()).delete(any(com.baomidou.mybatisplus.core.conditions.Wrapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void staleDeleteKeepsAllCargoAssociations() {
|
||||
when(appointmentMapper.selectOne(any())).thenReturn(appointment(99L, "APT-1", "ONT8"));
|
||||
when(appointmentMapper.delete(any(com.baomidou.mybatisplus.core.conditions.Wrapper.class))).thenReturn(0);
|
||||
assertThrows(ResponseStatusException.class, () -> service.delete("APT-1", 0));
|
||||
verify(itemMapper, never()).delete(any(com.baomidou.mybatisplus.core.conditions.Wrapper.class));
|
||||
}
|
||||
|
||||
private BatchFbaAppointmentRequest request(List<Long> lineIds, String number) {
|
||||
return new BatchFbaAppointmentRequest("100", lineIds, number, appointmentAt, expectedLoadingAt,
|
||||
"SUCCESS", "dock");
|
||||
return new BatchFbaAppointmentRequest(lineIds, number, appointmentAt, expectedLoadingAt,
|
||||
"SUCCESS", "dock", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void calendarRejectsInvalidOrUnboundedDateRangesBeforeQuerying() {
|
||||
LocalDate from = LocalDate.of(2026, 9, 1);
|
||||
for (LocalDate to : List.of(from, from.minusDays(1), from.plusDays(43))) {
|
||||
assertThrows(ResponseStatusException.class, () -> service.calendar(from, to));
|
||||
}
|
||||
verify(appointmentMapper, never()).selectList(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void emptyCalendarDoesNotQueryAppointmentItems() {
|
||||
when(appointmentMapper.selectList(any())).thenReturn(List.of());
|
||||
assertEquals(List.of(), service.calendar(LocalDate.of(2026, 9, 1), LocalDate.of(2026, 10, 1)));
|
||||
verify(itemMapper, never()).selectList(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void calendarLoadsAllItemsInOneBatchAndKeepsAppointmentAssociation() {
|
||||
var first = appointment(99L, "APT-1", "ONT8");
|
||||
var second = appointment(100L, "APT-2", "LAX9");
|
||||
InboundFbaAppointmentItem item = new InboundFbaAppointmentItem();
|
||||
item.setAppointmentId(100L);
|
||||
item.setLineId(11L);
|
||||
item.setInboundCode("IN-11");
|
||||
when(appointmentMapper.selectList(any())).thenReturn(List.of(first, second));
|
||||
when(itemMapper.selectList(any())).thenReturn(List.of(item));
|
||||
var result = service.calendar(LocalDate.of(2026, 9, 1), LocalDate.of(2026, 10, 1));
|
||||
assertEquals(2, result.size());
|
||||
assertEquals(0, result.get(0).items().size());
|
||||
assertEquals("IN-11", result.get(1).items().get(0).inboundCode());
|
||||
verify(itemMapper).selectList(any());
|
||||
}
|
||||
|
||||
private FbaAppointmentLineSnapshot line(Long id, String inboundCode, String fba) {
|
||||
return new FbaAppointmentLineSnapshot(id, 1000L, id + 100L, inboundCode, fba);
|
||||
return new FbaAppointmentLineSnapshot(id, 1000L, id + 100L, inboundCode, fba, "CUSTOMER-" + id);
|
||||
}
|
||||
|
||||
private InboundFbaAppointment appointment(Long id, String number, String fba) {
|
||||
InboundFbaAppointment value = new InboundFbaAppointment();
|
||||
value.setId(id);
|
||||
value.setCustomerId("100");
|
||||
value.setAppointmentNo(number);
|
||||
value.setAppointmentAt(appointmentAt);
|
||||
value.setExpectedLoadingAt(expectedLoadingAt);
|
||||
@@ -180,6 +280,7 @@ class InboundFbaAppointmentServiceTest {
|
||||
value.setAppointmentRemark("dock");
|
||||
value.setFbaWarehouseCode(fba);
|
||||
value.setSelectedCount(1);
|
||||
value.setVersion(0);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user