修复V4 Trace确认态字段刷新

This commit is contained in:
andy
2026-07-21 19:31:05 +07:00
parent 6e97778633
commit 350bb3310b
2 changed files with 205 additions and 2 deletions

View File

@@ -788,6 +788,24 @@ class ReservationV4CommandControllerTest {
.andExpect(jsonPath("$.business_cards[0].confirmed_payload.trace_items[1].attachment_url").doesNotExist())
.andExpect(content().string(not(containsString("SHOULD-NOT-PERSIST"))))
.andExpect(content().string(not(containsString("https://oss.example.test"))));
MvcResult refreshedResult = performAuthorized(mockMvc, adminToken(),
get("/api/reservation/order-tasks/{orderTaskId}", seeded.orderTask().id())
.param("hotel_id", HOTEL_ID))
.andExpect(status().isOk())
.andReturn();
JsonNode refreshedDetail = objectMapper.readTree(refreshedResult.getResponse().getContentAsString());
assertTraceFieldValue(refreshedDetail, "/trace_items/0/text", "Updated trace");
assertTraceFieldValue(refreshedDetail, "/trace_items/0/department_code", "HSK");
assertTraceFieldValue(refreshedDetail, "/trace_items/1/target_room_type_code", "RM3");
assertTraceFieldValue(refreshedDetail, "/trace_items/1/extra_bed_room_count", 2);
assertTraceFieldValidationErrorsEmpty(refreshedDetail, "/trace_items/0/text");
org.assertj.core.api.Assertions.assertThat(refreshedDetail.path("business_cards").get(0)
.path("validation_errors").isArray())
.isTrue();
org.assertj.core.api.Assertions.assertThat(refreshedDetail.path("business_cards").get(0)
.path("validation_errors").size())
.isZero();
}
@Test
@@ -1570,6 +1588,107 @@ class ReservationV4CommandControllerTest {
.andExpect(jsonPath("$.business_cards[0].confirmed_payload.target_order").doesNotExist());
}
@Test
void shouldRefreshExtraBedTraceFieldsFromConfirmedPayloadAfterReviewResolution() throws Exception {
SeededOrderTask seeded = seedReviewOrderTaskWithBusinessCard(
HOTEL_ID,
"mail-v4-command-review-trace-extra-bed-refresh-001",
Instant.parse("2026-07-19T01:22:29Z"),
990000000000070127L,
ReservationV4TargetResolutionStatus.RESOLVED.name(),
ReservationV4CardStatus.PENDING_CONFIRM.name(),
ReservationV4CardStatus.REVIEW_REQUIRED.name(),
ReservationV4CardType.TRACE_RESERVATION_NOTES.name(),
"TRACE_RESERVATION_NOTES",
"""
{
"card_type":"TRACE_RESERVATION_NOTES",
"event_type":"TRACE_RESERVATION_NOTES",
"target_order":{"locator_value":"SHOULD-NOT-PERSIST-TRACE"},
"business_fields":{
"event_type":"TRACE_RESERVATION_NOTES",
"trace_items":[
{
"item_type":"EXTRA_BED",
"target_room_type_code":"UNKNOWN_ROOM",
"extra_bed_room_count":0,
"department_code":"SALES",
"content":"SHOULD-NOT-PERSIST-CONTENT",
"attachment_url":"https://oss.example.test/trace-review-secret.png"
}
]
}
}
""",
"""
[
{
"field_path": "trace_items.0.target_room_type_code",
"field_pointer": "/trace_items/0/target_room_type_code",
"message": "房型代码不在第一版目录中。",
"detail": "trace_items.0.target_room_type_code: 房型代码不在第一版目录中。"
},
{
"field_path": "trace_items.0.extra_bed_room_count",
"field_pointer": "/trace_items/0/extra_bed_room_count",
"message": "加床房间数必须为正整数。",
"detail": "trace_items.0.extra_bed_room_count: 加床房间数必须为正整数。"
},
{
"field_path": "trace_items.0.department_code",
"field_pointer": "/trace_items/0/department_code",
"message": "Department Code 只允许 FO、HSK、FO+HSK。",
"detail": "trace_items.0.department_code: Department Code 只允许 FO、HSK、FO+HSK。"
}
]
""");
confirmBasicCard(seeded);
performAuthorized(mockMvc, adminToken(), post(
"/api/reservation/order-tasks/{orderTaskId}/cards/{cardId}/review-resolution",
seeded.orderTask().id(),
seeded.businessCard().id())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"version": 0,
"reason": "修正 Trace Extra Bed 字段",
"field_overrides": [
{"field_pointer": "/trace_items/0/target_room_type_code", "value": "RM2"},
{"field_pointer": "/trace_items/0/extra_bed_room_count", "value": 2},
{"field_pointer": "/trace_items/0/department_code", "value": "FO+HSK"}
]
}
"""))
.andExpect(status().isOk())
.andExpect(jsonPath("$.business_cards[0].card_status").value("CONFIRMED"))
.andExpect(jsonPath("$.business_cards[0].confirmed_payload.trace_items[0].target_room_type_code")
.value("RM2"))
.andExpect(jsonPath("$.business_cards[0].confirmed_payload.trace_items[0].extra_bed_room_count")
.value(2))
.andExpect(jsonPath("$.business_cards[0].confirmed_payload.trace_items[0].department_code")
.value("FO+HSK"));
MvcResult refreshedResult = performAuthorized(mockMvc, adminToken(),
get("/api/reservation/order-tasks/{orderTaskId}", seeded.orderTask().id())
.param("hotel_id", HOTEL_ID))
.andExpect(status().isOk())
.andReturn();
JsonNode refreshedDetail = objectMapper.readTree(refreshedResult.getResponse().getContentAsString());
assertTraceFieldValue(refreshedDetail, "/trace_items/0/target_room_type_code", "RM2");
assertTraceFieldValue(refreshedDetail, "/trace_items/0/extra_bed_room_count", 2);
assertTraceFieldValue(refreshedDetail, "/trace_items/0/department_code", "FO+HSK");
assertTraceFieldValidationErrorsEmpty(refreshedDetail, "/trace_items/0/target_room_type_code");
assertTraceFieldValidationErrorsEmpty(refreshedDetail, "/trace_items/0/extra_bed_room_count");
assertTraceFieldValidationErrorsEmpty(refreshedDetail, "/trace_items/0/department_code");
org.assertj.core.api.Assertions.assertThat(refreshedDetail.path("business_cards").get(0)
.path("validation_errors").isArray())
.isTrue();
org.assertj.core.api.Assertions.assertThat(refreshedDetail.path("business_cards").get(0)
.path("validation_errors").size())
.isZero();
}
@Test
void shouldResolveEditableRoomInformationPointerWhenLeafMissingInPayload() throws Exception {
SeededOrderTask seeded = seedReviewOrderTaskWithBusinessCard(
@@ -2430,6 +2549,44 @@ class ReservationV4CommandControllerTest {
return objectMapper.getNodeFactory().textNode("UPDATED");
}
private void assertTraceFieldValue(JsonNode detail, String pointer, String expectedValue) {
JsonNode field = traceField(detail, pointer);
org.assertj.core.api.Assertions.assertThat(field.path("value").asText())
.as(pointer + " 刷新后的字段值")
.isEqualTo(expectedValue);
}
private void assertTraceFieldValue(JsonNode detail, String pointer, int expectedValue) {
JsonNode field = traceField(detail, pointer);
org.assertj.core.api.Assertions.assertThat(field.path("value").asInt())
.as(pointer + " 刷新后的字段值")
.isEqualTo(expectedValue);
}
private void assertTraceFieldValidationErrorsEmpty(JsonNode detail, String pointer) {
JsonNode field = traceField(detail, pointer);
org.assertj.core.api.Assertions.assertThat(field.path("validation_errors").isArray())
.as(pointer + " 字段错误集合")
.isTrue();
org.assertj.core.api.Assertions.assertThat(field.path("validation_errors").size())
.as(pointer + " 字段错误数量")
.isZero();
}
private JsonNode traceField(JsonNode detail, String pointer) {
for (JsonNode card : detail.path("business_cards")) {
if (!ReservationV4CardType.TRACE_RESERVATION_NOTES.name().equals(card.path("card_type").asText())) {
continue;
}
for (JsonNode field : card.path("fields")) {
if (pointer.equals(field.path("field_pointer").asText())) {
return field;
}
}
}
throw new AssertionError("未找到 Trace 字段:" + pointer);
}
private void confirmRoomInformationBusinessCard(SeededOrderTask seeded, String groupBookingStatus) throws Exception {
String groupBookingStatusFragment = groupBookingStatus == null
? ""