优化订单任务列表排序并补充上线文档
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
package cn.nianxx.thhotel.workflows.reservation.control;
|
||||
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
@@ -18,8 +19,17 @@ import cn.nianxx.thhotel.platform.message.common.request.CaptureSourceMessageCom
|
||||
import cn.nianxx.thhotel.platform.message.common.result.SourceMessageCaptureResult;
|
||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageCaptureService;
|
||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageQueryService;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationOrderDraft;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationOrderSnapshot;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationTaskDraft;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.enums.ReservationOrderKeyType;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.enums.ReservationOrderStatus;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.enums.ReservationOrderVisibility;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.enums.ReservationTaskStatus;
|
||||
import cn.nianxx.thhotel.workflows.reservation.repository.ReservationAiWorkflowRepository;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -156,6 +166,138 @@ class ReservationFrontendQueryControllerTest {
|
||||
.andExpect(jsonPath("$.page.total").value(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnTaskWorkbenchListWithLatestSourceMessageFirst() throws Exception {
|
||||
SourceMessageCaptureResult oldSource = captureSourceMessage(
|
||||
"mail-frontend-task-sort-old-001",
|
||||
"Frontend Query Task Sort Old",
|
||||
Instant.parse("2026-07-08T01:00:00Z"));
|
||||
SourceMessageCaptureResult latestSource = captureSourceMessage(
|
||||
"mail-frontend-task-sort-latest-001",
|
||||
"Frontend Query Task Sort Latest",
|
||||
Instant.parse("2026-07-10T09:30:00Z"));
|
||||
Long oldOrderId = 930000000000001401L;
|
||||
Long latestOrderId = 930000000000001402L;
|
||||
Long oldTaskId = 930000000000001601L;
|
||||
Long latestTaskId = 930000000000001602L;
|
||||
insertGroupOrder(oldOrderId, oldSource.inboxId(), "GRP-FRONTEND-TASK-SORT-OLD", "ACTIVE");
|
||||
insertGroupOrder(latestOrderId, latestSource.inboxId(), "GRP-FRONTEND-TASK-SORT-LATEST", "ACTIVE");
|
||||
insertTransition(930000000000001501L, oldSource.inboxId(), 1, "GRP-FRONTEND-TASK-SORT-OLD",
|
||||
"New Booking", "NEW_BOOKING", "NEW_BOOKING");
|
||||
insertTransition(930000000000001502L, latestSource.inboxId(), 1, "GRP-FRONTEND-TASK-SORT-LATEST",
|
||||
"Update Booking", "UPDATE_BOOKING", "UPDATE_BOOKING");
|
||||
insertTask(oldTaskId, oldOrderId, oldSource.inboxId(), 930000000000001501L, "New Booking",
|
||||
"NEW_BOOKING", "NEW_BOOKING", "PENDING_CONFIRM", 1);
|
||||
insertTask(latestTaskId, latestOrderId, latestSource.inboxId(), 930000000000001502L, "Update Booking",
|
||||
"UPDATE_BOOKING", "UPDATE_BOOKING", "PENDING_CONFIRM", 1);
|
||||
|
||||
mockMvc.perform(get("/api/reservation/tasks")
|
||||
.param("hotel_id", HOTEL_ID)
|
||||
.param("keyword", "GRP-FRONTEND-TASK-SORT-")
|
||||
.param("page_num", "1")
|
||||
.param("page_size", "20"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.items[0].task_id").value(latestTaskId.toString()))
|
||||
.andExpect(jsonPath("$.items[0].source_subject").value("Frontend Query Task Sort Latest"))
|
||||
.andExpect(jsonPath("$.items[1].task_id").value(oldTaskId.toString()))
|
||||
.andExpect(jsonPath("$.items[1].source_subject").value("Frontend Query Task Sort Old"))
|
||||
.andExpect(jsonPath("$.page.total").value(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnOrderListWithLatestTaskActivityFirst() throws Exception {
|
||||
SourceMessageCaptureResult oldSource = captureSourceMessage(
|
||||
"mail-frontend-order-sort-old-001",
|
||||
"Frontend Query Order Sort Old",
|
||||
Instant.parse("2026-07-08T01:00:00Z"));
|
||||
SourceMessageCaptureResult latestSource = captureSourceMessage(
|
||||
"mail-frontend-order-sort-latest-001",
|
||||
"Frontend Query Order Sort Latest",
|
||||
Instant.parse("2026-07-10T09:30:00Z"));
|
||||
Long staleButRecentlyUpdatedOrderId = 930000000000001701L;
|
||||
Long latestActivityOrderId = 930000000000001702L;
|
||||
Long staleTaskId = 930000000000001901L;
|
||||
Long latestTaskId = 930000000000001902L;
|
||||
insertGroupOrder(staleButRecentlyUpdatedOrderId, oldSource.inboxId(),
|
||||
"GRP-FRONTEND-ORDER-SORT-STALE", "ACTIVE");
|
||||
insertGroupOrder(latestActivityOrderId, latestSource.inboxId(),
|
||||
"GRP-FRONTEND-ORDER-SORT-LATEST", "ACTIVE");
|
||||
updateOrderUpdatedAt(staleButRecentlyUpdatedOrderId, Instant.parse("2026-07-09T00:00:00Z"));
|
||||
updateOrderUpdatedAt(latestActivityOrderId, Instant.parse("2026-07-08T02:00:00Z"));
|
||||
insertTransition(930000000000001801L, oldSource.inboxId(), 1, "GRP-FRONTEND-ORDER-SORT-STALE",
|
||||
"New Booking", "NEW_BOOKING", "NEW_BOOKING");
|
||||
insertTransition(930000000000001802L, latestSource.inboxId(), 1, "GRP-FRONTEND-ORDER-SORT-LATEST",
|
||||
"Update Booking", "UPDATE_BOOKING", "UPDATE_BOOKING");
|
||||
insertTask(staleTaskId, staleButRecentlyUpdatedOrderId, oldSource.inboxId(), 930000000000001801L,
|
||||
"New Booking", "NEW_BOOKING", "NEW_BOOKING", "PENDING_CONFIRM", 1);
|
||||
insertTask(latestTaskId, latestActivityOrderId, latestSource.inboxId(), 930000000000001802L,
|
||||
"Update Booking", "UPDATE_BOOKING", "UPDATE_BOOKING", "PENDING_CONFIRM", 1);
|
||||
updateOrderLatestActivityAt(staleButRecentlyUpdatedOrderId, Instant.parse("2026-07-09T00:00:00Z"));
|
||||
updateOrderLatestActivityAt(latestActivityOrderId, Instant.parse("2026-07-10T09:30:00Z"));
|
||||
|
||||
mockMvc.perform(get("/api/reservation/orders")
|
||||
.param("hotel_id", HOTEL_ID)
|
||||
.param("keyword", "GRP-FRONTEND-ORDER-SORT-")
|
||||
.param("page_num", "1")
|
||||
.param("page_size", "20"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.items[0].order_id").value(latestActivityOrderId.toString()))
|
||||
.andExpect(jsonPath("$.items[0].group_code").value("GRP-FRONTEND-ORDER-SORT-LATEST"))
|
||||
.andExpect(jsonPath("$.items[1].order_id").value(staleButRecentlyUpdatedOrderId.toString()))
|
||||
.andExpect(jsonPath("$.items[1].group_code").value("GRP-FRONTEND-ORDER-SORT-STALE"))
|
||||
.andExpect(jsonPath("$.page.total").value(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldTouchOrderLatestActivityWhenRepositoryInsertsTask() {
|
||||
SourceMessageCaptureResult source = captureSourceMessage(
|
||||
"mail-frontend-order-activity-touch-001",
|
||||
"Frontend Query Order Activity Touch",
|
||||
Instant.parse("2026-07-08T01:00:00Z"));
|
||||
LocalDateTime orderCreatedAt = LocalDateTime.parse("2026-07-08T01:00:00");
|
||||
LocalDateTime taskCreatedAt = LocalDateTime.parse("2026-07-10T09:30:00");
|
||||
ReservationOrderSnapshot order = workflowRepository.insertOrder(new ReservationOrderDraft(
|
||||
HOTEL_ID,
|
||||
ReservationOrderKeyType.GROUP_CODE.name(),
|
||||
"GRP-FRONTEND-ORDER-ACTIVITY-TOUCH",
|
||||
"GRP-FRONTEND-ORDER-ACTIVITY-TOUCH",
|
||||
"TMP-FRONTEND-ORDER-ACTIVITY-TOUCH",
|
||||
ReservationOrderStatus.ACTIVE.name(),
|
||||
ReservationOrderVisibility.VISIBLE.name(),
|
||||
"AI_CANDIDATE",
|
||||
null,
|
||||
"GRP-FRONTEND-ORDER-ACTIVITY-TOUCH",
|
||||
source.inboxId(),
|
||||
orderCreatedAt));
|
||||
|
||||
workflowRepository.insertTask(new ReservationTaskDraft(
|
||||
HOTEL_ID,
|
||||
order.id(),
|
||||
source.inboxId(),
|
||||
930000000000002001L,
|
||||
"normal_task",
|
||||
"Update Booking",
|
||||
"UPDATE_BOOKING",
|
||||
"UPDATE_BOOKING",
|
||||
"frontend_query",
|
||||
ReservationTaskStatus.PENDING_CONFIRM.name(),
|
||||
true,
|
||||
1,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
taskCreatedAt));
|
||||
|
||||
Timestamp latestActivityAt = jdbcTemplate.queryForObject("""
|
||||
SELECT latest_activity_at
|
||||
FROM workflow_reservation_order
|
||||
WHERE id = ?
|
||||
""", Timestamp.class, order.id());
|
||||
assertThat(latestActivityAt).isNotNull();
|
||||
assertThat(latestActivityAt.toLocalDateTime()).isEqualTo(taskCreatedAt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnOrderDetailWithTaskTimeline() throws Exception {
|
||||
SourceMessageCaptureResult source = captureSourceMessage(
|
||||
@@ -272,6 +414,13 @@ class ReservationFrontendQueryControllerTest {
|
||||
}
|
||||
|
||||
private SourceMessageCaptureResult captureSourceMessage(String externalMessageId, String subject) {
|
||||
return captureSourceMessage(externalMessageId, subject, Instant.parse("2026-07-08T08:00:00Z"));
|
||||
}
|
||||
|
||||
private SourceMessageCaptureResult captureSourceMessage(
|
||||
String externalMessageId,
|
||||
String subject,
|
||||
Instant receivedAt) {
|
||||
return captureService.capture(new CaptureSourceMessageCommand(
|
||||
HOTEL_ID,
|
||||
"AGENTBUS",
|
||||
@@ -280,7 +429,8 @@ class ReservationFrontendQueryControllerTest {
|
||||
"thread-" + externalMessageId,
|
||||
"frame-" + externalMessageId,
|
||||
"session-frontend-query",
|
||||
Instant.parse("2026-07-08T08:00:00Z"),
|
||||
receivedAt,
|
||||
null,
|
||||
"guest@example.test",
|
||||
subject,
|
||||
"Please handle booking message.",
|
||||
@@ -291,6 +441,22 @@ class ReservationFrontendQueryControllerTest {
|
||||
));
|
||||
}
|
||||
|
||||
private void updateOrderUpdatedAt(Long orderId, Instant updatedAt) {
|
||||
jdbcTemplate.update("""
|
||||
UPDATE workflow_reservation_order
|
||||
SET updated_at = ?
|
||||
WHERE id = ?
|
||||
""", Timestamp.from(updatedAt), orderId);
|
||||
}
|
||||
|
||||
private void updateOrderLatestActivityAt(Long orderId, Instant latestActivityAt) {
|
||||
jdbcTemplate.update("""
|
||||
UPDATE workflow_reservation_order
|
||||
SET latest_activity_at = ?
|
||||
WHERE id = ?
|
||||
""", Timestamp.from(latestActivityAt), orderId);
|
||||
}
|
||||
|
||||
private void insertActiveGroupOrder(Long orderId, Long sourceMessageId, String groupCode) {
|
||||
insertGroupOrder(orderId, sourceMessageId, groupCode, "ACTIVE");
|
||||
}
|
||||
@@ -300,10 +466,10 @@ class ReservationFrontendQueryControllerTest {
|
||||
INSERT INTO workflow_reservation_order (
|
||||
id, hotel_id, order_key_type, order_business_key, active_business_key,
|
||||
temporary_order_code, order_status, business_key_source, display_name,
|
||||
source_message_id, version, created_at, updated_at
|
||||
source_message_id, version, latest_activity_at, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, 'GROUP_CODE', ?, ?, ?, ?, 'AI_CANDIDATE', ?, ?, 0,
|
||||
CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""", orderId, HOTEL_ID, groupCode, groupCode, "TMP-" + orderId, orderStatus, groupCode, sourceMessageId);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user