实现前端P0订单任务查询接口
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
package cn.nianxx.thhotel.workflows.reservation.control;
|
||||
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import cn.nianxx.thhotel.ThHotelApplication;
|
||||
import cn.nianxx.thhotel.platform.message.common.request.CaptureSourceMessageCommand;
|
||||
import cn.nianxx.thhotel.platform.message.common.result.SourceMessageCaptureResult;
|
||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageCaptureService;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@SpringBootTest(classes = ThHotelApplication.class)
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
class ReservationFrontendQueryControllerTest {
|
||||
|
||||
private static final String HOTEL_ID = "HOTEL-TEST";
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private SourceMessageCaptureService captureService;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Test
|
||||
void shouldReturnTaskWorkbenchListWithRealtimeAvailability() throws Exception {
|
||||
SourceMessageCaptureResult source = captureSourceMessage(
|
||||
"mail-frontend-task-list-001",
|
||||
"Frontend Query List Smoke");
|
||||
Long orderId = 930000000000000101L;
|
||||
Long firstTaskId = 930000000000000301L;
|
||||
Long secondTaskId = 930000000000000302L;
|
||||
insertActiveGroupOrder(orderId, source.inboxId(), "GRP-FRONTEND-LIST-001");
|
||||
insertTransition(930000000000000201L, source.inboxId(), 1, "GRP-FRONTEND-LIST-001",
|
||||
"New Booking", "NEW_BOOKING", "NEW_BOOKING");
|
||||
insertTransition(930000000000000202L, source.inboxId(), 2, "GRP-FRONTEND-LIST-001",
|
||||
"Update Booking", "UPDATE_BOOKING", "UPDATE_BOOKING");
|
||||
insertTask(firstTaskId, orderId, source.inboxId(), 930000000000000201L, "New Booking",
|
||||
"NEW_BOOKING", "NEW_BOOKING", "PENDING_CONFIRM", 1);
|
||||
insertTask(secondTaskId, orderId, source.inboxId(), 930000000000000202L, "Update Booking",
|
||||
"UPDATE_BOOKING", "UPDATE_BOOKING", "PENDING_CONFIRM", 2);
|
||||
|
||||
mockMvc.perform(get("/api/reservation/tasks")
|
||||
.param("hotel_id", HOTEL_ID)
|
||||
.param("order_id", orderId.toString())
|
||||
.param("page_num", "1")
|
||||
.param("page_size", "20"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.items[0].task_id").value(firstTaskId.toString()))
|
||||
.andExpect(jsonPath("$.items[0].order_id").value(orderId.toString()))
|
||||
.andExpect(jsonPath("$.items[0].hotel_id").value(HOTEL_ID))
|
||||
.andExpect(jsonPath("$.items[0].display_order_key").value("GRP-FRONTEND-LIST-001"))
|
||||
.andExpect(jsonPath("$.items[0].task_type").value("NEW_BOOKING"))
|
||||
.andExpect(jsonPath("$.items[0].task_status").value("PENDING_CONFIRM"))
|
||||
.andExpect(jsonPath("$.items[0].queue_sequence").value(1))
|
||||
.andExpect(jsonPath("$.items[0].queue_participation").value(true))
|
||||
.andExpect(jsonPath("$.items[0].can_process").value(true))
|
||||
.andExpect(jsonPath("$.items[0].readonly_reason_code").value("PROCESSABLE"))
|
||||
.andExpect(jsonPath("$.items[0].source_message_id").value(source.inboxId().toString()))
|
||||
.andExpect(jsonPath("$.items[0].source_subject").value("Frontend Query List Smoke"))
|
||||
.andExpect(jsonPath("$.items[1].task_id").value(secondTaskId.toString()))
|
||||
.andExpect(jsonPath("$.items[1].task_type").value("UPDATE_BOOKING"))
|
||||
.andExpect(jsonPath("$.items[1].can_process").value(false))
|
||||
.andExpect(jsonPath("$.items[1].readonly_reason_code").value("PREVIOUS_TASK_NOT_FINISHED"))
|
||||
.andExpect(jsonPath("$.page.page_num").value(1))
|
||||
.andExpect(jsonPath("$.page.page_size").value(20))
|
||||
.andExpect(jsonPath("$.page.total").value(2));
|
||||
|
||||
mockMvc.perform(get("/api/reservation/tasks")
|
||||
.param("hotel_id", HOTEL_ID)
|
||||
.param("keyword", "Frontend Query List Smoke")
|
||||
.param("page_num", "1")
|
||||
.param("page_size", "20"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.items[0].source_subject").value("Frontend Query List Smoke"))
|
||||
.andExpect(jsonPath("$.items[1].source_subject").value("Frontend Query List Smoke"))
|
||||
.andExpect(jsonPath("$.page.total").value(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnOrderDetailWithTaskTimeline() throws Exception {
|
||||
SourceMessageCaptureResult source = captureSourceMessage(
|
||||
"mail-frontend-order-detail-001",
|
||||
"Frontend Query Detail Smoke");
|
||||
Long orderId = 930000000000000401L;
|
||||
Long firstTaskId = 930000000000000601L;
|
||||
Long secondTaskId = 930000000000000602L;
|
||||
insertActiveGroupOrder(orderId, source.inboxId(), "GRP-FRONTEND-DETAIL-001");
|
||||
insertTransition(930000000000000501L, source.inboxId(), 1, "GRP-FRONTEND-DETAIL-001",
|
||||
"New Booking", "NEW_BOOKING", "NEW_BOOKING");
|
||||
insertTransition(930000000000000502L, source.inboxId(), 2, "GRP-FRONTEND-DETAIL-001",
|
||||
"Update Booking", "UPDATE_BOOKING", "UPDATE_BOOKING");
|
||||
insertTask(firstTaskId, orderId, source.inboxId(), 930000000000000501L, "New Booking",
|
||||
"NEW_BOOKING", "NEW_BOOKING", "COMPLETED", 1);
|
||||
insertTask(secondTaskId, orderId, source.inboxId(), 930000000000000502L, "Update Booking",
|
||||
"UPDATE_BOOKING", "UPDATE_BOOKING", "PENDING_CONFIRM", 2);
|
||||
|
||||
mockMvc.perform(get("/api/reservation/orders/{orderId}", orderId)
|
||||
.param("hotel_id", HOTEL_ID)
|
||||
.param("include_tasks", "true")
|
||||
.param("include_source_summary", "true"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.order.order_id").value(orderId.toString()))
|
||||
.andExpect(jsonPath("$.order.hotel_id").value(HOTEL_ID))
|
||||
.andExpect(jsonPath("$.order.order_status").value("ACTIVE"))
|
||||
.andExpect(jsonPath("$.order.temporary_order_no").value("TMP-" + orderId))
|
||||
.andExpect(jsonPath("$.order.group_code").value("GRP-FRONTEND-DETAIL-001"))
|
||||
.andExpect(jsonPath("$.order.confirmation_number").value(nullValue()))
|
||||
.andExpect(jsonPath("$.order.display_name").value("GRP-FRONTEND-DETAIL-001"))
|
||||
.andExpect(jsonPath("$.tasks[0].task_id").value(firstTaskId.toString()))
|
||||
.andExpect(jsonPath("$.tasks[0].task_status").value("COMPLETED"))
|
||||
.andExpect(jsonPath("$.tasks[0].readonly_reason_code").value("TASK_FINISHED"))
|
||||
.andExpect(jsonPath("$.tasks[1].task_id").value(secondTaskId.toString()))
|
||||
.andExpect(jsonPath("$.tasks[1].task_status").value("PENDING_CONFIRM"))
|
||||
.andExpect(jsonPath("$.tasks[1].can_process").value(true))
|
||||
.andExpect(jsonPath("$.tasks[1].readonly_reason_code").value("PROCESSABLE"))
|
||||
.andExpect(jsonPath("$.warnings.length()").value(0));
|
||||
|
||||
mockMvc.perform(get("/api/reservation/orders/{orderId}", orderId)
|
||||
.param("hotel_id", HOTEL_ID)
|
||||
.param("include_tasks", "false"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.order.order_id").value(orderId.toString()))
|
||||
.andExpect(jsonPath("$.tasks.length()").value(0));
|
||||
}
|
||||
|
||||
private SourceMessageCaptureResult captureSourceMessage(String externalMessageId, String subject) {
|
||||
return captureService.capture(new CaptureSourceMessageCommand(
|
||||
HOTEL_ID,
|
||||
"AGENTBUS",
|
||||
"EMAIL",
|
||||
externalMessageId,
|
||||
"thread-" + externalMessageId,
|
||||
"frame-" + externalMessageId,
|
||||
"session-frontend-query",
|
||||
Instant.parse("2026-07-08T08:00:00Z"),
|
||||
"guest@example.test",
|
||||
subject,
|
||||
"Please handle booking message.",
|
||||
"<html><body>Please handle booking message.</body></html>",
|
||||
"{\"source\":{\"external_message_id\":\"" + externalMessageId + "\"}}",
|
||||
"agentbus-outlook-v1",
|
||||
List.of()
|
||||
));
|
||||
}
|
||||
|
||||
private void insertActiveGroupOrder(Long orderId, Long sourceMessageId, String groupCode) {
|
||||
jdbcTemplate.update("""
|
||||
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
|
||||
)
|
||||
VALUES (?, ?, 'GROUP_CODE', ?, ?, ?, 'ACTIVE', 'AI_CANDIDATE', ?, ?, 0,
|
||||
CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""", orderId, HOTEL_ID, groupCode, groupCode, "TMP-" + orderId, groupCode, sourceMessageId);
|
||||
}
|
||||
|
||||
private void insertTransition(
|
||||
Long transitionId,
|
||||
Long sourceMessageId,
|
||||
Integer sourceEventIndex,
|
||||
String groupCode,
|
||||
String aiTaskType,
|
||||
String systemTaskType,
|
||||
String taskCardType) {
|
||||
jdbcTemplate.update("""
|
||||
INSERT INTO workflow_reservation_ai_transition (
|
||||
id, hotel_id, batch_id, source_message_id, source_event_index, array_index,
|
||||
execution_order, catalog_code, skill_id, result_type, ai_task_type,
|
||||
system_task_type, task_card_type, task_subtype, current_or_history,
|
||||
group_code, item_payload_sha256, item_idempotency_key, blocked_until_parent_completed,
|
||||
ai_payload_json, case_keys_json, extracted_fields_json, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 'S02', 'frontend_query_skill',
|
||||
'normal_task', ?, ?, ?, 'frontend_query', 'current', ?, ?, ?, 0,
|
||||
'{}', '{}', '{}', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""", transitionId, HOTEL_ID, transitionId - 1, sourceMessageId, sourceEventIndex,
|
||||
sourceEventIndex, sourceEventIndex, aiTaskType, systemTaskType, taskCardType, groupCode,
|
||||
"0".repeat(64), transitionId.toString());
|
||||
}
|
||||
|
||||
private void insertTask(
|
||||
Long taskId,
|
||||
Long orderId,
|
||||
Long sourceMessageId,
|
||||
Long transitionId,
|
||||
String aiTaskType,
|
||||
String systemTaskType,
|
||||
String taskCardType,
|
||||
String taskStatus,
|
||||
Integer executionOrder) {
|
||||
jdbcTemplate.update("""
|
||||
INSERT INTO workflow_reservation_task (
|
||||
id, hotel_id, order_id, source_message_id, ai_transition_id,
|
||||
result_type, ai_task_type, system_task_type, task_card_type, task_subtype,
|
||||
task_status, queue_participation, execution_order, blocked_until_parent_completed,
|
||||
version, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, 'normal_task', ?, ?, ?, 'frontend_query',
|
||||
?, 1, ?, 0, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""", taskId, HOTEL_ID, orderId, sourceMessageId, transitionId, aiTaskType,
|
||||
systemTaskType, taskCardType, taskStatus, executionOrder);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user