统一V4待处理计数并补齐审计查询
This commit is contained in:
@@ -588,12 +588,16 @@ class ReservationFrontendQueryControllerTest {
|
||||
.value(contains("ACTIVE")))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + activeOrderId + "')].open_task_count")
|
||||
.value(contains(1)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + activeOrderId + "')].open_work_item_count")
|
||||
.value(contains(0)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + activeOrderId + "')].next_processable_task_id")
|
||||
.value(contains(pendingTaskId.toString())))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + endedOrderId + "')].order_status")
|
||||
.value(contains("ENDED")))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + endedOrderId + "')].open_task_count")
|
||||
.value(contains(0)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + endedOrderId + "')].open_work_item_count")
|
||||
.value(contains(0)))
|
||||
.andExpect(jsonPath("$.page.total").value(2));
|
||||
|
||||
performAuthorized(mockMvc, adminToken(), get("/api/reservation/orders")
|
||||
@@ -732,6 +736,8 @@ class ReservationFrontendQueryControllerTest {
|
||||
.value(contains(legacyTaskId.toString())))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + basicFirstOrderId + "')].v4_open_order_task_count")
|
||||
.value(contains(2)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + basicFirstOrderId + "')].open_work_item_count")
|
||||
.value(contains(2)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + basicFirstOrderId + "')].next_v4_order_task_id")
|
||||
.value(contains(basicFirstOrderTask.id().toString())))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + basicFirstOrderId + "')].next_v4_action_card_id")
|
||||
@@ -742,6 +748,8 @@ class ReservationFrontendQueryControllerTest {
|
||||
.value(contains("PENDING_CONFIRM")))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + reviewFirstOrderId + "')].v4_open_order_task_count")
|
||||
.value(contains(1)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + reviewFirstOrderId + "')].open_work_item_count")
|
||||
.value(contains(1)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + reviewFirstOrderId + "')].next_v4_order_task_id")
|
||||
.value(contains(reviewOrderTask.id().toString())))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + reviewFirstOrderId + "')].next_v4_action_card_id")
|
||||
@@ -760,6 +768,8 @@ class ReservationFrontendQueryControllerTest {
|
||||
.value(contains("PENDING_CONFIRM")))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + completedOnlyOrderId + "')].v4_open_order_task_count")
|
||||
.value(contains(0)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + completedOnlyOrderId + "')].open_work_item_count")
|
||||
.value(contains(0)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + completedOnlyOrderId + "')].next_v4_order_task_id")
|
||||
.value(contains(nullValue())))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + completedOnlyOrderId + "')].next_v4_action_type")
|
||||
@@ -768,6 +778,8 @@ class ReservationFrontendQueryControllerTest {
|
||||
.value(contains(nullValue())))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + noV4OrderId + "')].v4_open_order_task_count")
|
||||
.value(contains(0)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + noV4OrderId + "')].open_work_item_count")
|
||||
.value(contains(0)))
|
||||
.andExpect(jsonPath("$.items[?(@.order_id=='" + noV4OrderId + "')].next_v4_action_type")
|
||||
.value(contains("NONE")));
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import cn.nianxx.thhotel.platform.message.common.result.SourceMessageCaptureResu
|
||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageCaptureService;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationAiBatchDraft;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationAiTransitionDraft;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationAuditLogDraft;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationV4OrderTaskDraft;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationV4OrderTaskSnapshot;
|
||||
import cn.nianxx.thhotel.workflows.reservation.common.dto.ReservationV4SourceNotificationDraft;
|
||||
@@ -367,6 +368,58 @@ class ReservationV4QueryControllerTest {
|
||||
.andExpect(content().string(not(containsString("Sensitive raw notification body"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnV4OrderTaskAudits() throws Exception {
|
||||
ReservationV4OrderTaskSnapshot orderTask = seedOrderTask(
|
||||
"mail-v4-query-order-task-audits-001",
|
||||
Instant.parse("2026-07-18T04:10:00Z"));
|
||||
insertV4OrderTaskAudit(orderTask, "V4_CARD_CONFIRM", "v4-query-admin",
|
||||
Instant.parse("2026-07-18T04:11:00Z"));
|
||||
insertV4OrderTaskAudit(orderTask, "V4_CARD_REVIEW_RESOLVE", "v4-query-admin",
|
||||
Instant.parse("2026-07-18T04:12:00Z"));
|
||||
ReservationV4OrderTaskSnapshot otherOrderTask = seedOrderTask(
|
||||
"mail-v4-query-order-task-audits-other-001",
|
||||
Instant.parse("2026-07-18T04:13:00Z"));
|
||||
insertV4OrderTaskAudit(otherOrderTask, "V4_CARD_CONFIRM", "v4-query-admin",
|
||||
Instant.parse("2026-07-18T04:14:00Z"));
|
||||
|
||||
performAuthorized(mockMvc, adminToken(), get("/api/reservation/order-tasks/{orderTaskId}/audits",
|
||||
orderTask.id()).param("hotel_id", HOTEL_ID))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.order_task_id").value(orderTask.id().toString()))
|
||||
.andExpect(jsonPath("$.items.length()").value(2))
|
||||
.andExpect(jsonPath("$.items[0].action").value("V4_CARD_CONFIRM"))
|
||||
.andExpect(jsonPath("$.items[0].actor_id").value("v4-query-admin"))
|
||||
.andExpect(jsonPath("$.items[0].after_snapshot.v4_order_task_id").value(orderTask.id().toString()))
|
||||
.andExpect(jsonPath("$.items[1].action").value("V4_CARD_REVIEW_RESOLVE"))
|
||||
.andExpect(jsonPath("$.items[1].after_snapshot.v4_order_task_id").value(orderTask.id().toString()))
|
||||
.andExpect(jsonPath("$.items[0].occurred_at").value(matchesPattern(UTC_INSTANT_PATTERN)))
|
||||
.andExpect(content().string(not(containsString(otherOrderTask.id().toString()))))
|
||||
.andExpect(content().string(not(containsString("Sensitive raw audit body"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnV4SourceNotificationAudits() throws Exception {
|
||||
ReservationV4SourceNotificationSnapshot notification = seedSourceNotification(
|
||||
"mail-v4-query-notification-audits-001",
|
||||
"S10",
|
||||
Instant.parse("2026-07-18T04:20:00Z"));
|
||||
insertV4SourceNotificationAudit(notification, "v4-query-admin",
|
||||
Instant.parse("2026-07-18T04:21:00Z"));
|
||||
|
||||
performAuthorized(mockMvc, adminToken(), get("/api/reservation/source-notifications/{notificationId}/audits",
|
||||
notification.id()).param("hotel_id", HOTEL_ID))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.notification_id").value(notification.id().toString()))
|
||||
.andExpect(jsonPath("$.items.length()").value(1))
|
||||
.andExpect(jsonPath("$.items[0].action").value("V4_SOURCE_NOTIFICATION_ACK"))
|
||||
.andExpect(jsonPath("$.items[0].actor_type").value("USER"))
|
||||
.andExpect(jsonPath("$.items[0].after_snapshot.v4_source_notification_id")
|
||||
.value(notification.id().toString()))
|
||||
.andExpect(jsonPath("$.items[0].occurred_at").value(matchesPattern(UTC_INSTANT_PATTERN)))
|
||||
.andExpect(content().string(not(containsString("Sensitive raw audit body"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectV4WorkbenchItemsWithoutLogin() throws Exception {
|
||||
mockMvc.perform(get("/api/reservation/workbench-items")
|
||||
@@ -400,6 +453,14 @@ class ReservationV4QueryControllerTest {
|
||||
notification.id()).param("hotel_id", HOTEL_ID))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.error_code").value("FRONTEND_PERMISSION_DENIED"));
|
||||
performAuthorized(mockMvc, noPermissionToken(), get("/api/reservation/order-tasks/{orderTaskId}/audits",
|
||||
orderTask.id()).param("hotel_id", HOTEL_ID))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.error_code").value("FRONTEND_PERMISSION_DENIED"));
|
||||
performAuthorized(mockMvc, noPermissionToken(), get("/api/reservation/source-notifications/{notificationId}/audits",
|
||||
notification.id()).param("hotel_id", HOTEL_ID))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.error_code").value("FRONTEND_PERMISSION_DENIED"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -427,6 +488,14 @@ class ReservationV4QueryControllerTest {
|
||||
notification.id()).param("hotel_id", OTHER_HOTEL_ID))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.error_code").value("HOTEL_ACCESS_DENIED"));
|
||||
performAuthorized(mockMvc, adminToken(), get("/api/reservation/order-tasks/{orderTaskId}/audits",
|
||||
orderTask.id()).param("hotel_id", OTHER_HOTEL_ID))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.error_code").value("HOTEL_ACCESS_DENIED"));
|
||||
performAuthorized(mockMvc, adminToken(), get("/api/reservation/source-notifications/{notificationId}/audits",
|
||||
notification.id()).param("hotel_id", OTHER_HOTEL_ID))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(jsonPath("$.error_code").value("HOTEL_ACCESS_DENIED"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -670,4 +739,49 @@ class ReservationV4QueryControllerTest {
|
||||
"PAYMENT.attachment_ids 未匹配来源附件。",
|
||||
now));
|
||||
}
|
||||
|
||||
private void insertV4OrderTaskAudit(
|
||||
ReservationV4OrderTaskSnapshot orderTask,
|
||||
String action,
|
||||
String actorId,
|
||||
Instant occurredAt) {
|
||||
aiWorkflowRepository.insertAuditLog(new ReservationAuditLogDraft(
|
||||
HOTEL_ID,
|
||||
orderTask.orderId(),
|
||||
null,
|
||||
null,
|
||||
"USER",
|
||||
actorId,
|
||||
action,
|
||||
"前端查询 V4 审计测试。",
|
||||
"""
|
||||
{"v4_order_task_id":"%s","card_status":"PENDING_CONFIRM","raw":"Sensitive raw audit body"}
|
||||
""".formatted(orderTask.id()),
|
||||
"""
|
||||
{"v4_order_task_id":"%s","card_status":"CONFIRMED","field_pointers":["/basic_information/account_code"]}
|
||||
""".formatted(orderTask.id()),
|
||||
LocalDateTime.ofInstant(occurredAt, ZoneOffset.UTC)));
|
||||
}
|
||||
|
||||
private void insertV4SourceNotificationAudit(
|
||||
ReservationV4SourceNotificationSnapshot notification,
|
||||
String actorId,
|
||||
Instant occurredAt) {
|
||||
aiWorkflowRepository.insertAuditLog(new ReservationAuditLogDraft(
|
||||
HOTEL_ID,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"USER",
|
||||
actorId,
|
||||
"V4_SOURCE_NOTIFICATION_ACK",
|
||||
"确认已处理。",
|
||||
"""
|
||||
{"v4_source_notification_id":"%s","notification_status":"ACK_REQUIRED","raw":"Sensitive raw audit body"}
|
||||
""".formatted(notification.id()),
|
||||
"""
|
||||
{"v4_source_notification_id":"%s","notification_status":"ACKED"}
|
||||
""".formatted(notification.id()),
|
||||
LocalDateTime.ofInstant(occurredAt, ZoneOffset.UTC)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user