修复订单列表排序与活动时间刷新
This commit is contained in:
@@ -22,7 +22,7 @@ public interface ReservationOrderMapper extends BaseMapper<ReservationOrderEntit
|
|||||||
SELECT o.*
|
SELECT o.*
|
||||||
FROM workflow_reservation_order o
|
FROM workflow_reservation_order o
|
||||||
WHERE o.hotel_id = #{hotelId}
|
WHERE o.hotel_id = #{hotelId}
|
||||||
AND o.order_visibility != #{hiddenSystemVisibility}
|
AND o.order_visibility = #{visibleVisibility}
|
||||||
<if test="orderStatus != null and orderStatus != ''">
|
<if test="orderStatus != null and orderStatus != ''">
|
||||||
AND o.order_status = #{orderStatus}
|
AND o.order_status = #{orderStatus}
|
||||||
</if>
|
</if>
|
||||||
@@ -56,7 +56,7 @@ public interface ReservationOrderMapper extends BaseMapper<ReservationOrderEntit
|
|||||||
)
|
)
|
||||||
</if>
|
</if>
|
||||||
ORDER BY
|
ORDER BY
|
||||||
COALESCE(o.latest_activity_at, o.updated_at) DESC,
|
o.latest_activity_at DESC,
|
||||||
o.updated_at DESC,
|
o.updated_at DESC,
|
||||||
o.id DESC
|
o.id DESC
|
||||||
</script>
|
</script>
|
||||||
@@ -68,6 +68,6 @@ public interface ReservationOrderMapper extends BaseMapper<ReservationOrderEntit
|
|||||||
@Param("groupCode") String groupCode,
|
@Param("groupCode") String groupCode,
|
||||||
@Param("confirmationNumber") String confirmationNumber,
|
@Param("confirmationNumber") String confirmationNumber,
|
||||||
@Param("keyword") String keyword,
|
@Param("keyword") String keyword,
|
||||||
@Param("hiddenSystemVisibility") String hiddenSystemVisibility,
|
@Param("visibleVisibility") String visibleVisibility,
|
||||||
@Param("sourceMessageIds") List<Long> sourceMessageIds);
|
@Param("sourceMessageIds") List<Long> sourceMessageIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
|||||||
trim(request.groupCode()),
|
trim(request.groupCode()),
|
||||||
trim(request.confirmationNumber()),
|
trim(request.confirmationNumber()),
|
||||||
trim(request.keyword()),
|
trim(request.keyword()),
|
||||||
ReservationOrderVisibility.HIDDEN_SYSTEM.name(),
|
ReservationOrderVisibility.VISIBLE.name(),
|
||||||
sourceMessageIds);
|
sourceMessageIds);
|
||||||
return new ReservationPageSnapshot<>(
|
return new ReservationPageSnapshot<>(
|
||||||
page.getRecords().stream().map(this::toAiQueryOrderSnapshot).toList(),
|
page.getRecords().stream().map(this::toAiQueryOrderSnapshot).toList(),
|
||||||
@@ -788,11 +788,12 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
|||||||
public boolean updateOperaOperationAfterAttempt(
|
public boolean updateOperaOperationAfterAttempt(
|
||||||
String hotelId,
|
String hotelId,
|
||||||
Long operationId,
|
Long operationId,
|
||||||
|
Long orderId,
|
||||||
String operationStatus,
|
String operationStatus,
|
||||||
Long lastAttemptId,
|
Long lastAttemptId,
|
||||||
String lastErrorMessage,
|
String lastErrorMessage,
|
||||||
LocalDateTime now) {
|
LocalDateTime now) {
|
||||||
return operaOperationMapper.update(null, Wrappers.<ReservationOperaOperationEntity>lambdaUpdate()
|
boolean updated = operaOperationMapper.update(null, Wrappers.<ReservationOperaOperationEntity>lambdaUpdate()
|
||||||
.set(ReservationOperaOperationEntity::getOperationStatus, operationStatus)
|
.set(ReservationOperaOperationEntity::getOperationStatus, operationStatus)
|
||||||
.set(ReservationOperaOperationEntity::getLastAttemptId, lastAttemptId)
|
.set(ReservationOperaOperationEntity::getLastAttemptId, lastAttemptId)
|
||||||
.set(ReservationOperaOperationEntity::getLastErrorMessage, lastErrorMessage)
|
.set(ReservationOperaOperationEntity::getLastErrorMessage, lastErrorMessage)
|
||||||
@@ -800,6 +801,10 @@ public class MybatisReservationAiWorkflowRepository implements ReservationAiWork
|
|||||||
.setSql("attempt_count = attempt_count + 1")
|
.setSql("attempt_count = attempt_count + 1")
|
||||||
.eq(ReservationOperaOperationEntity::getHotelId, hotelId)
|
.eq(ReservationOperaOperationEntity::getHotelId, hotelId)
|
||||||
.eq(ReservationOperaOperationEntity::getId, operationId)) > 0;
|
.eq(ReservationOperaOperationEntity::getId, operationId)) > 0;
|
||||||
|
if (updated) {
|
||||||
|
touchOrderLatestActivity(hotelId, orderId, now);
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -248,6 +248,7 @@ public interface ReservationAiWorkflowRepository {
|
|||||||
boolean updateOperaOperationAfterAttempt(
|
boolean updateOperaOperationAfterAttempt(
|
||||||
String hotelId,
|
String hotelId,
|
||||||
Long operationId,
|
Long operationId,
|
||||||
|
Long orderId,
|
||||||
String operationStatus,
|
String operationStatus,
|
||||||
Long lastAttemptId,
|
Long lastAttemptId,
|
||||||
String lastErrorMessage,
|
String lastErrorMessage,
|
||||||
|
|||||||
@@ -500,6 +500,7 @@ public class ReservationTaskWorkflowServiceImpl implements ReservationTaskWorkfl
|
|||||||
workflowRepository.updateOperaOperationAfterAttempt(
|
workflowRepository.updateOperaOperationAfterAttempt(
|
||||||
task.hotelId(),
|
task.hotelId(),
|
||||||
operation.id(),
|
operation.id(),
|
||||||
|
task.orderId(),
|
||||||
operationStatus,
|
operationStatus,
|
||||||
attemptId,
|
attemptId,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- M002 前端订单列表排序优化:订单自身维护最近业务活动时间,避免列表查询每次聚合全量任务。
|
-- M002 前端订单列表排序优化:订单自身维护最近业务活动时间,避免列表查询每次聚合全量任务。
|
||||||
ALTER TABLE workflow_reservation_order
|
ALTER TABLE workflow_reservation_order
|
||||||
ADD COLUMN latest_activity_at DATETIME(6) NULL COMMENT '订单最近业务活动 UTC 时间,用于订单列表最新活动排序';
|
ADD COLUMN latest_activity_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '订单最近业务活动 UTC 时间,用于订单列表最新活动排序';
|
||||||
|
|
||||||
-- 历史数据回填:优先取订单更新时间和所属任务最新来源/创建时间中的较大值。
|
-- 历史数据回填:优先取订单更新时间和所属任务最新来源/创建时间中的较大值。
|
||||||
UPDATE workflow_reservation_order
|
UPDATE workflow_reservation_order
|
||||||
@@ -19,4 +19,4 @@ SET latest_activity_at = GREATEST(
|
|||||||
|
|
||||||
-- 订单列表按可见性和最新活动时间倒序分页。
|
-- 订单列表按可见性和最新活动时间倒序分页。
|
||||||
CREATE INDEX idx_reservation_order_visibility_activity
|
CREATE INDEX idx_reservation_order_visibility_activity
|
||||||
ON workflow_reservation_order (hotel_id, order_visibility, latest_activity_at, id);
|
ON workflow_reservation_order (hotel_id, order_visibility, latest_activity_at DESC, updated_at DESC, id DESC);
|
||||||
|
|||||||
@@ -248,6 +248,44 @@ class ReservationFrontendQueryControllerTest {
|
|||||||
.andExpect(jsonPath("$.page.total").value(2));
|
.andExpect(jsonPath("$.page.total").value(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldKeepOrderLatestActivityAtRequiredForIndexedSorting() {
|
||||||
|
String isNullable = jdbcTemplate.queryForObject("""
|
||||||
|
SELECT IS_NULLABLE
|
||||||
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
|
WHERE TABLE_NAME = 'WORKFLOW_RESERVATION_ORDER'
|
||||||
|
AND COLUMN_NAME = 'LATEST_ACTIVITY_AT'
|
||||||
|
""", String.class);
|
||||||
|
|
||||||
|
assertThat(isNullable).isEqualTo("NO");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldOnlyReturnVisibleOrdersInFrontendOrderList() throws Exception {
|
||||||
|
SourceMessageCaptureResult visibleSource = captureSourceMessage(
|
||||||
|
"mail-frontend-order-visible-filter-001",
|
||||||
|
"Frontend Query Visible Filter");
|
||||||
|
SourceMessageCaptureResult archivedSource = captureSourceMessage(
|
||||||
|
"mail-frontend-order-visible-filter-archived-001",
|
||||||
|
"Frontend Query Visible Filter Archived");
|
||||||
|
Long visibleOrderId = 930000000000002201L;
|
||||||
|
Long archivedOrderId = 930000000000002202L;
|
||||||
|
insertGroupOrder(visibleOrderId, visibleSource.inboxId(),
|
||||||
|
"GRP-FRONTEND-VISIBLE-FILTER-001", "ACTIVE");
|
||||||
|
insertGroupOrder(archivedOrderId, archivedSource.inboxId(),
|
||||||
|
"GRP-FRONTEND-VISIBLE-FILTER-ARCHIVED", "ACTIVE");
|
||||||
|
updateOrderVisibility(archivedOrderId, "ARCHIVED_SYSTEM");
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/reservation/orders")
|
||||||
|
.param("hotel_id", HOTEL_ID)
|
||||||
|
.param("keyword", "GRP-FRONTEND-VISIBLE-FILTER-")
|
||||||
|
.param("page_num", "1")
|
||||||
|
.param("page_size", "20"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.items[0].order_id").value(visibleOrderId.toString()))
|
||||||
|
.andExpect(jsonPath("$.page.total").value(1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldTouchOrderLatestActivityWhenRepositoryInsertsTask() {
|
void shouldTouchOrderLatestActivityWhenRepositoryInsertsTask() {
|
||||||
SourceMessageCaptureResult source = captureSourceMessage(
|
SourceMessageCaptureResult source = captureSourceMessage(
|
||||||
@@ -457,6 +495,14 @@ class ReservationFrontendQueryControllerTest {
|
|||||||
""", Timestamp.from(latestActivityAt), orderId);
|
""", Timestamp.from(latestActivityAt), orderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateOrderVisibility(Long orderId, String orderVisibility) {
|
||||||
|
jdbcTemplate.update("""
|
||||||
|
UPDATE workflow_reservation_order
|
||||||
|
SET order_visibility = ?
|
||||||
|
WHERE id = ?
|
||||||
|
""", orderVisibility, orderId);
|
||||||
|
}
|
||||||
|
|
||||||
private void insertActiveGroupOrder(Long orderId, Long sourceMessageId, String groupCode) {
|
private void insertActiveGroupOrder(Long orderId, Long sourceMessageId, String groupCode) {
|
||||||
insertGroupOrder(orderId, sourceMessageId, groupCode, "ACTIVE");
|
insertGroupOrder(orderId, sourceMessageId, groupCode, "ACTIVE");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import cn.nianxx.thhotel.platform.message.common.result.SourceMessageCaptureResu
|
|||||||
import cn.nianxx.thhotel.platform.message.service.SourceMessageCaptureService;
|
import cn.nianxx.thhotel.platform.message.service.SourceMessageCaptureService;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
import java.sql.Timestamp;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.HexFormat;
|
import java.util.HexFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -1968,6 +1969,18 @@ class SuperAgentTaskResultControllerTest {
|
|||||||
"CNF-CP5-OPERA-RETRY-001");
|
"CNF-CP5-OPERA-RETRY-001");
|
||||||
String taskId = taskAndOperationIds[0];
|
String taskId = taskAndOperationIds[0];
|
||||||
String firstOperationId = taskAndOperationIds[1];
|
String firstOperationId = taskAndOperationIds[1];
|
||||||
|
Long orderId = jdbcTemplate.queryForObject("""
|
||||||
|
SELECT order_id
|
||||||
|
FROM workflow_reservation_task
|
||||||
|
WHERE id = ?
|
||||||
|
""", Long.class, Long.valueOf(taskId));
|
||||||
|
Timestamp staleLatestActivityAt = Timestamp.from(Instant.parse("2026-07-01T00:00:00Z"));
|
||||||
|
jdbcTemplate.update("""
|
||||||
|
UPDATE workflow_reservation_order
|
||||||
|
SET latest_activity_at = ?,
|
||||||
|
updated_at = ?
|
||||||
|
WHERE id = ?
|
||||||
|
""", staleLatestActivityAt, staleLatestActivityAt, orderId);
|
||||||
|
|
||||||
mockMvc.perform(post(
|
mockMvc.perform(post(
|
||||||
"/api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute",
|
"/api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute",
|
||||||
@@ -1984,6 +1997,12 @@ class SuperAgentTaskResultControllerTest {
|
|||||||
.andExpect(jsonPath("$.operation_status").value("FAILED"))
|
.andExpect(jsonPath("$.operation_status").value("FAILED"))
|
||||||
.andExpect(jsonPath("$.attempt_count").value(1))
|
.andExpect(jsonPath("$.attempt_count").value(1))
|
||||||
.andExpect(jsonPath("$.attempts[0].attempt_status").value("FAILED"));
|
.andExpect(jsonPath("$.attempts[0].attempt_status").value("FAILED"));
|
||||||
|
Timestamp failedAttemptLatestActivityAt = jdbcTemplate.queryForObject("""
|
||||||
|
SELECT latest_activity_at
|
||||||
|
FROM workflow_reservation_order
|
||||||
|
WHERE id = ?
|
||||||
|
""", Timestamp.class, orderId);
|
||||||
|
assertThat(failedAttemptLatestActivityAt.toInstant()).isAfter(staleLatestActivityAt.toInstant());
|
||||||
|
|
||||||
mockMvc.perform(post(
|
mockMvc.perform(post(
|
||||||
"/api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry",
|
"/api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry",
|
||||||
|
|||||||
Reference in New Issue
Block a user