@curless/hotel-storefront 0.50.3 → 0.50.4
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/dist/card.generated.d.ts +1 -1
- package/dist/card.generated.js +2 -2
- package/dist/card.generated.js.map +1 -1
- package/dist/demo-hotels.d.ts.map +1 -1
- package/dist/demo-hotels.js +9 -2
- package/dist/demo-hotels.js.map +1 -1
- package/dist/huazhu/backend.d.ts.map +1 -1
- package/dist/huazhu/backend.js +90 -23
- package/dist/huazhu/backend.js.map +1 -1
- package/dist/huazhu/sandbox.d.ts +7 -0
- package/dist/huazhu/sandbox.d.ts.map +1 -1
- package/dist/huazhu/sandbox.js +2 -2
- package/dist/huazhu/sandbox.js.map +1 -1
- package/dist/legal.d.ts.map +1 -1
- package/dist/legal.js +5 -1
- package/dist/legal.js.map +1 -1
- package/dist/present.d.ts +4 -0
- package/dist/present.d.ts.map +1 -1
- package/dist/present.js +8 -1
- package/dist/present.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/tools.d.ts +8 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +91 -5
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +21 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -1166,6 +1166,12 @@ const HOTEL_PAGE = {
|
|
|
1166
1166
|
* none - and never in what the assistant is told.
|
|
1167
1167
|
*/
|
|
1168
1168
|
soldOut: ARR,
|
|
1169
|
+
/**
|
|
1170
|
+
* Where some rates are listed but not booked here (`Room.notSoldHere`, paid
|
|
1171
|
+
* in advance on a deployment that takes no payment): what that means and
|
|
1172
|
+
* what to offer - the same sentence as the text.
|
|
1173
|
+
*/
|
|
1174
|
+
notSoldHere: STR,
|
|
1169
1175
|
};
|
|
1170
1176
|
/**
|
|
1171
1177
|
* What request_booking answers - and book_picked_room, which books the same way
|
|
@@ -2173,10 +2179,22 @@ const LABEL_WORDS = {
|
|
|
2173
2179
|
const labelWords = (r) => {
|
|
2174
2180
|
const words = [
|
|
2175
2181
|
...(r.labels ?? []).map((l) => LABEL_WORDS[l]),
|
|
2176
|
-
...(r.payment === 'prepaid'
|
|
2182
|
+
...(r.payment === 'prepaid'
|
|
2183
|
+
? [r.notSoldHere ? 'paid in advance - not booked here' : 'paid in advance']
|
|
2184
|
+
: []),
|
|
2177
2185
|
];
|
|
2178
2186
|
return words.length ? ` [${words.join(', ')}]` : '';
|
|
2179
2187
|
};
|
|
2188
|
+
/**
|
|
2189
|
+
* What is said of rates listed but not booked here (`Room.notSoldHere`) - in
|
|
2190
|
+
* the text and, word for word, in the structure (`notSoldHere`): the model reads
|
|
2191
|
+
* the structure (2026-10-28). Listed and marked as the group sells them; the
|
|
2192
|
+
* card says no more than 预付 on them (robin, 2026-10-30), so the assistant is
|
|
2193
|
+
* the one who knows - and says it when the guest wants one.
|
|
2194
|
+
*/
|
|
2195
|
+
export const notSoldHereWords = (group) => `Rates marked paid in advance are listed as ${group} sells them, but a stay paid in advance cannot be booked here yet: this connector books rates paid at the hotel. If the guest wants one, say so plainly - nothing is booked or charged - and offer a rate paid at the hotel, other dates, or booking it with ${group} directly.`;
|
|
2196
|
+
/** The group a hotel is with, by name - the deployment's own brand outside a market. */
|
|
2197
|
+
const groupNameOf = (deps, hotelId) => holderOf(deps, deps.backend.supplierOf?.(hotelId)).name;
|
|
2180
2198
|
/** What a rate says about cancelling, as the text puts it. */
|
|
2181
2199
|
const cancelWords = (r) => r.freeCancellationUntil
|
|
2182
2200
|
? `free to cancel until ${freeUntilText(r)}`
|
|
@@ -2383,7 +2401,13 @@ const dateFlex = (dates, stay) => {
|
|
|
2383
2401
|
dates: dates.map((d) => ({
|
|
2384
2402
|
checkIn: d.checkIn,
|
|
2385
2403
|
checkOut: d.checkOut,
|
|
2386
|
-
|
|
2404
|
+
// "Sold out" only when it is (D2, robin 2026-10-30): a day with rooms
|
|
2405
|
+
// that cannot be booked here says why instead.
|
|
2406
|
+
...(d.from
|
|
2407
|
+
? { from: formatMoney(d.from) }
|
|
2408
|
+
: !d.why || d.why === 'sold-out'
|
|
2409
|
+
? { soldOut: true }
|
|
2410
|
+
: { noRoomsCode: d.why }),
|
|
2387
2411
|
...(d.chosen ? { chosen: true } : {}),
|
|
2388
2412
|
// The chosen date cannot match: `beatsBy` is a price strictly below it.
|
|
2389
2413
|
...(beatsBy !== undefined && d.from?.minor === beatsBy ? { best: true } : {}),
|
|
@@ -3119,7 +3143,11 @@ const comparedInWords = (c) => {
|
|
|
3119
3143
|
: p.refundable
|
|
3120
3144
|
? 'no free cancellation'
|
|
3121
3145
|
: 'non-refundable',
|
|
3122
|
-
p.payment === 'prepaid'
|
|
3146
|
+
p.payment === 'prepaid'
|
|
3147
|
+
? p.notSoldHere
|
|
3148
|
+
? 'paid in advance - not booked here'
|
|
3149
|
+
: 'paid in advance'
|
|
3150
|
+
: '',
|
|
3123
3151
|
p.breakfast ? 'breakfast included' : 'no breakfast',
|
|
3124
3152
|
]
|
|
3125
3153
|
.filter(Boolean)
|
|
@@ -3534,7 +3562,10 @@ const putRoomLine = async (deps, t, ctx, key, store, args, detail) => {
|
|
|
3534
3562
|
let took = '';
|
|
3535
3563
|
const type = room ? undefined : roomTypeNamed(dated.rooms, roomRef);
|
|
3536
3564
|
if (type) {
|
|
3537
|
-
const
|
|
3565
|
+
const fitting = type.rooms.filter((r) => r.sleeps >= stay.guests && r.roomsLeft >= wanted);
|
|
3566
|
+
// A rate booked here before one only shown (`notSoldHere`), where the type has both.
|
|
3567
|
+
const sold = fitting.filter((r) => !r.notSoldHere);
|
|
3568
|
+
const fits = sold.length ? sold : fitting;
|
|
3538
3569
|
const [first, ...rest] = fits;
|
|
3539
3570
|
const cheapest = first
|
|
3540
3571
|
? rest.reduce((a, b) => (b.stayTotal.minor < a.stayTotal.minor ? b : a), first)
|
|
@@ -3576,6 +3607,45 @@ const putRoomLine = async (deps, t, ctx, key, store, args, detail) => {
|
|
|
3576
3607
|
text: `${type ? `${detail.hotel.name} has no ${type.name} that sleeps ${stay.guests} and has ${wanted === 1 ? 'a room' : `${wanted} rooms`} left for those nights.` : `${detail.hotel.name} has no room type by that name for those nights.`} It has: ${dated.rooms.map((r) => `${r.name} (${han && r.names?.zh ? `${r.names.zh}, ` : ''}\`${r.id}\`)`).join(', ')}. Call again with the id.`,
|
|
3577
3608
|
};
|
|
3578
3609
|
}
|
|
3610
|
+
// ⚠️ LISTED, NOT BOOKED HERE (robin, 2026-10-30): a rate paid in advance
|
|
3611
|
+
// where this deployment takes no payment goes in no trip and no pick. The
|
|
3612
|
+
// press on its Reserve - or the assistant asking for it - is answered with
|
|
3613
|
+
// what is true and what is left: nothing booked, nothing charged; the rates
|
|
3614
|
+
// here paid at the hotel, a press each; other dates; or the group itself.
|
|
3615
|
+
// Never a review that fails at Book, after the guest typed their name.
|
|
3616
|
+
if (room.notSoldHere) {
|
|
3617
|
+
const open = dated.rooms.filter((r) => !r.notSoldHere && r.sleeps >= stay.guests && r.roomsLeft >= wanted);
|
|
3618
|
+
const group = groupNameOf(deps, hotelId);
|
|
3619
|
+
const said = [
|
|
3620
|
+
`Nothing was booked or charged: ${room.name} is paid in advance, and a stay paid in advance cannot be booked here yet - this connector books rates paid at the hotel.`,
|
|
3621
|
+
open.length
|
|
3622
|
+
? `Paid at the hotel at ${detail.hotel.name} for those nights: ${open.map((r) => `${r.name} (\`${r.id}\`)`).join(', ')}.`
|
|
3623
|
+
: `No rate at ${detail.hotel.name} for those nights is paid at the hotel.`,
|
|
3624
|
+
`Other dates, or booking this rate with ${group} directly, are the other ways on.`,
|
|
3625
|
+
].join(' ');
|
|
3626
|
+
return {
|
|
3627
|
+
structured: {
|
|
3628
|
+
view: 'error',
|
|
3629
|
+
...common(deps, key),
|
|
3630
|
+
error: 'prepaid-not-here',
|
|
3631
|
+
room: { id: room.id, name: room.name, ...(room.names ? { names: room.names } : {}) },
|
|
3632
|
+
rooms: open.map((r) => ({
|
|
3633
|
+
id: r.id,
|
|
3634
|
+
name: r.name,
|
|
3635
|
+
...(r.names ? { names: r.names } : {}),
|
|
3636
|
+
})),
|
|
3637
|
+
hotel: {
|
|
3638
|
+
id: detail.hotel.id,
|
|
3639
|
+
name: detail.hotel.name,
|
|
3640
|
+
...(detail.hotel.names ? { names: detail.hotel.names } : {}),
|
|
3641
|
+
},
|
|
3642
|
+
stay,
|
|
3643
|
+
group,
|
|
3644
|
+
said,
|
|
3645
|
+
},
|
|
3646
|
+
text: said,
|
|
3647
|
+
};
|
|
3648
|
+
}
|
|
3579
3649
|
deps.trips.set(store, {
|
|
3580
3650
|
kind: 'room',
|
|
3581
3651
|
hotelId,
|
|
@@ -4343,6 +4413,12 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
4343
4413
|
: ''}.`
|
|
4344
4414
|
: '',
|
|
4345
4415
|
].filter(Boolean);
|
|
4416
|
+
// A price on the list that is not booked here (`notSoldHere`): said as on
|
|
4417
|
+
// the hotel's page, in both - see `notSoldHereWords`.
|
|
4418
|
+
const notSoldOn = hotels.find((h) => h.forStay?.notSoldHere);
|
|
4419
|
+
const notSold = notSoldOn ? notSoldHereWords(groupNameOf(deps, notSoldOn.id)) : '';
|
|
4420
|
+
if (notSold)
|
|
4421
|
+
priceNotes.push(notSold);
|
|
4346
4422
|
// Every one by name and city, and that there are no others - or, told
|
|
4347
4423
|
// only "2 hotels", the model asked for the list again to learn which.
|
|
4348
4424
|
const inAll = homeList
|
|
@@ -4377,6 +4453,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
4377
4453
|
// In both, like a plan's: a host with no card may hand its model this
|
|
4378
4454
|
// rather than the text.
|
|
4379
4455
|
...(ctx.noCards ? { notDrawn: LIST_NOT_DRAWN } : {}),
|
|
4456
|
+
...(notSold ? { notSoldHere: notSold } : {}),
|
|
4380
4457
|
},
|
|
4381
4458
|
text: [
|
|
4382
4459
|
inAll ||
|
|
@@ -4512,6 +4589,9 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
4512
4589
|
// card needs no call to the server.
|
|
4513
4590
|
const terms = roomTermsOf(args);
|
|
4514
4591
|
const soldOut = soldOutTypesOf(detail, enough, roomsWanted);
|
|
4592
|
+
const notSold = enough.some((r) => r.notSoldHere)
|
|
4593
|
+
? notSoldHereWords(groupNameOf(deps, h.id))
|
|
4594
|
+
: '';
|
|
4515
4595
|
const rooms = enough.map((r) => ({
|
|
4516
4596
|
...r,
|
|
4517
4597
|
facets: facetsOf(r),
|
|
@@ -4551,6 +4631,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
4551
4631
|
activeFilters: activeKeysOf(terms),
|
|
4552
4632
|
// Types with no room to book for these nights, said and not left out.
|
|
4553
4633
|
...(byTheHour || !soldOut.length ? {} : { soldOut }),
|
|
4634
|
+
...(notSold ? { notSoldHere: notSold } : {}),
|
|
4554
4635
|
...flex.structured,
|
|
4555
4636
|
},
|
|
4556
4637
|
text: [
|
|
@@ -4561,6 +4642,7 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
4561
4642
|
terms && flex.text
|
|
4562
4643
|
? `${flex.text} (That is the cheapest room of any kind, not only one with ${termWords(terms)}.)`
|
|
4563
4644
|
: flex.text,
|
|
4645
|
+
notSold,
|
|
4564
4646
|
deps.vocab.demo ? noteFor(deps.vocab) : '',
|
|
4565
4647
|
]
|
|
4566
4648
|
.filter(Boolean)
|
|
@@ -5443,7 +5525,11 @@ const answerTool = async (deps, name, rawArgs, ctx) => {
|
|
|
5443
5525
|
// Each stay's rate says its terms where they bind - see `ItineraryItem.refundable`.
|
|
5444
5526
|
const termsOf = (x) => [
|
|
5445
5527
|
x.refundable === false ? 'non-refundable' : '',
|
|
5446
|
-
x.payment === 'prepaid'
|
|
5528
|
+
x.payment === 'prepaid'
|
|
5529
|
+
? x.notSoldHere
|
|
5530
|
+
? 'paid in advance - not booked here'
|
|
5531
|
+
: 'paid in advance'
|
|
5532
|
+
: '',
|
|
5447
5533
|
]
|
|
5448
5534
|
.filter(Boolean)
|
|
5449
5535
|
.join(', ');
|