实现V4 Rooming List轻量事项卡
This commit is contained in:
@@ -386,6 +386,134 @@ describe('reservation V4 pages', () => {
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('https://oss.example')
|
||||
})
|
||||
|
||||
it('renders Rooming List cards as lightweight action items without rows, attachments or raw payloads', async () => {
|
||||
const detail = createOrderTaskDetail()
|
||||
useRoomingListBusinessCard(detail)
|
||||
useBoundOrder(detail)
|
||||
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
|
||||
|
||||
const wrapper = await mountWithPlugins(
|
||||
ReservationV4OrderTaskDetailView,
|
||||
'/reservation/order-tasks/9001',
|
||||
)
|
||||
await flushPromises()
|
||||
|
||||
const roomingListSection = wrapper
|
||||
.findAll('.task-card-section')
|
||||
.find((section) => section.find('[data-testid="rooming-list-card"]').exists())
|
||||
expect(roomingListSection).toBeTruthy()
|
||||
const roomingListCard = roomingListSection!.find('[data-testid="rooming-list-card"]')
|
||||
expect(roomingListCard.exists()).toBe(true)
|
||||
expect(roomingListSection!.text()).toContain(zhCN.taskV4.roomingList.title)
|
||||
expect(roomingListCard.text()).toContain(zhCN.taskV4.roomingList.description)
|
||||
expect(roomingListCard.text()).toContain('GRP-001')
|
||||
expect(roomingListSection!.findAll('a').filter((link) => link.text() === zhCN.task.viewOrder)).toHaveLength(1)
|
||||
expect(wrapper.text()).toContain(zhCN.taskV4.sourceMessageCard)
|
||||
expect(wrapper.text().indexOf(zhCN.taskV4.sourceMessageCard)).toBeGreaterThan(
|
||||
wrapper.text().indexOf(zhCN.taskV4.roomingList.title),
|
||||
)
|
||||
|
||||
expect(roomingListSection!.find('details.safe-payload').exists()).toBe(false)
|
||||
expect(roomingListSection!.text()).not.toContain('ROW_SHOULD_NOT_RENDER')
|
||||
expect(roomingListSection!.text()).not.toContain('attachment_ids')
|
||||
expect(roomingListSection!.text()).not.toContain('https://oss.example/private/rooming-list.xlsx')
|
||||
expect(roomingListSection!.text()).not.toContain('AI_PAYLOAD_SHOULD_NOT_RENDER')
|
||||
expect(roomingListSection!.text()).not.toContain('PMS_IMPORT_SHOULD_NOT_RENDER')
|
||||
expect(roomingListSection!.text()).not.toContain('OHIP_SHOULD_NOT_RENDER')
|
||||
expect(roomingListSection!.text()).not.toContain('Excel')
|
||||
expect(wrapper.find('[data-testid="payment-attachment-preview"]').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('shows an explanatory unbound order label for Rooming List cards without target order clues', async () => {
|
||||
const detail = createOrderTaskDetail()
|
||||
useRoomingListBusinessCard(detail)
|
||||
detail.order_task.display_order_key = null
|
||||
detail.order_task.order_ref = null
|
||||
detail.order_task.target_locator_type = null
|
||||
detail.order_task.target_locator_value = null
|
||||
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
|
||||
|
||||
const wrapper = await mountWithPlugins(
|
||||
ReservationV4OrderTaskDetailView,
|
||||
'/reservation/order-tasks/9001',
|
||||
)
|
||||
await flushPromises()
|
||||
|
||||
const roomingListCard = wrapper.find('[data-testid="rooming-list-card"]')
|
||||
expect(roomingListCard.text()).toContain(zhCN.taskV4.roomingList.unboundOrder)
|
||||
})
|
||||
|
||||
it('confirms Rooming List cards with version only and applies the refreshed backend detail', async () => {
|
||||
const detail = createOrderTaskDetail()
|
||||
useRoomingListBusinessCard(detail)
|
||||
const confirmedDetail = createOrderTaskDetail()
|
||||
useRoomingListBusinessCard(confirmedDetail, 'CONFIRMED')
|
||||
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
|
||||
vi.mocked(service.confirmReservationV4OrderTaskCard).mockResolvedValue(confirmedDetail)
|
||||
|
||||
const wrapper = await mountWithPlugins(
|
||||
ReservationV4OrderTaskDetailView,
|
||||
'/reservation/order-tasks/9001',
|
||||
)
|
||||
await flushPromises()
|
||||
|
||||
const roomingListSection = wrapper
|
||||
.findAll('.task-card-section')
|
||||
.find((section) => section.find('[data-testid="rooming-list-card"]').exists())
|
||||
expect(roomingListSection).toBeTruthy()
|
||||
await roomingListSection!.find('button.primary-button').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(service.confirmReservationV4OrderTaskCard).toHaveBeenCalledWith('9001', 'card-rooming-list', {
|
||||
version: 12,
|
||||
})
|
||||
const submittedRequest = vi.mocked(service.confirmReservationV4OrderTaskCard).mock.calls[0]?.[2]
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('confirmed_payload')
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('rows')
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('attachment_ids')
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('https://oss.example')
|
||||
expect(wrapper.text()).toContain(zhCN.status.CONFIRMED)
|
||||
})
|
||||
|
||||
it('resolves Rooming List review cards without submitting row or attachment overrides', async () => {
|
||||
const detail = createOrderTaskDetail()
|
||||
useRoomingListBusinessCard(detail, 'REVIEW_REQUIRED')
|
||||
detail.order_task.order_id = 'order-2001'
|
||||
detail.order_task.target_resolution_status = 'RESOLVED'
|
||||
const resolvedDetail = createOrderTaskDetail()
|
||||
useRoomingListBusinessCard(resolvedDetail, 'PENDING_CONFIRM')
|
||||
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
|
||||
vi.mocked(service.resolveReservationV4OrderTaskCardReview).mockResolvedValue(resolvedDetail)
|
||||
|
||||
const wrapper = await mountWithPlugins(
|
||||
ReservationV4OrderTaskDetailView,
|
||||
'/reservation/order-tasks/9001',
|
||||
)
|
||||
await flushPromises()
|
||||
|
||||
const roomingListSection = wrapper
|
||||
.findAll('.task-card-section')
|
||||
.find((section) => section.find('[data-testid="rooming-list-card"]').exists())
|
||||
expect(roomingListSection).toBeTruthy()
|
||||
expect(roomingListSection!.find('.review-box').exists()).toBe(true)
|
||||
expect(roomingListSection!.find('.task-card-section__fields').exists()).toBe(false)
|
||||
await roomingListSection!.find('textarea').setValue('handled rooming list')
|
||||
await roomingListSection!.find('button.primary-button').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(service.confirmReservationV4OrderTaskCard).not.toHaveBeenCalled()
|
||||
expect(service.resolveReservationV4OrderTaskCardReview).toHaveBeenCalledWith('9001', 'card-rooming-list', {
|
||||
version: 12,
|
||||
confirmed_order_id: 'order-2001',
|
||||
reason: 'handled rooming list',
|
||||
field_overrides: [],
|
||||
})
|
||||
const submittedRequest = vi.mocked(service.resolveReservationV4OrderTaskCardReview).mock.calls[0]?.[2]
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('rows')
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('attachment_ids')
|
||||
expect(JSON.stringify(submittedRequest)).not.toContain('https://oss.example')
|
||||
})
|
||||
|
||||
it('renders New Booking Room Information as a business form and confirms stable final values', async () => {
|
||||
const detail = createOrderTaskDetail({
|
||||
businessEventType: 'NEW_BOOKING',
|
||||
@@ -1360,6 +1488,75 @@ function usePaymentBusinessCard(detail: ReservationV4OrderTaskDetailResult): voi
|
||||
]
|
||||
}
|
||||
|
||||
function useRoomingListBusinessCard(
|
||||
detail: ReservationV4OrderTaskDetailResult,
|
||||
cardStatus = 'PENDING_CONFIRM',
|
||||
): void {
|
||||
const isPendingConfirm = cardStatus === 'PENDING_CONFIRM'
|
||||
const isReviewRequired = cardStatus === 'REVIEW_REQUIRED'
|
||||
detail.business_cards = [
|
||||
createCard('card-rooming-list', 'ROOMING_LIST', cardStatus, {
|
||||
version: 12,
|
||||
availability: createAvailability({
|
||||
confirmable: isPendingConfirm,
|
||||
reviewable: isReviewRequired,
|
||||
editable: false,
|
||||
read_only: !isPendingConfirm,
|
||||
}),
|
||||
display_payload: {
|
||||
rows: [
|
||||
{
|
||||
guest_name: 'ROW_SHOULD_NOT_RENDER',
|
||||
room_no: '1001',
|
||||
},
|
||||
],
|
||||
attachment_ids: ['rooming-list-att-1'],
|
||||
attachment_url: 'https://oss.example/private/rooming-list.xlsx',
|
||||
ai_payload_json: 'AI_PAYLOAD_SHOULD_NOT_RENDER',
|
||||
pms_import_plan: 'PMS_IMPORT_SHOULD_NOT_RENDER',
|
||||
ohip_payload: 'OHIP_SHOULD_NOT_RENDER',
|
||||
},
|
||||
fields: [
|
||||
createField('/rooming_list/rows/0/guest_name', {
|
||||
display_name: 'Rooming list row',
|
||||
value: 'ROW_SHOULD_NOT_RENDER',
|
||||
editable: true,
|
||||
edit_scope: 'CONFIRM',
|
||||
write_target: 'CONFIRMED_PAYLOAD_JSON',
|
||||
}),
|
||||
createField('/rooming_list/attachment_ids', {
|
||||
display_name: 'attachment_ids',
|
||||
value: ['rooming-list-att-1'],
|
||||
editable: true,
|
||||
edit_scope: 'CONFIRM',
|
||||
write_target: 'CONFIRMED_PAYLOAD_JSON',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
]
|
||||
detail.card_counts = {
|
||||
...detail.card_counts,
|
||||
pending_confirm_count: cardStatus === 'PENDING_CONFIRM' ? 2 : 1,
|
||||
confirmed_count: cardStatus === 'CONFIRMED' ? 1 : 0,
|
||||
}
|
||||
}
|
||||
|
||||
function useBoundOrder(detail: ReservationV4OrderTaskDetailResult): void {
|
||||
detail.bound_order = {
|
||||
order_id: 'order-2001',
|
||||
hotel_id: 'HOTEL-TEST',
|
||||
order_status: 'ACTIVE',
|
||||
temporary_order_no: null,
|
||||
confirmation_number: null,
|
||||
group_code: 'GRP-001',
|
||||
block_code: null,
|
||||
allotment_code: null,
|
||||
display_name: 'GRP-001',
|
||||
created_at: '2026-07-08T03:00:00Z',
|
||||
updated_at: '2026-07-08T03:00:00Z',
|
||||
}
|
||||
}
|
||||
|
||||
function createPaymentConversationMedia(): SourceMessageOriginalMedia[] {
|
||||
return [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user