实现V4 Rooming List轻量事项卡
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<section
|
||||
class="rooming-list-card"
|
||||
data-testid="rooming-list-card"
|
||||
>
|
||||
<div class="rooming-list-card__body">
|
||||
<div>
|
||||
<span>{{ t('taskV4.roomingList.targetOrder') }}</span>
|
||||
<strong>{{ orderLabel }}</strong>
|
||||
</div>
|
||||
<RouterLink
|
||||
v-if="boundOrderId"
|
||||
class="rooming-list-card__link"
|
||||
:to="`/reservation/orders/${boundOrderId}`"
|
||||
>
|
||||
{{ t('task.viewOrder') }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<p>{{ t('taskV4.roomingList.description') }}</p>
|
||||
<small>{{ t('taskV4.roomingList.confirmHint') }}</small>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
orderReference?: string | null
|
||||
targetLocator?: string | null
|
||||
boundOrderId?: string | null
|
||||
boundOrderDisplayName?: string | null
|
||||
}>(), {
|
||||
orderReference: null,
|
||||
targetLocator: null,
|
||||
boundOrderId: null,
|
||||
boundOrderDisplayName: null,
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const orderLabel = computed(() =>
|
||||
readableValue(props.boundOrderDisplayName) ||
|
||||
readableValue(props.orderReference) ||
|
||||
readableValue(props.targetLocator) ||
|
||||
t('taskV4.roomingList.unboundOrder'),
|
||||
)
|
||||
|
||||
function readableValue(value?: string | null): string {
|
||||
const trimmedValue = value?.trim() ?? ''
|
||||
return trimmedValue === '-' ? '' : trimmedValue
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.rooming-list-card {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin: 0 20px 18px;
|
||||
border: 1px solid var(--th-color-slate-200);
|
||||
border-radius: var(--th-radius-sm);
|
||||
background: var(--th-color-slate-50);
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.rooming-list-card__body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.rooming-list-card__body div {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.rooming-list-card__body span {
|
||||
color: var(--th-color-slate-500);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.rooming-list-card__body strong {
|
||||
color: var(--th-color-slate-900);
|
||||
font-size: 14px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.rooming-list-card p,
|
||||
.rooming-list-card small {
|
||||
margin: 0;
|
||||
color: var(--th-color-slate-600);
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.rooming-list-card small {
|
||||
color: var(--th-color-slate-500);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rooming-list-card__link {
|
||||
color: var(--th-color-blue-600);
|
||||
flex: 0 0 auto;
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.rooming-list-card__link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.rooming-list-card__body {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -46,8 +46,15 @@
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
/>
|
||||
<template v-else>
|
||||
<ReservationV4RoomingListCard
|
||||
v-if="isRoomingListCard"
|
||||
:order-reference="orderReference"
|
||||
:target-locator="targetLocator"
|
||||
:bound-order-id="boundOrderId"
|
||||
:bound-order-display-name="boundOrderDisplayName"
|
||||
/>
|
||||
<ReservationV4PaymentAttachmentPreview
|
||||
v-if="isPaymentCard"
|
||||
v-else-if="isPaymentCard"
|
||||
:card="card"
|
||||
:source-message-id="sourceMessageId"
|
||||
/>
|
||||
@@ -65,7 +72,7 @@
|
||||
</template>
|
||||
|
||||
<details
|
||||
v-if="!isRoomInformationCard && safePayloadRows.length"
|
||||
v-if="!isRoomInformationCard && !isRoomingListCard && safePayloadRows.length"
|
||||
class="safe-payload"
|
||||
>
|
||||
<summary>
|
||||
@@ -133,7 +140,7 @@
|
||||
{{ submitting ? t('taskV4.confirmingCard') : t('taskV4.confirmCard') }}
|
||||
</button>
|
||||
<RouterLink
|
||||
v-if="boundOrderId"
|
||||
v-if="boundOrderId && !isRoomingListCard"
|
||||
class="card-order-link"
|
||||
:to="`/reservation/orders/${boundOrderId}`"
|
||||
>
|
||||
@@ -155,7 +162,7 @@
|
||||
{{ submitting ? t('taskV4.confirmingCard') : t('taskV4.confirmCard') }}
|
||||
</button>
|
||||
<RouterLink
|
||||
v-if="boundOrderId"
|
||||
v-if="boundOrderId && !isRoomingListCard"
|
||||
class="card-order-link"
|
||||
:to="`/reservation/orders/${boundOrderId}`"
|
||||
>
|
||||
@@ -173,6 +180,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import ReservationStatusBadge from '@/components/reservation/ReservationStatusBadge.vue'
|
||||
import ReservationV4PaymentAttachmentPreview from '@/components/reservation/ReservationV4PaymentAttachmentPreview.vue'
|
||||
import ReservationV4RoomInformationCard from '@/components/reservation/ReservationV4RoomInformationCard.vue'
|
||||
import ReservationV4RoomingListCard from '@/components/reservation/ReservationV4RoomingListCard.vue'
|
||||
import ReservationV4TaskCardFieldRenderer from '@/components/reservation/ReservationV4TaskCardFieldRenderer.vue'
|
||||
import type { ReservationRecord, ReservationV4TaskCardResult } from '@/types/reservation'
|
||||
import { formatReservationReadonlyReason } from '@/utils/reservationDisplay'
|
||||
@@ -196,6 +204,8 @@ const props = withDefaults(defineProps<{
|
||||
hotelId?: string
|
||||
orderTaskId?: string | null
|
||||
sourceMessageId?: string | null
|
||||
orderReference?: string | null
|
||||
targetLocator?: string | null
|
||||
actionErrors?: string[]
|
||||
successMessage?: string
|
||||
reviewForm?: ReviewForm
|
||||
@@ -203,11 +213,14 @@ const props = withDefaults(defineProps<{
|
||||
canConfirm: boolean
|
||||
canReview: boolean
|
||||
boundOrderId?: string | null
|
||||
boundOrderDisplayName?: string | null
|
||||
}>(), {
|
||||
validationErrors: () => ({}),
|
||||
hotelId: undefined,
|
||||
orderTaskId: null,
|
||||
sourceMessageId: null,
|
||||
orderReference: null,
|
||||
targetLocator: null,
|
||||
actionErrors: () => [],
|
||||
successMessage: '',
|
||||
reviewForm: () => ({
|
||||
@@ -215,6 +228,7 @@ const props = withDefaults(defineProps<{
|
||||
reason: '',
|
||||
}),
|
||||
boundOrderId: null,
|
||||
boundOrderDisplayName: null,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -227,6 +241,7 @@ const emit = defineEmits<{
|
||||
const { t } = useI18n()
|
||||
const isRoomInformationCard = computed(() => props.card.card_type === 'ROOM_INFORMATION')
|
||||
const isPaymentCard = computed(() => props.card.card_type === 'PAYMENT')
|
||||
const isRoomingListCard = computed(() => props.card.card_type === 'ROOMING_LIST')
|
||||
const visibleFields = computed(() =>
|
||||
isPaymentCard.value
|
||||
? props.card.fields.filter((field) => !isPaymentAttachmentIdField(field))
|
||||
|
||||
@@ -623,6 +623,13 @@ export default {
|
||||
unavailableReason: 'Unavailable reason: {reason}',
|
||||
fileMeta: '{type} · {size}',
|
||||
},
|
||||
roomingList: {
|
||||
title: 'Rooming List action',
|
||||
targetOrder: 'Target order',
|
||||
unboundOrder: 'No visible order is bound yet',
|
||||
description: 'The current source message contains a Rooming List item that needs manual handling.',
|
||||
confirmHint: 'This first version only confirms that the item has been handled manually. Guest details and attachment content are not displayed or processed here.',
|
||||
},
|
||||
lookup: {
|
||||
loading: 'Loading catalog',
|
||||
empty: 'No options in the current catalog. A no-match search does not mean the catalog is uninitialized.',
|
||||
|
||||
@@ -623,6 +623,13 @@ export default {
|
||||
unavailableReason: 'เหตุผลที่ใช้ไม่ได้: {reason}',
|
||||
fileMeta: '{type} · {size}',
|
||||
},
|
||||
roomingList: {
|
||||
title: 'งาน Rooming List',
|
||||
targetOrder: 'ออเดอร์เป้าหมาย',
|
||||
unboundOrder: 'ยังไม่มีออเดอร์ที่มองเห็นได้ผูกอยู่',
|
||||
description: 'ข้อความต้นทางปัจจุบันมีรายการ Rooming List ที่ต้องให้เจ้าหน้าที่จัดการ',
|
||||
confirmHint: 'เวอร์ชันแรกนี้ใช้ยืนยันว่ารายการได้รับการจัดการด้วยคนแล้วเท่านั้น ไม่แสดงหรือประมวลผลรายชื่อแขกและเนื้อหาไฟล์แนบในหน้านี้',
|
||||
},
|
||||
lookup: {
|
||||
loading: 'กำลังโหลดแค็ตตาล็อก',
|
||||
empty: 'ไม่มีตัวเลือกในแค็ตตาล็อกปัจจุบัน หากค้นหาไม่พบไม่ได้หมายความว่าแค็ตตาล็อกยังไม่เริ่มต้น',
|
||||
|
||||
@@ -623,6 +623,13 @@ export default {
|
||||
unavailableReason: '不可用原因:{reason}',
|
||||
fileMeta: '{type} · {size}',
|
||||
},
|
||||
roomingList: {
|
||||
title: 'Rooming List / 房表事项',
|
||||
targetOrder: '目标订单',
|
||||
unboundOrder: '暂未绑定可见订单',
|
||||
description: '当前来源消息包含需要人工处理的 Rooming List 事项,请在酒店内部流程处理后确认该卡片。',
|
||||
confirmHint: '第一版仅确认该事项已由人工处理,不展示或处理名单明细和附件内容。',
|
||||
},
|
||||
lookup: {
|
||||
loading: '目录加载中',
|
||||
empty: '当前目录没有可选项;如果是搜索无结果,不代表目录未初始化。',
|
||||
|
||||
@@ -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 [
|
||||
{
|
||||
|
||||
@@ -89,6 +89,8 @@
|
||||
:hotel-id="detail.order_task.hotel_id"
|
||||
:order-task-id="detail.order_task.order_task_id"
|
||||
:source-message-id="detail.order_task.source_message_id"
|
||||
:order-reference="displayOrderReference"
|
||||
:target-locator="targetLocator"
|
||||
:action-errors="cardActionErrors[detail.basic_information_card.card_id] ?? []"
|
||||
:success-message="cardSuccessMessages[detail.basic_information_card.card_id] ?? ''"
|
||||
:review-form="reviewForms[detail.basic_information_card.card_id]"
|
||||
@@ -96,6 +98,7 @@
|
||||
:can-confirm="canConfirmCard(detail.basic_information_card)"
|
||||
:can-review="canReviewCard(detail.basic_information_card)"
|
||||
:bound-order-id="detail.bound_order?.order_id"
|
||||
:bound-order-display-name="detail.bound_order?.display_name"
|
||||
@update:model-value="setCardValues(detail.basic_information_card, $event)"
|
||||
@update:review-form="setReviewForm(detail.basic_information_card.card_id, $event)"
|
||||
@confirm="submitConfirm(detail.basic_information_card)"
|
||||
@@ -132,6 +135,8 @@
|
||||
:hotel-id="detail.order_task.hotel_id"
|
||||
:order-task-id="detail.order_task.order_task_id"
|
||||
:source-message-id="detail.order_task.source_message_id"
|
||||
:order-reference="displayOrderReference"
|
||||
:target-locator="targetLocator"
|
||||
:action-errors="cardActionErrors[businessCard.card_id] ?? []"
|
||||
:success-message="cardSuccessMessages[businessCard.card_id] ?? ''"
|
||||
:review-form="reviewForms[businessCard.card_id]"
|
||||
@@ -139,6 +144,7 @@
|
||||
:can-confirm="canConfirmCard(businessCard)"
|
||||
:can-review="canReviewCard(businessCard)"
|
||||
:bound-order-id="detail.bound_order?.order_id"
|
||||
:bound-order-display-name="detail.bound_order?.display_name"
|
||||
@update:model-value="setCardValues(businessCard, $event)"
|
||||
@update:review-form="setReviewForm(businessCard.card_id, $event)"
|
||||
@confirm="submitConfirm(businessCard)"
|
||||
@@ -459,7 +465,7 @@ function editableFieldKeys(card: ReservationV4TaskCardResult): string[] {
|
||||
}
|
||||
|
||||
function submissionFieldsForCard(card: ReservationV4TaskCardResult): ReservationV4TaskCardResult['fields'] {
|
||||
if (isPaymentCard(card)) {
|
||||
if (isVersionOnlyConfirmCard(card)) {
|
||||
return []
|
||||
}
|
||||
return card.card_type === 'ROOM_INFORMATION'
|
||||
@@ -473,7 +479,7 @@ function buildConfirmRequest(
|
||||
card: ReservationV4TaskCardResult,
|
||||
submissionFields: ReservationV4TaskCardResult['fields'],
|
||||
): ReservationV4CardConfirmRequest {
|
||||
if (isPaymentCard(card)) {
|
||||
if (isVersionOnlyConfirmCard(card)) {
|
||||
return {
|
||||
version: card.version,
|
||||
}
|
||||
@@ -488,6 +494,14 @@ function isPaymentCard(card: ReservationV4TaskCardResult): boolean {
|
||||
return card.card_type === 'PAYMENT'
|
||||
}
|
||||
|
||||
function isRoomingListCard(card: ReservationV4TaskCardResult): boolean {
|
||||
return card.card_type === 'ROOMING_LIST'
|
||||
}
|
||||
|
||||
function isVersionOnlyConfirmCard(card: ReservationV4TaskCardResult): boolean {
|
||||
return isPaymentCard(card) || isRoomingListCard(card)
|
||||
}
|
||||
|
||||
function isGroupRoomInformationBreakfastField(
|
||||
card: ReservationV4TaskCardResult,
|
||||
field: ReservationV4TaskCardResult['fields'][number],
|
||||
@@ -521,6 +535,9 @@ function applyCardActionError(card: ReservationV4TaskCardResult, error: unknown,
|
||||
}
|
||||
|
||||
function cardTitle(card: ReservationV4TaskCardResult): string {
|
||||
if (isRoomingListCard(card)) {
|
||||
return t('taskV4.roomingList.title')
|
||||
}
|
||||
return formatReservationTaskCard(t, card.card_type)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user