优化订单任务列表排序并补充上线文档

This commit is contained in:
andy
2026-07-13 12:20:05 +08:00
parent 51ebc8e767
commit 4b98cf9491
10 changed files with 344 additions and 46 deletions

View File

@@ -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);
}