接入V4任务卡目录查询

This commit is contained in:
andy
2026-07-19 15:35:58 +07:00
parent 8b37232ac9
commit d808732107
16 changed files with 803 additions and 38 deletions

View File

@@ -20,7 +20,10 @@ vi.mock('@/services/reservationService', async (importOriginal) => {
...actual,
ackReservationV4SourceNotification: vi.fn(),
confirmReservationV4OrderTaskCard: vi.fn(),
fetchReservationV4AccountLookups: vi.fn(),
fetchReservationV4OrderTaskDetail: vi.fn(),
fetchReservationV4RateCodeLookups: vi.fn(),
fetchReservationV4RoomTypeLookups: vi.fn(),
fetchReservationV4SourceNotificationDetail: vi.fn(),
resolveReservationV4OrderTaskCardReview: vi.fn(),
}
@@ -33,12 +36,16 @@ describe('reservation V4 pages', () => {
sessionStorage.clear()
vi.mocked(service.ackReservationV4SourceNotification).mockReset()
vi.mocked(service.confirmReservationV4OrderTaskCard).mockReset()
vi.mocked(service.fetchReservationV4AccountLookups).mockReset()
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockReset()
vi.mocked(service.fetchReservationV4RateCodeLookups).mockReset()
vi.mocked(service.fetchReservationV4RoomTypeLookups).mockReset()
vi.mocked(service.fetchReservationV4SourceNotificationDetail).mockReset()
vi.mocked(service.resolveReservationV4OrderTaskCardReview).mockReset()
mockCatalogLookups()
})
it('renders V4 order task cards and confirms only editable basic information fields', async () => {
it('renders V4 order task cards, loads lookup options and confirms only selected codes', async () => {
const detail = createOrderTaskDetail()
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
vi.mocked(service.confirmReservationV4OrderTaskCard).mockResolvedValue({
@@ -60,8 +67,21 @@ describe('reservation V4 pages', () => {
expect(wrapper.text()).toContain('基础信息卡')
expect(wrapper.text()).toContain('业务任务卡')
expect(wrapper.text()).toContain('Backend contract issue')
expect(service.fetchReservationV4AccountLookups).toHaveBeenCalledWith({
hotel_id: 'HOTEL-TEST',
page_num: 1,
page_size: 100,
})
expect(service.fetchReservationV4RoomTypeLookups).toHaveBeenCalledWith({
hotel_id: 'HOTEL-TEST',
page_num: 1,
page_size: 100,
})
await wrapper.find('select').setValue('HANATOUR')
await wrapper.find('select').setValue('ACC-LIVE')
await flushPromises()
expect(wrapper.text()).toContain('LEISURE')
expect(wrapper.text()).toContain('TRAVEL_AGENT')
await wrapper.findAll('button').find((button) => button.text().includes('确认卡片'))?.trigger('click')
await flushPromises()
@@ -69,7 +89,7 @@ describe('reservation V4 pages', () => {
version: 7,
confirmed_payload: {
basic_information: {
account_code: 'HANATOUR',
account_code: 'ACC-LIVE',
},
},
})
@@ -153,6 +173,74 @@ describe('reservation V4 pages', () => {
})
})
it('shows non-blocking lookup empty, stale and warning states', async () => {
const detail = createOrderTaskDetail()
vi.mocked(service.fetchReservationV4AccountLookups).mockResolvedValue({
hotel_id: 'HOTEL-TEST',
catalog_type: 'ACCOUNT',
catalog_source: 'PMS_SYNC',
catalog_version: 'stale-v1',
stale: true,
items: [],
page: {
page_num: 1,
page_size: 100,
total: 0,
},
warnings: ['PMS sync is stale'],
})
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
const wrapper = await mountWithPlugins(
ReservationV4OrderTaskDetailView,
'/reservation/order-tasks/9001',
)
await flushPromises()
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.empty)
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.stale)
expect(wrapper.text()).toContain('PMS sync is stale')
expect(wrapper.text()).toContain('PMS_SYNC')
expect(wrapper.text()).toContain('stale-v1')
})
it('does not submit a catalog field value that is missing from the loaded lookup result', async () => {
const detail = createOrderTaskDetail({
basicAccountValue: 'UNKNOWN_ACCOUNT',
basicAccountRequired: true,
})
vi.mocked(service.fetchReservationV4AccountLookups).mockResolvedValue({
hotel_id: 'HOTEL-TEST',
catalog_type: 'ACCOUNT',
catalog_source: 'SYSTEM_MANAGED',
catalog_version: 'catalog-v1',
stale: false,
items: [],
page: {
page_num: 1,
page_size: 100,
total: 0,
},
warnings: [],
})
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
const wrapper = await mountWithPlugins(
ReservationV4OrderTaskDetailView,
'/reservation/order-tasks/9001',
)
await flushPromises()
expect(wrapper.text()).toContain('UNKNOWN_ACCOUNT')
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.currentNotInCatalog.replace('{value}', 'UNKNOWN_ACCOUNT'))
await wrapper.findAll('button').find((button) => button.text().includes('确认卡片'))?.trigger('click')
await flushPromises()
expect(service.confirmReservationV4OrderTaskCard).not.toHaveBeenCalled()
expect(wrapper.text()).toContain(zhCN.taskV4.validationFailed)
})
it('requires confirmed order id before resolving an unresolved V4 review card', async () => {
const detail = createOrderTaskDetail({
businessCardStatus: 'REVIEW_REQUIRED',
@@ -277,10 +365,83 @@ async function mountWithPlugins(component: object, initialPath: string) {
})
}
function mockCatalogLookups() {
vi.mocked(service.fetchReservationV4AccountLookups).mockResolvedValue({
hotel_id: 'HOTEL-TEST',
catalog_type: 'ACCOUNT',
catalog_source: 'SYSTEM_MANAGED',
catalog_version: 'catalog-v1',
stale: false,
items: [
{
code: 'ACC-LIVE',
display_name: 'Live Account',
status: 'ACTIVE',
catalog_source: 'SYSTEM_MANAGED',
market_code: 'LEISURE',
market_name: 'Leisure',
source_code: 'TRAVEL_AGENT',
source_name: 'Travel Agent',
adult_capacity: null,
pricing_available: null,
},
],
page: {
page_num: 1,
page_size: 100,
total: 1,
},
warnings: [],
})
vi.mocked(service.fetchReservationV4RoomTypeLookups).mockResolvedValue({
hotel_id: 'HOTEL-TEST',
catalog_type: 'ROOM_TYPE',
catalog_source: 'SYSTEM_MANAGED',
catalog_version: 'catalog-v1',
stale: false,
items: [
{
code: 'TWN',
display_name: 'Twin',
status: 'ACTIVE',
catalog_source: 'SYSTEM_MANAGED',
market_code: null,
market_name: null,
source_code: null,
source_name: null,
adult_capacity: 2,
pricing_available: null,
},
],
page: {
page_num: 1,
page_size: 100,
total: 1,
},
warnings: [],
})
vi.mocked(service.fetchReservationV4RateCodeLookups).mockResolvedValue({
hotel_id: 'HOTEL-TEST',
catalog_type: 'RATE_CODE',
catalog_source: 'SYSTEM_MANAGED',
catalog_version: 'catalog-v1',
stale: false,
items: [],
page: {
page_num: 1,
page_size: 100,
total: 0,
},
warnings: [],
})
}
function createOrderTaskDetail(options: {
businessCardStatus?: string
businessCardAvailability?: Partial<ReservationV4TaskCardResult['availability']>
sourceDisplayPayload?: ReservationV4TaskCardResult['display_payload']
basicAccountValue?: string
basicAccountRequired?: boolean
} = {}): ReservationV4OrderTaskDetailResult {
const sourceCard = createCard('card-source', 'SOURCE_MESSAGE_DISPLAY', 'READONLY', {
fields: [],
@@ -301,7 +462,8 @@ function createOrderTaskDetail(options: {
fields: [
createField('/basic_information/account_code', {
display_name: 'Account',
value: '',
value: options.basicAccountValue ?? '',
required: options.basicAccountRequired ?? false,
options_source: 'RESERVATION_V4_ACCOUNT_CATALOG',
control_type: 'SELECT',
}),