@revolugo/common 7.0.1 ā 7.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/cancellation-policies.test.ts +8 -2
- package/src/cancellation-policies.ts +57 -4
- package/src/constants/poller.ts +6 -0
- package/src/currencies/types.ts +1 -1
- package/src/currencies/utils.ts +52 -52
- package/src/schemas/booking-policy.ts +51 -0
- package/src/schemas/cancellation-policies.ts +18 -13
- package/src/schemas/currency.ts +1 -1
- package/src/schemas/global.ts +139 -0
- package/src/schemas/hotel-offer.ts +40 -28
- package/src/schemas/hotel-room-offer.ts +33 -14
- package/src/schemas/hotel-room.ts +1 -4
- package/src/schemas/hotel.ts +225 -258
- package/src/schemas/index.ts +2 -1
- package/src/schemas/list-polling-meta.ts +7 -2
- package/src/schemas/tag.ts +22 -8
- package/src/schemas/taxes.ts +4 -2
- package/src/types/calendar.ts +2 -2
- package/src/types/elements/amenity.ts +10 -10
- package/src/types/elements/booking-policy.ts +8 -8
- package/src/types/elements/booking.ts +16 -16
- package/src/types/elements/contact-person.ts +7 -0
- package/src/types/elements/elements-events.ts +2 -0
- package/src/types/elements/event-metadata.ts +6 -6
- package/src/types/elements/hotel-offer-list.ts +1 -1
- package/src/types/elements/hotel-offer-request.ts +21 -21
- package/src/types/elements/hotel-offer.ts +16 -16
- package/src/types/elements/hotel-offers-filters.ts +1 -1
- package/src/types/elements/hotel-room-offer-request.ts +22 -22
- package/src/types/elements/hotel-room-offer.ts +17 -17
- package/src/types/elements/hotel-room.ts +6 -6
- package/src/types/elements/hotel-rooming-list.ts +8 -8
- package/src/types/elements/hotel.ts +7 -7
- package/src/types/elements/meta-polling.ts +6 -6
- package/src/types/event.ts +1 -1
- package/src/types/hotel-contract.ts +1 -1
- package/src/types/hotel-room-stock.ts +1 -1
- package/src/types/pagination.ts +2 -2
- package/src/utils/create-composite-key.ts +2 -2
- package/src/utils/debounce.ts +1 -1
- package/src/utils/generate-dummy-hotel-images.ts +7 -5
- package/src/utils/get-sanitized-room-count.ts +1 -1
- package/src/utils/images.ts +5 -0
- package/src/utils/parse-children.ts +1 -1
- package/src/utils/poller.ts +56 -55
- package/src/schemas/hotel-offer-request.ts +0 -43
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revolugo/common",
|
|
3
|
-
"version": "7.0.1",
|
|
3
|
+
"version": "7.1.0-alpha.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Revolugo common",
|
|
6
6
|
"author": "Revolugo",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dayjs": "1.11.19",
|
|
35
35
|
"ky": "1.14.3",
|
|
36
36
|
"slugify": "1.6.6",
|
|
37
|
-
"type-fest": "5.4.
|
|
37
|
+
"type-fest": "5.4.4",
|
|
38
38
|
"uuid": "13.0.0",
|
|
39
39
|
"zod": "4.3.6"
|
|
40
40
|
},
|
|
@@ -238,7 +238,10 @@ describe('sanitizeCancellationPolicies', () => {
|
|
|
238
238
|
|
|
239
239
|
describe('when Booking Date < Release Date < Check In Date', () => {
|
|
240
240
|
const releaseDate = '2021-01-05'
|
|
241
|
-
const
|
|
241
|
+
const releaseDateCP = dayjs(releaseDate)
|
|
242
|
+
.add(1, 'day')
|
|
243
|
+
.format('YYYY-MM-DD')
|
|
244
|
+
const releaseDatetime = getFormattedUTCLocalTime(releaseDateCP, timezone)
|
|
242
245
|
const bookingDatetime = getFormattedUTCLocalTime(
|
|
243
246
|
'2021-01-01T10:00:00',
|
|
244
247
|
timezone,
|
|
@@ -404,7 +407,10 @@ describe('sanitizeCancellationPolicies', () => {
|
|
|
404
407
|
|
|
405
408
|
describe('when Booking Date < Release Date < DF_0', () => {
|
|
406
409
|
const releaseDate = '2020-12-30'
|
|
407
|
-
const
|
|
410
|
+
const releaseDateCP = dayjs(releaseDate)
|
|
411
|
+
.add(1, 'day')
|
|
412
|
+
.format('YYYY-MM-DD')
|
|
413
|
+
const releaseDatetime = getFormattedUTCLocalTime(releaseDateCP, timezone)
|
|
408
414
|
const bookingDatetime = getFormattedUTCLocalTime(
|
|
409
415
|
'2020-12-20T10:00:00',
|
|
410
416
|
timezone,
|
|
@@ -34,6 +34,31 @@ export interface SanitizeCancellationPolicies {
|
|
|
34
34
|
timezone?: string
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
function initReleaseDateUTC({
|
|
38
|
+
checkInDate,
|
|
39
|
+
releaseDate,
|
|
40
|
+
timezone,
|
|
41
|
+
}: {
|
|
42
|
+
checkInDate: string
|
|
43
|
+
releaseDate?: string
|
|
44
|
+
timezone: string
|
|
45
|
+
}): string | undefined {
|
|
46
|
+
if (!releaseDate) {
|
|
47
|
+
return undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (dayjs(releaseDate).isSameOrAfter(dayjs(checkInDate))) {
|
|
51
|
+
return dayjs.tz(releaseDate, timezone).startOf('day').utc().format()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return dayjs
|
|
55
|
+
.tz(releaseDate, timezone)
|
|
56
|
+
.add(1, 'day')
|
|
57
|
+
.startOf('day')
|
|
58
|
+
.utc()
|
|
59
|
+
.format()
|
|
60
|
+
}
|
|
61
|
+
|
|
37
62
|
// eslint-disable-next-line complexity, max-statements, max-lines-per-function
|
|
38
63
|
export function sanitizeCancellationPolicies({
|
|
39
64
|
bookingDatetime,
|
|
@@ -62,8 +87,11 @@ export function sanitizeCancellationPolicies({
|
|
|
62
87
|
|
|
63
88
|
const nextDayCheckInDateUTC = nextDay(checkInDatetimeUTC)
|
|
64
89
|
|
|
65
|
-
const releaseDatetimeUTC =
|
|
66
|
-
|
|
90
|
+
const releaseDatetimeUTC = initReleaseDateUTC({
|
|
91
|
+
checkInDate,
|
|
92
|
+
releaseDate,
|
|
93
|
+
timezone,
|
|
94
|
+
})
|
|
67
95
|
|
|
68
96
|
if (dayjs(bookingDatetimeUTC).isAfter(nextDayCheckInDateUTC)) {
|
|
69
97
|
return sanitizeCancellationPolicies({
|
|
@@ -452,10 +480,10 @@ export function getSanitizedCancellationPolicies({
|
|
|
452
480
|
initialDate,
|
|
453
481
|
timezone,
|
|
454
482
|
}: {
|
|
455
|
-
checkInDate: string
|
|
456
483
|
cancellationPolicies: ICancellationPolicy[]
|
|
457
|
-
|
|
484
|
+
checkInDate: string
|
|
458
485
|
initialDate?: string
|
|
486
|
+
timezone?: string
|
|
459
487
|
}): ICancellationPolicy[] {
|
|
460
488
|
if (!cancellationPolicies.length) {
|
|
461
489
|
return []
|
|
@@ -511,3 +539,28 @@ export function isFreeCancellable(cps: ICancellationPolicy[]): boolean {
|
|
|
511
539
|
dayjs().isBetween(dayjs(freeCp.dateFrom), dayjs(freeCp.dateTo)))
|
|
512
540
|
)
|
|
513
541
|
}
|
|
542
|
+
|
|
543
|
+
export function filterForCustomers(
|
|
544
|
+
cps: ICancellationPolicy[],
|
|
545
|
+
): ICancellationPolicy[] {
|
|
546
|
+
const now = dayjs()
|
|
547
|
+
const nowPlus2Hours = now.add(2, 'hours')
|
|
548
|
+
|
|
549
|
+
return cps.reduce<ICancellationPolicy[]>((result, cp) => {
|
|
550
|
+
if (
|
|
551
|
+
dayjs(cp.dateFrom).isSameOrBefore(nowPlus2Hours) &&
|
|
552
|
+
dayjs(cp.dateTo).isAfter(nowPlus2Hours)
|
|
553
|
+
) {
|
|
554
|
+
result.push({
|
|
555
|
+
...cp,
|
|
556
|
+
dateFrom: now.format(),
|
|
557
|
+
})
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (dayjs(cp.dateFrom).isAfter(nowPlus2Hours)) {
|
|
561
|
+
result.push(cp)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return result
|
|
565
|
+
}, [])
|
|
566
|
+
}
|
package/src/constants/poller.ts
CHANGED
package/src/currencies/types.ts
CHANGED
|
@@ -3,11 +3,11 @@ import type { CurrencyCode } from './constants.ts'
|
|
|
3
3
|
export interface ICurrency {
|
|
4
4
|
code: CurrencyCode
|
|
5
5
|
decimalDigits: number
|
|
6
|
+
deprecated?: boolean
|
|
6
7
|
name: string
|
|
7
8
|
namePlural: string
|
|
8
9
|
rounding: number
|
|
9
10
|
symbol: string
|
|
10
11
|
symbolNative: string
|
|
11
12
|
zeroDecimal: boolean
|
|
12
|
-
deprecated?: boolean
|
|
13
13
|
}
|
package/src/currencies/utils.ts
CHANGED
|
@@ -98,49 +98,50 @@ export class MoneyCalculator {
|
|
|
98
98
|
this.isNormalized = isNormalized
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
public
|
|
102
|
-
|
|
101
|
+
public ceil(): this {
|
|
102
|
+
this.amount = Math.ceil(this.amount)
|
|
103
|
+
|
|
104
|
+
return this
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public convert({
|
|
108
|
+
currency,
|
|
109
|
+
exchangeRate,
|
|
110
|
+
}: {
|
|
111
|
+
currency: CurrencyCode
|
|
112
|
+
exchangeRate: number
|
|
113
|
+
}): this {
|
|
114
|
+
if (this.currency === currency || this.amount === 0) {
|
|
103
115
|
return this
|
|
104
116
|
}
|
|
105
117
|
|
|
106
|
-
|
|
107
|
-
amount: this.amount,
|
|
108
|
-
currency: this.currency,
|
|
109
|
-
})
|
|
118
|
+
const startingIsNormalized = this.isNormalized
|
|
110
119
|
|
|
111
|
-
|
|
120
|
+
if (startingIsNormalized) {
|
|
121
|
+
this.denormalize()
|
|
122
|
+
}
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
this.amount *= exchangeRate
|
|
125
|
+
this.currency = currency
|
|
115
126
|
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
if (startingIsNormalized) {
|
|
128
|
+
this.normalize()
|
|
129
|
+
}
|
|
118
130
|
|
|
119
131
|
return this
|
|
120
132
|
}
|
|
121
133
|
|
|
122
|
-
public
|
|
123
|
-
if (this.isNormalized) {
|
|
134
|
+
public denormalize(): this {
|
|
135
|
+
if (!this.isNormalized) {
|
|
124
136
|
return this
|
|
125
137
|
}
|
|
126
138
|
|
|
127
|
-
this.amount =
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
currency: this.currency,
|
|
132
|
-
// Making sure Javascript doesnt give us back a float number
|
|
133
|
-
// 1172.64 * 100 = 117264.00000000001 š©
|
|
134
|
-
}).toFixed(0),
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
this.isNormalized = true
|
|
138
|
-
|
|
139
|
-
return this
|
|
140
|
-
}
|
|
139
|
+
this.amount = denormalizeAmount({
|
|
140
|
+
amount: this.amount,
|
|
141
|
+
currency: this.currency,
|
|
142
|
+
})
|
|
141
143
|
|
|
142
|
-
|
|
143
|
-
this.amount = Math.ceil(this.amount)
|
|
144
|
+
this.isNormalized = false
|
|
144
145
|
|
|
145
146
|
return this
|
|
146
147
|
}
|
|
@@ -151,12 +152,6 @@ export class MoneyCalculator {
|
|
|
151
152
|
return this
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
public round(): this {
|
|
155
|
-
this.amount = Math.round(this.amount)
|
|
156
|
-
|
|
157
|
-
return this
|
|
158
|
-
}
|
|
159
|
-
|
|
160
155
|
public format(locale?: string, space?: string): string {
|
|
161
156
|
return formatAmount({
|
|
162
157
|
amount: this.amount,
|
|
@@ -170,29 +165,34 @@ export class MoneyCalculator {
|
|
|
170
165
|
return this.amount
|
|
171
166
|
}
|
|
172
167
|
|
|
173
|
-
public
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (this.
|
|
168
|
+
public markup(percentage: number): this {
|
|
169
|
+
this.amount /= 1 - percentage
|
|
170
|
+
|
|
171
|
+
return this
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public normalize(): this {
|
|
175
|
+
if (this.isNormalized) {
|
|
181
176
|
return this
|
|
182
177
|
}
|
|
183
178
|
|
|
184
|
-
|
|
179
|
+
this.amount = Number(
|
|
180
|
+
normalizeAmount({
|
|
181
|
+
// Making sure we only have 2 decimals after comma
|
|
182
|
+
amount: Number(this.amount.toFixed(2)),
|
|
183
|
+
currency: this.currency,
|
|
184
|
+
// Making sure Javascript doesnt give us back a float number
|
|
185
|
+
// 1172.64 * 100 = 117264.00000000001 š©
|
|
186
|
+
}).toFixed(0),
|
|
187
|
+
)
|
|
185
188
|
|
|
186
|
-
|
|
187
|
-
this.denormalize()
|
|
188
|
-
}
|
|
189
|
+
this.isNormalized = true
|
|
189
190
|
|
|
190
|
-
this
|
|
191
|
-
|
|
191
|
+
return this
|
|
192
|
+
}
|
|
192
193
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
194
|
+
public round(): this {
|
|
195
|
+
this.amount = Math.round(this.amount)
|
|
196
196
|
|
|
197
197
|
return this
|
|
198
198
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
import { CANCELLATION_POLICY_SCHEMA } from './cancellation-policies.ts'
|
|
6
|
+
import { CURRENCY_SCHEMA } from './currency.ts'
|
|
7
|
+
import {
|
|
8
|
+
ADULT_COUNT_SCHEMA,
|
|
9
|
+
CHECK_IN_DATE_SCHEMA,
|
|
10
|
+
CHECK_OUT_DATE_SCHEMA,
|
|
11
|
+
CHILDREN_SCHEMA,
|
|
12
|
+
IS_PRICE_INCREASED,
|
|
13
|
+
} from './global.ts'
|
|
14
|
+
import { HOTEL_ROOM_OFFER_SCHEMA } from './hotel-room-offer.ts'
|
|
15
|
+
|
|
16
|
+
export const BOOKING_POLICY_SCHEMA = z
|
|
17
|
+
.object({
|
|
18
|
+
adult_count: ADULT_COUNT_SCHEMA,
|
|
19
|
+
cancellation_policies: z.array(CANCELLATION_POLICY_SCHEMA).openapi({
|
|
20
|
+
description:
|
|
21
|
+
'The list of cancellation policy date range with their corresponding penalty percentage.',
|
|
22
|
+
}),
|
|
23
|
+
check_in_date: CHECK_IN_DATE_SCHEMA,
|
|
24
|
+
check_out_date: CHECK_OUT_DATE_SCHEMA,
|
|
25
|
+
children: CHILDREN_SCHEMA.optional().nullish(),
|
|
26
|
+
currency: CURRENCY_SCHEMA,
|
|
27
|
+
expires_at: z.coerce.date().openapi({
|
|
28
|
+
description:
|
|
29
|
+
'Expiration date for this **Booking Policy**.\n\nThe returned **Booking Policy** (price and cancellation policies) is valid bookable policy up to this **expires_at** date, while it may be valid for a longer period in the case of some suppliers, this API call is equivalent to an availability check and it is important not to let long periods between retrieval of this policy and the booking confirmation call itself as this will often reduce the likelihood of a **Hotel Room Offer** being successfully booked.',
|
|
30
|
+
}),
|
|
31
|
+
has_rooming_lists: z.boolean().openapi({
|
|
32
|
+
description:
|
|
33
|
+
'Indicates whether the **Booking Policy** supports rooming lists, allowing individual guest details to be provided per room.',
|
|
34
|
+
}),
|
|
35
|
+
hotel_id: z.string().openapi({
|
|
36
|
+
description: 'Hotel id',
|
|
37
|
+
}),
|
|
38
|
+
hotel_room_offer: HOTEL_ROOM_OFFER_SCHEMA.openapi({
|
|
39
|
+
description:
|
|
40
|
+
'The **Hotel Room Offer** associated with this **Booking Policy**.',
|
|
41
|
+
}),
|
|
42
|
+
id: z.string().openapi({
|
|
43
|
+
description: '**Booking Policy** id',
|
|
44
|
+
}),
|
|
45
|
+
is_price_increased: IS_PRICE_INCREASED,
|
|
46
|
+
})
|
|
47
|
+
.openapi('bookingPoliciesApi', {
|
|
48
|
+
description:
|
|
49
|
+
'A **Booking Policy** represents a validated and bookable snapshot of a **Hotel Room Offer**, including its price, cancellation policies, and expiration date.',
|
|
50
|
+
})
|
|
51
|
+
/* eslint-enable camelcase */
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
/* eslint-disable camelcase */
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
|
|
4
|
-
export const CANCELLATION_POLICY_SCHEMA = z
|
|
5
|
-
|
|
4
|
+
export const CANCELLATION_POLICY_SCHEMA = z
|
|
5
|
+
.object({
|
|
6
|
+
date_from: z.string().openapi({
|
|
7
|
+
description:
|
|
8
|
+
'The start date and time of the cancellation policy, given in the hotel timezone.',
|
|
9
|
+
}),
|
|
10
|
+
date_to: z.string().openapi({
|
|
11
|
+
description:
|
|
12
|
+
'The end date and time of the cancellation policy, given in the hotel timezone.',
|
|
13
|
+
}),
|
|
14
|
+
penalty_percentage: z.number().min(0).max(100).openapi({
|
|
15
|
+
description:
|
|
16
|
+
'The penalty percentage that is due in case of cancellation during the **date_from** to **date_to** period range.',
|
|
17
|
+
}),
|
|
18
|
+
})
|
|
19
|
+
.openapi('CancellationPolicyApi', {
|
|
6
20
|
description:
|
|
7
|
-
'
|
|
8
|
-
})
|
|
9
|
-
date_to: z.string().openapi({
|
|
10
|
-
description:
|
|
11
|
-
'The end date and time of the cancellation policy, given in the hotel timezone.',
|
|
12
|
-
}),
|
|
13
|
-
penalty_percentage: z.number().min(0).max(100).openapi({
|
|
14
|
-
description:
|
|
15
|
-
'The penalty percentage that is due in case of cancellation during the **date_from** to **date_to** period range.',
|
|
16
|
-
}),
|
|
17
|
-
})
|
|
21
|
+
'Defines the cancellation penalty that applies within a specific date and time range, expressed as a percentage of the booking cost.',
|
|
22
|
+
})
|
|
18
23
|
/* eslint-enable camelcase */
|
package/src/schemas/currency.ts
CHANGED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
BreakfastOption,
|
|
6
|
+
CountryIso2Code,
|
|
7
|
+
Locale,
|
|
8
|
+
Status,
|
|
9
|
+
} from '../constants/index.ts'
|
|
10
|
+
|
|
11
|
+
export const validStringDate = (): z.ZodString =>
|
|
12
|
+
z
|
|
13
|
+
.string()
|
|
14
|
+
.regex(/^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$/u)
|
|
15
|
+
|
|
16
|
+
export const ADD_BREAKFAST_SCHEMA = z
|
|
17
|
+
.boolean()
|
|
18
|
+
.nullish()
|
|
19
|
+
.openapi('addBreakfast', {
|
|
20
|
+
description: `This parameter allows to add breakfast to the booking as long as every requested Hotel Room Offers **breakfast_option = ${BreakfastOption.Optional}** .\n\nThe final breakfast count that will be included in the Hotel Room Offer will be returned in the response and is calculated as follows: \n\n - If the returned Hotel Room Offer **total room count** > **hotel_room_offer_request.adult_count** then **breakfast_count** will be equal to the **total room count** of the returned Hotel Room Offer, \n\n - Otherwise **breakfast_count** will be equal to the minimum value between related **hotel_room_offer_request.adult_count** and returned Hotel Room Offer **total occupancy**. \n\n <div style="background-color: #ffffef; padding: 20px; border: 1px solid lightgrey; border-radius: 5px;"><b style="color: red; margin-top: 10px;">š DEPRECATED.</b>\n\n <b style="color: orange;">If you already use this field, don't worry as we still support it with the following behaviour:</b>\n- <span style="color: orange;">When **add_breakfast = true** then **breakfast_count = MIN(guest count, total offer occupancy)** where **guest count** is the total number of adult and children over 3.</span>\n- <span style="color: orange;">Otherwise **breakfast_count = 0**.</span></div>`,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export const ADULT_COUNT_SCHEMA = z
|
|
24
|
+
.number()
|
|
25
|
+
.int()
|
|
26
|
+
.min(1)
|
|
27
|
+
.max(200)
|
|
28
|
+
.openapi('adultCount', {
|
|
29
|
+
description:
|
|
30
|
+
'The total number of adults who will be staying in the property.',
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export const BREAKFAST_COUNT = z
|
|
34
|
+
.number()
|
|
35
|
+
.optional()
|
|
36
|
+
.openapi('breakfastCount', {
|
|
37
|
+
description: `This parameter describes the quantity of breakfast / night that should be included in the **Booking**. When **breakfast_option = ${BreakfastOption.Optional}**, valid **breakfast_count** lower bound is **room count** and upper bound is **guest count**, where **guest count** is the number of adult and children over 3.\n\nā ļø The actual breakfast count that will be included in the **Booking** is the one that is returned in the response of this endpoint and might be different from this **breakfast_count** paramater in some cases. Please, make sure to check the actual breakfast count included in the **Hotel Room Offer** returned in the response of this endpoint.`,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
export const CHECK_IN_DATE_SCHEMA = validStringDate().openapi('checkInDate', {
|
|
41
|
+
description: 'Date of check-in formatted as YYYY-MM-DD.',
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
export const CHECK_OUT_DATE_SCHEMA = validStringDate().openapi('checkOutDate', {
|
|
45
|
+
description: 'Date of check-out formatted as YYYY-MM-DD.',
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
export const CHILDREN_SCHEMA = z
|
|
49
|
+
.string()
|
|
50
|
+
.regex(/^(([0-9]{1})|(1[0-7]){1})(,(([0-9]{1})|(1[0-7]){1}))*$|^$/u)
|
|
51
|
+
.openapi('children', {
|
|
52
|
+
description:
|
|
53
|
+
'A comma-separated list of child ages (0 up to 17). e.g.: "3,7" represents 2 children respectively 3 and 7 years old.',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
export const IMAGES_SCHEMA = z
|
|
57
|
+
.object({
|
|
58
|
+
count: z.number().openapi({ description: 'Number of images.' }).nullish(),
|
|
59
|
+
highres: z
|
|
60
|
+
.boolean()
|
|
61
|
+
.openapi({ description: 'Whether images exist in highres format.' })
|
|
62
|
+
.nullish(),
|
|
63
|
+
|
|
64
|
+
lowres: z
|
|
65
|
+
.boolean()
|
|
66
|
+
.openapi({ description: 'Whether images exist in lowres format.' })
|
|
67
|
+
.nullish(),
|
|
68
|
+
prefix: z
|
|
69
|
+
.string()
|
|
70
|
+
.openapi({ description: 'Base URL for the images.' })
|
|
71
|
+
.nullish(),
|
|
72
|
+
suffix: z
|
|
73
|
+
.string()
|
|
74
|
+
.openapi({
|
|
75
|
+
description:
|
|
76
|
+
'This parameter usually represents the extension of the image (e.g.: .jpg, .png)',
|
|
77
|
+
})
|
|
78
|
+
.nullish(),
|
|
79
|
+
thumb: z
|
|
80
|
+
.boolean()
|
|
81
|
+
.openapi({
|
|
82
|
+
description:
|
|
83
|
+
'Whether images exist in thumb format (for thumbnails preview).',
|
|
84
|
+
})
|
|
85
|
+
.nullish(),
|
|
86
|
+
})
|
|
87
|
+
.openapi({
|
|
88
|
+
description:
|
|
89
|
+
'š DEPRECATED - Hotel images details.\n\nIn order to retrieve a specific image you need to construct the complete URL from the images parameters: **[images.prefix][highres|lowres|thumb]/[index]/[images.suffix]**. If **images.count = n**, then index is in [0...n-1] range.\n\ne.g.: https://s3.eu-west-3.amazonaws.com/revolugo/hotels/yhKY/images/highres/0.jpg',
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
export const IS_PRICE_INCREASED = z.boolean().openapi({
|
|
93
|
+
description:
|
|
94
|
+
'Indicates whether the price of the **Hotel Room Offer** (without breakfast included) has increased compared to the price returned by [Retrieve Hotel Room Offers endpoint](/v1/documentation#operation/getV1Hotel_room_offers).\n\nIn some case, the returned price may increase for various reasons including: Currency rate change between the POST **Booking Policies** call and the GET **Hotel Room Offers** call, **Hotel Room Offer** price has increased since the GET **Hotel Room Offers** call.\n\nIf **is_price_increased** is **true**, it means that the actual/updated price of the **Hotel Room Offer** is greater than the price previously returned by [Retrieve Hotel Room Offers endpoint](/v1/documentation#operation/getV1Hotel_room_offers). If **is_price_increased** is **false**, the price of the **Hotel Room Offer** is equal to the price returned by [Retrieve Hotel Room Offers endpoint](/v1/documentation#operation/getV1Hotel_room_offers).\n\nā ļø It is strongly advised to clearly inform your customer of any price increase that may occur.',
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
export const LANG_SCHEMA = z
|
|
98
|
+
.enum(Locale)
|
|
99
|
+
.openapi('Locale', {
|
|
100
|
+
description:
|
|
101
|
+
'Set the language for the returned content using a valid language code.',
|
|
102
|
+
enum: Object.values(Locale),
|
|
103
|
+
})
|
|
104
|
+
.default(Locale.en_US)
|
|
105
|
+
|
|
106
|
+
export const META = z
|
|
107
|
+
.object({
|
|
108
|
+
status: z
|
|
109
|
+
.enum(Status)
|
|
110
|
+
.openapi('Status', { description: 'Status of the response.' }),
|
|
111
|
+
})
|
|
112
|
+
.openapi('Meta', { description: 'Meta data of the response' })
|
|
113
|
+
|
|
114
|
+
export const ROOM_COUNT_SCHEMA = z
|
|
115
|
+
.number()
|
|
116
|
+
.min(1)
|
|
117
|
+
.max(200)
|
|
118
|
+
.openapi('RoomCount', {
|
|
119
|
+
description:
|
|
120
|
+
'The total number of rooms requested for the stay. Results may display offers matching a different room count than the requested one, however those results will always provide enough occupancy for the total guest count needed.\n\nConstraint: The **room_count** cannot be greater than the requested guest count (adult and children guests) and the minimum **room_count** cannot be less than the total guest count (adult and children guests) divided by 4, meaning that the maximum number of guest in a single room cannot be greeater than 4.',
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
export const COUNTRY_ISO2_CODE_SCHEMA = z
|
|
124
|
+
.enum(CountryIso2Code)
|
|
125
|
+
.refine(check => Object.values(CountryIso2Code).includes(check), {
|
|
126
|
+
message: 'Invalid ISO Alpha-2 country code.',
|
|
127
|
+
})
|
|
128
|
+
.openapi('CountryIso2Code', {
|
|
129
|
+
description: 'ISO Alpha-2 country code.',
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
export const SOURCE_MARKET_SCHEMA = COUNTRY_ISO2_CODE_SCHEMA.openapi(
|
|
133
|
+
'SourceMarket',
|
|
134
|
+
{
|
|
135
|
+
description:
|
|
136
|
+
'For sourcing availability within certain markets, a source market option may be used to get more accurate prices. You may use any valid ISO Alpha-2 country code, e.g. JP.',
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
/* eslint-enable camelcase */
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
CHECK_IN_DATE_SCHEMA,
|
|
8
8
|
CHECK_OUT_DATE_SCHEMA,
|
|
9
9
|
CHILDREN_SCHEMA,
|
|
10
|
-
} from './
|
|
10
|
+
} from './global.ts'
|
|
11
11
|
import { HOTEL_ROOM_OFFER_SCHEMA } from './hotel-room-offer.ts'
|
|
12
12
|
import { HOTEL_IMAGES, HOTEL_SCHEMA, VENUES_SCHEMA } from './hotel.ts'
|
|
13
13
|
import { LIST_POLLING_META_SCHEMA } from './list-polling-meta.ts'
|
|
@@ -23,34 +23,46 @@ List of hotel images in various sizes featuring an indicator for the primary (he
|
|
|
23
23
|
hotel_room_offers: z.array(HOTEL_ROOM_OFFER_SCHEMA),
|
|
24
24
|
tags: TAGS_SCHEMA,
|
|
25
25
|
venues: VENUES_SCHEMA,
|
|
26
|
-
}).openapi('hotelOfferApi'
|
|
26
|
+
}).openapi('hotelOfferApi', {
|
|
27
|
+
description:
|
|
28
|
+
'Hotel Offer combining hotel details with available Hotel Room Offers.',
|
|
29
|
+
})
|
|
27
30
|
|
|
28
|
-
export const HOTEL_OFFERS_SCHEMA = z.array(HOTEL_OFFER_SCHEMA)
|
|
31
|
+
export const HOTEL_OFFERS_SCHEMA = z.array(HOTEL_OFFER_SCHEMA).openapi({
|
|
32
|
+
description: 'List of Hotel Offers.',
|
|
33
|
+
})
|
|
29
34
|
|
|
30
|
-
export const HOTEL_OFFERS_RESPONSE_SCHEMA = z
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
export const HOTEL_OFFERS_RESPONSE_SCHEMA = z
|
|
36
|
+
.object({
|
|
37
|
+
data: z.object({
|
|
38
|
+
adult_count: ADULT_COUNT_SCHEMA,
|
|
39
|
+
check_in_date: CHECK_IN_DATE_SCHEMA,
|
|
40
|
+
check_out_date: CHECK_OUT_DATE_SCHEMA,
|
|
41
|
+
children: CHILDREN_SCHEMA.optional().nullish(),
|
|
42
|
+
currency: CURRENCY_SCHEMA,
|
|
43
|
+
hotel_offers: HOTEL_OFFERS_SCHEMA.openapi({
|
|
44
|
+
description: 'List of Hotel Offers',
|
|
45
|
+
}),
|
|
46
|
+
price_histogram: z
|
|
47
|
+
.array(z.number())
|
|
48
|
+
.openapi({
|
|
49
|
+
description:
|
|
50
|
+
'**Hotel Offers** price histogram dataset based on the price of the cheapest **Hotel Room Offer** included on each **Hotel Offer** returned. It represents the number of available **Hotel Offers** grouped by price sorted ascendingly. Each item of the list represents a price step based on returned **price_min**, **price_max** and requested **price_histogram_step_count**',
|
|
51
|
+
})
|
|
52
|
+
.nullish(),
|
|
53
|
+
price_max: z.number().nullish().openapi({
|
|
54
|
+
description: 'Maximum price of available returned **Hotel Offers**',
|
|
55
|
+
}),
|
|
56
|
+
price_min: z.number().nullish().openapi({
|
|
57
|
+
description: 'Minimum price of available returned **Hotel Offers**',
|
|
58
|
+
}),
|
|
49
59
|
}),
|
|
50
|
-
|
|
51
|
-
description:
|
|
60
|
+
event: z.any().optional().openapi({
|
|
61
|
+
description:
|
|
62
|
+
'Event associated with the Hotel Offers response, when applicable.',
|
|
52
63
|
}),
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
meta: LIST_POLLING_META_SCHEMA,
|
|
65
|
+
})
|
|
66
|
+
.openapi({
|
|
67
|
+
description: 'Response envelope for the Hotel Offers polling endpoint.',
|
|
68
|
+
})
|