@curless/hotel-storefront 0.34.0 → 0.35.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.
Files changed (55) hide show
  1. package/dist/aggregate/make.d.ts.map +1 -1
  2. package/dist/aggregate/make.js +7 -1
  3. package/dist/aggregate/make.js.map +1 -1
  4. package/dist/backend.d.ts +2 -2
  5. package/dist/backend.d.ts.map +1 -1
  6. package/dist/card.generated.d.ts +1 -1
  7. package/dist/card.generated.js +2 -2
  8. package/dist/card.generated.js.map +1 -1
  9. package/dist/config.d.ts +24 -4
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js.map +1 -1
  12. package/dist/huazhu/backend.d.ts +2 -2
  13. package/dist/huazhu/backend.d.ts.map +1 -1
  14. package/dist/huazhu/backend.js +119 -10
  15. package/dist/huazhu/backend.js.map +1 -1
  16. package/dist/huazhu/bookings.d.ts +2 -0
  17. package/dist/huazhu/bookings.d.ts.map +1 -1
  18. package/dist/huazhu/bookings.js.map +1 -1
  19. package/dist/huazhu/catalog.d.ts +7 -1
  20. package/dist/huazhu/catalog.d.ts.map +1 -1
  21. package/dist/huazhu/catalog.js +8 -4
  22. package/dist/huazhu/catalog.js.map +1 -1
  23. package/dist/huazhu/make.d.ts.map +1 -1
  24. package/dist/huazhu/make.js +44 -13
  25. package/dist/huazhu/make.js.map +1 -1
  26. package/dist/legal.d.ts.map +1 -1
  27. package/dist/legal.js +131 -83
  28. package/dist/legal.js.map +1 -1
  29. package/dist/payments/checkout.d.ts +49 -1
  30. package/dist/payments/checkout.d.ts.map +1 -1
  31. package/dist/payments/checkout.js +9 -0
  32. package/dist/payments/checkout.js.map +1 -1
  33. package/dist/payments/fake-stripe.d.ts +37 -0
  34. package/dist/payments/fake-stripe.d.ts.map +1 -0
  35. package/dist/payments/fake-stripe.js +123 -0
  36. package/dist/payments/fake-stripe.js.map +1 -0
  37. package/dist/payments/stripe-checkout.d.ts +44 -0
  38. package/dist/payments/stripe-checkout.d.ts.map +1 -0
  39. package/dist/payments/stripe-checkout.js +166 -0
  40. package/dist/payments/stripe-checkout.js.map +1 -0
  41. package/dist/server.d.ts +2 -2
  42. package/dist/server.js +2 -2
  43. package/dist/surface.d.ts.map +1 -1
  44. package/dist/surface.js +34 -20
  45. package/dist/surface.js.map +1 -1
  46. package/dist/tools.d.ts.map +1 -1
  47. package/dist/tools.js +45 -23
  48. package/dist/tools.js.map +1 -1
  49. package/dist/types.d.ts +17 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/vocab.d.ts +20 -0
  52. package/dist/vocab.d.ts.map +1 -1
  53. package/dist/vocab.js +25 -2
  54. package/dist/vocab.js.map +1 -1
  55. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"card.generated.js","sourceRoot":"","sources":["../src/card.generated.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,wEAAwE;AACxE,gFAAgF;AAChF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,eAAe,GAAW,MAAM,CAAC,IAAI,CAChD,kv1yBAAkv1yB,EAClv1yB,QAAQ,CACT,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAEnB,6GAA6G;AAC7G,MAAM,CAAC,MAAM,qBAAqB,GAChC,kEAAkE,CAAC"}
1
+ {"version":3,"file":"card.generated.js","sourceRoot":"","sources":["../src/card.generated.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,wEAAwE;AACxE,gFAAgF;AAChF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,eAAe,GAAW,MAAM,CAAC,IAAI,CAChD,kvwzBAAkvwzB,EAClvwzB,QAAQ,CACT,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAEnB,6GAA6G;AAC7G,MAAM,CAAC,MAAM,qBAAqB,GAChC,kEAAkE,CAAC"}
package/dist/config.d.ts CHANGED
@@ -247,10 +247,17 @@ export type ApiSource = {
247
247
  * is `<prefix>_GATEWAY_KEY` in the environment, never here.
248
248
  */
249
249
  prepaid?: {
250
- /** The gateway, e.g. https://mcp.curless.ai. */
251
- gatewayUrl: string;
252
- /** The Curless merchant the money is taken for (a test-mode one). */
253
- merchantId: string;
250
+ /**
251
+ * Who takes the money: the agentbank gateway (the default), or Stripe
252
+ * directly - its hosted Checkout page and refunds, test mode only, the key
253
+ * in `<prefix>_STRIPE_KEY` (robin, 2026-10-15: Curless's acquiring is not
254
+ * connected yet, and no merchant can be opened there).
255
+ */
256
+ provider?: 'gateway' | 'stripe';
257
+ /** The gateway, e.g. https://mcp.curless.ai. Needed for `gateway`. */
258
+ gatewayUrl?: string;
259
+ /** The Curless merchant the money is taken for (a test-mode one). Needed for `gateway`. */
260
+ merchantId?: string;
254
261
  /** On the paying page as whose order it is. Default: the brand. */
255
262
  merchantName?: string;
256
263
  merchantUrl?: string;
@@ -269,6 +276,19 @@ export type ApiSource = {
269
276
  * tester they hold a real room.
270
277
  */
271
278
  sandbox?: boolean;
279
+ /**
280
+ * The group's own TEST environment (华住, 2026-10-15: test-*.huazhu.com): its
281
+ * test hotels, rates and photographs - the group's, not invented - and test
282
+ * bookings in its test system, which hold no room for anyone and are never
283
+ * paid. The payloads say `demo` and `test`, the card prints its strip, and
284
+ * the instructions and pages say it is a test system, never "simulated".
285
+ *
286
+ * ⚠️ NOT `sandbox`, and never both: a sandbox's hotels are made up and its
287
+ * pictures stock; a test system's are the group's own. Without either, an
288
+ * api source is taken to be real - and a test system taken for real would
289
+ * tell a tester they hold a room at a hotel.
290
+ */
291
+ test?: boolean;
272
292
  /**
273
293
  * A directory this deployment may WRITE: the copy of the hotel list and the
274
294
  * bookings it made. Absolute, or against the config file's directory - and
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAiUA,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CACjC,CAAC;KACE,WAAW,EAAE;KACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;KAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAE3B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAmC,EAAE,EAAE;IAC/D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,OAAO,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;IAC7D,OAAO;QACL,UAAU,EAAE,QAAQ,MAAM,GAAG,MAAM,EAAE;QACrC,QAAQ,EAAE,OAAO,MAAM,GAAG,IAAI,EAAE;QAChC,yEAAyE;QACzE,0EAA0E;QAC1E,+CAA+C;QAC/C,MAAM,EAAE,WAAW,MAAM,GAAG,MAAM,EAAE;QACpC,UAAU,EAAE,QAAQ,MAAM,QAAQ;QAClC,SAAS,EAAE,UAAU,MAAM,MAAM;QACjC,QAAQ,EAAE,QAAQ,MAAM,MAAM;QAC9B,SAAS,EAAE,SAAS,MAAM,MAAM;QAChC,cAAc,EAAE,WAAW,MAAM,SAAS;QAC1C,YAAY,EAAE,WAAW,MAAM,UAAU;QACzC,mBAAmB,EAAE,WAAW,MAAM,cAAc;QACpD,aAAa,EAAE,UAAU,MAAM,SAAS;QACxC,yEAAyE;QACzE,kEAAkE;QAClE,aAAa,EAAE,WAAW,MAAM,gBAAgB;QAChD,aAAa,EAAE,UAAU,MAAM,SAAS;QACxC,QAAQ,EAAE,OAAO,MAAM,GAAG,IAAI,WAAW;QACzC,wEAAwE;QACxE,2EAA2E;QAC3E,6DAA6D;QAC7D,OAAO,EAAE,WAAW,MAAM,GAAG,MAAM,EAAE;QACrC,SAAS,EAAE,QAAQ,MAAM,WAAW;QACpC,MAAM,EAAE,WAAW,MAAM,QAAQ;QACjC,OAAO,EAAE,YAAY,MAAM,QAAQ;QACnC,iBAAiB,EAAE,UAAU,MAAM,aAAa;KACxC,CAAC;AACb,CAAC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAqVA,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CACjC,CAAC;KACE,WAAW,EAAE;KACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;KAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAE3B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAmC,EAAE,EAAE;IAC/D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,OAAO,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;IAC7D,OAAO;QACL,UAAU,EAAE,QAAQ,MAAM,GAAG,MAAM,EAAE;QACrC,QAAQ,EAAE,OAAO,MAAM,GAAG,IAAI,EAAE;QAChC,yEAAyE;QACzE,0EAA0E;QAC1E,+CAA+C;QAC/C,MAAM,EAAE,WAAW,MAAM,GAAG,MAAM,EAAE;QACpC,UAAU,EAAE,QAAQ,MAAM,QAAQ;QAClC,SAAS,EAAE,UAAU,MAAM,MAAM;QACjC,QAAQ,EAAE,QAAQ,MAAM,MAAM;QAC9B,SAAS,EAAE,SAAS,MAAM,MAAM;QAChC,cAAc,EAAE,WAAW,MAAM,SAAS;QAC1C,YAAY,EAAE,WAAW,MAAM,UAAU;QACzC,mBAAmB,EAAE,WAAW,MAAM,cAAc;QACpD,aAAa,EAAE,UAAU,MAAM,SAAS;QACxC,yEAAyE;QACzE,kEAAkE;QAClE,aAAa,EAAE,WAAW,MAAM,gBAAgB;QAChD,aAAa,EAAE,UAAU,MAAM,SAAS;QACxC,QAAQ,EAAE,OAAO,MAAM,GAAG,IAAI,WAAW;QACzC,wEAAwE;QACxE,2EAA2E;QAC3E,6DAA6D;QAC7D,OAAO,EAAE,WAAW,MAAM,GAAG,MAAM,EAAE;QACrC,SAAS,EAAE,QAAQ,MAAM,WAAW;QACpC,MAAM,EAAE,WAAW,MAAM,QAAQ;QACjC,OAAO,EAAE,YAAY,MAAM,QAAQ;QACnC,iBAAiB,EAAE,UAAU,MAAM,aAAa;KACxC,CAAC;AACb,CAAC,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { type BackendCapabilities, type HotelBackend } from '../backend.js';
2
2
  import { type BookingLimits } from '../limits.js';
3
- import type { GatewayCheckout } from '../payments/checkout.js';
3
+ import type { Checkout } from '../payments/checkout.js';
4
4
  import type { Quote, ShownQuote } from '../types.js';
5
5
  import { type BookingStore, type Reconciler, type StoredBooking } from './bookings.js';
6
6
  import { type Catalog } from './catalog.js';
@@ -36,7 +36,7 @@ export type HuazhuHotelsOptions = {
36
36
  * page before Huazhu is asked (`OPN`). A sandbox only - see `ApiSource.prepaid`.
37
37
  */
38
38
  prepaid?: {
39
- checkout: GatewayCheckout;
39
+ checkout: Checkout;
40
40
  payWithinMs?: number;
41
41
  };
42
42
  now?: () => number;
@@ -1 +1 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/huazhu/backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/huazhu/backend.ts"],"names":[],"mappings":"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"}
@@ -129,6 +129,29 @@ const mealPlanOf = (s) => {
129
129
  const plan = MEAL_PLAN[s.mealType];
130
130
  return plan ? { plan, ...(s.mealCount > 0 ? { count: s.mealCount } : {}) } : undefined;
131
131
  };
132
+ /**
133
+ * What kind of rate a Huazhu rate's name says it is - "门市价含早" is the
134
+ * standard rate - for a card to say in the guest's language (香格里拉,
135
+ * 2026-10-15). The more particular words first; a name that says none of
136
+ * them - "集团OTA双早" - has no kind, and the card shows it as it is.
137
+ */
138
+ const RATE_KIND = [
139
+ ['周中特惠', 'weekday-special'],
140
+ ['限时特惠', 'flash-sale'],
141
+ ['夜宵房', 'late-night'],
142
+ ['精选套餐', 'package'],
143
+ ['套餐', 'package'],
144
+ ['会员价', 'member'],
145
+ ['门市价', 'standard'],
146
+ ['时租', 'hourly'],
147
+ ['钟点', 'hourly'],
148
+ ['特惠', 'special'],
149
+ ];
150
+ const rateKindOf = (p) => {
151
+ const name = p.rateCodeName ?? '';
152
+ const said = RATE_KIND.find(([word]) => name.includes(word))?.[1];
153
+ return said ?? (p.checkinType === 'HOUR' ? 'hourly' : undefined);
154
+ };
132
155
  /** Huazhu's bed names as codes; another is `other`, with its own word. */
133
156
  const BED_KIND = { 大床: 'king', 双床: 'twin', 单人床: 'single' };
134
157
  const bedTypesOf = (rt) => (rt?.bedTypeList ?? [])
@@ -457,7 +480,11 @@ export const createHuazhuHotels = (opts) => {
457
480
  const ariTtl = opts.ariTtlMs ?? 60_000;
458
481
  const productsTtl = opts.productsTtlMs ?? 10 * 60_000;
459
482
  const allowTags = new Set(opts.allowTags ?? []);
460
- const view = { language: opts.language, tz: opts.tz };
483
+ const view = {
484
+ language: opts.language,
485
+ tz: opts.tz,
486
+ ...(opts.testEnvironment ? { test: true } : {}),
487
+ };
461
488
  const en = opts.language === 'en';
462
489
  /** A room type's name in the connector's language - see english.ts. */
463
490
  const roomTypeOf = (p) => (en ? roomNameEn(p.roomTypeName) : undefined) ?? p.roomTypeName;
@@ -568,7 +595,7 @@ export const createHuazhuHotels = (opts) => {
568
595
  /** A hotel's own name in each language Huazhu writes it in - beside every `hotelName`. */
569
596
  const hotelNamesOf = (hotelId) => {
570
597
  const raw = findHotel(hotelId);
571
- return raw ? namesOf(raw).name : undefined;
598
+ return raw ? namesOf(raw, !!opts.testEnvironment).name : undefined;
572
599
  };
573
600
  /**
574
601
  * Every hotel a name could be - the ones `findHotel` will not choose
@@ -928,7 +955,11 @@ export const createHuazhuHotels = (opts) => {
928
955
  ...(bedTypesOf(rt).length ? { bedTypes: bedTypesOf(rt) } : {}),
929
956
  roomsLeft: s.roomsLeft,
930
957
  roomType: { id: p.product.roomTypeCode, name: roomTypeOf(p.product) },
931
- rate: { id: p.product.rateCode, name: rateNameOf(p.product) },
958
+ rate: {
959
+ id: p.product.rateCode,
960
+ name: rateNameOf(p.product),
961
+ ...(rateKindOf(p.product) ? { kind: rateKindOf(p.product) } : {}),
962
+ },
932
963
  labels: rateLabels(p.product, { type: s.mealType, count: s.mealCount }),
933
964
  // ⚠️ PREPAID ONLY WHERE THIS DEPLOYMENT TAKES PAYMENT - a sandbox's test
934
965
  // mode (`opts.prepaid`); everywhere else `sell` leaves prepaid rates out
@@ -1140,7 +1171,9 @@ export const createHuazhuHotels = (opts) => {
1140
1171
  kind: 'room',
1141
1172
  hotelId: h.hotelId,
1142
1173
  hotelName,
1143
- ...(namesOf(h).name ? { hotelNames: namesOf(h).name } : {}),
1174
+ ...(namesOf(h, !!opts.testEnvironment).name
1175
+ ? { hotelNames: namesOf(h, !!opts.testEnvironment).name }
1176
+ : {}),
1144
1177
  roomRef: room.id,
1145
1178
  title: room.name,
1146
1179
  detail: [
@@ -1154,6 +1187,16 @@ export const createHuazhuHotels = (opts) => {
1154
1187
  // The same as codes, for a card in another language: each of the
1155
1188
  // detail's parts - beds · window · meals · hours (`hourly`) - so the
1156
1189
  // card can say all of it, not some (香格里拉, 2026-10-14).
1190
+ // The rate part of the title - "门市价含早" of "高级大床房 · 门市价含早"
1191
+ // - and what kind of rate it is, for a card in another language.
1192
+ ...(room.rate
1193
+ ? {
1194
+ rate: {
1195
+ name: room.rate.name,
1196
+ ...(room.rate.kind ? { kind: room.rate.kind } : {}),
1197
+ },
1198
+ }
1199
+ : {}),
1157
1200
  ...(room.bedTypes?.length ? { bedTypes: room.bedTypes } : {}),
1158
1201
  ...(room.window ? { window: room.window } : {}),
1159
1202
  ...(room.meal ? { meal: room.meal } : {}),
@@ -1587,7 +1630,8 @@ export const createHuazhuHotels = (opts) => {
1587
1630
  const tries = (p.refund?.tries ?? 0) + 1;
1588
1631
  const at = p.refund?.at ?? now();
1589
1632
  try {
1590
- const r = await checkout.refund(p.sessionId, reason);
1633
+ // Named by when it was decided: the same refund retried is the same refund.
1634
+ const r = await checkout.refund(p.sessionId, reason, `${row.distributorResId}-${at}`);
1591
1635
  store.update(id, {
1592
1636
  prepaid: { ...p, refund: { reason, at, requestId: r.requestId, status: r.status, tries } },
1593
1637
  });
@@ -1603,6 +1647,7 @@ export const createHuazhuHotels = (opts) => {
1603
1647
  }
1604
1648
  };
1605
1649
  /** Whether a booking paid in advance still has money work to do. */
1650
+ let ticking = false;
1606
1651
  const moneyPending = (b) => {
1607
1652
  const p = b.prepaid;
1608
1653
  if (!p)
@@ -1611,6 +1656,9 @@ export const createHuazhuHotels = (opts) => {
1611
1656
  return true;
1612
1657
  if (!p.paidAt)
1613
1658
  return false;
1659
+ // Booked: Huazhu's order number still to be written onto the payment, once.
1660
+ if (b.status === 'confirmed' && b.resId && !p.noted && !p.refund && checkout?.annotate)
1661
+ return true;
1614
1662
  if (!p.refund?.requestId)
1615
1663
  return !!p.refund || b.status === 'failed' || b.status === 'unconfirmed';
1616
1664
  return !['refunded', 'failed', 'rejected'].includes(p.refund.status ?? '');
@@ -1642,6 +1690,36 @@ export const createHuazhuHotels = (opts) => {
1642
1690
  return; // asked again on the next pass
1643
1691
  }
1644
1692
  if (state === 'paid') {
1693
+ // ⚠️ THE MONEY HELD TO THE QUOTE BEFORE ANYTHING IS BOOKED (总线程,
1694
+ // 2026-10-15): what the page took, to the fen and in the currency,
1695
+ // is the total the guest was shown. A page paid for anything else
1696
+ // books nothing, and all of what it took goes back.
1697
+ let took;
1698
+ try {
1699
+ took = await checkout.paidAmount(p.sessionId);
1700
+ }
1701
+ catch {
1702
+ return; // asked again on the next pass
1703
+ }
1704
+ const want = row.quote.total;
1705
+ if (!took || took.amountMinor !== want.minor || took.currency !== want.currency) {
1706
+ const said = took ? `${took.amountMinor} ${took.currency}` : 'an amount it could not say';
1707
+ store.update(row.id, {
1708
+ status: 'failed',
1709
+ prepaid: {
1710
+ ...p,
1711
+ paidAt: now(),
1712
+ url: undefined,
1713
+ refund: {
1714
+ reason: `the payment page took ${said}, not the ${want.minor} ${want.currency} quoted - nothing was booked`,
1715
+ at: now(),
1716
+ tries: 0,
1717
+ },
1718
+ },
1719
+ });
1720
+ console.error(`[huazhu prepaid ${row.id}] ⚠️ paid ${said} against ${want.minor} ${want.currency} quoted: not booked, refunding`);
1721
+ return;
1722
+ }
1645
1723
  store.update(row.id, { prepaid: { ...p, paidAt: now(), url: undefined } });
1646
1724
  await bookPaid(row.id);
1647
1725
  }
@@ -1655,6 +1733,22 @@ export const createHuazhuHotels = (opts) => {
1655
1733
  }
1656
1734
  if (!p.paidAt)
1657
1735
  return;
1736
+ // ⚠️ HUAZHU'S ORDER NUMBER ON THE PAYMENT, ONCE (总线程, 2026-10-15), so
1737
+ // Stripe's dashboard and Huazhu's order are one look apart. Tried once:
1738
+ // a failure is said in the log and never touches the booking.
1739
+ if (row.status === 'confirmed' && row.resId && !p.noted && !p.refund && checkout.annotate) {
1740
+ store.update(row.id, { prepaid: { ...p, noted: now() } });
1741
+ try {
1742
+ await checkout.annotate(p.sessionId ?? '', {
1743
+ huazhu_res_id: row.resId,
1744
+ ...(row.resCode ? { huazhu_res_code: row.resCode } : {}),
1745
+ });
1746
+ }
1747
+ catch (err) {
1748
+ console.error(`[huazhu prepaid ${row.id}] Huazhu's order ${row.resId} could not be written onto payment ${p.sessionId}: ${err.message}`);
1749
+ }
1750
+ return;
1751
+ }
1658
1752
  if (!p.refund?.requestId &&
1659
1753
  (p.refund || row.status === 'failed' || row.status === 'unconfirmed')) {
1660
1754
  await refundOf(row.id, p.refund?.reason ??
@@ -1707,7 +1801,9 @@ export const createHuazhuHotels = (opts) => {
1707
1801
  failed.push({
1708
1802
  hotelId: line.hotelId,
1709
1803
  hotelName: named?.hotel ?? (raw ? toHotel(raw, view, now()).name : line.hotelId),
1710
- ...(raw && namesOf(raw).name ? { hotelNames: namesOf(raw).name } : {}),
1804
+ ...(raw && namesOf(raw, !!opts.testEnvironment).name
1805
+ ? { hotelNames: namesOf(raw, !!opts.testEnvironment).name }
1806
+ : {}),
1711
1807
  stay: line.stay,
1712
1808
  ...(line.hourly ? { hourly: line.hourly } : {}),
1713
1809
  ...(named?.room ? { roomName: named.room } : {}),
@@ -1857,6 +1953,7 @@ export const createHuazhuHotels = (opts) => {
1857
1953
  try {
1858
1954
  opened = await checkout.open({
1859
1955
  ref: dres,
1956
+ code: row.confirmationCode,
1860
1957
  title: `${plan.qline.hotelName} · ${plan.qline.title}`.slice(0, 200),
1861
1958
  amountMinor: allIn,
1862
1959
  currency: cur,
@@ -2064,9 +2161,19 @@ export const createHuazhuHotels = (opts) => {
2064
2161
  * money going back.
2065
2162
  */
2066
2163
  async prepaidTick() {
2067
- for (const row of store.all())
2068
- if (moneyPending(row))
2069
- await settlePrepaid(row);
2164
+ // ⚠️ ONE PASS AT A TIME: a pass slower than the ten seconds between
2165
+ // them would otherwise book a paid stay, or give money back, twice.
2166
+ if (ticking)
2167
+ return;
2168
+ ticking = true;
2169
+ try {
2170
+ for (const row of store.all())
2171
+ if (moneyPending(row))
2172
+ await settlePrepaid(row);
2173
+ }
2174
+ finally {
2175
+ ticking = false;
2176
+ }
2070
2177
  },
2071
2178
  imageDomains() {
2072
2179
  const hosts = new Set();
@@ -2091,6 +2198,8 @@ export const createHuazhuHotels = (opts) => {
2091
2198
  const ceilingHitAt = store.ceilingHitAt;
2092
2199
  const ceiling = ceilingHitAt !== undefined && now() - ceilingHitAt < DAY_MS;
2093
2200
  return {
2201
+ // Which Huazhu this is, for whoever checks a deployment: its test system or not.
2202
+ ...(opts.testEnvironment ? { test: true } : {}),
2094
2203
  catalog: catalog.state(),
2095
2204
  bookings: rows.length,
2096
2205
  pending: rows.filter((r) => r.pendingSince !== undefined).length,
@@ -2466,7 +2575,7 @@ export const createHuazhuHotels = (opts) => {
2466
2575
  const name = hotel?.name ?? h.hotelName;
2467
2576
  // 全季酒店(北京国贸店) already says 北京 - as the demonstration's do.
2468
2577
  const city = hotel?.city && !name.includes(hotel.city) ? hotel.city : undefined;
2469
- const names = namesOf(h).name;
2578
+ const names = namesOf(h, !!opts.testEnvironment).name;
2470
2579
  return { id: h.hotelId, name, ...(city ? { city } : {}), ...(names ? { names } : {}) };
2471
2580
  });
2472
2581
  },