@revolugo/common 7.0.1 → 7.1.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.
Files changed (47) hide show
  1. package/package.json +2 -2
  2. package/src/cancellation-policies.test.ts +8 -2
  3. package/src/cancellation-policies.ts +57 -4
  4. package/src/constants/poller.ts +6 -0
  5. package/src/currencies/types.ts +1 -1
  6. package/src/currencies/utils.ts +52 -52
  7. package/src/schemas/booking-policy.ts +51 -0
  8. package/src/schemas/cancellation-policies.ts +18 -13
  9. package/src/schemas/currency.ts +1 -1
  10. package/src/schemas/global.ts +139 -0
  11. package/src/schemas/hotel-offer.ts +40 -28
  12. package/src/schemas/hotel-room-offer.ts +33 -14
  13. package/src/schemas/hotel-room.ts +1 -4
  14. package/src/schemas/hotel.ts +225 -258
  15. package/src/schemas/index.ts +2 -1
  16. package/src/schemas/list-polling-meta.ts +7 -2
  17. package/src/schemas/tag.ts +22 -8
  18. package/src/schemas/taxes.ts +4 -2
  19. package/src/types/calendar.ts +2 -2
  20. package/src/types/elements/amenity.ts +10 -10
  21. package/src/types/elements/booking-policy.ts +8 -8
  22. package/src/types/elements/booking.ts +16 -16
  23. package/src/types/elements/contact-person.ts +7 -0
  24. package/src/types/elements/elements-events.ts +2 -0
  25. package/src/types/elements/event-metadata.ts +6 -6
  26. package/src/types/elements/hotel-offer-list.ts +1 -1
  27. package/src/types/elements/hotel-offer-request.ts +21 -21
  28. package/src/types/elements/hotel-offer.ts +16 -16
  29. package/src/types/elements/hotel-offers-filters.ts +1 -1
  30. package/src/types/elements/hotel-room-offer-request.ts +22 -22
  31. package/src/types/elements/hotel-room-offer.ts +17 -17
  32. package/src/types/elements/hotel-room.ts +6 -6
  33. package/src/types/elements/hotel-rooming-list.ts +8 -8
  34. package/src/types/elements/hotel.ts +7 -7
  35. package/src/types/elements/meta-polling.ts +6 -6
  36. package/src/types/event.ts +1 -1
  37. package/src/types/hotel-contract.ts +1 -1
  38. package/src/types/hotel-room-stock.ts +1 -1
  39. package/src/types/pagination.ts +2 -2
  40. package/src/utils/create-composite-key.ts +2 -2
  41. package/src/utils/debounce.ts +1 -1
  42. package/src/utils/generate-dummy-hotel-images.ts +7 -5
  43. package/src/utils/get-sanitized-room-count.ts +1 -1
  44. package/src/utils/images.ts +5 -0
  45. package/src/utils/parse-children.ts +1 -1
  46. package/src/utils/poller.ts +56 -55
  47. 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.0",
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.3",
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 releaseDatetime = getFormattedUTCLocalTime(releaseDate, timezone)
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 releaseDatetime = getFormattedUTCLocalTime(releaseDate, timezone)
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
- releaseDate && dayjs.tz(releaseDate, timezone).startOf('day').utc().format()
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
- timezone?: string
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
+ }
@@ -9,3 +9,9 @@ export enum PollerType {
9
9
  // eslint-disable-next-line @typescript-eslint/naming-convention
10
10
  HOTEL_SEARCH_POLLING = 'HOTEL_SEARCH_POLLING',
11
11
  }
12
+
13
+ export enum Status {
14
+ Complete = 'COMPLETE',
15
+ Error = 'ERROR',
16
+ InProgress = 'IN_PROGRESS',
17
+ }
@@ -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
  }
@@ -98,49 +98,50 @@ export class MoneyCalculator {
98
98
  this.isNormalized = isNormalized
99
99
  }
100
100
 
101
- public denormalize(): this {
102
- if (!this.isNormalized) {
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
- this.amount = denormalizeAmount({
107
- amount: this.amount,
108
- currency: this.currency,
109
- })
118
+ const startingIsNormalized = this.isNormalized
110
119
 
111
- this.isNormalized = false
120
+ if (startingIsNormalized) {
121
+ this.denormalize()
122
+ }
112
123
 
113
- return this
114
- }
124
+ this.amount *= exchangeRate
125
+ this.currency = currency
115
126
 
116
- public markup(percentage: number): this {
117
- this.amount /= 1 - percentage
127
+ if (startingIsNormalized) {
128
+ this.normalize()
129
+ }
118
130
 
119
131
  return this
120
132
  }
121
133
 
122
- public normalize(): this {
123
- if (this.isNormalized) {
134
+ public denormalize(): this {
135
+ if (!this.isNormalized) {
124
136
  return this
125
137
  }
126
138
 
127
- this.amount = Number(
128
- normalizeAmount({
129
- // Making sure we only have 2 decimals after comma
130
- amount: Number(this.amount.toFixed(2)),
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
- public ceil(): this {
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 convert({
174
- currency,
175
- exchangeRate,
176
- }: {
177
- exchangeRate: number
178
- currency: CurrencyCode
179
- }): this {
180
- if (this.currency === currency || this.amount === 0) {
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
- const startingIsNormalized = this.isNormalized
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
- if (startingIsNormalized) {
187
- this.denormalize()
188
- }
189
+ this.isNormalized = true
189
190
 
190
- this.amount *= exchangeRate
191
- this.currency = currency
191
+ return this
192
+ }
192
193
 
193
- if (startingIsNormalized) {
194
- this.normalize()
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.object({
5
- date_from: z.string().openapi({
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
- 'The start date and time of the cancellation policy, given in the hotel timezone.',
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 */
@@ -4,4 +4,4 @@ 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.' })
@@ -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 './hotel-offer-request.ts'
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.object({
31
- data: z.object({
32
- adult_count: ADULT_COUNT_SCHEMA,
33
- check_in_date: CHECK_IN_DATE_SCHEMA,
34
- check_out_date: CHECK_OUT_DATE_SCHEMA,
35
- children: CHILDREN_SCHEMA.optional().nullish(),
36
- currency: CURRENCY_SCHEMA,
37
- hotel_offers: HOTEL_OFFERS_SCHEMA.openapi({
38
- description: 'List of Hotel Offers',
39
- }),
40
- price_histogram: z
41
- .array(z.number())
42
- .openapi({
43
- description:
44
- '**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**',
45
- })
46
- .nullish(),
47
- price_max: z.number().nullish().openapi({
48
- description: 'Maximum price of available returned **Hotel Offers**',
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
- price_min: z.number().nullish().openapi({
51
- description: 'Minimum price of available returned **Hotel Offers**',
60
+ event: z.any().optional().openapi({
61
+ description:
62
+ 'Event associated with the Hotel Offers response, when applicable.',
52
63
  }),
53
- }),
54
- event: z.any().optional(),
55
- meta: LIST_POLLING_META_SCHEMA,
56
- })
64
+ meta: LIST_POLLING_META_SCHEMA,
65
+ })
66
+ .openapi({
67
+ description: 'Response envelope for the Hotel Offers polling endpoint.',
68
+ })