完成M002 V3 CP4列表详情展示

This commit is contained in:
andy
2026-07-11 15:53:22 +08:00
parent 9bcbe8a3ac
commit 6416c1b78a
15 changed files with 647 additions and 30 deletions

View File

@@ -745,6 +745,78 @@ class SuperAgentTaskResultControllerTest {
assertThat(taskCount).isEqualTo(1L);
}
@Test
void shouldExposeStructuredS99NotificationInTaskListAndDetail() throws Exception {
captureSourceMessage("mail-v3-s99-frontend-visible-001");
String body = """
{
"source_message": {
"source_message_id": "mail-v3-s99-frontend-visible-001",
"subject": null,
"from": null,
"cc": [],
"received_at": null,
"source_channel": "Email"
},
"route_code": "S99",
"handler_type": "main_agent_outcome",
"result_type": "source_message_review_notification",
"current_or_history": "current",
"agent_assessment": {
"status": "insufficient_business_material",
"reason_code": "cannot_form_business_material_package",
"automation_action": "none"
},
"notification": {
"required": true,
"notification_type": "source_message_review",
"show_source_message": true,
"requires_user_decision": true
},
"manual_review": {
"reason_code": "cannot_form_business_material_package",
"review_notes": "需要人工查看原邮件。"
}
}
""";
MvcResult result = mockMvc.perform(signedPost(body, "nonce-v3-s99-frontend-visible-001"))
.andExpect(status().isCreated())
.andReturn();
String taskId = com.jayway.jsonpath.JsonPath.read(
result.getResponse().getContentAsString(),
"$.items[0].task_id"
);
mockMvc.perform(get("/api/reservation/tasks")
.param("hotel_id", "HOTEL-TEST")
.param("task_type", "SOURCE_MESSAGE_ONLY")
.param("keyword", "mail-v3-s99-frontend-visible-001"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.items[0].task_id").value(taskId))
.andExpect(jsonPath("$.items[0].result_type").value("source_message_review_notification"))
.andExpect(jsonPath("$.items[0].ai_task_type").value("S99"))
.andExpect(jsonPath("$.items[0].route_code").value("S99"))
.andExpect(jsonPath("$.items[0].system_process_category").value("SOURCE_MESSAGE_NOTIFICATION"));
mockMvc.perform(get("/api/reservation/tasks/{taskId}", taskId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.result_type").value("source_message_review_notification"))
.andExpect(jsonPath("$.ai_task_type").value("S99"))
.andExpect(jsonPath("$.task_subtype").value("S99"))
.andExpect(jsonPath("$.route_code").value("S99"))
.andExpect(jsonPath("$.system_process_category").value("SOURCE_MESSAGE_NOTIFICATION"))
.andExpect(jsonPath("$.source_message_only_result.result_type")
.value("source_message_review_notification"))
.andExpect(jsonPath("$.source_message_only_result.route_code").value("S99"))
.andExpect(jsonPath("$.source_message_only_result.agent_assessment.status")
.value("insufficient_business_material"))
.andExpect(jsonPath("$.source_message_only_result.notification.notification_type")
.value("source_message_review"))
.andExpect(jsonPath("$.source_message_only_result.manual_review.reason_code")
.value("cannot_form_business_material_package"));
}
@Test
void shouldCreateBusinessTaskFromV3BusinessRootMessageEvent() throws Exception {
SourceMessageCaptureResult source = captureSourceMessage("mail-v3-business-root-001");
@@ -968,6 +1040,116 @@ class SuperAgentTaskResultControllerTest {
assertThat(taskCount).isEqualTo(1L);
}
@Test
void shouldExposeV3RouteAndRelatedTransitionBlocksInFrontendQueries() throws Exception {
captureSourceMessage("mail-v3-frontend-route-blocks-001");
String body = """
{
"source_message": {
"source_message_id": "mail-v3-frontend-route-blocks-001",
"subject": "Mixed events",
"from": null,
"cc": [],
"received_at": null,
"source_channel": "Email"
},
"message_events": [
{
"event_type": "Trace",
"source_event_index": "E1",
"current_or_history": "current",
"case_keys": {
"group_code": "GRP-V3-FRONTEND-BLOCK-001",
"confirmation_number": null
},
"extracted_fields": {},
"contract_errors": [
{
"path": "/extracted_fields",
"code": "unsupported_contract"
}
],
"manual_review": null
},
{
"event_type": "New Booking",
"source_event_index": "E2",
"current_or_history": "current",
"case_keys": {
"group_code": null,
"confirmation_number": "CNF-V3-FRONTEND-BLOCK-001"
},
"extracted_fields": {
"booking_object_type": "FIT Reservation"
},
"manual_review": null
}
],
"case_candidates": [],
"extraction_warnings": [],
"unhandled_current_intents": [
{
"intent_type": "unsupported_active_request",
"reason_code": "no_task_card_available"
}
]
}
""";
MvcResult result = mockMvc.perform(signedPost(body, "nonce-v3-frontend-route-blocks-001"))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.accepted_count").value(3))
.andReturn();
String orderId = com.jayway.jsonpath.JsonPath.read(
result.getResponse().getContentAsString(),
"$.items[1].order_id"
);
String taskId = com.jayway.jsonpath.JsonPath.read(
result.getResponse().getContentAsString(),
"$.items[1].task_id"
);
mockMvc.perform(get("/api/reservation/tasks")
.param("hotel_id", "HOTEL-TEST")
.param("keyword", "mail-v3-frontend-route-blocks-001"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.items[0].task_id").value(taskId))
.andExpect(jsonPath("$.items[0].result_type").value("normal_task"))
.andExpect(jsonPath("$.items[0].ai_task_type").value("New Booking"))
.andExpect(jsonPath("$.items[0].route_code").value("R01_NEW_FIT_RESERVATION_NORMAL"))
.andExpect(jsonPath("$.items[0].system_process_category").value("BUSINESS_TASK"));
mockMvc.perform(get("/api/reservation/orders/{orderId}", orderId)
.param("hotel_id", "HOTEL-TEST")
.param("include_tasks", "true"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.tasks[0].task_id").value(taskId))
.andExpect(jsonPath("$.tasks[0].result_type").value("normal_task"))
.andExpect(jsonPath("$.tasks[0].ai_task_type").value("New Booking"))
.andExpect(jsonPath("$.tasks[0].route_code").value("R01_NEW_FIT_RESERVATION_NORMAL"))
.andExpect(jsonPath("$.tasks[0].system_process_category").value("BUSINESS_TASK"));
mockMvc.perform(get("/api/reservation/tasks/{taskId}", taskId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.result_type").value("normal_task"))
.andExpect(jsonPath("$.ai_task_type").value("New Booking"))
.andExpect(jsonPath("$.task_subtype").value("new_fit_reservation"))
.andExpect(jsonPath("$.route_code").value("R01_NEW_FIT_RESERVATION_NORMAL"))
.andExpect(jsonPath("$.system_process_category").value("BUSINESS_TASK"))
.andExpect(jsonPath("$.adapter_contract_errors.length()").value(1))
.andExpect(jsonPath("$.adapter_contract_errors[0].adapter_error_code")
.value("EVENT_CONTRACT_ERROR"))
.andExpect(jsonPath("$.adapter_contract_errors[0].payload_fragment.contract_errors[0].code")
.value("unsupported_contract"))
.andExpect(jsonPath("$.unhandled_intents.length()").value(1))
.andExpect(jsonPath("$.unhandled_intents[0].route_code")
.value("R42_UNHANDLED_CURRENT_INTENT"))
.andExpect(jsonPath("$.unhandled_intents[0].system_process_category")
.value("UNHANDLED_CURRENT_INTENT"))
.andExpect(jsonPath("$.unhandled_intents[0].payload_fragment.intent_type")
.value("unsupported_active_request"));
}
@Test
void shouldPersistAdapterContractErrorForIncompleteV3ManualReview() throws Exception {
SourceMessageCaptureResult source = captureSourceMessage("mail-v3-manual-review-incomplete-001");