@revolugo/common 7.1.1 → 7.2.0-alpha.0
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 +8 -8
- package/src/cancellation-policies.ts +1 -1
- package/src/constants/hotel-room-offer.ts +0 -5
- package/src/constants/poller.ts +8 -0
- package/src/countries/index.ts +1 -0
- package/src/currencies/utils.ts +8 -7
- package/src/models/paginated-queries.ts +2 -2
- package/src/schemas/booking-policy.ts +51 -0
- package/src/schemas/breakfast.ts +33 -0
- package/src/schemas/cancellation-policies.ts +18 -13
- package/src/schemas/currency.ts +3 -1
- package/src/schemas/global.ts +120 -0
- package/src/schemas/hotel-offer.ts +40 -28
- package/src/schemas/hotel-room-offer.ts +31 -30
- package/src/schemas/hotel.ts +225 -258
- package/src/schemas/index.ts +3 -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/elements/booking-policy.ts +1 -1
- package/src/types/elements/booking.ts +1 -1
- package/src/types/elements/contact-person.ts +4 -4
- package/src/types/elements/hotel-offer.ts +1 -1
- package/src/types/elements/hotel-room-offer-request.ts +1 -0
- package/src/types/elements/hotel-room-offer.ts +2 -2
- package/src/types/elements/hotel.ts +1 -1
- package/src/types/elements/index.ts +1 -1
- package/src/utils/case-transformers.ts +1 -1
- package/src/utils/dayjs.ts +2 -2
- package/src/utils/omit.ts +2 -0
- package/src/utils/pick.ts +2 -0
- package/src/utils/shake.ts +1 -0
- package/src/schemas/hotel-offer-request.ts +0 -43
package/package.json
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revolugo/common",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.2.0-alpha.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Revolugo common",
|
|
6
6
|
"author": "Revolugo",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"engines": {
|
|
9
|
-
"node": ">=20.18.1 <25"
|
|
10
|
-
},
|
|
11
|
-
"volta": {
|
|
12
|
-
"extends": "../../package.json"
|
|
13
|
-
},
|
|
14
7
|
"files": [
|
|
15
8
|
"src"
|
|
16
9
|
],
|
|
10
|
+
"type": "module",
|
|
17
11
|
"exports": {
|
|
18
12
|
"./amenities": "./src/amenities/index.ts",
|
|
19
13
|
"./cancellation-policies": "./src/cancellation-policies.ts",
|
|
@@ -38,6 +32,12 @@
|
|
|
38
32
|
"uuid": "13.0.0",
|
|
39
33
|
"zod": "4.3.6"
|
|
40
34
|
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20.18.1 <25"
|
|
37
|
+
},
|
|
38
|
+
"volta": {
|
|
39
|
+
"extends": "../../package.json"
|
|
40
|
+
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"test": "vitest"
|
|
43
43
|
}
|
package/src/constants/poller.ts
CHANGED
|
@@ -3,9 +3,17 @@ export enum PollerStatus {
|
|
|
3
3
|
InProgress = 'IN_PROGRESS',
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
export type PollerStatusType = `${PollerStatus}`
|
|
7
|
+
|
|
6
8
|
export enum PollerType {
|
|
7
9
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8
10
|
HOTEL_ROOM_OFFERS = 'HOTEL_ROOM_OFFERS',
|
|
9
11
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
10
12
|
HOTEL_SEARCH_POLLING = 'HOTEL_SEARCH_POLLING',
|
|
11
13
|
}
|
|
14
|
+
|
|
15
|
+
export enum Status {
|
|
16
|
+
Complete = 'COMPLETE',
|
|
17
|
+
Error = 'ERROR',
|
|
18
|
+
InProgress = 'IN_PROGRESS',
|
|
19
|
+
}
|
package/src/countries/index.ts
CHANGED
package/src/currencies/utils.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { CURRENCIES } from './currencies.ts'
|
|
2
2
|
|
|
3
3
|
import type { CurrencyCode } from './constants.ts'
|
|
4
|
+
import type { CurrencyType } from '../types/index.ts'
|
|
4
5
|
|
|
5
|
-
export function getCurrencySymbol(currency:
|
|
6
|
+
export function getCurrencySymbol(currency: CurrencyType): string {
|
|
6
7
|
const symbol = CURRENCIES[currency]?.symbol
|
|
7
8
|
|
|
8
9
|
if (!symbol) {
|
|
@@ -12,7 +13,7 @@ export function getCurrencySymbol(currency: CurrencyCode): string {
|
|
|
12
13
|
return symbol
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
export function isZeroDecimal(currency:
|
|
16
|
+
export function isZeroDecimal(currency: CurrencyType): boolean {
|
|
16
17
|
return (CURRENCIES[currency] && CURRENCIES[currency].zeroDecimal) || false
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -27,7 +28,7 @@ export function normalizeAmount({
|
|
|
27
28
|
currency,
|
|
28
29
|
}: {
|
|
29
30
|
amount: number
|
|
30
|
-
currency:
|
|
31
|
+
currency: CurrencyType
|
|
31
32
|
}): number {
|
|
32
33
|
if (isZeroDecimal(currency)) {
|
|
33
34
|
return amount
|
|
@@ -41,7 +42,7 @@ export function denormalizeAmount({
|
|
|
41
42
|
currency,
|
|
42
43
|
}: {
|
|
43
44
|
amount: number
|
|
44
|
-
currency:
|
|
45
|
+
currency: CurrencyType
|
|
45
46
|
}): number {
|
|
46
47
|
if (isZeroDecimal(currency)) {
|
|
47
48
|
return amount
|
|
@@ -81,7 +82,7 @@ export function formatAmount({
|
|
|
81
82
|
|
|
82
83
|
export class MoneyCalculator {
|
|
83
84
|
private amount: number
|
|
84
|
-
private currency:
|
|
85
|
+
private currency: CurrencyType
|
|
85
86
|
private isNormalized: boolean
|
|
86
87
|
|
|
87
88
|
constructor({
|
|
@@ -90,7 +91,7 @@ export class MoneyCalculator {
|
|
|
90
91
|
isNormalized = false,
|
|
91
92
|
}: {
|
|
92
93
|
amount: number
|
|
93
|
-
currency:
|
|
94
|
+
currency: CurrencyType
|
|
94
95
|
isNormalized?: boolean
|
|
95
96
|
}) {
|
|
96
97
|
this.amount = amount
|
|
@@ -108,7 +109,7 @@ export class MoneyCalculator {
|
|
|
108
109
|
currency,
|
|
109
110
|
exchangeRate,
|
|
110
111
|
}: {
|
|
111
|
-
currency:
|
|
112
|
+
currency: CurrencyType
|
|
112
113
|
exchangeRate: number
|
|
113
114
|
}): this {
|
|
114
115
|
if (this.currency === currency || this.amount === 0) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { IPaginatedQueriesConfig } from '../types/index.ts'
|
|
2
2
|
|
|
3
3
|
/* @__PURE__ */
|
|
4
|
-
export const PAGINATED_QUERY_DEFAULT_CONFIG
|
|
4
|
+
export const PAGINATED_QUERY_DEFAULT_CONFIG = {
|
|
5
5
|
defaultScope: {
|
|
6
6
|
limit: 20,
|
|
7
7
|
order: 'DESC',
|
|
8
8
|
orderBy: 'createdAt',
|
|
9
9
|
},
|
|
10
|
-
}
|
|
10
|
+
} satisfies Required<IPaginatedQueriesConfig>
|
|
@@ -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.nullish(),
|
|
26
|
+
currency: CURRENCY_SCHEMA,
|
|
27
|
+
expires_at: z.coerce.date().nullable().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 */
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { BreakfastOption } from '../constants/index.ts'
|
|
4
|
+
import { HotelRoomOfferTypeEnum } from '../types/index.ts'
|
|
5
|
+
|
|
6
|
+
export const BREAKFAST_OPTION_DESCRIPTION = `This parameter describes the breakfast option for the given **Hotel Room Offer**:
|
|
7
|
+
- **breakfast_option = "${BreakfastOption.Included}"**:
|
|
8
|
+
1. When **HotelRoomOffer.type = "${HotelRoomOfferTypeEnum.Package}"**:
|
|
9
|
+
the returned **Hotel Room Offer** includes breakfast for the requested **guest count (adult_count + children over 3)**, you cannot choose otherwise, and the returned **price** already includes it,
|
|
10
|
+
2. When **HotelRoomOffer.type = "${HotelRoomOfferTypeEnum.HotelRoom}"**:
|
|
11
|
+
the returned **Hotel Room Offer** includes breakfast for the **Hotel Room Offer** maximum occupancy, you cannot choose otherwise, and the returned **price** already includes it,
|
|
12
|
+
-**breakfast_option = "${BreakfastOption.Optional}"**: the returned **Hotel Room Offer** does not include by default the breakfast and so does the returned **price**, but you'll be able to let your customers choose to add it to their booking. In that case, a **breakfast_price_per_guest_per_night** expressed in the requested **currency** will be available in the returned data, and you'll be to perform one of the two following actions: \n - Call **[Create Hotel Room Offer endpoint](/v1/documentation#operation/postV1Hotel_room_offers)** and get a fresh **Hotel Room Offer** with updated price \n - Compute and display the total price of the **Hotel Room Offer** related to the guest_count and night count requested including extra breafasts.,
|
|
13
|
+
- **breakfast_option = "${BreakfastOption.NotIncluded}"**: the returned **Hotel Room Offer** does not include breakfast and you cannot choose otherwise through API. Guest may still be able to add extra breakfast option(s) at the time of check-in directly at the hotel's reception.`
|
|
14
|
+
|
|
15
|
+
export const BREAKFAST_OPTION_SCHEMA = z
|
|
16
|
+
.enum(BreakfastOption)
|
|
17
|
+
.openapi('BreakfastOption', { description: BREAKFAST_OPTION_DESCRIPTION })
|
|
18
|
+
|
|
19
|
+
export type BreakfastOptionSchema = z.infer<typeof BREAKFAST_OPTION_SCHEMA>
|
|
20
|
+
|
|
21
|
+
export const ADD_BREAKFAST_SCHEMA = z
|
|
22
|
+
.boolean()
|
|
23
|
+
.nullish()
|
|
24
|
+
.openapi('addBreakfast', {
|
|
25
|
+
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>`,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
export const BREAKFAST_COUNT = z
|
|
29
|
+
.number()
|
|
30
|
+
.optional()
|
|
31
|
+
.openapi('breakfastCount', {
|
|
32
|
+
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.`,
|
|
33
|
+
})
|
|
@@ -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
|
@@ -4,4 +4,6 @@ import { STRIPE_CURRENCY_CODES } from '../currencies/index.ts'
|
|
|
4
4
|
|
|
5
5
|
export const CURRENCY_SCHEMA = z
|
|
6
6
|
.enum(STRIPE_CURRENCY_CODES)
|
|
7
|
-
.openapi({ description: 'ISO 4217 currency code.' })
|
|
7
|
+
.openapi('CurrencyClient', { description: 'ISO 4217 currency code.' })
|
|
8
|
+
|
|
9
|
+
export type CurrencySchema = z.infer<typeof CURRENCY_SCHEMA>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
import { CountryIso2Code, Locale, Status } from '../constants/index.ts'
|
|
5
|
+
|
|
6
|
+
export const validStringDate = (): z.ZodString =>
|
|
7
|
+
z
|
|
8
|
+
.string()
|
|
9
|
+
.regex(/^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$/u)
|
|
10
|
+
|
|
11
|
+
export const ADULT_COUNT_SCHEMA = z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.min(1)
|
|
15
|
+
.max(200)
|
|
16
|
+
.openapi('adultCount', {
|
|
17
|
+
description:
|
|
18
|
+
'The total number of adults who will be staying in the property.',
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
export const CHECK_IN_DATE_SCHEMA = validStringDate().openapi('checkInDate', {
|
|
22
|
+
description: 'Date of check-in formatted as YYYY-MM-DD.',
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const CHECK_OUT_DATE_SCHEMA = validStringDate().openapi('checkOutDate', {
|
|
26
|
+
description: 'Date of check-out formatted as YYYY-MM-DD.',
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export const CHILDREN_SCHEMA = z
|
|
30
|
+
.string()
|
|
31
|
+
.regex(/^(([0-9]{1})|(1[0-7]){1})(,(([0-9]{1})|(1[0-7]){1}))*$|^$/u)
|
|
32
|
+
.openapi('children', {
|
|
33
|
+
description:
|
|
34
|
+
'A comma-separated list of child ages (0 up to 17). e.g.: "3,7" represents 2 children respectively 3 and 7 years old.',
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export const IMAGES_SCHEMA = z
|
|
38
|
+
.object({
|
|
39
|
+
count: z.number().openapi({ description: 'Number of images.' }).nullish(),
|
|
40
|
+
highres: z
|
|
41
|
+
.boolean()
|
|
42
|
+
.openapi({ description: 'Whether images exist in highres format.' })
|
|
43
|
+
.nullish(),
|
|
44
|
+
|
|
45
|
+
lowres: z
|
|
46
|
+
.boolean()
|
|
47
|
+
.openapi({ description: 'Whether images exist in lowres format.' })
|
|
48
|
+
.nullish(),
|
|
49
|
+
prefix: z
|
|
50
|
+
.string()
|
|
51
|
+
.openapi({ description: 'Base URL for the images.' })
|
|
52
|
+
.nullish(),
|
|
53
|
+
suffix: z
|
|
54
|
+
.string()
|
|
55
|
+
.openapi({
|
|
56
|
+
description:
|
|
57
|
+
'This parameter usually represents the extension of the image (e.g.: .jpg, .png)',
|
|
58
|
+
})
|
|
59
|
+
.nullish(),
|
|
60
|
+
thumb: z
|
|
61
|
+
.boolean()
|
|
62
|
+
.openapi({
|
|
63
|
+
description:
|
|
64
|
+
'Whether images exist in thumb format (for thumbnails preview).',
|
|
65
|
+
})
|
|
66
|
+
.nullish(),
|
|
67
|
+
})
|
|
68
|
+
.openapi({
|
|
69
|
+
description:
|
|
70
|
+
'🛑 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',
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export const IS_PRICE_INCREASED = z.boolean().openapi({
|
|
74
|
+
description:
|
|
75
|
+
'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.',
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
export const LANG_SCHEMA = z
|
|
79
|
+
.enum(Locale)
|
|
80
|
+
.openapi('Locale', {
|
|
81
|
+
description:
|
|
82
|
+
'Set the language for the returned content using a valid language code.',
|
|
83
|
+
enum: Object.values(Locale),
|
|
84
|
+
})
|
|
85
|
+
.default(Locale.en_US)
|
|
86
|
+
|
|
87
|
+
export const META = z
|
|
88
|
+
.object({
|
|
89
|
+
status: z
|
|
90
|
+
.enum(Status)
|
|
91
|
+
.openapi('Status', { description: 'Status of the response.' }),
|
|
92
|
+
})
|
|
93
|
+
.openapi('Meta', { description: 'Meta data of the response' })
|
|
94
|
+
|
|
95
|
+
export const ROOM_COUNT_SCHEMA = z
|
|
96
|
+
.number()
|
|
97
|
+
.min(1)
|
|
98
|
+
.max(200)
|
|
99
|
+
.openapi('RoomCount', {
|
|
100
|
+
description:
|
|
101
|
+
'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.',
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
export const COUNTRY_ISO2_CODE_SCHEMA = z
|
|
105
|
+
.enum(CountryIso2Code)
|
|
106
|
+
.refine(check => Object.values(CountryIso2Code).includes(check), {
|
|
107
|
+
message: 'Invalid ISO Alpha-2 country code.',
|
|
108
|
+
})
|
|
109
|
+
.openapi('CountryIso2Code', {
|
|
110
|
+
description: 'ISO Alpha-2 country code.',
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
export const SOURCE_MARKET_SCHEMA = COUNTRY_ISO2_CODE_SCHEMA.openapi(
|
|
114
|
+
'SourceMarket',
|
|
115
|
+
{
|
|
116
|
+
description:
|
|
117
|
+
'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.',
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
/* 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
|
+
})
|
|
@@ -1,31 +1,25 @@
|
|
|
1
1
|
/* eslint-disable camelcase */
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
HotelRoomOfferType,
|
|
7
|
-
PackageType,
|
|
8
|
-
StayTaxesInfoEnum,
|
|
9
|
-
} from '../constants/index.ts'
|
|
4
|
+
import { PackageType, StayTaxesInfoEnum } from '../constants/index.ts'
|
|
5
|
+
import { HotelRoomOfferTypeEnum } from '../types/elements/hotel-room-offer-type.ts'
|
|
10
6
|
|
|
7
|
+
import { BREAKFAST_OPTION_SCHEMA } from './breakfast.ts'
|
|
11
8
|
import { CANCELLATION_POLICY_SCHEMA } from './cancellation-policies.ts'
|
|
12
9
|
import { CURRENCY_SCHEMA } from './currency.ts'
|
|
13
|
-
import { SOURCE_MARKET_SCHEMA } from './
|
|
10
|
+
import { SOURCE_MARKET_SCHEMA } from './global.ts'
|
|
14
11
|
import { HOTEL_ROOMS_SCHEMA } from './hotel-room.ts'
|
|
12
|
+
import { HOTEL_IMAGE } from './hotel.ts'
|
|
15
13
|
import { LIST_POLLING_META_SCHEMA } from './list-polling-meta.ts'
|
|
16
14
|
import { TAGS_SCHEMA } from './tag.ts'
|
|
17
15
|
import { TAXES_SCHEMA } from './taxes.ts'
|
|
18
16
|
|
|
19
|
-
export const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
2. When **HotelRoomOffer.type = "${HotelRoomOfferType.HotelRoom}"**:
|
|
24
|
-
the returned **Hotel Room Offer** includes breakfast for the **Hotel Room Offer** maximum occupancy, you cannot choose otherwise, and the returned **price** already includes it,
|
|
25
|
-
-**breakfast_option = "${BreakfastOption.Optional}"**: the returned **Hotel Room Offer** does not include by default the breakfast and so does the returned **price**, but you'll be able to let your customers choose to add it to their booking. In that case, a **breakfast_price_per_guest_per_night** expressed in the requested **currency** will be available in the returned data, and you'll be to perform one of the two following actions: \n - Call **[Create Hotel Room Offer endpoint](/v1/documentation#operation/postV1Hotel_room_offers)** and get a fresh **Hotel Room Offer** with updated price \n - Compute and display the total price of the **Hotel Room Offer** related to the guest_count and night count requested including extra breafasts.,
|
|
26
|
-
- **breakfast_option = "${BreakfastOption.NotIncluded}"**: the returned **Hotel Room Offer** does not include breakfast and you cannot choose otherwise through API. Guest may still be able to add extra breakfast option(s) at the time of check-in directly at the hotel's reception.`
|
|
17
|
+
export const HOTEL_ROOM_OFFERS_IMAGES = z.array(z.array(HOTEL_IMAGE)).openapi({
|
|
18
|
+
description:
|
|
19
|
+
'List of hotel room offer images in various sizes featuring an indicator for the primary (hero) image',
|
|
20
|
+
})
|
|
27
21
|
|
|
28
|
-
export const PACKAGE_TYPES_DESCRIPTION = `An **Hotel Room Offer** of type **${
|
|
22
|
+
export const PACKAGE_TYPES_DESCRIPTION = `An **Hotel Room Offer** of type **${HotelRoomOfferTypeEnum.Package}** can be of **4 types**, described by **package_type** parameter: \n\n - **${PackageType.Cheapest}** : The cheapest combination of hotel rooms that can accommodate the requested guest count. Note that it may not match the requested room count (e.g., 4 guests and 2 rooms requested may return an hotel room package including only 1 room with an occupancy of 4). \n\n -**${PackageType.MatchingRoomCount}** : the cheapest hotel room package that can accommodate the given guest count and that matches exactly the room count given. \n\n -**${PackageType.BestMatch}** : The cheapest hotel room package that matches the given room and guest count with a balanced distribution of guests across the rooms (e.g.; 8 guests and 3 rooms requested may return an **Hotel Room Offer** package including 2 rooms with an occupancy of 3 on each one and 1 room with an occupancy of 2). \n\n -**${PackageType.Regular}** : any other available package.`
|
|
29
23
|
|
|
30
24
|
export const HOTEL_ROOM_OFFER_SCHEMA = z
|
|
31
25
|
.object({
|
|
@@ -33,9 +27,7 @@ export const HOTEL_ROOM_OFFER_SCHEMA = z
|
|
|
33
27
|
description:
|
|
34
28
|
'Quantity of breakfast per night included in the given **Hotel Room Offer**',
|
|
35
29
|
}),
|
|
36
|
-
breakfast_option:
|
|
37
|
-
description: BREAKFAST_OPTION_DESCRIPTION,
|
|
38
|
-
}),
|
|
30
|
+
breakfast_option: BREAKFAST_OPTION_SCHEMA,
|
|
39
31
|
breakfast_price_per_guest_per_night: z.number().nullish().openapi({
|
|
40
32
|
description:
|
|
41
33
|
'Price of breakfast per guest per night for the given **Hotel Room Offer**, expressed in the requested **currency**, when applicable.\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;">Field renamed to "breakfast_unit_price"</div>',
|
|
@@ -54,8 +46,8 @@ export const HOTEL_ROOM_OFFER_SCHEMA = z
|
|
|
54
46
|
.number()
|
|
55
47
|
.nullish()
|
|
56
48
|
.openapi({
|
|
57
|
-
description: `When **type = ${
|
|
58
|
-
When **type = ${
|
|
49
|
+
description: `When **type = ${HotelRoomOfferTypeEnum.HotelRoom}**: this parameters represents the available quantity for the given **Hotel Room Offer**.
|
|
50
|
+
When **type = ${HotelRoomOfferTypeEnum.Package}**: count = 1 always.`,
|
|
59
51
|
}),
|
|
60
52
|
currency: CURRENCY_SCHEMA,
|
|
61
53
|
hotel_id: z
|
|
@@ -64,7 +56,7 @@ export const HOTEL_ROOM_OFFER_SCHEMA = z
|
|
|
64
56
|
hotel_rooms: HOTEL_ROOMS_SCHEMA.openapi({
|
|
65
57
|
description: 'List of Hotel Rooms included in the Hotel Room Offer.',
|
|
66
58
|
}),
|
|
67
|
-
id: z.string().openapi({ description: 'Hotel Room Offer id.' })
|
|
59
|
+
id: z.string().optional().openapi({ description: 'Hotel Room Offer id.' }),
|
|
68
60
|
package_type: z
|
|
69
61
|
.enum(PackageType)
|
|
70
62
|
.openapi({
|
|
@@ -81,13 +73,13 @@ export const HOTEL_ROOM_OFFER_SCHEMA = z
|
|
|
81
73
|
.openapi({ description: 'Either INCLUDED, NOT_INCLUDED or UNKNOWN' }),
|
|
82
74
|
tags: TAGS_SCHEMA,
|
|
83
75
|
tax_included_price: z.number().openapi({
|
|
84
|
-
description: `Price of the given **Hotel Room Offer** including breakfast(s) when applicable, and including all taxes from returned **taxes** list parameter expressed in the requested **currency**.\n\nThis data is not returned for a **Hotel Room Offer** of type **${
|
|
76
|
+
description: `Price of the given **Hotel Room Offer** including breakfast(s) when applicable, and including all taxes from returned **taxes** list parameter expressed in the requested **currency**.\n\nThis data is not returned for a **Hotel Room Offer** of type **${HotelRoomOfferTypeEnum.HotelRoom}**, you'll need to compute and display the actual tax included price of the final **Hotel Room** package corresponding to the guest count and night count requested, or make a call to the **[Create Hotel Room Offer](/v1/documentation#operation/postV1Hotel_room_offers)** endpoint in order to get a valid and bookable **Hotel Room Offer** where **type = ${HotelRoomOfferTypeEnum.Package}** based on a packaged list of **Hotel Room Offers** of type **${HotelRoomOfferTypeEnum.HotelRoom}**.`,
|
|
85
77
|
}),
|
|
86
78
|
taxes: TAXES_SCHEMA,
|
|
87
79
|
type: z
|
|
88
|
-
.enum(
|
|
80
|
+
.enum(HotelRoomOfferTypeEnum)
|
|
89
81
|
.openapi({
|
|
90
|
-
description: `Hotel Room Offer type.\n\n **Hotel Room Offers** with **type = "${
|
|
82
|
+
description: `Hotel Room Offer type.\n\n **Hotel Room Offers** with **type = "${HotelRoomOfferTypeEnum.Package}"** are **Hotel Room Offers** that are already bookable and you'll be able to follow the next step of the **Booking Flow** calling **[Create Booking Policies endpoint](/v1/documentation#operation/postV1Booking_policies)**. \n\n Otherwise, you'll be able to create a new **Hotel Room Offer** with **type = "${HotelRoomOfferTypeEnum.Package}"** from multiple **Hotel Room Offers** with **type = "${HotelRoomOfferTypeEnum.HotelRoom}"**. See **[Create Hotel Room Offer endpoint](/v1/documentation#operation/postV1Hotel_room_offers)** for details.`,
|
|
91
83
|
})
|
|
92
84
|
.optional(),
|
|
93
85
|
})
|
|
@@ -95,10 +87,19 @@ export const HOTEL_ROOM_OFFER_SCHEMA = z
|
|
|
95
87
|
description: 'Description of the Hotel Room Offer.',
|
|
96
88
|
})
|
|
97
89
|
|
|
98
|
-
export const HOTEL_ROOM_OFFERS_SCHEMA = z
|
|
90
|
+
export const HOTEL_ROOM_OFFERS_SCHEMA = z
|
|
91
|
+
.array(HOTEL_ROOM_OFFER_SCHEMA)
|
|
92
|
+
.openapi({
|
|
93
|
+
description: 'List of Hotel Room Offers.',
|
|
94
|
+
})
|
|
99
95
|
|
|
100
|
-
export const HOTEL_ROOM_OFFERS_RESPONSE_SCHEMA = z
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
96
|
+
export const HOTEL_ROOM_OFFERS_RESPONSE_SCHEMA = z
|
|
97
|
+
.object({
|
|
98
|
+
data: HOTEL_ROOM_OFFERS_SCHEMA,
|
|
99
|
+
meta: LIST_POLLING_META_SCHEMA,
|
|
100
|
+
})
|
|
101
|
+
.openapi({
|
|
102
|
+
description:
|
|
103
|
+
'Response envelope for the Hotel Room Offers polling endpoint.',
|
|
104
|
+
})
|
|
104
105
|
/* eslint-enable camelcase */
|